@a11yfred/neighbor 1.0.3 → 1.0.4

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
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.4 - 2026-05-13
4
+
5
+ ### Bug fixes
6
+
7
+ - **`no-placeholder-only`** — no longer false-positives on `<input>` elements inside a `role="search"` landmark with an accessible name. The input is correctly labeled at the group level in that pattern.
8
+ - **`no-dialog-without-close`** — no longer false-positives on `role="dialog"` elements whose children are passed dynamically (`{children}`). When a close button cannot be statically detected, the rule skips rather than reporting.
9
+
10
+ ---
11
+
3
12
  ## 1.0.0 - 2026-05-12
4
13
 
5
14
  ### Breaking change
package/lib/rules.js CHANGED
@@ -845,6 +845,11 @@ export function makeNoPlaceholderOnly(h) {
845
845
  if (h.getElementName(node) !== 'input') return
846
846
  if (!h.hasAttr(node, 'placeholder')) return
847
847
  if (h.hasAccessibleName(node)) return
848
+ // An input inside a search landmark with an accessible name is labeled at group level.
849
+ // e.g. <form role="search" aria-label="..."><input placeholder="..." /></form>
850
+ for (const ancestor of h.getAncestors(node)) {
851
+ if (h.getRoleValue(ancestor) === 'search' && h.hasAccessibleName(ancestor)) return
852
+ }
848
853
  context.report({ node: h.getAttr(node, 'placeholder'), messageId: 'placeholderOnly' })
849
854
  },
850
855
  }
@@ -1206,6 +1211,13 @@ export function makeNoDialogWithoutClose(h) {
1206
1211
  [h.elementWithChildrenVisitor](node) {
1207
1212
  const opening = h.getOpeningElement(node)
1208
1213
  if (h.getRoleValue(opening) !== 'dialog') return
1214
+ // If any child is a JSX expression container or spread, children are
1215
+ // passed dynamically and cannot be statically inspected for a close button.
1216
+ const children = node.children ?? []
1217
+ const hasDynamicChildren = children.some(
1218
+ c => c.type === 'JSXExpressionContainer' || c.type === 'JSXSpreadChild'
1219
+ )
1220
+ if (hasDynamicChildren) return
1209
1221
  const hasClose = h.getChildOpeningElementsFromWrapper(node).some(child => {
1210
1222
  const el = h.getElementName(child)
1211
1223
  const role = h.getRoleValue(child)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a11yfred/neighbor",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Accessibility linting for a11yfred - ESLint (markup + content), Stylelint (CSS). Won't you be my neighbor?",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -78,7 +78,7 @@
78
78
  }
79
79
  },
80
80
  "devDependencies": {
81
- "@a11yfred/neighbor": "^1.0.1",
81
+ "@a11yfred/neighbor": "^1.0.3",
82
82
  "eslint": "^9.39.4",
83
83
  "eslint-plugin-jsx-a11y": "^6.10.2",
84
84
  "stylelint": "^17.11.0"