Skip to content

feat(scaffold): add v2 mail form templates with reusable c-form-* components - #952

Open
yusasa16 wants to merge 17 commits into
v6from
refactor/form-template-redesign
Open

feat(scaffold): add v2 mail form templates with reusable c-form-* components#952
yusasa16 wants to merge 17 commits into
v6from
refactor/form-template-redesign

Conversation

@yusasa16

@yusasa16 yusasa16 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

メールフォームのテンプレート(入力・確認ページ)を、再利用可能な c-form-* コンポーネント群で組み直した新デザイン版(v2)として追加する。

現行のテンプレートは CMS が要求するマークアップをページ内に直書きしており、項目の追加や構造の変更のたびに同じパターンを手で複製する必要がある。v2 では CMS が参照する id / name / label の紐付けや fieldset / legend 構造をそのまま保ちつつ、見た目のマークアップと配置責任をコンポーネントに分離する。既存プロジェクトへの影響を避けるため、現行テンプレートは変更せず並行運用とする。

構成

コンポーネント 役割
c-form フォーム全体のラッパー(CSS のみ)。__field-list / __agreement / __submit の 3 スロットを持つ
c-form-fieldset 項目グループ。見出し、必須/任意バッジ、注意書き、フィールド群のスロット
c-form-field 1 入力の枡。前後見出し、入力スロット、説明文、エラーメッセージ
c-form-input-{text,textarea,select,checkbox,radio,file} 入力要素本体
c-form-input-confirm-{text,textarea,multi} 確認ページの値表示
  • 各コンポーネントは __assets/_libs/component/.pug(mixin)と .css を 1 セットで置き、CSS は htdocs/css/style.csslayer(component) に登録する
  • mixin はすべて params = {} を受け取り、Object.assign で既定値を埋める。.c-form-field__input などスロットの中身は呼び出し側が block で渡す
  • 配置責任は親のスロット(__element)が持ち、子コンポーネントは内部スタイルのみを持つ。コンポーネント間の余白やグリッド配置を子に持たせない

設計上の判断

  • id / name / for は呼び出し側が明示的に渡す: CMS が出力する id / name は命名規則から機械的に導出できないため、mixin 内で生成せずテンプレート側で実値を指定する
  • c-form-fieldsetisGrouped: truefieldset / legend 構造、false で div 構造になる。false のとき for を渡すと見出しが label[for]、渡さなければ span になる。checkbox / radio は単体でも fieldset / legend にする(CMS 要件)
  • c-form-fieldfor を渡すと前見出しが label[for] になり、前見出しが空なら後見出しが label[for] になる(CMS 要件)。isConfirm: true で説明文とエラーメッセージ欄を省く
  • checkbox / radio は未選択時にもキーが送信されるよう hidden input を先頭に出力する(CMS 仕様)。checkbox には required を付けない。各 input に付くと「全項目チェック必須」の挙動になるため、「1 つ以上選択」の検証はサーバー側の責務とする。radio の hidden は各 radio と同じ name を共有するため hiddenId のみ受け取る
  • c-content-main 内に c- コンポーネントを置く: コーディングガイドラインではメインコンテンツ内で c- 接頭辞を使わないが、フォームは CMS 出力と密結合した独立部品としてコンポーネント化する方が保守しやすいため、例外として採用する
  • 選択肢データの分離: 都道府県と生まれ年の option 一覧を _libs/data/data.ymlprefectureOptions / birthYearOptions)に置き、テンプレートから参照する

テンプレート

  • 300_form_input_v2.pug / 301_form_confirm_v2.pug を追加し、__tmpl/index.pug に「(新デザイン)」として登録
  • 300_form_input.pug / 301_form_confirm.pug は変更なし。302_form_complete.pug は対象外

