eslint-plugin-smarthr 0.5.8 → 0.5.10

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,23 @@
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
+ ### [0.5.10](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.5.9...v0.5.10) (2024-04-26)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * <FormControl> 内に三項演算子がある場合に、入力要素が複数あると誤認されないようにする ([#139](https://github.com/kufu/eslint-plugin-smarthr/issues/139)) ([8a234c7](https://github.com/kufu/eslint-plugin-smarthr/commit/8a234c73e140725ff1926d4d23f64c263e46d5d6))
11
+
12
+ ### [0.5.9](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.5.7...v0.5.9) (2024-04-22)
13
+
14
+
15
+ ### Features
16
+
17
+ * a11y-prohibit-input-maxlength-attribute ([#135](https://github.com/kufu/eslint-plugin-smarthr/issues/135)) ([9f9d010](https://github.com/kufu/eslint-plugin-smarthr/commit/9f9d010e819d936fe5f55556a8f65e6485c552ce))
18
+ * a11y系コンポーネントでBase,BaseColumnにas="section"などSectioningContentが指定された場合、outlineが切られていると判断するよう修正 ([#138](https://github.com/kufu/eslint-plugin-smarthr/issues/138)) ([7b62c62](https://github.com/kufu/eslint-plugin-smarthr/commit/7b62c6293cf057e97616992dd30fcf67b758f32f))
19
+ * best-practice-for-layouts に <Stack align="center"> を <Center> に置き換えることを促すチェックを追加 ([#133](https://github.com/kufu/eslint-plugin-smarthr/issues/133)) ([5835530](https://github.com/kufu/eslint-plugin-smarthr/commit/58355308bf9a5d18d2d731e699c54806af969ed9))
20
+ * best-practice-for-layoutsでStackコンポーネントにgap={0}が指定されている場合、適切に置き換え・または削除を促すように修正 ([#137](https://github.com/kufu/eslint-plugin-smarthr/issues/137)) ([2a11919](https://github.com/kufu/eslint-plugin-smarthr/commit/2a11919ffa20ddbbc6a59210ec14d81d2d510cda))
21
+
5
22
  ### [0.5.8](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.5.7...v0.5.8) (2024-04-09)
6
23
 
7
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-smarthr",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "author": "SmartHR",
5
5
  "license": "MIT",
6
6
  "description": "A sharable ESLint plugin for SmartHR",
@@ -1,6 +1,6 @@
1
1
  # smarthr/a11y-heading-in-sectioning-content
2
2
 
3
- - Headingコンポーネントをsmarthr-ui/SectioningContent(Article, Aside, Nav, Section, SectioningFragment) のいずれかで囲むことを促すルールです
3
+ - Headingコンポーネントをsmarthr-ui/SectioningContent(Article, Aside, Nav, Section) のいずれかで囲むことを促すルールです
4
4
  - article, aside, nav, section で Heading とHeadingの対象となる範囲を囲むとブラウザが正確に解釈できるようになるメリットがあります
5
5
  - またsmarthr-ui/SectioningContentで smarthr-ui/Headingを囲むことで、Headingのレベル(h1~h6)を自動的に計算するメリットもあります
6
6
  - Headingコンポーネントをsmarthr-ui/Layout(Center, Reel, Sidebar, Stack) のいずれかで囲んでおり、かつas, forwardedAsのいずれかの属性で 'section', 'article', 'aside', 'nav' が指定されている場合、SectioningContentで囲んでいるものとして扱われるようになります
@@ -14,6 +14,8 @@ const EXPECTED_NAMES = {
14
14
  'Reel$': 'Reel$',
15
15
  'Sidebar$': 'Sidebar$',
16
16
  'Stack$': 'Stack$',
17
+ 'Base$': 'Base$',
18
+ 'BaseColumn$': 'BaseColumn$',
17
19
  }
18
20
 
19
21
  const unexpectedMessageTemplate = `{{extended}} は smarthr-ui/{{expected}} をextendすることを期待する名称になっています
@@ -42,6 +44,8 @@ const UNEXPECTED_NAMES = {
42
44
  'Reel$': '(Reel)$',
43
45
  'Sidebar$': '(Sidebar)$',
44
46
  'Stack$': '(Stack)$',
47
+ 'Base$': '(Base)$',
48
+ 'BaseColumn$': '(BaseColumn)$',
45
49
  }
46
50
 
47
51
  const headingRegex = /((^h(1|2|3|4|5|6))|Heading)$/
@@ -50,7 +54,7 @@ const declaratorHeadingRegex = /Heading$/
50
54
  const sectioningRegex = /((A(rticle|side))|Nav|Section|^SectioningFragment)$/
51
55
  const bareTagRegex = /^(article|aside|nav|section)$/
52
56
  const modelessDialogRegex = /ModelessDialog$/
53
- const layoutComponentRegex = /((C(ent|lust)er)|Reel|Sidebar|Stack)$/
57
+ const layoutComponentRegex = /((C(ent|lust)er)|Reel|Sidebar|Stack|Base(Column)?)$/
54
58
  const asRegex = /^(as|forwardedAs)$/
55
59
  const ignoreCheckParentTypeRegex = /^(Program|ExportNamedDeclaration)$/
56
60
  const noHeadingTagNamesRegex = /^(span|legend)$/
@@ -61,14 +65,12 @@ const includeSectioningAsAttr = (a) => a.name?.name.match(asRegex) && bareTagReg
61
65
  const findHeadingAttribute = (a) => headingAttributeRegex.test(a.name?.name || '')
62
66
 
63
67
  const headingMessage = `smarthr-ui/Headingと紐づく内容の範囲(アウトライン)が曖昧になっています。
64
- - smarthr-uiのArticle, Aside, Nav, SectionのいずれかでHeadingコンポーネントと内容をラップしてHeadingに対応する範囲を明確に指定してください。
65
- - 'as="section"' などでアウトラインを示している場合、as属性を指定した要素をsmarthr-ui/SectioningFragmentでラップしてください。
66
- - 要素内のHeadingのレベルが自動計算されるようになります。`
68
+ - smarthr-uiのArticle, Aside, Nav, SectionのいずれかでHeadingコンポーネントと内容をラップしてHeadingに対応する範囲を明確に指定してください。`
67
69
  const rootHeadingMessage = `${headingMessage}
68
70
  - Headingをh1にしたい場合(機能名、ページ名などこのページ内でもっとも重要な見出しの場合)、smarthr-ui/PageHeadingを利用してください。その場合はSectionなどでアウトラインを示す必要はありません。`
69
71
  const pageHeadingMessage = 'smarthr-ui/PageHeading が同一ファイル内に複数存在しています。PageHeadingはh1タグを出力するため最も重要な見出しにのみ利用してください。'
70
72
  const pageHeadingInSectionMessage = 'smarthr-ui/PageHeadingはsmarthr-uiのArticle, Aside, Nav, Sectionで囲まないでください。囲んでしまうとページ全体の見出しではなくなってしまいます。'
71
- const noTagAttrMessage = `tag属性を指定せず、smarthr-uiのArticle, Aside, Nav, Section, SectioningFragmentのいずれかの自動レベル計算に任せるよう、tag属性を削除してください。
73
+ const noTagAttrMessage = `tag属性を指定せず、smarthr-uiのArticle, Aside, Nav, Sectionのいずれかの自動レベル計算に任せるよう、tag属性を削除してください。
72
74
  - tag属性を指定することで意図しないレベルに固定されてしまう可能性があります。`
73
75
 
74
76
  const VariableDeclaratorBareToSHR = (context, node) => {
@@ -73,7 +73,7 @@
73
73
  <DatePicker />
74
74
  ~
75
75
  <DatePicker />
76
- </Fieldset>
76
+ </FormControl>
77
77
 
78
78
  <Fieldset title="any heading">
79
79
  <FormControl role="group">
@@ -94,6 +94,7 @@ module.exports = {
94
94
  const checkAdditionalMultiInputComponents = (name) => additionalMultiInputComponents && name.match(additionalMultiInputComponents)
95
95
 
96
96
  let formControls = []
97
+ let conditionalformControls = []
97
98
  let checkboxFormControls = []
98
99
 
99
100
  return {
@@ -102,6 +103,7 @@ module.exports = {
102
103
  const nodeName = node.name.name || '';
103
104
  const isFormControlInput = nodeName.match(FORM_CONTROL_INPUTS_REGEX)
104
105
  const isAdditionalMultiInput = checkAdditionalMultiInputComponents(nodeName)
106
+ let conditionalExpressions = []
105
107
 
106
108
  if (isFormControlInput || isAdditionalMultiInput || checkAdditionalInputComponents(nodeName)) {
107
109
  let isInMap = false
@@ -162,15 +164,25 @@ module.exports = {
162
164
  if (name) {
163
165
  if (name.match(FROM_CONTROLS_REGEX)) {
164
166
  const hit = formControls.includes(n)
167
+ let conditionalHit = false
165
168
 
166
169
  if (!hit) {
167
170
  formControls.push(n)
168
171
 
172
+
169
173
  if (isCheckbox) {
170
174
  checkboxFormControls.push(n)
171
175
  }
172
176
  }
173
177
 
178
+ if (conditionalExpressions.length > 0) {
179
+ conditionalHit = conditionalformControls.includes(n)
180
+
181
+ if (!conditionalHit) {
182
+ conditionalformControls.push(n)
183
+ }
184
+ }
185
+
174
186
  const isMultiInput = isPreMultiple || hit || isInMap
175
187
  const matcherFormControl = name.match(FORM_CONTROL_REGEX)
176
188
 
@@ -184,7 +196,7 @@ module.exports = {
184
196
  - Fieldsetで同じname属性のラジオボタン全てを囲むことで正しくグループ化され、適切なタイトル・説明を追加出来ます` : ''}${isPureInput ? `
185
197
  - 可能なら${nodeName}は${convertComp}への変更を検討してください。難しい場合は ${nodeName} と結びつくlabel要素が必ず存在するよう、マークアップする必要があることに注意してください。` : ''}`,
186
198
  });
187
- } else if (isMultiInput && !openingElement.attributes.find(findRoleGroup)) {
199
+ } else if (isMultiInput && !conditionalHit && !openingElement.attributes.find(findRoleGroup)) {
188
200
  context.report({
189
201
  node: n,
190
202
  message: `${name} が複数の入力要素を含んでいます。ラベルと入力要素の紐づけが正しく行われない可能性があるため、以下の方法のいずれかで修正してください。
@@ -245,6 +257,10 @@ module.exports = {
245
257
 
246
258
  break
247
259
  }
260
+ case 'ConditionalExpression': {
261
+ conditionalExpressions.push(n)
262
+ break
263
+ }
248
264
  case 'VariableDeclarator': {
249
265
  if (n.parent.parent?.type && n.parent.parent.type.match(IGNORE_INPUT_CHECK_PARENT_TYPE)) {
250
266
  const name = n.id.name
@@ -9,6 +9,8 @@ const EXPECTED_NAMES = {
9
9
  'Reel$': '(Reel)$',
10
10
  'Sidebar$': '(Sidebar)$',
11
11
  'Stack$': '(Stack)$',
12
+ 'Base$': '(Base)$',
13
+ 'BaseColumn$': '(BaseColumn)$',
12
14
  }
13
15
 
14
16
  const UNEXPECTED_NAMES = EXPECTED_NAMES
@@ -16,7 +18,7 @@ const UNEXPECTED_NAMES = EXPECTED_NAMES
16
18
  const BARE_SECTIONING_TAG_REGEX = /^(article|aside|nav|section)$/
17
19
  const SECTIONING_REGEX = /((A(rticle|side))|Nav|Section)$/
18
20
  const SECTIONING_FRAGMENT_REGEX = /^SectioningFragment$/
19
- const LAYOUT_REGEX = /((C(ent|lust)er)|Reel|Sidebar|Stack)$/
21
+ const LAYOUT_REGEX = /((C(ent|lust)er)|Reel|Sidebar|Stack|Base(Column)?)$/
20
22
  const AS_REGEX = /^(as|forwardedAs)$/
21
23
 
22
24
  const includeSectioningAsAttr = (a) => a.name?.name?.match(AS_REGEX) && a.value.value?.match(BARE_SECTIONING_TAG_REGEX)
@@ -24,9 +24,6 @@ const checkFalsyJSXText = (c) => (
24
24
  )
25
25
  )
26
26
 
27
- const findJustifyAttr = (a) => a.name?.name === 'justify'
28
- const findAlignAttr = (a) => a.name?.name === 'align'
29
-
30
27
  const searchChildren = (node) => {
31
28
  if (
32
29
  node.type === 'JSXFragment' ||
@@ -74,27 +71,56 @@ module.exports = {
74
71
  const matcher = nodeName.match(MULTI_CHILDREN_REGEX)
75
72
 
76
73
  if (matcher) {
77
- const children = node.parent.children.filter(checkFalsyJSXText)
78
-
79
- if (children.length === 1) {
80
- const layoutType = matcher[1]
81
- const justifyAttr = layoutType === 'Cluster' ? node.attributes.find(findJustifyAttr) : null
74
+ const layoutType = matcher[1]
75
+ let justifyAttr = null
76
+ let alignAttr = null
77
+ let gapAttr = null
78
+
79
+ node.attributes.forEach((a) => {
80
+ switch (a.name?.name) {
81
+ case 'justify':
82
+ justifyAttr = a
83
+ break
84
+ case 'align':
85
+ alignAttr = a
86
+ break
87
+ case 'gap':
88
+ gapAttr = a
89
+ break
90
+ }
91
+ })
82
92
 
83
- if (justifyAttr && FLEX_END_REGEX.test(justifyAttr.value.value)) {
93
+ if (layoutType === 'Stack') {
94
+ if (alignAttr && FLEX_END_REGEX.test(alignAttr.value.value)) {
84
95
  return
96
+ } else if (gapAttr?.value.type === 'JSXExpressionContainer' && gapAttr.value.expression.value === 0) {
97
+ context.report({
98
+ node,
99
+ message: `${nodeName} に "gap={0}" が指定されており、smarthr-ui/${layoutType} の利用方法として誤っている可能性があります。以下の修正方法を検討してください。
100
+ - 方法1: 子要素を一つにまとめられないか検討してください
101
+ - 例: "<Stack gap={0}><p>hoge</p><p>fuga</p></Stack>" を "<p>hoge<br />fuga</p>" にするなど
102
+ - 方法2: 子要素のstyleを確認しgap属性を0以外にできないか検討してください
103
+ - 子要素が個別に持っているmarginなどのstyleを${nodeName}のgap属性で共通化できないか確認してください
104
+ - 方法3: 別要素でマークアップし直すか、${nodeName}を削除してください
105
+ - 親要素に smarthr-ui/Cluster, smarthr-ui/Stack などが存在している場合、div・spanなどで1要素にまとめる必要がある場合があります
106
+ - as, forwardedAsなどでSectioningContent系要素に変更している場合、対応するsmarthr-ui/Section, Aside, Nav, Article のいずれかに差し替えてください`
107
+ })
85
108
  }
109
+ }
86
110
 
87
- const alignAttr = layoutType === 'Stack' ? node.attributes.find(findAlignAttr) : null
111
+ const children = node.parent.children.filter(checkFalsyJSXText)
88
112
 
89
- if (alignAttr && FLEX_END_REGEX.test(alignAttr.value.value)) {
113
+ if (children.length === 1) {
114
+ if (justifyAttr && FLEX_END_REGEX.test(justifyAttr.value.value)) {
90
115
  return
91
116
  }
92
117
 
118
+
93
119
  if (searchChildren(children[0])) {
94
120
  context.report({
95
121
  node,
96
122
  message:
97
- (justifyAttr && justifyAttr.value.value === 'center' || alignAttr && alignAttr.value.value === 'center')
123
+ (justifyAttr?.value.value === 'center' || alignAttr?.value.value === 'center')
98
124
  ? `${nodeName} は smarthr-ui/${layoutType} ではなく smarthr-ui/Center でマークアップしてください`
99
125
  : `${nodeName}には子要素が一つしか無いため、${layoutType}でマークアップする意味がありません。
100
126
  - styleを確認し、div・spanなど、別要素でマークアップし直すか、${nodeName}を削除してください
@@ -13,14 +13,12 @@ const ruleTester = new RuleTester({
13
13
  });
14
14
 
15
15
  const lowerMessage = `smarthr-ui/Headingと紐づく内容の範囲(アウトライン)が曖昧になっています。
16
- - smarthr-uiのArticle, Aside, Nav, SectionのいずれかでHeadingコンポーネントと内容をラップしてHeadingに対応する範囲を明確に指定してください。
17
- - 'as=\"section\"' などでアウトラインを示している場合、as属性を指定した要素をsmarthr-ui/SectioningFragmentでラップしてください。
18
- - 要素内のHeadingのレベルが自動計算されるようになります。`
16
+ - smarthr-uiのArticle, Aside, Nav, SectionのいずれかでHeadingコンポーネントと内容をラップしてHeadingに対応する範囲を明確に指定してください。`
19
17
  const message = `${lowerMessage}
20
18
  - Headingをh1にしたい場合(機能名、ページ名などこのページ内でもっとも重要な見出しの場合)、smarthr-ui/PageHeadingを利用してください。その場合はSectionなどでアウトラインを示す必要はありません。`
21
19
  const pageMessage = 'smarthr-ui/PageHeading が同一ファイル内に複数存在しています。PageHeadingはh1タグを出力するため最も重要な見出しにのみ利用してください。'
22
20
  const pageInSectionMessage = 'smarthr-ui/PageHeadingはsmarthr-uiのArticle, Aside, Nav, Sectionで囲まないでください。囲んでしまうとページ全体の見出しではなくなってしまいます。'
23
- const noTagAttrMessage = `tag属性を指定せず、smarthr-uiのArticle, Aside, Nav, Section, SectioningFragmentのいずれかの自動レベル計算に任せるよう、tag属性を削除してください。
21
+ const noTagAttrMessage = `tag属性を指定せず、smarthr-uiのArticle, Aside, Nav, Sectionのいずれかの自動レベル計算に任せるよう、tag属性を削除してください。
24
22
  - tag属性を指定することで意図しないレベルに固定されてしまう可能性があります。`
25
23
  const notHaveHeadingMessage = (elementName) => `${elementName} はHeading要素を含んでいません。
26
24
  - SectioningContentはHeadingを含むようにマークアップする必要があります
@@ -74,6 +72,8 @@ ruleTester.run('a11y-heading-in-sectioning-content', rule, {
74
72
  { code: '<HogeReel forwardedAs="aside"><div><Heading>hoge</Heading></div></HogeReel>' },
75
73
  { code: '<HogeSidebar forwardedAs="nav"><div><Heading>hoge</Heading></div></HogeSidebar>' },
76
74
  { code: '<HogeStack forwardedAs="section"><div><Heading>hoge</Heading></div></HogeStack>' },
75
+ { code: '<HogeBase as="aside"><Heading>hoge</Heading></HogeBase>' },
76
+ { code: '<HogeBaseColumn forwardedAs="nav"><Heading>hoge</Heading></HogeBaseColumn>' },
77
77
  ],
78
78
  invalid: [
79
79
  { code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
@@ -135,6 +135,7 @@ ruleTester.run('a11y-input-in-form-control', rule, {
135
135
  { code: '<Fieldset><HogeRadioButtonPanels /></Fieldset>' },
136
136
  { code: '<Fieldset><HogeCheckBoxs /></Fieldset>' },
137
137
  { code: '<Fieldset><HogeCheckBoxes /></Fieldset>' },
138
+ { code: '<HogeFormControl>{ dateInput ? <DateInput /> : <Input /> }</HogeFormControl>'},
138
139
  ],
139
140
  invalid: [
140
141
  { code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
@@ -179,5 +180,7 @@ ruleTester.run('a11y-input-in-form-control', rule, {
179
180
  { code: '<HogeFormControl><HogeRadioButtons /></HogeFormControl>', errors: [ { message: invalidRadioInFormControl('HogeRadioButtons') } ] },
180
181
  { code: '<HogeFormControl><HogeCheckBoxs /></HogeFormControl>', errors: [ { message: invalidMultiInputsInFormControl() } ] },
181
182
  { code: '<HogeFormControl><HogeCheckBoxes /></HogeFormControl>', errors: [ { message: invalidMultiInputsInFormControl() } ] },
183
+ { code: "<HogeFormControl>{ dateInput ? <DateInput /> : <Input /> }<CheckBox /></HogeFormControl>", errors: [ { message: invalidMultiInputsInFormControl() } ]},
184
+ { code: "<HogeFormControl><CheckBox />{ dateInput ? <DateInput /> : <Input /> }</HogeFormControl>", errors: [ { message: invalidMultiInputsInFormControl() } ]},
182
185
  ]
183
186
  })
@@ -27,5 +27,7 @@ ruleTester.run('a11y-prohibit-useless-sectioning-fragment', rule, {
27
27
  { code: `<SectioningFragment><AnyAside>hoge</AnyAside></SectioningFragment>`, errors: [ { message: error('<AnyAside>') } ] },
28
28
  { code: `<SectioningFragment><HogeStack as="aside">hoge</HogeStack></SectioningFragment>`, errors: [ { message: error('<HogeStack as="aside">') } ] },
29
29
  { code: `<SectioningFragment><HogeReel forwardedAs="nav">hoge</HogeReel></SectioningFragment>`, errors: [ { message: error('<HogeReel forwardedAs="nav">') } ] },
30
+ { code: `<SectioningFragment><FugaBase as="article">hoge</FugaBase></SectioningFragment>`, errors: [ { message: error('<FugaBase as="article">') } ] },
31
+ { code: `<SectioningFragment><FugaBaseColumn as="article">hoge</FugaBaseColumn></SectioningFragment>`, errors: [ { message: error('<FugaBaseColumn as="article">') } ] },
30
32
  ]
31
33
  })
@@ -54,7 +54,7 @@ ruleTester.run('best-practice-for-button-element', rule, {
54
54
  { code: `<AnyCluster>{a ? <Hoge /> : a.b.map(action)}</AnyCluster>` },
55
55
  { code: `<AnyCluster>{a ? <Hoge /> : a ? <Hoge /> : a.b.map(action)}</AnyCluster>` },
56
56
  { code: `<Cluster justify="flex-end">{a}</Cluster>` },
57
- { code: `<HogeCluster justify="end">{a}</HogeCluster>` },
57
+ { code: `<HogeCluster justify="end" gap={0}>{a}</HogeCluster>` },
58
58
  { code: `<Stack align="flex-end">{a}</Stack>` },
59
59
  { code: `<HogeStack align="end">{a}</HogeStack>` },
60
60
  ],
@@ -85,6 +85,14 @@ ruleTester.run('best-practice-for-button-element', rule, {
85
85
  { code: `<AnyCluster>{a ? <Hoge /> : a ? <Hoge /> : a.b.hoge(action)}</AnyCluster>`, errors: [ { message: errorMessage('Cluster', 'AnyCluster') } ] },
86
86
  { code: `<HogeCluster justify="center">{a}</HogeCluster>`, errors: [ { message: 'HogeCluster は smarthr-ui/Cluster ではなく smarthr-ui/Center でマークアップしてください' } ] },
87
87
  { code: `<HogeStack align="center">{a}</HogeStack>`, errors: [ { message: 'HogeStack は smarthr-ui/Stack ではなく smarthr-ui/Center でマークアップしてください' } ] },
88
+ { code: `<HogeStack gap={0}>{a}{b}</HogeStack>`, errors: [ { message: `HogeStack に "gap={0}" が指定されており、smarthr-ui/Stack の利用方法として誤っている可能性があります。以下の修正方法を検討してください。
89
+ - 方法1: 子要素を一つにまとめられないか検討してください
90
+ - 例: "<Stack gap={0}><p>hoge</p><p>fuga</p></Stack>" を "<p>hoge<br />fuga</p>" にするなど
91
+ - 方法2: 子要素のstyleを確認しgap属性を0以外にできないか検討してください
92
+ - 子要素が個別に持っているmarginなどのstyleをHogeStackのgap属性で共通化できないか確認してください
93
+ - 方法3: 別要素でマークアップし直すか、HogeStackを削除してください
94
+ - 親要素に smarthr-ui/Cluster, smarthr-ui/Stack などが存在している場合、div・spanなどで1要素にまとめる必要がある場合があります
95
+ - as, forwardedAsなどでSectioningContent系要素に変更している場合、対応するsmarthr-ui/Section, Aside, Nav, Article のいずれかに差し替えてください` } ] },
88
96
  ]
89
97
  })
90
98