Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
// TODO: コミットを通すための暫定設定。PR 作成までにルールの上書き内容を調整する
"extends": ["../../../../markuplint.config.js"],
"rules": {
"class-naming": false,
"placeholder-label-option": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
.c-form-field {
display: block flow;
container: c-form-field / inline-size;
}

.c-form-field__grid {
display: grid;
grid-template:
'main' auto
'.' 0.5rem
'description' auto
'.' 0.5rem
'error-message' auto / minmax(0, 1fr);

> :where(.c-form-field__main) {
grid-area: main;
}

> :where(.c-form-field__description) {
grid-area: description;
}

> :where(.c-form-field__error-message) {
grid-area: error-message;
}
}

.c-form-field__main {
&:has(
.c-form-field__input > .c-form-input-text,
.c-form-field__input > .c-form-input-select
) {
display: flex;
flex-flow: row nowrap;
align-items: center;

@container (max-inline-size: 40ch) {
flex-direction: column;
align-items: start;
}

> :where(:not(:empty) + :not(:empty)) {
margin-inline-start: 0.5rem;

@container (max-inline-size: 40ch) {
margin-inline-start: 0;
}
}

> :where(.c-form-field__attachment-before, .c-form-field__attachment-after) {
flex-shrink: 0;
max-inline-size: calc(100% / 4);
}

> :where(.c-form-field__input) {
min-inline-size: 0;
max-inline-size: 100%;
}
}
}

.c-form-field__attachment-before {
/* 前見出しのスタイルを記述 */
}

.c-form-field__attachment-after {
/* 後見出しのスタイルを記述 */
}

.c-form-field__description {
/* 説明文のスタイルを記述 */
}

.c-form-field__error-message {
/* エラーメッセージのスタイルを記述 */
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//- isGrouped: 同一 fieldset/legend 内に複数フィールドを配置する場合に true。
親の見出し構造と一致させること(グループ化あり = fieldset/legend、なし = div/label)
.c-form-field__input の中身(cFormInputXxx の呼び出し)は呼び出し側が block で渡す
mixin cFormField(params = {})
-
const props = Object.assign({ type: "text", name: "", beforeAttachment: "", afterAttachment: "", description: "", errorMessage: "", isGrouped: false, isConfirm: false }, params);
const nameFirstLetterUppercased = props.name.charAt(0).toUpperCase() + props.name.slice(1);
const idInput = `MailMessage${nameFirstLetterUppercased}`;
const idField = `FieldMailMessage${nameFirstLetterUppercased}`;
// checkbox / radio は各選択肢が label を持つため、前後見出しは label にしない
const hasOwnOptionLabels = props.type === "checkbox" || props.type === "radio";
// CMS要件: グループ化している場合は 前見出し を labelとする。前見出しが空であれば 後見出しを labelとする
const isBeforeAttachmentLabel = Boolean(props.isGrouped && !hasOwnOptionLabels && props.beforeAttachment);
const isAfterAttachmentLabel = Boolean(props.isGrouped && !hasOwnOptionLabels && !props.beforeAttachment && props.afterAttachment);
.c-form-field(data-type=props.type id=idField)
.c-form-field__grid
.c-form-field__main
.c-form-field__attachment-before
if isBeforeAttachmentLabel
label(for=idInput) #{ props.beforeAttachment }
else if props.beforeAttachment
span #{ props.beforeAttachment }

.c-form-field__input
block

.c-form-field__attachment-after
if isAfterAttachmentLabel
label(for=idInput) #{ props.afterAttachment }
else if props.afterAttachment
span #{ props.afterAttachment }

if !props.isConfirm
.c-form-field__description
span #{ props.description }
.c-form-field__error-message
span #{ props.errorMessage }
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.c-form-fieldset {
display: block flow;
}

.c-form-fieldset__grid {
display: grid;
grid-template:
'heading' auto
'.' 0.5rem
'attention' auto
'.' 0.5rem
'field' auto
/ 1fr auto;

> :where(.c-form-fieldset__heading) {
grid-area: heading;
}

> :where(.c-form-fieldset__attention) {
grid-area: attention;
}

> :where(.c-form-fieldset__field) {
grid-area: field;
}
}

.c-form-fieldset__heading {
> :where(*) {
display: inline flow;
}

> :where(:not(:first-child)) {
margin-inline: 0.5rem 0;
}
}

.c-form-fieldset__field {
> :where(:not(:first-child)) {
margin-block-start: 1rem;
}
}

.c-form-fieldset__heading-main {
&:where(label) {
cursor: pointer;
}
}

.c-form-fieldset__heading-badge {
/* 必須・任意バッジのスタイルを記述 */

&:where([data-kind='required']) {
/* 必須バッジのスタイルを記述 */
}

&:where([data-kind='optional']) {
/* 任意バッジのスタイルを記述 */
}
}

.c-form-fieldset__attention {
/* 注意書きのスタイルを記述 */
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//- name/key のどちらを渡すかで fieldset/legend(isGrouped)か div/label かを自動判定する:
- name: 単一 input に label-for で紐付けられる場合(text/select/textarea/file の単一フィールド)
- key: 単一 input に紐付けられない場合(複数フィールドをまとめる、または checkbox/radio は
CMS要件により単一フィールドでも fieldset/legend にする)を、意味のわかる短い語で渡す
mixin cFormFieldset(params = {})
-
const props = Object.assign({ heading: "", name: null, key: null, isRequired: false, attention: "" }, params);
const badgeKind = props.isRequired ? "required" : "optional";
const badgeLabel = props.isRequired ? "必須" : "任意";
const isGrouped = Boolean(props.key);
// c-form-field.pug の idInput と同じ計算式(name/key から MailMessage+PascalCase のidを導出)
const toPascalCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
const groupSource = props.key || props.name;
const id = groupSource ? `GroupMailMessage${toPascalCase(groupSource)}` : null;
const labelFor = !isGrouped && props.name ? `MailMessage${toPascalCase(props.name)}` : null;
.c-form-fieldset(id=id)
if isGrouped
fieldset.c-form-fieldset__grid
legend.c-form-fieldset__heading
span.c-form-fieldset__heading-main #{ props.heading }
span.c-form-fieldset__heading-badge(data-kind=badgeKind) #{ badgeLabel }
.c-form-fieldset__attention
span #{ props.attention }
.c-form-fieldset__field
block
else
.c-form-fieldset__grid
.c-form-fieldset__heading
if labelFor
label.c-form-fieldset__heading-main(for=labelFor) #{ props.heading }
else
span.c-form-fieldset__heading-main #{ props.heading }
span.c-form-fieldset__heading-badge(data-kind=badgeKind) #{ badgeLabel }
.c-form-fieldset__attention
span #{ props.attention }
.c-form-fieldset__field
block
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* stylelint-disable-next-line @d-zero/component */
.c-form-input-confirm-text {
display: block flow;
}

/* stylelint-disable-next-line @d-zero/component */
.c-form-input-confirm-multi {
display: block flow;

:where(ul li) {
list-style: disc;
}
}

/* stylelint-disable-next-line @d-zero/component */
.c-form-input-confirm-textarea {
display: block flow;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
mixin cFormInputConfirmText(params = {})
-
const props = Object.assign({ value: "__入力内容__" }, params);
.c-form-input-confirm-text
span #{ props.value }

mixin cFormInputConfirmMulti(params = {})
-
const props = Object.assign({ value: ["__選択項目1__", "__選択項目2__"] }, params);
.c-form-input-confirm-multi
ul
each value in props.value
li #{ value }

mixin cFormInputConfirmTextarea(params = {})
-
const props = Object.assign({ value: "__選択項目__" }, params);
.c-form-input-confirm-textarea
p #{ props.value }
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* stylelint-disable-next-line @d-zero/component */
.c-form-input-text {
max-inline-size: 100%;

&:not([size]) {
inline-size: 100%;
}
}

/* stylelint-disable-next-line @d-zero/component */
.c-form-input-select {
padding-block: 0.5rem;
padding-inline: 0.5rem calc(0.5rem + 24px + 2px);
appearance: none;
background-image: url('/img/bg-arrow.svg');
background-repeat: no-repeat;
background-position: right calc(0.2rem + 2px) top calc(100% / 2 + 2px);
border: 1px solid var(--border-color);
border-radius: 0.2rem;
}

/* stylelint-disable-next-line @d-zero/component */
.c-form-input-checkbox {
/* チェックボックスのスタイルを記述 */
}

/* stylelint-disable-next-line @d-zero/component */
.c-form-input-radio {
/* ラジオボタンのスタイルを記述 */
}

/* stylelint-disable-next-line @d-zero/component */
.c-form-input-textarea {
&:not([cols]) {
inline-size: 100%;
}
}

/* stylelint-disable-next-line @d-zero/component */
.c-form-input-file {
/* ファイル選択のスタイルを記述 */
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
mixin cFormInputText(params = {})
-
const props = Object.assign({ name: "field1", maxlength: null, size: null, isRequired: true }, params);
const inputName = `data[MailMessage][${props.name}]`;
const idInput = `MailMessage${props.name.charAt(0).toUpperCase() + props.name.slice(1)}`;
input.c-form-input-text(
type="text"
name=inputName
maxlength=props.maxlength
size=props.size
required=props.isRequired
id=idInput)

mixin cFormInputSelect(params = {})
-
const props = Object.assign({ name: "address1", options: [{value: "", label: "選択してください"}], isRequired: true }, params);
const inputName = `data[MailMessage][${props.name}]`;
const idInput = `MailMessage${props.name.charAt(0).toUpperCase() + props.name.slice(1)}`;
select.c-form-input-select(name=inputName required=props.isRequired id=idInput)
each option in props.options
option(value=option.value)= option.label

//- checkbox には required を出力しない(各 input に付くと「全項目チェック必須」の挙動になるため。
「1つ以上選択必須」の検証はサーバー側の責務)
mixin cFormInputCheckbox(params = {})
-
const props = Object.assign({ name: "category", options: [{value: "Item1", label: "項目1"}] }, params);
const idInput = `MailMessage${props.name.charAt(0).toUpperCase() + props.name.slice(1)}`;
const hiddenName = `data[MailMessage][${props.name}]`;
const inputName = `data[MailMessage][${props.name}][]`;
//- 未選択時にもキーが送信されるようにするための hidden(CMS 仕様)
.c-form-input-checkbox
input.c-form-input-checkbox__hidden(type="hidden" name=hiddenName value id=idInput)
each option in props.options
-
const id = idInput + option.value;
.c-form-input-checkbox__item
input(type="checkbox" name=inputName value=option.value id=id)
label(for=id) #{ option.label }

mixin cFormInputRadio(params = {})
-
const props = Object.assign({ name: "sex", options: [{value: "1", label: "男性"}, {value: "2", label: "女性"}], isRequired: true }, params);
const idInput = `MailMessage${props.name.charAt(0).toUpperCase() + props.name.slice(1)}`;
const inputName = `data[MailMessage][${props.name}]`;
const idHidden = `${idInput}_`;
//- 未選択時にもキーが送信されるようにするための hidden(CMS 仕様)
.c-form-input-radio
input.c-form-input-radio__hidden(type="hidden" name=inputName value id=idHidden)
each option in props.options
-
const id = idInput + option.value;
.c-form-input-radio__item
span
input(type="radio" name=inputName required=props.isRequired value=option.value id=id)
label(for=id) #{ option.label }

mixin cFormInputTextarea(params = {})
-
const props = Object.assign({ name: "message", rows: null, cols: null, isRequired: true }, params);
const inputName = `data[MailMessage][${props.name}]`;
const idInput = `MailMessage${props.name.charAt(0).toUpperCase() + props.name.slice(1)}`;
textarea.c-form-input-textarea(
name=inputName
rows=props.rows
cols=props.cols
required=props.isRequired
id=idInput)

mixin cFormInputFile(params = {})
-
const props = Object.assign({ name: "file", isRequired: true }, params);
const inputName = `data[MailMessage][${props.name}]`;
const idInput = `MailMessage${props.name.charAt(0).toUpperCase() + props.name.slice(1)}`;
input.c-form-input-file(name=inputName type="file" required=props.isRequired id=idInput)
Loading