lint 設定

  • markuplint.config.js の overrides
    • c-form-input-select.pug: options が動的で静的解析できないため placeholder-label-option を無効化。プレースホルダーの option は呼び出し側が先頭に渡す
    • __tmpl/*_v2.pug: 基底設定は c-content-main 配下の c- 接頭辞を禁止しているため、form.c-form に限り許可する。入れ子のコンポーネントは c-form 配下として扱われるため追加の許可は不要
  • .stylelintrc: at-rule-prelude-no-invalid / declaration-property-value-no-unknown を暫定的に無効化。css-tree の依存解決が揃っていない環境で cursor@container など正当な CSS に対して例外で異常終了するため(stylelint が正当な CSS(cursor / @container)で Bad syntax reference 例外を投げ、CSS を含むコミットができない #1040)。依存が揃った時点で戻す

Closes #897

Test plan

  • yarn workspace @d-zero/scaffold build:only300_form_input_v2.pug / 301_form_confirm_v2.pug / css/style.css のビルドが通る
  • 現行テンプレートと v2 のビルド出力を比較し、id / name / label[for] のセット、および fieldset / legend / label / required / data-type の個数が一致する
  • scaffold の lint:html / lint:css / lint:format / lint:spell / lint:js / lint:pug が通る(stylelint の警告・エラーは本 PR の対象外ファイル由来)
  • コンポーネント CSS はレイアウト骨格のみ。バッジ、注意書き、余白値などの装飾はデザイン確定後に調整する
  • c-form のラッパーを pug mixin 化するか検討する(mixin 化すれば *_v2.pug の markuplint override は不要になる)
  • 依存解決が揃ったら .stylelintrc の 2 ルール無効化を戻す(stylelint が正当な CSS(cursor / @container)で Bad syntax reference 例外を投げ、CSS を含むコミットができない #1040

🤖 Generated with Claude Code

yusasa16 and others added 8 commits July 21, 2026 19:45
- extract .mail-field markup from 300_form_input.pug into mail-field.pug mixins
- render label/span attachments per CMS grouping rules with checkbox/radio exceptions
- output hidden inputs for checkbox/radio groups to keep unchecked keys submitted
- move prefecture and birth-year options to data.yml
- add tentative markuplint overrides for the form component directory

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…onent

- extract .cc-form-fieldset markup from 300_form_input.pug into cc-form-fieldset.pug
- render fieldset/legend or div/label structure via isGrouped, with field content
  injected through a pug block
- replace ambiguous badge string prop with an isRequired boolean, normalizing the
  previously badge-less tel field to show the optional badge

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- add mail-field-confirm.pug with a mailFieldConfirm mixin mirroring mail-field.pug's
  type dispatch, for the confirm page's static placeholder markup (no id, label
  switching, description, or error-message needed there)
- let ccFormFieldset fall back to a plain span heading when labelFor is omitted, so
  the confirm page (no focusable input to label) can reuse it with isGrouped: false
- replace the 14 repeated .cc-form-fieldset blocks in 301_form_confirm.pug with
  ccFormFieldset + mailFieldConfirm calls, keeping the confirm page's existing
  (sometimes blank) attachment text and attention as-is
- normalize checkbox/radio fields to always render both attachment spans, and always
  show the required/optional badge, matching ccFormFieldset's existing behavior

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace ccFormFieldset's id/isGrouped/labelFor props with name (single
field) and key (grouped field): the wrapper id, label-for target, and
fieldset/legend vs div/label structure are now all computed from
whichever one is passed, instead of being hand-typed per call site.

Also drop the now-meaningless isGrouped from mailField calls for
checkbox/radio inputs, since their own option labels make it a no-op.
Turn mail-field's span.mail-input into a block so the caller composes
the concrete mailInputXxx mixin instead of mailField dispatching on a
nested input.type config object. This drops the now-dead isRequired
passthrough and moves mailInputText/Select/Checkbox/Radio/Textarea/File
into their own mail-input.pug, each deriving its own id from name
instead of receiving it from mail-field.
Align mail-field/mail-input/cc-form-fieldset mixins with the c- prefixed
BEM naming used by other components, and split the 301 confirm-screen
placeholder markup into its own c-form-input-confirm component.
Restore 300_form_input.pug, 301_form_confirm.pug, and the related
c-content-main.css fieldset styles to their pre-redesign state so the
new component-based design can be added as a separate template
instead of overwriting the original.
Add 300_form_input_v2.pug and 301_form_confirm_v2.pug using the new
c-form-fieldset/c-form-field/c-form-input component set, kept as
separate templates alongside the originals. List them in the template
index.
@yusasa16 yusasa16 changed the title Refactor/form template redesign feat(scaffold): add v2 mail form templates with reusable c-form-* components Jul 21, 2026
yusasa16 and others added 5 commits July 27, 2026 10:30
Remove the PascalCase id/name derivation from the c-form mixins and
hardcode the actual CMS values at the call sites, since the real CMS
output uses irregular ids and names that cannot be derived by rule:

- c-form-input: accept id and full name strings, add hiddenId and
  per-option ids for checkbox/radio, default isRequired to false
- c-form-field: replace name-derived ids with id/for props, decide
  attachment label vs span by presence of for, drop isGrouped
- c-form-fieldset: rename heading to label, add id/for/isGrouped
  props, remove name/key based derivation
- 300_form_input_v2: hardcode id/name/for values transcribed from
  the v1 reference template
- 301_form_confirm_v2: rename heading to label, drop dead value
  params, omit ids to fix the duplicated FieldMailMessage id

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
stylelint 17.4.0 resolves @csstools/css-syntax-patches-for-csstree to 1.1.5,
whose syntax data requires css-tree ^3.2.1 as a peer dependency, while css-tree
stays pinned at 3.1.0 by @d-zero/csstree-scss-syntax, @d-zero/stylelint-rules,
and @markuplint/types. With this combination declaration-property-value-no-unknown
and at-rule-prelude-no-invalid throw "Bad syntax reference" on valid css such as
cursor and @container, aborting every commit that stages css files. Disable the
two rules until the dependency resolutions are aligned.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r file

- move c-form components from _libs/component/form/ up to _libs/component/ to match
  the flat one-component-per-file layout
- split c-form-input.pug/.css into per-component files (text, select, checkbox,
  radio, textarea, file) and c-form-input-confirm.pug/.css into text, multi, textarea
- update the includes in the v2 templates and the @import entries in style.css
- replace the form-scoped .markuplintrc with an override in markuplint.config.js
  limited to c-form-input-select.pug (the class-naming override is no longer needed)
- drop the stylelint-disable comments for @d-zero/component now that each css file
  contains a single component

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…EM elements

Replace the legacy cc-form classes in the v2 mail form templates with a
c-form component: `.cc-form` becomes `.c-form`, and `.cc-form-field-list`,
`.cc-form-agreement`, `.cc-form-submit` become `c-form__field-list`,
`c-form__agreement`, `c-form__submit`. Add c-form.css as a component-layer
stylesheet and register it in style.css. Leave `.cc-form-description` and
the v1 templates untouched.

Add a markuplint override scoped to `*_v2.pug` that allows `form.c-form`
inside `.c-content-main`, since the base config forbids `c-` prefixed
classes there; the v2 form deliberately places the component in main
content.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@yusasa16 yusasa16 self-assigned this Sep 7, 2026
yusasa16 and others added 2 commits September 7, 2026 13:34
Port the visual rules of cc-form.css to the c-form-* component stylesheets so the
v2 mail form templates render the same as the v1 templates:

- c-form: give each item in the field-list slot the 1rem/2rem padding that the v1
  fieldset carried; drop the extra agreement/submit margins and submit flex layout
- c-form-fieldset: flex heading with 18/16rem bold text, badge and attention
  typography, 1rem gap before the field slot, 1rem bottom padding and a bottom
  border on the last field; hide the attention slot when it is empty
- c-form-field: remove the container query and the 0.5rem grid gap rows, place
  attachments with 1rem margins, let the input slot grow, bold before-attachment,
  12/16rem description and error text
- c-form-input-*: 1px border, 0.2rem radius and 0.5rem inline padding on text,
  textarea and file inputs; flex item layout for checkbox and radio options

Also align 300_form_input_v2.pug with the v1 markup by dropping the size attribute
on the email input and the after-attachment on the contents checkbox field.

Fieldset/legend resets and font inheritance for form controls come from kiso.css,
so they are not repeated here.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Select the horizontal before/input/after layout of `.c-form-field__main` by the
field's `data-type` (text or select) instead of the input component class inside
the slot. This matches the v1 rule, which keys on `data-type`, so the confirm page
values rendered by `c-form-input-confirm-text` line up horizontally as well, while
radio and file fields stay stacked. It also removes the dependency of c-form-field
on the c-form-input-* class names, and `:where()` keeps the specificity at that of
`.c-form-field__main` alone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@yusasa16
yusasa16 marked this pull request as ready for review September 7, 2026 07:05
…redesign

# Conflicts:
#	packages/@d-zero/scaffold/__assets/_libs/data/data.yml
#	packages/@d-zero/scaffold/__assets/htdocs/css/style.css
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant