eslint-plugin-smarthr 1.8.0 → 1.9.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 +16 -0
- package/package.json +4 -4
- package/rules/a11y-anchor-has-href-attribute/index.js +1 -1
- package/rules/a11y-delegate-element-has-role-presentation/index.js +21 -21
- package/rules/a11y-heading-in-sectioning-content/index.js +27 -9
- package/rules/a11y-input-in-form-control/index.js +18 -26
- package/rules/a11y-prohibit-sectioning-content-in-form/README.md +6 -5
- package/test/a11y-delegate-element-has-role-presentation.js +2 -2
- package/test/a11y-heading-in-sectioning-content.js +7 -2
- package/test/a11y-input-in-form-control.js +39 -36
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
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
|
+
## [1.9.0](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v1.8.1...eslint-plugin-smarthr-v1.9.0) (2025-09-08)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* a11y-input-form-controlのラベル設定チェックのロジックを変更する ([#753](https://github.com/kufu/tamatebako/issues/753)) ([f4b5308](https://github.com/kufu/tamatebako/commit/f4b5308911c45862670eca58abffeeb75d20c16e))
|
|
11
|
+
|
|
12
|
+
## [1.8.1](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v1.8.0...eslint-plugin-smarthr-v1.8.1) (2025-06-12)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* a11y-anchor-has-href-attribute での特殊分岐条件を react-router-dom から react-router に変更 ([#678](https://github.com/kufu/tamatebako/issues/678)) ([5941384](https://github.com/kufu/tamatebako/commit/59413842b5b7e5ca6ee88a511792ae6a81be988b))
|
|
18
|
+
* a11y-delegate-element-has-role-presentationでインタラクティブな要素を判定する際、コンポーネント名が複数形でも許容する ([#679](https://github.com/kufu/tamatebako/issues/679)) ([67567bd](https://github.com/kufu/tamatebako/commit/67567bde757624ed46649fb0401e24dc904865ba))
|
|
19
|
+
* a11y-heading-in-sectioning-contentでNavにaria-labelが設定されている場合を許容する ([#680](https://github.com/kufu/tamatebako/issues/680)) ([12f26be](https://github.com/kufu/tamatebako/commit/12f26be9d461d1580711263ae974ed948c74fc1d))
|
|
20
|
+
|
|
5
21
|
## [1.8.0](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v1.7.0...eslint-plugin-smarthr-v1.8.0) (2025-06-09)
|
|
6
22
|
|
|
7
23
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-smarthr",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"author": "SmartHR",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A sharable ESLint plugin for SmartHR",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"engines": {
|
|
9
|
-
"node": ">=22.
|
|
9
|
+
"node": ">=22.17.1"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"test": "jest"
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"json5": "^2.2.3"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"typescript-eslint": "^8.
|
|
29
|
+
"typescript-eslint": "^8.40.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"eslint": "^9"
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"eslintplugin",
|
|
38
38
|
"smarthr"
|
|
39
39
|
],
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "de243698bc64eeb8c3ac0592d96d129eabe1847a"
|
|
41
41
|
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
const INTERACTIVE_COMPONENT_NAMES = `(${[
|
|
2
|
-
'(B|b)utton',
|
|
3
|
-
'(Check|Combo)(B|b)ox',
|
|
4
|
-
'(Date(timeLocal)?|Time|Month|Wareki)Picker',
|
|
5
|
-
'(I|i)nput(File)?',
|
|
6
|
-
'(S|s)elect',
|
|
7
|
-
'(T|t)extarea',
|
|
8
|
-
'(ActionDialogWith|RemoteDialog)Trigger',
|
|
9
|
-
'AccordionPanel',
|
|
2
|
+
'(B|b)utton(s)?',
|
|
3
|
+
'(Check|Combo)(B|b)ox(es|s)?',
|
|
4
|
+
'(Date(timeLocal)?|Time|Month|Wareki)Picker(s)?',
|
|
5
|
+
'(I|i)nput(File)?(s)?',
|
|
6
|
+
'(S|s)elect(s)?',
|
|
7
|
+
'(T|t)extarea(s)?',
|
|
8
|
+
'(ActionDialogWith|RemoteDialog)Trigger(s)?',
|
|
9
|
+
'AccordionPanel(s)?',
|
|
10
10
|
'^a',
|
|
11
11
|
'Anchor',
|
|
12
|
-
'Link',
|
|
13
|
-
'DropZone',
|
|
14
|
-
'Field(S|s)et',
|
|
15
|
-
'FilterDropdown',
|
|
16
|
-
'(F|f)orm(Control|Group|Dialog)?',
|
|
17
|
-
'Pagination',
|
|
18
|
-
'RadioButton(Panel)?',
|
|
19
|
-
'RemoteTrigger(.+)Dialog',
|
|
20
|
-
'RightFixedNote',
|
|
21
|
-
'SegmentedControl',
|
|
22
|
-
'SideNav',
|
|
23
|
-
'Switch',
|
|
24
|
-
'TabItem',
|
|
12
|
+
'Link(s)?',
|
|
13
|
+
'DropZone(s)?',
|
|
14
|
+
'Field(S|s)et(s)?',
|
|
15
|
+
'FilterDropdown(s)?',
|
|
16
|
+
'(F|f)orm(Control|Group|Dialog)?(s)?',
|
|
17
|
+
'Pagination(s)?',
|
|
18
|
+
'RadioButton(Panel)?(s)?',
|
|
19
|
+
'RemoteTrigger(.+)Dialog(s)?',
|
|
20
|
+
'RightFixedNote(s)?',
|
|
21
|
+
'SegmentedControl(s)?',
|
|
22
|
+
'SideNav(s)?',
|
|
23
|
+
'Switch(s)?',
|
|
24
|
+
'TabItem(s)?',
|
|
25
25
|
].join('|')})$`
|
|
26
26
|
const INTERACTIVE_ON_REGEX = /^on(Change|Input|Focus|Blur|(Double)?Click|Key(Down|Up|Press)|Mouse(Enter|Over|Down|Up|Leave)|Select|Submit)$/
|
|
27
27
|
const MEANED_ROLE_REGEX = /^(combobox|group|slider|toolbar)$/
|
|
@@ -10,9 +10,9 @@ const ignoreCheckParentTypeRegex = /^(Program|ExportNamedDeclaration)$/
|
|
|
10
10
|
const noHeadingTagNamesRegex = /^(span|legend)$/
|
|
11
11
|
const ignoreHeadingCheckParentTypeRegex = /^(Program|ExportNamedDeclaration)$/
|
|
12
12
|
const headingAttributeRegex = /^(heading|title)$/
|
|
13
|
+
const ariaLabelRegex = /^aria-label(ledby)?$/
|
|
13
14
|
|
|
14
15
|
const includeSectioningAsAttr = (a) => asRegex.test(a.name?.name) && bareTagRegex.test(a.value.value)
|
|
15
|
-
const findHeadingAttribute = (a) => headingAttributeRegex.test(a.name?.name || '')
|
|
16
16
|
|
|
17
17
|
const headingMessage = `smarthr-ui/Headingと紐づく内容の範囲(アウトライン)が曖昧になっています。
|
|
18
18
|
- smarthr-uiのArticle, Aside, Nav, SectionのいずれかでHeadingコンポーネントと内容をラップしてHeadingに対応する範囲を明確に指定してください。`
|
|
@@ -250,23 +250,41 @@ module.exports = {
|
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
} else if (!node.selfClosing) {
|
|
253
|
-
const isSection =
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
253
|
+
const isSection = elementName.match(sectioningRegex)
|
|
254
|
+
let isNav = false
|
|
255
|
+
|
|
256
|
+
if (isSection) {
|
|
257
|
+
isNav = isSection[1] === 'Nav'
|
|
258
|
+
|
|
259
|
+
for (let i = 0; i < node.attributes.length; i++) {
|
|
260
|
+
const attrName = node.attributes[i].name?.name || ''
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
// HINT: SectioningContent系コンポーネントの拡張の場合、title, heading属性などにHeadingのテキストが仕込まれている場合がある
|
|
264
|
+
// 対象属性を持っている場合はcorrectとして扱う
|
|
265
|
+
headingAttributeRegex.test(attrName) ||
|
|
266
|
+
// HINT: Navかつaria-labelを持っている場合も許容する
|
|
267
|
+
isNav && ariaLabelRegex.test(attrName)
|
|
268
|
+
) {
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
}
|
|
259
272
|
}
|
|
260
273
|
|
|
261
274
|
const layoutSectionAsAttr = !isSection && layoutComponentRegex.test(elementName) ? node.attributes.find(includeSectioningAsAttr) : null
|
|
262
275
|
|
|
263
|
-
if (
|
|
276
|
+
if (
|
|
277
|
+
(isSection || layoutSectionAsAttr) &&
|
|
278
|
+
!searchBubbleUpSections(node.parent.parent) &&
|
|
279
|
+
!forInSearchChildren(node.parent.children)
|
|
280
|
+
) {
|
|
264
281
|
context.report({
|
|
265
282
|
node,
|
|
266
283
|
message: `${isSection ? elementName : `<${elementName} ${layoutSectionAsAttr.name.name}="${layoutSectionAsAttr.value.value}">`} はHeading要素を含んでいません。
|
|
267
284
|
- SectioningContentはHeadingを含むようにマークアップする必要があります
|
|
268
285
|
- ${elementName}に設定しているいずれかの属性がHeading,もしくはHeadingのテキストに該当する場合、その属性の名称を ${headingAttributeRegex.toString()} にマッチする名称に変更してください
|
|
269
|
-
- Headingにするべき適切な文字列が存在しない場合、 ${isSection ? `${elementName} は削除するか、SectioningContentではない要素に差し替えてください` : `${layoutSectionAsAttr.name.name}="${layoutSectionAsAttr.value.value}"を削除、もしくは別の要素に変更してください`}
|
|
286
|
+
- Headingにするべき適切な文字列が存在しない場合、 ${isSection ? `${elementName} は削除するか、SectioningContentではない要素に差し替えてください` : `${layoutSectionAsAttr.name.name}="${layoutSectionAsAttr.value.value}"を削除、もしくは別の要素に変更してください`}${isNav ? `
|
|
287
|
+
- nav要素の場合、aria-label、もしくはaria-labelledby属性を設定し、どんなナビゲーションなのかがわかる名称を設定してください` : ''}`,
|
|
270
288
|
})
|
|
271
289
|
}
|
|
272
290
|
}
|
|
@@ -21,7 +21,6 @@ const IGNORE_INPUT_CHECK_PARENT_TYPE = /^(Program|ExportNamedDeclaration)$/
|
|
|
21
21
|
|
|
22
22
|
const findRoleGroup = (a) => a.name?.name === 'role' && a.value.value === 'group'
|
|
23
23
|
const findAsSectioning = (a) => AS_REGEX.test(a.name?.name) && BARE_SECTIONING_TAG_REGEX.test(a.value.value)
|
|
24
|
-
const findTitle = (i) => i.key.name === 'title'
|
|
25
24
|
|
|
26
25
|
const SCHEMA = [
|
|
27
26
|
{
|
|
@@ -78,18 +77,10 @@ module.exports = {
|
|
|
78
77
|
for (const i of node.attributes) {
|
|
79
78
|
if (i.name) {
|
|
80
79
|
// HINT: idが設定されている場合、htmlForでlabelと紐づく可能性が高いため無視する
|
|
81
|
-
// HINT: titleが設定されている場合、なんの入力要素かはわかるため無視する
|
|
82
80
|
switch (i.name.name) {
|
|
83
81
|
case 'id':
|
|
84
|
-
case 'title':
|
|
85
82
|
isPseudoLabel = true
|
|
86
83
|
break
|
|
87
|
-
case 'inputAttributes': {
|
|
88
|
-
if (!isPseudoLabel && i.value.expression.type === 'ObjectExpression' && i.value.expression.properties.some(findTitle)) {
|
|
89
|
-
isPseudoLabel = true
|
|
90
|
-
}
|
|
91
|
-
break
|
|
92
|
-
}
|
|
93
84
|
case 'type':
|
|
94
85
|
switch (i.value.value) {
|
|
95
86
|
case 'radio':
|
|
@@ -155,18 +146,19 @@ module.exports = {
|
|
|
155
146
|
- Fieldsetで同じname属性のラジオボタン全てを囲むことで正しくグループ化され、適切なタイトル・説明を追加出来ます` : ''}${isPureInput ? `
|
|
156
147
|
- 可能なら${nodeName}は${convertComp}への変更を検討してください。難しい場合は ${nodeName} と結びつくlabel要素が必ず存在するよう、マークアップする必要があることに注意してください。` : ''}`,
|
|
157
148
|
});
|
|
158
|
-
} else if (isMultiInput && !conditionalHit
|
|
149
|
+
} else if (isMultiInput && !conditionalHit) {
|
|
159
150
|
context.report({
|
|
160
151
|
node: n,
|
|
161
152
|
message: `${name} が複数の入力要素を含んでいます。ラベルと入力要素の紐づけが正しく行われない可能性があるため、以下の方法のいずれかで修正してください。
|
|
162
|
-
- 方法1:
|
|
163
|
-
- 方法2: 郵便番号や電話番号など、本来一つの概念の入力要素を分割して複数の入力要素にしている場合、一つの入力要素にまとめることを検討してください
|
|
153
|
+
- 方法1: 郵便番号や電話番号など、本来一つの概念の入力要素を分割して複数の入力要素にしている場合、一つの入力要素にまとめることを検討してください
|
|
164
154
|
- コピーアンドペーストがしやすくなる、ブラウザの自動補完などがより適切に反映されるなど多大なメリットがあります
|
|
165
|
-
- 方法
|
|
166
|
-
|
|
155
|
+
- 方法2: ${name}をsmarthr-ui/Fieldset、もしくはそれを拡張したコンポーネントに変更した上で、入力要素を一つずつsmarthr-ui/FormControlで囲むようにマークアップを変更してください
|
|
156
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
157
|
+
- この場合、FormControlのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)
|
|
158
|
+
- 方法3: ${name} が smarthr-ui/${matcherFormControl[1]}、もしくはそれを拡張しているコンポーネントではない場合、名称を ${FROM_CONTROLS_REGEX} にマッチしないものに変更してください`,
|
|
167
159
|
});
|
|
168
160
|
}
|
|
169
|
-
// HINT:
|
|
161
|
+
// HINT: 何らかの方法でラベルが設定されている場合、無視する
|
|
170
162
|
} else if (!isRadio && !isCheckbox && !isPseudoLabel) {
|
|
171
163
|
const isSelect = nodeName.match(SELECT_REGEX)
|
|
172
164
|
|
|
@@ -174,14 +166,14 @@ module.exports = {
|
|
|
174
166
|
node: n,
|
|
175
167
|
message: `${name} が ラベルを持たない入力要素(${nodeName})を含んでいます。入力要素が何であるかを正しく伝えるため、以下の方法のいずれかで修正してください。
|
|
176
168
|
- 方法1: ${name} を smarthr-ui/FormControl、もしくはそれを拡張したコンポーネントに変更してください
|
|
169
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
170
|
+
- この場合、FormControlのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)
|
|
177
171
|
- 方法2: ${nodeName} がlabel要素を含むコンポーネントである場合、名称を${FORM_CONTROL_REGEX}にマッチするものに変更してください
|
|
178
172
|
- smarthr-ui/FormControl、smarthr-ui/FormGroup はlabel要素を内包しています
|
|
179
173
|
- 方法3: ${nodeName} がRadioButton、もしくはCheckboxを表すコンポーネントの場合、名称を${LABELED_INPUTS_REGEX}にマッチするものに変更してください
|
|
180
174
|
- smarthr-ui/RadioButton、smarthr-ui/RadioButtonPanel、smarthr-ui/Checkbox はlabel要素を内包しています
|
|
181
175
|
- 方法4: ${name} が smarthr-ui/Fieldset、もしくはそれを拡張しているコンポーネントではない場合、名称を ${FIELDSET_REGEX} にマッチしないものに変更してください
|
|
182
|
-
- 方法5: 別途label要素が存在し、それらと紐づけたい場合はlabel要素のhtmlFor属性、${nodeName}のid属性に同じ文字列を指定してください。この文字列はhtml
|
|
183
|
-
- 方法6: 上記のいずれの方法も適切ではない場合、${nodeName}のtitle属性に "どんな値を${isSelect ? '選択' : '入力'}すれば良いのか" の説明を設定してください
|
|
184
|
-
- 例: <${nodeName} title="${isSelect ? '検索対象を選択してください' : '姓を全角カタカナのみで入力してください'}" />`,
|
|
176
|
+
- 方法5: 別途label要素が存在し、それらと紐づけたい場合はlabel要素のhtmlFor属性、${nodeName}のid属性に同じ文字列を指定してください。この文字列はhtml内で一意である必要があります`,
|
|
185
177
|
});
|
|
186
178
|
}
|
|
187
179
|
|
|
@@ -202,10 +194,10 @@ module.exports = {
|
|
|
202
194
|
message: `${nodeName}は${actualName}より先に、smarthr-ui/${wrapComponentName}が入力要素を囲むようマークアップを以下のいずれかの方法で変更してください。
|
|
203
195
|
- 方法1: ${actualName} を${wrapComponentName}、もしくはそれを拡張したコンポーネントに変更してください
|
|
204
196
|
- ${actualName} 内のHeading要素は${wrapComponentName}のtitle属性に変更してください
|
|
205
|
-
- 方法2: ${actualName} と ${nodeName} の間に ${wrapComponentName}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
197
|
+
- 方法2: ${actualName} と ${nodeName} の間に ${wrapComponentName} が存在するようにマークアップを変更してください
|
|
198
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
199
|
+
- この場合、${wrapComponentName}のdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)${isRadio ? '' : `
|
|
200
|
+
- 方法3: 別途label要素が存在し、それらと紐づけたい場合はlabel要素のhtmlFor属性、${nodeName}のid属性に同じ文字列を指定してください。この文字列はhtml内で一意である必要があります`}`,
|
|
209
201
|
});
|
|
210
202
|
}
|
|
211
203
|
|
|
@@ -252,11 +244,11 @@ module.exports = {
|
|
|
252
244
|
node,
|
|
253
245
|
message: `${nodeName} を、smarthr-ui/${wrapComponentName} もしくはそれを拡張したコンポーネントが囲むようマークアップを変更してください。
|
|
254
246
|
- ${wrapComponentName}で入力要素を囲むことでラベルと入力要素が適切に紐づき、操作性が高まります${isRadio ? `
|
|
255
|
-
- FieldsetでRadioButtonを囲むことでグループ化された入力要素に対して適切なタイトル・説明を追加出来ます` :
|
|
247
|
+
- FieldsetでRadioButtonを囲むことでグループ化された入力要素に対して適切なタイトル・説明を追加出来ます` : `
|
|
248
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
249
|
+
- この場合、${wrapComponentName}のdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)`}
|
|
256
250
|
- ${nodeName}が入力要素とラベル・タイトル・説明など含む概念を表示するコンポーネントの場合、コンポーネント名を${FROM_CONTROLS_REGEX}とマッチするように修正してください
|
|
257
|
-
- ${nodeName}が入力要素自体を表現するコンポーネントの一部である場合、ルートとなるコンポーネントの名称を${FORM_CONTROL_INPUTS_REGEX}
|
|
258
|
-
- 上記のいずれの方法も適切ではない場合、${nodeName}のtitle属性に "どんな値を${isSelect ? '選択' : '入力'}すれば良いのか" の説明を設定してください
|
|
259
|
-
- 例: <${nodeName} title="${isSelect ? '検索対象を選択してください' : '姓を全角カタカナのみで入力してください'}" />`}`,
|
|
251
|
+
- ${nodeName}が入力要素自体を表現するコンポーネントの一部である場合、ルートとなるコンポーネントの名称を${FORM_CONTROL_INPUTS_REGEX}とマッチするように修正してください`,
|
|
260
252
|
});
|
|
261
253
|
}
|
|
262
254
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# smarthr/a11y-prohibit-sectioning-content-in-form
|
|
2
2
|
|
|
3
3
|
- form, fieldset, smarthr-ui/Fieldset 以下でSectioningContent(section, aside, article, nav)が利用されている場合、smarthr-ui/Fieldsetに置き換えることを促すルールです
|
|
4
|
-
-
|
|
5
|
-
- form要素内からHeadingが取り除かれ、Fieldset
|
|
6
|
-
|
|
7
|
-
-
|
|
4
|
+
- このルールは適用することでマークアップの方針が定められ、利用者の利便性を上げることを目的にしています
|
|
5
|
+
- form要素内からHeadingが取り除かれ、Fieldsetに統一され、見出しを表現する要素がlegend, label要素のみになることで、スクリーンリーダーのジャンプ機能などの利便性が大幅に向上します
|
|
6
|
+
- 大抵のスクリーンリーダーのジャンプ機能では、heading・legend要素は区別されており、同一フォーム内にこれら要素が混在していると、切り替える手間が発生します
|
|
7
|
+
- 上記操作をフォーム入力中に行うことになるため、入力要素がスキップされる場合が発生しやすく、基本的にheading と legend・label要素を同一フォーム内で混在させることは非推奨です
|
|
8
|
+
- fieldset要素は内部に入力要素を含まずとも利用可能です
|
|
9
|
+
- formとしてマークアップされている要素の子要素として存在する場合、見出し・説明文などもフォームを構成する一要素である、という思想のルールです
|
|
8
10
|
- a11y-form-control-in-form と組み合わせることでより厳密なフォームのマークアップを行えます
|
|
9
11
|
|
|
10
|
-
|
|
11
12
|
## rules
|
|
12
13
|
|
|
13
14
|
```js
|
|
@@ -11,7 +11,7 @@ const ruleTester = new RuleTester({
|
|
|
11
11
|
},
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
const defaultInteractiveMessage = '((B|b)utton
|
|
14
|
+
const defaultInteractiveMessage = '((B|b)utton(s)?|(Check|Combo)(B|b)ox(es|s)?|(Date(timeLocal)?|Time|Month|Wareki)Picker(s)?|(I|i)nput(File)?(s)?|(S|s)elect(s)?|(T|t)extarea(s)?|(ActionDialogWith|RemoteDialog)Trigger(s)?|AccordionPanel(s)?|^a|Anchor|Link(s)?|DropZone(s)?|Field(S|s)et(s)?|FilterDropdown(s)?|(F|f)orm(Control|Group|Dialog)?(s)?|Pagination(s)?|RadioButton(Panel)?(s)?|RemoteTrigger(.+)Dialog(s)?|RightFixedNote(s)?|SegmentedControl(s)?|SideNav(s)?|Switch(s)?|TabItem(s)?)$'
|
|
15
15
|
const defaultInteractiveRegex = `/(${defaultInteractiveMessage})/`
|
|
16
16
|
const messageNonInteractiveEventHandler = (nodeName, onAttrs, interactiveComponentRegex = defaultInteractiveRegex) => {
|
|
17
17
|
const onAttrsText = onAttrs.join(', ')
|
|
@@ -50,7 +50,7 @@ ruleTester.run('smarthr/a11y-delegate-element-has-role-presentation', rule, {
|
|
|
50
50
|
{ code: '<Wrapper onClick={any} role="presentation"><Hoge /></Wrapper>', options: [{ additionalInteractiveComponentRegex: ['^Hoge$'] }] },
|
|
51
51
|
{ code: '<Wrapper onClick={any} role="presentation"><any><Link /></any></Wrapper>' },
|
|
52
52
|
{ code: '<Wrapper onClick={any} role="presentation">{any && <AnyButton />}</Wrapper>' },
|
|
53
|
-
{ code: '<Wrapper onClick={any} role="presentation">{any || <
|
|
53
|
+
{ code: '<Wrapper onClick={any} role="presentation">{any || <AnyButtons />}</Wrapper>' },
|
|
54
54
|
{ code: '<Wrapper onClick={any} role="presentation">{any1 && (any2 || any3) && <AnyButton />}</Wrapper>' },
|
|
55
55
|
{ code: '<Wrapper onClick={any} role="presentation">{any ? <AnyButton /> : null}</Wrapper>' },
|
|
56
56
|
{ code: '<Wrapper onClick={any} role="presentation">{any1 ? (any2 ? <HogeLink /> : null) : null}</Wrapper>' },
|
|
@@ -19,10 +19,11 @@ const pageMessage = 'smarthr-ui/PageHeading が同一ファイル内に複数存
|
|
|
19
19
|
const pageInSectionMessage = 'smarthr-ui/PageHeadingはsmarthr-uiのArticle, Aside, Nav, Sectionで囲まないでください。囲んでしまうとページ全体の見出しではなくなってしまいます。'
|
|
20
20
|
const noTagAttrMessage = `tag属性を指定せず、smarthr-uiのArticle, Aside, Nav, Sectionのいずれかの自動レベル計算に任せるよう、tag属性を削除してください。
|
|
21
21
|
- tag属性を指定することで意図しないレベルに固定されてしまう可能性があります。`
|
|
22
|
-
const notHaveHeadingMessage = (elementName) => `${elementName} はHeading要素を含んでいません。
|
|
22
|
+
const notHaveHeadingMessage = (elementName, isNav) => `${elementName} はHeading要素を含んでいません。
|
|
23
23
|
- SectioningContentはHeadingを含むようにマークアップする必要があります
|
|
24
24
|
- ${elementName}に設定しているいずれかの属性がHeading,もしくはHeadingのテキストに該当する場合、その属性の名称を /^(heading|title)$/ にマッチする名称に変更してください
|
|
25
|
-
- Headingにするべき適切な文字列が存在しない場合、 ${elementName} は削除するか、SectioningContent
|
|
25
|
+
- Headingにするべき適切な文字列が存在しない場合、 ${elementName} は削除するか、SectioningContentではない要素に差し替えてください${isNav ? `
|
|
26
|
+
- nav要素の場合、aria-label、もしくはaria-labelledby属性を設定し、どんなナビゲーションなのかがわかる名称を設定してください` : ''}`
|
|
26
27
|
|
|
27
28
|
ruleTester.run('a11y-heading-in-sectioning-content', rule, {
|
|
28
29
|
valid: [
|
|
@@ -48,6 +49,8 @@ ruleTester.run('a11y-heading-in-sectioning-content', rule, {
|
|
|
48
49
|
{ code: '<HogeStack forwardedAs="section"><div><Heading>hoge</Heading></div></HogeStack>' },
|
|
49
50
|
{ code: '<HogeBase as="aside"><Heading>hoge</Heading></HogeBase>' },
|
|
50
51
|
{ code: '<HogeBaseColumn forwardedAs="nav"><Heading>hoge</Heading></HogeBaseColumn>' },
|
|
52
|
+
{ code: '<HogeNav aria-label="any"><Any /></HogeNav>' },
|
|
53
|
+
{ code: '<HogeNav aria-labelledby="any"><Any /></HogeNav>' },
|
|
51
54
|
],
|
|
52
55
|
invalid: [
|
|
53
56
|
{ code: 'const StyledArticle = styled.article``', errors: [ { message: `"article"を利用せず、smarthr-ui/Articleを拡張してください。Headingのレベルが自動計算されるようになります。(例: "styled.article" -> "styled(Article)")` } ] },
|
|
@@ -64,5 +67,7 @@ ruleTester.run('a11y-heading-in-sectioning-content', rule, {
|
|
|
64
67
|
{ code: '<Section></Section>', errors: [ { message: notHaveHeadingMessage('Section') } ] },
|
|
65
68
|
{ code: '<Aside><HogeSection></HogeSection></Aside>', errors: [ { message: notHaveHeadingMessage('Aside') }, { message: notHaveHeadingMessage('HogeSection') } ] },
|
|
66
69
|
{ code: '<Aside any="hoge"><HogeSection><Heading /></HogeSection></Aside>', errors: [ { message: notHaveHeadingMessage('Aside') } ] },
|
|
70
|
+
{ code: '<HogeNav><Any /></HogeNav>', errors: [ { message: notHaveHeadingMessage('HogeNav', true) } ] },
|
|
71
|
+
{ code: '<HogeNav aria-diabled="true"><Any /></HogeNav>', errors: [ { message: notHaveHeadingMessage('HogeNav', true) } ] },
|
|
67
72
|
],
|
|
68
73
|
});
|
|
@@ -12,16 +12,16 @@ const ruleTester = new RuleTester({
|
|
|
12
12
|
})
|
|
13
13
|
const noLabeledInput = (name) => `${name} を、smarthr-ui/FormControl もしくはそれを拡張したコンポーネントが囲むようマークアップを変更してください。
|
|
14
14
|
- FormControlで入力要素を囲むことでラベルと入力要素が適切に紐づき、操作性が高まります
|
|
15
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
16
|
+
- この場合、FormControlのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)
|
|
15
17
|
- ${name}が入力要素とラベル・タイトル・説明など含む概念を表示するコンポーネントの場合、コンポーネント名を/(Form(Control|Group)|(F|^f)ieldset)$/とマッチするように修正してください
|
|
16
|
-
- ${name}が入力要素自体を表現するコンポーネントの一部である場合、ルートとなるコンポーネントの名称を/(RadioButton(Panel)?(s)?|Check(B|b)ox(es|s)?|(Search)?(I|^i)nput(File)?|(T|^t)extarea|(S|^s)elect|Combo(B|b)ox|(Date|Wareki|Time)Picker)
|
|
17
|
-
- 上記のいずれの方法も適切ではない場合、${name}のtitle属性に "どんな値を入力すれば良いのか" の説明を設定してください
|
|
18
|
-
- 例: <${name} title="姓を全角カタカナのみで入力してください" />`
|
|
18
|
+
- ${name}が入力要素自体を表現するコンポーネントの一部である場合、ルートとなるコンポーネントの名称を/(RadioButton(Panel)?(s)?|Check(B|b)ox(es|s)?|(Search)?(I|^i)nput(File)?|(T|^t)extarea|(S|^s)elect|Combo(B|b)ox|(Date|Wareki|Time)Picker)$/とマッチするように修正してください`
|
|
19
19
|
const noLabeledSelect = (name) => `${name} を、smarthr-ui/FormControl もしくはそれを拡張したコンポーネントが囲むようマークアップを変更してください。
|
|
20
20
|
- FormControlで入力要素を囲むことでラベルと入力要素が適切に紐づき、操作性が高まります
|
|
21
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
22
|
+
- この場合、FormControlのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)
|
|
21
23
|
- ${name}が入力要素とラベル・タイトル・説明など含む概念を表示するコンポーネントの場合、コンポーネント名を/(Form(Control|Group)|(F|^f)ieldset)$/とマッチするように修正してください
|
|
22
|
-
- ${name}が入力要素自体を表現するコンポーネントの一部である場合、ルートとなるコンポーネントの名称を/(RadioButton(Panel)?(s)?|Check(B|b)ox(es|s)?|(Search)?(I|^i)nput(File)?|(T|^t)extarea|(S|^s)elect|Combo(B|b)ox|(Date|Wareki|Time)Picker)
|
|
23
|
-
- 上記のいずれの方法も適切ではない場合、${name}のtitle属性に "どんな値を選択すれば良いのか" の説明を設定してください
|
|
24
|
-
- 例: <${name} title="検索対象を選択してください" />`
|
|
24
|
+
- ${name}が入力要素自体を表現するコンポーネントの一部である場合、ルートとなるコンポーネントの名称を/(RadioButton(Panel)?(s)?|Check(B|b)ox(es|s)?|(Search)?(I|^i)nput(File)?|(T|^t)extarea|(S|^s)elect|Combo(B|b)ox|(Date|Wareki|Time)Picker)$/とマッチするように修正してください`
|
|
25
25
|
const invalidPureCheckboxInFormControl = (name) => `HogeFormControl が ${name} を含んでいます。smarthr-ui/FormControl を smarthr-ui/Fieldset に変更し、正しくグルーピングされるように修正してください。
|
|
26
26
|
- 可能なら${name}はsmarthr-ui/Checkboxへの変更を検討してください。難しい場合は ${name} と結びつくlabel要素が必ず存在するよう、マークアップする必要があることに注意してください。`
|
|
27
27
|
const invalidCheckboxInFormControl = (name) => `HogeFormControl が ${name} を含んでいます。smarthr-ui/FormControl を smarthr-ui/Fieldset に変更し、正しくグルーピングされるように修正してください。`
|
|
@@ -31,42 +31,45 @@ const invalidPureRadioInFormControl = (name) => `HogeFormControl が ${name} を
|
|
|
31
31
|
const invalidRadioInFormControl = (name) => `HogeFormControl が ${name} を含んでいます。smarthr-ui/FormControl を smarthr-ui/Fieldset に変更し、正しくグルーピングされるように修正してください。
|
|
32
32
|
- Fieldsetで同じname属性のラジオボタン全てを囲むことで正しくグループ化され、適切なタイトル・説明を追加出来ます`
|
|
33
33
|
const invalidMultiInputsInFormControl = () => `HogeFormControl が複数の入力要素を含んでいます。ラベルと入力要素の紐づけが正しく行われない可能性があるため、以下の方法のいずれかで修正してください。
|
|
34
|
-
- 方法1:
|
|
35
|
-
- 方法2: 郵便番号や電話番号など、本来一つの概念の入力要素を分割して複数の入力要素にしている場合、一つの入力要素にまとめることを検討してください
|
|
34
|
+
- 方法1: 郵便番号や電話番号など、本来一つの概念の入力要素を分割して複数の入力要素にしている場合、一つの入力要素にまとめることを検討してください
|
|
36
35
|
- コピーアンドペーストがしやすくなる、ブラウザの自動補完などがより適切に反映されるなど多大なメリットがあります
|
|
37
|
-
- 方法
|
|
38
|
-
|
|
36
|
+
- 方法2: HogeFormControlをsmarthr-ui/Fieldset、もしくはそれを拡張したコンポーネントに変更した上で、入力要素を一つずつsmarthr-ui/FormControlで囲むようにマークアップを変更してください
|
|
37
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
38
|
+
- この場合、FormControlのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)
|
|
39
|
+
- 方法3: HogeFormControl が smarthr-ui/FormControl、もしくはそれを拡張しているコンポーネントではない場合、名称を /(Form(Control|Group)|(F|^f)ieldset)$/ にマッチしないものに変更してください`
|
|
39
40
|
const noLabeledInputInFieldset = (name) => `HogeFieldset が ラベルを持たない入力要素(${name})を含んでいます。入力要素が何であるかを正しく伝えるため、以下の方法のいずれかで修正してください。
|
|
40
41
|
- 方法1: HogeFieldset を smarthr-ui/FormControl、もしくはそれを拡張したコンポーネントに変更してください
|
|
42
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
43
|
+
- この場合、FormControlのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)
|
|
41
44
|
- 方法2: ${name} がlabel要素を含むコンポーネントである場合、名称を/(Form(Control|Group))$/にマッチするものに変更してください
|
|
42
45
|
- smarthr-ui/FormControl、smarthr-ui/FormGroup はlabel要素を内包しています
|
|
43
46
|
- 方法3: ${name} がRadioButton、もしくはCheckboxを表すコンポーネントの場合、名称を/(RadioButton(Panel)?(s)?|Check(B|b)ox(es|s)?)$/にマッチするものに変更してください
|
|
44
47
|
- smarthr-ui/RadioButton、smarthr-ui/RadioButtonPanel、smarthr-ui/Checkbox はlabel要素を内包しています
|
|
45
48
|
- 方法4: HogeFieldset が smarthr-ui/Fieldset、もしくはそれを拡張しているコンポーネントではない場合、名称を /Fieldset$/ にマッチしないものに変更してください
|
|
46
|
-
- 方法5: 別途label要素が存在し、それらと紐づけたい場合はlabel要素のhtmlFor属性、${name}のid属性に同じ文字列を指定してください。この文字列はhtml
|
|
47
|
-
- 方法6: 上記のいずれの方法も適切ではない場合、${name}のtitle属性に "どんな値を入力すれば良いのか" の説明を設定してください
|
|
48
|
-
- 例: <${name} title="姓を全角カタカナのみで入力してください" />`
|
|
49
|
+
- 方法5: 別途label要素が存在し、それらと紐づけたい場合はlabel要素のhtmlFor属性、${name}のid属性に同じ文字列を指定してください。この文字列はhtml内で一意である必要があります`
|
|
49
50
|
const noLabeledInputInFieldsetWithSelect = (name) => `HogeFieldset が ラベルを持たない入力要素(${name})を含んでいます。入力要素が何であるかを正しく伝えるため、以下の方法のいずれかで修正してください。
|
|
50
51
|
- 方法1: HogeFieldset を smarthr-ui/FormControl、もしくはそれを拡張したコンポーネントに変更してください
|
|
52
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
53
|
+
- この場合、FormControlのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)
|
|
51
54
|
- 方法2: ${name} がlabel要素を含むコンポーネントである場合、名称を/(Form(Control|Group))$/にマッチするものに変更してください
|
|
52
55
|
- smarthr-ui/FormControl、smarthr-ui/FormGroup はlabel要素を内包しています
|
|
53
56
|
- 方法3: ${name} がRadioButton、もしくはCheckboxを表すコンポーネントの場合、名称を/(RadioButton(Panel)?(s)?|Check(B|b)ox(es|s)?)$/にマッチするものに変更してください
|
|
54
57
|
- smarthr-ui/RadioButton、smarthr-ui/RadioButtonPanel、smarthr-ui/Checkbox はlabel要素を内包しています
|
|
55
58
|
- 方法4: HogeFieldset が smarthr-ui/Fieldset、もしくはそれを拡張しているコンポーネントではない場合、名称を /Fieldset$/ にマッチしないものに変更してください
|
|
56
|
-
- 方法5: 別途label要素が存在し、それらと紐づけたい場合はlabel要素のhtmlFor属性、${name}のid属性に同じ文字列を指定してください。この文字列はhtml
|
|
57
|
-
- 方法6: 上記のいずれの方法も適切ではない場合、${name}のtitle属性に "どんな値を選択すれば良いのか" の説明を設定してください
|
|
58
|
-
- 例: <${name} title="検索対象を選択してください" />`
|
|
59
|
+
- 方法5: 別途label要素が存在し、それらと紐づけたい場合はlabel要素のhtmlFor属性、${name}のid属性に同じ文字列を指定してください。この文字列はhtml内で一意である必要があります`
|
|
59
60
|
const useFormControlInsteadOfSection = (name, section) => `${name}は${section}より先に、smarthr-ui/FormControlが入力要素を囲むようマークアップを以下のいずれかの方法で変更してください。
|
|
60
61
|
- 方法1: ${section} をFormControl、もしくはそれを拡張したコンポーネントに変更してください
|
|
61
62
|
- ${section} 内のHeading要素はFormControlのtitle属性に変更してください
|
|
62
63
|
- 方法2: ${section} と ${name} の間に FormControl が存在するようにマークアップを変更してください
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
65
|
+
- この場合、FormControlのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)
|
|
66
|
+
- 方法3: 別途label要素が存在し、それらと紐づけたい場合はlabel要素のhtmlFor属性、${name}のid属性に同じ文字列を指定してください。この文字列はhtml内で一意である必要があります`
|
|
66
67
|
const useFormControlInsteadOfSectionInRadio = (name, section) => `${name}は${section}より先に、smarthr-ui/Fieldsetが入力要素を囲むようマークアップを以下のいずれかの方法で変更してください。
|
|
67
68
|
- 方法1: ${section} をFieldset、もしくはそれを拡張したコンポーネントに変更してください
|
|
68
69
|
- ${section} 内のHeading要素はFieldsetのtitle属性に変更してください
|
|
69
|
-
- 方法2: ${section} と ${name} の間に Fieldset
|
|
70
|
+
- 方法2: ${section} と ${name} の間に Fieldset が存在するようにマークアップを変更してください
|
|
71
|
+
- 画面上に表示するラベルが存在しない場合でも、必ずその入力要素は何であるか、どんな値を入力すればいいのか?を伝えるため、ラベルの設定は必須です。
|
|
72
|
+
- この場合、FieldsetのdangerouslyTitleHidden属性をtrueにして、ラベルを非表示にしてください(https://smarthr.design/products/components/form-control/)`
|
|
70
73
|
const invalidFieldsetHasRoleGroup = (fieldset, base) => `${fieldset}に 'role="group" が設定されています。${base} をつかってマークアップする場合、'role="group"' は不要です
|
|
71
74
|
- ${fieldset} が ${base}、もしくはそれを拡張しているコンポーネントではない場合、名称を /(Form(Control|Group)|(F|^f)ieldset)$/ にマッチしないものに変更してください`
|
|
72
75
|
const invalidChildreninFormControl = (children) => `FormControl が、${children} を子要素として持っており、マークアップとして正しくない状態になっています。以下のいずれかの方法で修正を試みてください。
|
|
@@ -79,16 +82,6 @@ const requireMultiInputInFormControlWithRoleGroup = () => `HogeFormControl内に
|
|
|
79
82
|
ruleTester.run('a11y-input-in-form-control', rule, {
|
|
80
83
|
valid: [
|
|
81
84
|
{ code: '<input type="hidden" />' },
|
|
82
|
-
{ code: '<input title="any"/>' },
|
|
83
|
-
{ code: '<HogeInput title="any"/>' },
|
|
84
|
-
{ code: '<textarea title="any"/>' },
|
|
85
|
-
{ code: '<HogeTextarea title="any"/>' },
|
|
86
|
-
{ code: '<select title="any"/>' },
|
|
87
|
-
{ code: '<HogeSelect title="any"/>' },
|
|
88
|
-
{ code: '<HogeInputFile title="any"/>' },
|
|
89
|
-
{ code: '<HogeComboBox title="any"/>' },
|
|
90
|
-
{ code: '<HogeDatePicker title="any"/>' },
|
|
91
|
-
{ code: '<HogeWarekiPicker title="any"/>' },
|
|
92
85
|
{ code: '<HogeFormGroup />' },
|
|
93
86
|
{ code: '<HogeFormControl />' },
|
|
94
87
|
{ code: '<HogeFieldset />' },
|
|
@@ -103,7 +96,6 @@ ruleTester.run('a11y-input-in-form-control', rule, {
|
|
|
103
96
|
{ code: '<HogeFieldset><input type="radio" /></HogeFieldset>' },
|
|
104
97
|
{ code: '<HogeFieldset><RadioButton /></HogeFieldset>' },
|
|
105
98
|
{ code: '<HogeFieldset><HogeRadioButtonPanel /></HogeFieldset>' },
|
|
106
|
-
{ code: '<HogeFormControl role="group"><HogeInput /><HogeSelect /></HogeFormControl>' },
|
|
107
99
|
{ code: '<FugaSection><HogeFormControl><HogeInput /></HogeFormControl></FugaSection>' },
|
|
108
100
|
{ code: '<Stack as="section"><HogeFormControl><HogeInput /></HogeFormControl></Stack>' },
|
|
109
101
|
{ code: `const AnyComboBox = () => <input />` },
|
|
@@ -114,11 +106,6 @@ ruleTester.run('a11y-input-in-form-control', rule, {
|
|
|
114
106
|
{ code: '<HogeFieldset><HogeCheckBox /><HogeInput id="any" /></HogeFieldset>' },
|
|
115
107
|
{ code: '<FugaSection><HogeInput id="any" /></FugaSection>' },
|
|
116
108
|
{ code: '<HogeTextarea id="any" />' },
|
|
117
|
-
{ code: '<HogeFieldset><HogeCheckBox /><HogeInput title="any" /></HogeFieldset>' },
|
|
118
|
-
{ code: '<FugaSection><HogeInput title="any" /></FugaSection>' },
|
|
119
|
-
{ code: '<HogeTextarea title="any" />' },
|
|
120
|
-
{ code: '<HogeComboBox inputAttributes={{ title: "any" }} />' },
|
|
121
|
-
{ code: '<HogeComboBox inputAttributes={{ title }} />' },
|
|
122
109
|
{ code: '<Fieldset><HogeRadioButtons /></Fieldset>' },
|
|
123
110
|
{ code: '<Fieldset><HogeRadioButtonPanels /></Fieldset>' },
|
|
124
111
|
{ code: '<Fieldset><HogeCheckBoxs /></Fieldset>' },
|
|
@@ -160,5 +147,21 @@ ruleTester.run('a11y-input-in-form-control', rule, {
|
|
|
160
147
|
{ code: '<HogeFormControl><HogeCheckBoxes /></HogeFormControl>', errors: [ { message: invalidMultiInputsInFormControl() } ] },
|
|
161
148
|
{ code: "<HogeFormControl>{ dateInput ? <DateInput /> : <Input /> }<CheckBox /></HogeFormControl>", errors: [ { message: invalidMultiInputsInFormControl() } ]},
|
|
162
149
|
{ code: "<HogeFormControl><CheckBox />{ dateInput ? <DateInput /> : <Input /> }</HogeFormControl>", errors: [ { message: invalidMultiInputsInFormControl() } ]},
|
|
150
|
+
{ code: '<input title="any"/>', errors: [ { message: noLabeledInput('input') } ] },
|
|
151
|
+
{ code: '<HogeInput title="any"/>', errors: [ { message: noLabeledInput('HogeInput') } ] },
|
|
152
|
+
{ code: '<textarea title="any"/>', errors: [ { message: noLabeledInput('textarea') } ] },
|
|
153
|
+
{ code: '<HogeTextarea title="any"/>', errors: [ { message: noLabeledInput('HogeTextarea') } ] },
|
|
154
|
+
{ code: '<select title="any"/>', errors: [ { message: noLabeledSelect('select') } ] },
|
|
155
|
+
{ code: '<HogeSelect title="any"/>', errors: [ { message: noLabeledSelect('HogeSelect') } ] },
|
|
156
|
+
{ code: '<HogeInputFile title="any"/>', errors: [ { message: noLabeledInput('HogeInputFile') } ] },
|
|
157
|
+
{ code: '<HogeComboBox title="any"/>', errors: [ { message: noLabeledInput('HogeComboBox') } ] },
|
|
158
|
+
{ code: '<HogeDatePicker title="any"/>', errors: [ { message: noLabeledInput('HogeDatePicker') } ] },
|
|
159
|
+
{ code: '<HogeWarekiPicker title="any"/>', errors: [ { message: noLabeledInput('HogeWarekiPicker') } ] },
|
|
160
|
+
{ code: '<HogeFieldset><HogeCheckBox /><HogeInput title="any" /></HogeFieldset>', errors: [ { message: noLabeledInputInFieldset('HogeInput') } ] },
|
|
161
|
+
{ code: '<FugaSection><HogeInput title="any" /></FugaSection>', errors: [ { message: useFormControlInsteadOfSection('HogeInput', 'FugaSection') } ] },
|
|
162
|
+
{ code: '<HogeTextarea title="any" />', errors: [ { message: noLabeledInput('HogeTextarea') } ] },
|
|
163
|
+
{ code: '<HogeComboBox inputAttributes={{ title: "any" }} />', errors: [ { message: noLabeledInput('HogeComboBox') } ] },
|
|
164
|
+
{ code: '<HogeComboBox inputAttributes={{ title }} />', errors: [ { message: noLabeledInput('HogeComboBox') } ] },
|
|
165
|
+
{ code: '<HogeFormControl role="group"><HogeInput /><HogeSelect /></HogeFormControl>', errors: [ { message: invalidMultiInputsInFormControl() } ] },
|
|
163
166
|
]
|
|
164
167
|
})
|