eslint-plugin-smarthr 4.0.2 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [6.0.0](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v5.0.0...eslint-plugin-smarthr-v6.0.0) (2026-01-28)
6
+
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ * **a11y-delegate-element-has-role-presentation:** ルールを削除します ([#1015](https://github.com/kufu/tamatebako/issues/1015))
11
+
12
+ ### Features
13
+
14
+ * **a11y-delegate-element-has-role-presentation:** ルールを削除します ([#1015](https://github.com/kufu/tamatebako/issues/1015)) ([4c5c7ab](https://github.com/kufu/tamatebako/commit/4c5c7ab43ab7a52f749963aa7b7cb359e6f623d5))
15
+ * best-practice-for-interactive-elementを追加 ([#1014](https://github.com/kufu/tamatebako/issues/1014)) ([e0a171b](https://github.com/kufu/tamatebako/commit/e0a171b056d8dbe775e3697633136e60c84afe5d))
16
+
17
+ ## [5.0.0](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v4.0.2...eslint-plugin-smarthr-v5.0.0) (2026-01-08)
18
+
19
+
20
+ ### ⚠ BREAKING CHANGES
21
+
22
+ * **best-practice-for-spread-syntax:** best-practice-for-spread-syntaxのチェック対象をObject内のスプレッド構文に広げ、autofixするように修正 ([#1009](https://github.com/kufu/tamatebako/issues/1009))
23
+
24
+ ### Features
25
+
26
+ * **best-practice-for-spread-syntax:** best-practice-for-spread-syntaxのチェック対象をObject内のスプレッド構文に広げ、autofixするように修正 ([#1009](https://github.com/kufu/tamatebako/issues/1009)) ([d334970](https://github.com/kufu/tamatebako/commit/d33497002710301b738f7e16382540a5ba35d36f))
27
+
5
28
  ## [4.0.2](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v4.0.1...eslint-plugin-smarthr-v4.0.2) (2026-01-07)
6
29
 
7
30
 
package/README.md CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  - [a11y-anchor-has-href-attribute](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/a11y-anchor-has-href-attribute)
4
4
  - [a11y-clickable-element-has-text](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/a11y-clickable-element-has-text)
5
- - [a11y-delegate-element-has-role-presentation](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/a11y-delegate-element-has-role-presentation)
6
5
  - [a11y-form-control-in-form](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/a11y-form-control-in-form)
7
6
  - [a11y-heading-in-sectioning-content](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/a11y-heading-in-sectioning-content)
8
7
  - [a11y-help-link-with-support-href](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/a11y-help-link-with-support-href)
@@ -19,19 +18,20 @@
19
18
  - [best-practice-for-button-element](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-button-element)
20
19
  - [best-practice-for-data-test-attribute](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-data-test-attribute)
21
20
  - [best-practice-for-date](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-date)
21
+ - [best-practice-for-interactive-element](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-interactive-element)
22
22
  - [best-practice-for-layouts](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-layouts)
23
23
  - [best-practice-for-nested-attributes-array-index](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-nested-attributes-array-index)
24
24
  - [best-practice-for-optional-chaining](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-optional-chaining)
25
25
  - [best-practice-for-prohibit-import-smarthr-ui-local](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-prohibit-import-smarthr-ui-local)
26
26
  - [best-practice-for-remote-trigger-dialog](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-remote-trigger-dialog)
27
27
  - [best-practice-for-rest-parameters](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-rest-parameters)
28
+ - [best-practice-for-spread-syntax](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-spread-syntax)
28
29
  - [best-practice-for-tailwind-prohibit-root-margin](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-tailwind-prohibit-root-margin)
29
30
  - [best-practice-for-tailwind-variants](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-tailwind-variants)
30
31
  - [best-practice-for-unnesessary-early-return](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-unnesessary-early-return)
31
32
  - [design-system-guideline-prohibit-double-icons](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/design-system-guideline-prohibit-double-icons)
32
33
  - [format-import-path](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/format-import-path)
33
34
  - [format-translate-component](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/format-translate-component)
34
- - [best-practice-for-spread-syntax](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-spread-syntax)
35
35
  - [no-import-other-domain](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/no-import-other-domain)
36
36
  - [prohibit-export-array-type](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/prohibit-export-array-type)
37
37
  - [prohibit-file-name](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/prohibit-file-name)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-smarthr",
3
- "version": "4.0.2",
3
+ "version": "6.0.0",
4
4
  "author": "SmartHR",
5
5
  "license": "MIT",
6
6
  "description": "A sharable ESLint plugin for SmartHR",
@@ -37,5 +37,5 @@
37
37
  "eslintplugin",
38
38
  "smarthr"
39
39
  ],
40
- "gitHead": "902835f740df61f2f9ce2c9bfeeff84788e0ed27"
40
+ "gitHead": "d9b333ac3b44127f7db54408dfa84ce49682a59e"
41
41
  }
@@ -1,14 +1,56 @@
1
1
  # smarthr/a11y-anchor-has-href-attribute
2
2
 
3
- - a, Anchor, Link コンポーネントに href 属性を設定することを促すルールです
4
- - href が設定されていないanchor要素は `遷移先が存在しない無効化されたリンク` という扱いになります
5
- - URLの変更を行わない場合、責務としても a より button が適切です
6
- - URL遷移を行う場合、hrefが設定されていないとキーボード操作やコンテキストメニューからの遷移ができなくなります
7
- - これらの操作は href属性を参照します
8
- - 無効化されたリンクであることを表したい場合 `href={undefined}` を設定してください
9
- - checkTypeオプションに 'allow-spread-attributes' を指定することで spread attributeが設定されている場合はcorrectに出来ます
10
- - react-router-dom packageを利用している場合、a要素にto属性が指定されている場合、href属性が指定されているものとして許容します
11
- - next/link コンポーネント直下のa要素にhref属性が指定されていないことを許容します
3
+ a, Anchor, Link コンポーネントに href 属性を設定することを促すルールです
4
+
5
+ ## なぜa要素にhref属性を設定するべきなのか
6
+
7
+ href属性が設定されていないa要素は**遷移先が存在しない無効化されたリンク**という扱いになります。
8
+ これはbutton要素で例えるなら**disalbed属性が設定された状態のbutton要素**と同等です。
9
+
10
+ またhref属性がないa要素ではtab移動の対象にならない・コンテキストメニュー(右クリックメニュー)から別タブで開く機能が使えない、などのデメリットが発生します。
11
+ これらの機能は **href属性が存在する == 有効なリンクである** ことから有効になります。
12
+
13
+ 逆説的に**設定したいhref属性が存在しない場合、a要素ではなくbutton要素を利用する**ように心がけてください。
14
+ a要素はあくまでURL遷移を表現するための要素であるため、それ以外の処理のトリガーとして利用するならばbutton要素のほうが適切です。
15
+
16
+ また**遷移先が存在しない無効化されたリンク**を表現したい場合、明示的に`href={undefined}`を設定することを推奨しています。
17
+
18
+ ## react-router, next/Linkを利用している場合
19
+
20
+ react-router, next/Linkを利用している場合、href属性と同等の機能を提供する別属性が存在するため、自動的にチェック方法が切り替わります。
21
+ 利用しているか否かの判定にはpackage.jsonが利用され、dependenciesに `react-router` もしくは `next` が存在するかどうかで判断されます。
22
+
23
+ ### react-routerを利用している場合
24
+
25
+ a要素にto属性が指定されている場合、href属性が指定されているものとして許容します。
26
+
27
+ ```jsx
28
+ // react-routerを利用している場合、かつto属性を設定しているためOK
29
+ <Link to={hoge}>any</Link>
30
+ ```
31
+
32
+ ### next/Linkを利用している場合
33
+
34
+
35
+ next/link コンポーネント直下のa要素にhref属性が指定されていないことを許容します。
36
+
37
+ ```jsx
38
+ // next/Linkを利用している場合、子のaにhref属性がなくてもOK
39
+ <Link href={hoge}><a>any</a></Link>
40
+ ```
41
+
42
+ ### spread-attributesが設定されているなら許容したい場合
43
+
44
+ 下記の様にspread attributesが設定されていれば、href属性が設定されている扱いにしたい場合、lintのoptionとして `checkType` に `allow-spread-attributes` を設定してください。
45
+
46
+ ```jsx
47
+ // checkType: 'allow-spread-attributes'
48
+ <XxxAnchor {...args} />
49
+ <XxxLink {...args} any="any" />
50
+ ```
51
+
52
+ 便利な設定ではありますが、**href属性が実際に設定されているかは判定出来ていないため、チェック漏れが発生する可能性があります。**
53
+ 設定される場合は慎重に検討してください。
12
54
 
13
55
  ## rules
14
56
 
@@ -26,12 +68,15 @@
26
68
  ## ❌ Incorrect
27
69
 
28
70
  ```jsx
71
+ // a要素と思われるコンポーネントにhref属性が設定されていないためNG
29
72
  <a>any</a>
30
73
  <XxxAnchor>any</XxxAnchor>
31
74
  <XxxLink>any</XxxLink>
32
75
  <XxxLink href>any</XxxLink>
76
+ ```
33
77
 
34
- // checkType: 'always'
78
+ ```jsx
79
+ // spread attributesでhref属性が含まれていてもデフォルト設定ではNGになる
35
80
  <XxxAnchor {...args} />
36
81
  <XxxLink {...args} any="any" />
37
82
  ```
@@ -39,17 +84,25 @@
39
84
  ## ✅ Correct
40
85
 
41
86
  ```jsx
87
+ // a要素と思われるコンポーネントにhref属性が設定されているのでOK
42
88
  <a href="https://www.google.com/search">any</a>
43
89
  <XxxAnchor href={hoge}>any</XxxAnchor>
44
90
  <XxxLink href={undefined}>any</XxxLink>
91
+ ```
45
92
 
46
- // nextを利用している場合
47
- <Link href={hoge}><a>any</a></Link>
48
-
49
- // react-router-domを利用している場合
93
+ ```jsx
94
+ // react-routerを利用している場合、かつto属性を設定しているためOK
50
95
  <Link to={hoge}>any</Link>
96
+ ```
51
97
 
52
- // checkType: 'allow-spread-attributes'
98
+ ```jsx
99
+ // next/Linkを利用している場合、子のaにhref属性がなくてもOK
100
+ <Link href={hoge}><a>any</a></Link>
101
+ ```
102
+
103
+ ```jsx
104
+ // checkType: 'allow-spread-attributes' を指定している場合、
105
+ // 仮にspread attributes内にhrefが含まれていなくてもOKになるため注意
53
106
  <XxxAnchor {...args} />
54
107
  <XxxLink {...args} any="any" />
55
108
  ```
@@ -1,11 +1,73 @@
1
1
  # smarthr/a11y-clickable-element-has-text
2
2
 
3
- - ButtonやAnchor,Link コンポーネントにテキスト要素が設定されていない場合、スクリーンリーダーで押したものが何だったのかわからない等の問題が発生する可能性を防ぐルールです
4
- - a要素やbutton要素の中身にtextがあることを担保するルール
5
- - 画像要素の場合は `visuallyHiddenText`や `alt`等代替テキストを設定する
6
- - SVGの場合はrole="img" と aria-labelを設定する
7
- - linkとかanchorのchildrenを含まない要素はチェックしない
8
- - 例) `<YyyAnchor />`
3
+ ButtonやAnchor,Link コンポーネントなどクリック可能(クリッカブル)な要素にテキストを設定することを促すルールです。
4
+
5
+ ## なぜクリッカブルな要素にテキストが必要なのか
6
+
7
+ スクリーンリーダーなどの一部のブラウザで**クリックした対象物が何であるか?という情報が欠落することを防ぐ**目的があります。
8
+ 閲覧可能なUI上では十分な情報が存在していても、テキスト読み上げなどでは情報が不足することがあるため、**クリックすることで起きる内容を説明する必要があります。**
9
+
10
+ ## 適切なテキストの設定方法について
11
+
12
+ 基本的にはchildrenにテキストを設定してください。
13
+
14
+ ```jsx
15
+ <button>アクション</button>
16
+ ```
17
+
18
+ 変数を設定した場合もテキストを設定したものとして扱われます
19
+
20
+ ```jsx
21
+ <AnyAnchor>{hoge}</AnyAnchor>
22
+ ```
23
+
24
+ ### 画像、もしくはそれに類する要素の場合
25
+
26
+ 画像要素の場合は `alt` 等、代替テキストを設定してください。
27
+
28
+ ```jsx
29
+ // 代替テキストを設定した画像を含むためOK
30
+ <AnyLink>
31
+ <XxxImage alt="fuga" />
32
+ </AnyLink>
33
+ ```
34
+
35
+ svg要素など、画像ではないが画像として扱いたい要素の場合、`role="img"` `aria-label="任意の文字列"` を指定することで**代替テキストが設定された画像**と同等に扱われるようになります。
36
+
37
+ ```jsx
38
+ // svgだが代替テキストを設定した画像として扱うためOK
39
+ <AnyButton>
40
+ <svg role="img" aria-label="HOGE">...</svg>
41
+ </AnyButton>
42
+ ```
43
+
44
+ ### 対象要素がそもそもテキストを内包している場合
45
+
46
+ a, button要素を拡張したコンポーネントがテキストを適切に内包している場合、childrenを設定しない状態で利用すればこのルールはcorrectとして扱います。
47
+
48
+ ```jsx
49
+ // childrenが存在しないため、コンポーネントがテキストを内包しているものとして扱うのでOK
50
+ <HogeAnchor />
51
+ ```
52
+
53
+ またchildrenにわたすコンポーネントがテキストを内包している場合、chilrenに渡すコンポーネントの名称のsuffixが `Text` になっていれば、correctとして扱われます。
54
+
55
+ ```jsx
56
+ // children内に XxxText 形式のコンポーネントが渡されているのでOK
57
+ <AnyLink>
58
+ <HogeText />
59
+ </AnyLink>
60
+ ```
61
+
62
+ childrenにわたすコンポーネントの名称を変更することが難しい場合、lintのoptionとして `componentsWithText` に配列として完全一致するコンポーネント名を設定すれば、そのコンポーネントはテキストを含むものとして扱われます。
63
+
64
+ ```jsx
65
+ // componentsWithText: ['Hoge'] を設定している場合
66
+ // Hogeコンポーネントはテキストを含むものとして扱われるのでOK
67
+ <XxxButton>
68
+ <Hoge />
69
+ </XxxButton>
70
+ ```
9
71
 
10
72
  ## rules
11
73
 
@@ -25,24 +87,16 @@
25
87
  ## ❌ Incorrect
26
88
 
27
89
  ```jsx
90
+ // テキストとみなされるものがchildrenに存在しないためNG
28
91
  <XxxAnchor>
29
92
  <Xxx />
30
93
  </XxxAnchor>
31
- ```
32
-
33
- ```jsx
34
94
  <XxxLink>
35
95
  <Yyy />
36
96
  </XxxLink>
37
- ```
38
-
39
- ```jsx
40
97
  <XxxButton>
41
98
  <Zzz />
42
99
  </XxxButton>
43
- ```
44
-
45
- ```jsx
46
100
  <XxxAnchor>
47
101
  <XxxTextYyyy />
48
102
  </XxxAnchor>
@@ -51,49 +105,40 @@
51
105
  ## ✅ Correct
52
106
 
53
107
  ```jsx
108
+ // テキストがchildrenに含まれるためOK
54
109
  <XxxAnchor>
55
110
  Hoge
56
111
  </XxxAnchor>
57
112
  ```
58
113
  ```jsx
114
+ // テキスト以外が同時に含まれている場合もOK
59
115
  <XxxLink>
60
116
  <YyyIcon />
61
117
  Fuga
62
118
  </XxxLink>
63
119
  ```
64
120
  ```jsx
65
- <XxxAnchor>
66
- <YyyIcon visuallyHiddenText="hoge" />
67
- </XxxAnchor>
68
- ```
69
- ```jsx
121
+ // 画像・Iconの場合、代替テキストが指定されていればテキストを含むものとして扱われるためOK
70
122
  <XxxButton>
71
123
  <YyyImage alt="fuga" />
72
124
  </XxxButton>
73
125
  ```
74
126
 
75
127
  ```jsx
128
+ // childrenが存在しないコンポーネントの場合、テキストを内包するものとして扱われるためOK
76
129
  <YyyAnchor />
77
130
  ```
78
131
 
79
132
  ```jsx
133
+ // childrenに含むコンポーネント名が、TextがsuffixになっているためOK
80
134
  <XxxAnchor>
81
135
  <XxxText />
82
136
  </XxxAnchor>
83
137
  ```
84
138
 
85
139
  ```jsx
86
- /*
87
- rules: {
88
- 'smarthr/a11y-clickable-element-has-text': [
89
- 'error',
90
- {
91
- componentsWithText: ['Hoge'],
92
- },
93
- ]
94
- },
95
- */
96
-
140
+ // componentsWithText: ['Hoge'] を設定している場合
141
+ // Hogeコンポーネントはテキストを含むものとして扱われるのでOK
97
142
  <XxxButton>
98
143
  <Hoge />
99
144
  </XxxButton>
@@ -1,12 +1,117 @@
1
1
  # smarthr/a11y-form-control-in-form
2
2
 
3
- - fieldset, Fieldset, FormControl を利用する場合、form要素で囲むことを促すルールです
4
- - form要素で囲むことで以下のようなメリットがあります
5
- - 適切にマークアップできるようになり、フォームの範囲などがスクリーンリーダーに正しく伝わる
6
- - 入力要素にfocusした状態でEnterを押せばフォームをsubmitできる
7
- - inputのrequired属性、pattern属性を利用した入力チェックをブラウザの機能として実行できる
8
- - smarthr/a11y-input-in-form-control と組み合わせることでより厳密なフォームのマークアップを行えます
3
+ fieldset, Fieldset, FormControl を利用する場合、form要素で囲むことを促すルールです。
4
+ このルールは[smarthr/a11y-input-in-form-control](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/a11y-input-in-form-control) と組み合わせることでより厳密なチェックを行えます。
9
5
 
6
+ ## なぜform要素で囲むことを推奨するのか
7
+
8
+ form要素で対象コンポーネントを囲むことで `formの範囲が明確になる` 以外に以下のメリットが存在します。
9
+
10
+ ### 入力要素にfocusした状態でEnterキーなどでフォームを送信(submit)できる
11
+
12
+ ブラウザの標準機能として入力要素にfocusした状態でEnterキー、またはそれに準ずるキーボード操作などをした場合、formを送信(submit)することができるようになります。
13
+ この機能は**ブラウザの標準機能として存在するため、submitできることを期待する利用者は多い**ため、form要素を利用したマークアップをすることを推奨しています。
14
+
15
+ 状況によっては**ユーザーの誤操作を防止するためEnterなどでsubmitさせたくない**場合もありえますが、この挙動は**ブラウザの標準機能のため、無効にする場合は慎重に判断してください。**
16
+
17
+ ### input要素のrequired属性、pattern属性を利用した入力チェックが有効になる
18
+
19
+ input要素のrequired属性、pattern属性はform要素で囲んでいない場合でも設定自体は出来ますが、submit時のチェック自体は発火しません。
20
+ これらの属性はform要素で囲まれる事により、はじめて有効になります。
21
+
22
+ ブラウザの機能として入力チェックを行うため、jsなどで同等の機能を実装した場合と比較して非常に高速なチェックが可能です。
23
+ ぜひ導入を検討してください。
24
+
25
+ ## FormControl、Fieldsetを内包するコンポーネントの名称について
26
+
27
+ FormControl・Fieldsetを内包するコンポーネントを命名する場合、名称のsuffixにFormControl、Fieldset、もしくはFormControls, Fieldsetsのいずれかを設定してください。
28
+
29
+ ```jsx
30
+ // FormControl、Fieldsetが内包されるコンポーネントの場合、名称のsuffixを
31
+ // FormControl、Fieldset、もしくはFormControls, Fieldsetsのいずれかにする
32
+ const SampleFormControls = () => (
33
+ <>
34
+ <StyledFormControl name="field1" />
35
+ <StyledFormControl name="field2" />
36
+ <StyledFormControl name="field3" />
37
+ </>
38
+ )
39
+ const SampleFieldset = (props) => (
40
+ <Fieldset {...props}>
41
+ <Any />
42
+ </>
43
+ )
44
+ ```
45
+
46
+ 上記ルールは **条件によってはFormControl, Fieldsetが表示されない場合がある** 際にも適用してください。
47
+
48
+ ```jsx
49
+ // AnyFieldsetは条件次第で表示されない場合があるが、それとは無関係にコンポーネント名は `XxxFieldset` とすること
50
+ const SampleFieldset = () => (
51
+ <>
52
+ <Hoge />
53
+ {condition && (
54
+ <AnyFieldset />
55
+ )}
56
+ <Fuga name="field3" />
57
+ </>
58
+ )
59
+ ```
60
+
61
+ このような名称にすることで、対象のコンポーネントがFormの入力要素関連のコンポーネントであることが明示され、lintによるチェックが正常に動作するようになります。
62
+ 名称を決定するルールは以下の通りです。
63
+
64
+ ### Fieldsetを含まず、FormControlを単一で含む場合 -> `XxxFormControl`
65
+
66
+ ```jsx
67
+ const SampleFormControl = (props) => (
68
+ <FormControl {...props} title="Sample" />
69
+ )
70
+ ```
71
+
72
+ ### FormControlを含まず、Fieldsetを単一で含む場合 -> `XxxFieldset`
73
+
74
+ ```jsx
75
+ const SampleFieldset = (props) => (
76
+ <Fieldset {...props} title="Sample" />
77
+ )
78
+ ```
79
+
80
+ ### Fieldsetを含まず、FormControlを複数含む可能性がある場合 -> `XxxFormControls`
81
+
82
+ ```jsx
83
+ const SampleFormControls = () => (
84
+ <>
85
+ <AnyFormControl name="field1" />
86
+ <AnyFormControl name="field2" />
87
+ <AnyFormControl name="field3" />
88
+ </>
89
+ )
90
+ ```
91
+
92
+ ### FormControlを含まず、Fieldsetを複数含む可能性がある場合 -> `XxxFieldsets`
93
+
94
+ ```jsx
95
+ const SampleFieldsets = () => (
96
+ <>
97
+ <AnyFieldset name="field1" />
98
+ <AnyFieldset name="field2" />
99
+ <AnyFieldset name="field3" />
100
+ </>
101
+ )
102
+ ```
103
+
104
+ ### FormControl, Fieldsetが複数混ざって存在する場合 -> `XxxFieldsets`
105
+
106
+ ```jsx
107
+ const SampleFieldsets = () => (
108
+ <>
109
+ <AnyFormControl name="field1" />
110
+ <AnyFieldset name="field2" />
111
+ <AnyFormControl name="field3" />
112
+ </>
113
+ )
114
+ ```
10
115
 
11
116
  ## rules
12
117
 
@@ -22,46 +127,84 @@
22
127
 
23
128
  ```jsx
24
129
  // formで囲まれていないためNG
25
- const AnyComponent = <>
26
- <FormControl />
27
- <HogeFieldset />
28
- <fieldset />
29
- </>
130
+ const Sample = () => (
131
+ <>
132
+ <FormControl />
133
+ <HogeFieldset />
134
+ <fieldset />
135
+ </>
136
+ )
137
+ ```
138
+
139
+ ```jsx
140
+ // FormControl、Fieldsetを内包するコンポーネントの場合、名称のsuffixが
141
+ // FormControl、Fieldset、もしくはFormControls, Fieldsetsのいずれかである必要があるためNG
142
+ const Sample1 = () => (
143
+ <>
144
+ <StyledFormControl name="field1" />
145
+ <StyledFormControl name="field2" />
146
+ <StyledFormControl name="field3" />
147
+ </>
148
+ )
149
+ const Sample2 = (props) => (
150
+ <Fieldset {...props}>
151
+ <Any />
152
+ </>
153
+ )
30
154
  ```
31
155
 
32
156
  ## ✅ Correct
33
157
 
34
158
  ```jsx
35
- // formで囲まれているためOK
36
- const AnyComponent = <StyledForm>
37
- <FormControl />
38
- <HogeFieldset />
39
- <fieldset />
40
- </StyledForm>
41
- const AnyComponent = <Hoge as="form">
42
- <FormControl />
43
- <HogeFieldset />
44
- <fieldset />
45
- </Hoge>
46
- const AnyComponent = <Hoge forwardedAs="form">
47
- <FormControl />
48
- <HogeFieldset />
49
- <fieldset />
50
- </Hoge>
159
+ // form要素で囲まれているならOK
160
+ const Sample1 = () => (
161
+ // form要素と推測されるコンポーネントならOK
162
+ <StyledForm>
163
+ <FormControl />
164
+ <HogeFieldset />
165
+ <fieldset />
166
+ </StyledForm>
167
+ )
168
+ const Sample2 = () => (
169
+ // as, forwardedAsでform要素にされているコンポーネントの場合もOK
170
+ <Hoge as="form">
171
+ <FormControl />
172
+ <HogeFieldset />
173
+ <fieldset />
174
+ </Hoge>
175
+ )
176
+ ```
51
177
 
178
+ ```jsx
52
179
  // Dialogの場合、FormDialog・RemoteTriggerFormDialogで囲めばOK
53
- const AnyComponent = <FormDialog>
54
- <FugaFormControl />
55
- </FormDialog>
56
- const AnyComponent = <RemoteTriggerAnyFormDialog>
57
- <FugaFormControl />
58
- </RemoteTriggerAnyFormDialog>
59
-
60
- // 対象のFormControl、Fieldsetがコンポーネントの一要素であり、その親コンポーネント名がFormControl、もしくはFieldsetの場合OK
61
- const AnyFormControl = <>
62
- <StyledFormControl />
63
- </>
64
- const AnyFieldset = <>
65
- <StyledFieldset />
66
- </>
180
+ const SampleFormDialog = () => (
181
+ <FormDialog>
182
+ <FugaFormControl />
183
+ </FormDialog>
184
+ )
185
+ const SampleRemoteTriggerFormDialog = () => (
186
+ <RemoteTriggerAnyFormDialog>
187
+ <FugaFormControl />
188
+ </RemoteTriggerAnyFormDialog>
189
+ )
190
+ ```
191
+
192
+ ```jsx
193
+ // FormControl、Fieldsetを内包するコンポーネントの場合、名称のsuffixが
194
+ // FormControl、Fieldset、もしくはFormControls, Fieldsetsのいずれかの場合OK
195
+ const SampleFormControls = () => (
196
+ <>
197
+ <StyledFormControl name="field1" />
198
+ <StyledFormControl name="field2" />
199
+ <StyledFormControl name="field3" />
200
+ </>
201
+ )
202
+ const SampleFieldset = (props) => (
203
+ <Fieldset {...props}>
204
+ <Any />
205
+ </>
206
+ )
207
+
208
+ // コンポーネント名を上記の様に調整することで
209
+ // これらのコンポーネントを利用する別コンポーネントでも正しくチェックが行えます
67
210
  ```