@elastic/eslint-plugin-eui 2.16.0-snapshot.1788177701701 → 3.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.
Files changed (35) hide show
  1. package/README.md +71 -2
  2. package/lib/cjs/index.js +4 -1
  3. package/lib/cjs/rules/button_group_no_invalid_children.d.ts +1 -3
  4. package/lib/cjs/rules/button_group_no_invalid_children.d.ts.map +1 -1
  5. package/lib/cjs/rules/button_group_no_invalid_children.js +28 -38
  6. package/lib/cjs/rules/button_group_selection_require_id.d.ts +3 -0
  7. package/lib/cjs/rules/button_group_selection_require_id.d.ts.map +1 -0
  8. package/lib/cjs/rules/button_group_selection_require_id.js +114 -0
  9. package/lib/cjs/rules/no_deprecated_icon_aliases.d.ts +45 -4
  10. package/lib/cjs/rules/no_deprecated_icon_aliases.d.ts.map +1 -1
  11. package/lib/cjs/rules/no_deprecated_icon_aliases.js +61 -7
  12. package/lib/cjs/utils/button_group_constants.d.ts +6 -0
  13. package/lib/cjs/utils/button_group_constants.d.ts.map +1 -0
  14. package/lib/cjs/utils/button_group_constants.js +19 -0
  15. package/lib/cjs/utils/collect_jsx_children.d.ts +3 -0
  16. package/lib/cjs/utils/collect_jsx_children.d.ts.map +1 -0
  17. package/lib/cjs/utils/collect_jsx_children.js +26 -0
  18. package/lib/esm/index.js +3 -0
  19. package/lib/esm/index.js.map +1 -1
  20. package/lib/esm/rules/button_group_no_invalid_children.d.ts +1 -3
  21. package/lib/esm/rules/button_group_no_invalid_children.js +34 -42
  22. package/lib/esm/rules/button_group_no_invalid_children.js.map +1 -1
  23. package/lib/esm/rules/button_group_selection_require_id.d.ts +2 -0
  24. package/lib/esm/rules/button_group_selection_require_id.js +118 -0
  25. package/lib/esm/rules/button_group_selection_require_id.js.map +1 -0
  26. package/lib/esm/rules/no_deprecated_icon_aliases.d.ts +45 -4
  27. package/lib/esm/rules/no_deprecated_icon_aliases.js +66 -5
  28. package/lib/esm/rules/no_deprecated_icon_aliases.js.map +1 -1
  29. package/lib/esm/utils/button_group_constants.d.ts +5 -0
  30. package/lib/esm/utils/button_group_constants.js +20 -0
  31. package/lib/esm/utils/button_group_constants.js.map +1 -0
  32. package/lib/esm/utils/collect_jsx_children.d.ts +2 -0
  33. package/lib/esm/utils/collect_jsx_children.js +21 -0
  34. package/lib/esm/utils/collect_jsx_children.js.map +1 -0
  35. package/package.json +2 -3
package/README.md CHANGED
@@ -380,10 +380,11 @@ Enforce that `EuiButtonGroup` children (when using the Children API) are valid b
380
380
  Valid direct children depend on the variant:
381
381
  - `variant="default"` (or no variant): `EuiButton`, `EuiButtonEmpty`, and `EuiButtonIcon`
382
382
  - `variant="segmented"`: `EuiButton` and `EuiButtonIcon` only (`EuiButtonEmpty` is not allowed)
383
+ - `variant="selection"`: `EuiButton` and `EuiButtonIcon` only (`EuiButtonEmpty` is not allowed)
383
384
 
384
- In addition, these wrapper components are allowed for both variants: `EuiPopover`, `EuiToolTip`, and `EuiCopy`.
385
+ In addition, these wrapper components are allowed for all variants: `EuiPopover`, `EuiToolTip`, and `EuiCopy`.
385
386
 
386
- For `variant="segmented"`, all children must also use the **same button type** — either all `EuiButton` or all `EuiButtonIcon`. Mixing both types is reported as an error, including when buttons appear inside `EuiToolTip`, as an `EuiPopover` trigger, or in an `EuiCopy` render prop.
387
+ For `variant="segmented"` and `variant="selection"`, all children must also use the **same button type** — either all `EuiButton` or all `EuiButtonIcon`. Mixing both types is reported as an error, including when buttons appear inside `EuiToolTip`, as an `EuiPopover` trigger, or in an `EuiCopy` render prop.
387
388
 
388
389
  #### Examples
389
390
 
@@ -406,6 +407,17 @@ For `variant="segmented"`, all children must also use the **same button type**
406
407
  <EuiButtonIcon iconType="trash" aria-label="Delete" />
407
408
  </EuiButtonGroup>
408
409
 
410
+ // ✗ Bad - variant="selection" with EuiButtonEmpty (not allowed)
411
+ <EuiButtonGroup legend="Format" variant="selection">
412
+ <EuiButtonEmpty color="text">Bold</EuiButtonEmpty>
413
+ </EuiButtonGroup>
414
+
415
+ // ✗ Bad - variant="selection" mixing EuiButton and EuiButtonIcon
416
+ <EuiButtonGroup legend="Format" variant="selection">
417
+ <EuiButton id="bold">Bold</EuiButton>
418
+ <EuiButtonIcon id="italic" iconType="italic" aria-label="Italic" />
419
+ </EuiButtonGroup>
420
+
409
421
  // ✓ Good - direct buttons
410
422
  <EuiButtonGroup legend="Actions">
411
423
  <EuiButton>Save</EuiButton>
@@ -469,6 +481,18 @@ For `variant="segmented"`, all children must also use the **same button type**
469
481
  <EuiButtonIcon iconType="pencil" aria-label="Edit" />
470
482
  <EuiButtonIcon iconType="trash" aria-label="Delete" />
471
483
  </EuiButtonGroup>
484
+
485
+ // ✓ Good - variant="selection" with all EuiButton
486
+ <EuiButtonGroup legend="Format" variant="selection">
487
+ <EuiButton id="bold">Bold</EuiButton>
488
+ <EuiButton id="italic">Italic</EuiButton>
489
+ </EuiButtonGroup>
490
+
491
+ // ✓ Good - variant="selection" with all EuiButtonIcon
492
+ <EuiButtonGroup legend="Format" variant="selection">
493
+ <EuiButtonIcon id="bold" iconType="bold" aria-label="Bold" />
494
+ <EuiButtonIcon id="italic" iconType="italic" aria-label="Italic" />
495
+ </EuiButtonGroup>
472
496
  ```
473
497
 
474
498
  #### Custom button wrapper components
@@ -480,6 +504,51 @@ If a project-specific button component (e.g. `<SaveButton />`) is used as a chil
480
504
  <SaveButton />
481
505
  ```
482
506
 
507
+ ### `@elastic/eui/button-group-selection-require-id`
508
+
509
+ Enforce that every `EuiButton` and `EuiButtonIcon` child of an `EuiButtonGroup` with `variant="selection"` has an `id` prop. The selection variant uses the `id` of each button to track which buttons are selected, so a missing `id` will cause incorrect or broken selection state at runtime.
510
+
511
+ The rule only fires when `variant="selection"` is set as a static string. Dynamic variants (`variant={myVar}`) are skipped conservatively. It traverses the same nesting depth as `button-group-no-invalid-children`: fragments, conditionals, variable resolution, `.map()`, and the three supported wrappers (`EuiToolTip`, `EuiPopover` trigger, `EuiCopy` render prop). Children with spread props (`{...props}`) are skipped — the `id` may be provided via the spread.
512
+
513
+ #### Examples
514
+
515
+ ```tsx
516
+ // ✗ Bad - missing id on direct child
517
+ <EuiButtonGroup legend="Format" variant="selection">
518
+ <EuiButton>Bold</EuiButton>
519
+ </EuiButtonGroup>
520
+
521
+ // ✗ Bad - missing id on button inside EuiToolTip
522
+ <EuiButtonGroup legend="Format" variant="selection">
523
+ <EuiToolTip content="Italic">
524
+ <EuiButton>Italic</EuiButton>
525
+ </EuiToolTip>
526
+ </EuiButtonGroup>
527
+
528
+ // ✗ Bad - missing id on EuiPopover trigger
529
+ <EuiButtonGroup legend="Format" variant="selection">
530
+ <EuiPopover button={<EuiButton>More</EuiButton>} isOpen={false} closePopover={() => {}}>
531
+ Panel content
532
+ </EuiPopover>
533
+ </EuiButtonGroup>
534
+
535
+ // ✓ Good - all children have id
536
+ <EuiButtonGroup legend="Format" variant="selection">
537
+ <EuiButton id="bold">Bold</EuiButton>
538
+ <EuiToolTip content="Italic">
539
+ <EuiButton id="italic">Italic</EuiButton>
540
+ </EuiToolTip>
541
+ <EuiPopover button={<EuiButton id="more">More</EuiButton>} isOpen={false} closePopover={() => {}}>
542
+ Panel content
543
+ </EuiPopover>
544
+ </EuiButtonGroup>
545
+
546
+ // ✓ Good - spread props are skipped (id may come from the spread)
547
+ <EuiButtonGroup legend="Format" variant="selection">
548
+ <EuiButton {...buttonProps} />
549
+ </EuiButtonGroup>
550
+ ```
551
+
483
552
  ## Testing
484
553
 
485
554
  ### Running unit tests
package/lib/cjs/index.js CHANGED
@@ -24,6 +24,7 @@ var _tooltip_no_interactive_content = require("./rules/a11y/tooltip_no_interacti
24
24
  var _tooltip_button_icon_wrap = require("./rules/a11y/tooltip_button_icon_wrap");
25
25
  var _no_deprecated_icon_aliases = require("./rules/no_deprecated_icon_aliases");
26
26
  var _button_group_no_invalid_children = require("./rules/button_group_no_invalid_children");
27
+ var _button_group_selection_require_id = require("./rules/button_group_selection_require_id");
27
28
  /*
28
29
  * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
29
30
  * or more contributor license agreements. Licensed under the Elastic License
@@ -57,7 +58,8 @@ const config = {
57
58
  'require-href-for-link': _require_href_for_link.RequireHrefForLink,
58
59
  'tooltip-no-interactive-content': _tooltip_no_interactive_content.TooltipNoInteractiveContent,
59
60
  'tooltip-button-icon-wrap': _tooltip_button_icon_wrap.TooltipButtonIconWrap,
60
- 'button-group-no-invalid-children': _button_group_no_invalid_children.ButtonGroupNoInvalidChildren
61
+ 'button-group-no-invalid-children': _button_group_no_invalid_children.ButtonGroupNoInvalidChildren,
62
+ 'button-group-selection-require-id': _button_group_selection_require_id.ButtonGroupSelectionRequireId
61
63
  },
62
64
  configs: {
63
65
  recommended: {
@@ -65,6 +67,7 @@ const config = {
65
67
  rules: {
66
68
  '@elastic/eui/accessible-interactive-element': 'warn',
67
69
  '@elastic/eui/button-group-no-invalid-children': 'error',
70
+ '@elastic/eui/button-group-selection-require-id': 'error',
68
71
  '@elastic/eui/callout-announce-on-mount': 'warn',
69
72
  '@elastic/eui/callout-prefer-props-for-content': 'warn',
70
73
  '@elastic/eui/consistent-is-invalid-props': 'warn',
@@ -1,5 +1,3 @@
1
1
  import { type TSESLint } from '@typescript-eslint/utils';
2
- export declare const VALID_BUTTONS: Set<string>;
3
- export declare const SEGMENTED_VALID_BUTTONS: Set<string>;
4
- export declare const ButtonGroupNoInvalidChildren: TSESLint.RuleModule<"invalidUnresolvableWrapperChild" | "invalidWrapperChild" | "invalidChild" | "invalidUnresolvableChild" | "invalidPopoverButton" | "invalidUnresolvablePopoverButton" | "invalidSegmentedMixedTypes", [], unknown, TSESLint.RuleListener>;
2
+ export declare const ButtonGroupNoInvalidChildren: TSESLint.RuleModule<"invalidUnresolvableWrapperChild" | "invalidWrapperChild" | "invalidChild" | "invalidUnresolvableChild" | "invalidPopoverButton" | "invalidUnresolvablePopoverButton" | "invalidMixedTypes", [], unknown, TSESLint.RuleListener>;
5
3
  //# sourceMappingURL=button_group_no_invalid_children.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"button_group_no_invalid_children.d.ts","sourceRoot":"","sources":["../../../src/rules/button_group_no_invalid_children.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;AAQlC,eAAO,MAAM,aAAa,aAIxB,CAAC;AACH,eAAO,MAAM,uBAAuB,aAA0C,CAAC;AA4D/E,eAAO,MAAM,4BAA4B,+PA2OxC,CAAC"}
1
+ {"version":3,"file":"button_group_no_invalid_children.d.ts","sourceRoot":"","sources":["../../../src/rules/button_group_no_invalid_children.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;AAwDlC,eAAO,MAAM,4BAA4B,sPAsPxC,CAAC"}
@@ -3,13 +3,14 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.VALID_BUTTONS = exports.SEGMENTED_VALID_BUTTONS = exports.ButtonGroupNoInvalidChildren = void 0;
6
+ exports.ButtonGroupNoInvalidChildren = void 0;
7
7
  var _utils = require("@typescript-eslint/utils");
8
8
  var _has_spread = require("../utils/has_spread");
9
9
  var _flat_map = require("../utils/flat_map");
10
10
  var _get_element_name = require("../utils/get_element_name");
11
- var _walk_jsx_children = require("../utils/walk_jsx_children");
12
11
  var _get_attr_value = require("../utils/get_attr_value");
12
+ var _collect_jsx_children = require("../utils/collect_jsx_children");
13
+ var _button_group_constants = require("../utils/button_group_constants");
13
14
  /*
14
15
  * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
15
16
  * or more contributor license agreements. Licensed under the Elastic License
@@ -18,27 +19,12 @@ var _get_attr_value = require("../utils/get_attr_value");
18
19
  * Side Public License, v 1.
19
20
  */
20
21
 
21
- const BUTTON_GROUP = 'EuiButtonGroup';
22
- const VALID_BUTTONS = exports.VALID_BUTTONS = new Set(['EuiButton', 'EuiButtonEmpty', 'EuiButtonIcon']);
23
- const SEGMENTED_VALID_BUTTONS = exports.SEGMENTED_VALID_BUTTONS = new Set(['EuiButton', 'EuiButtonIcon']);
24
- const VALID_WRAPPERS = new Set(['EuiToolTip', 'EuiPopover', 'EuiCopy']);
25
- const VALID_WRAPPERS_LIST = Array.from(VALID_WRAPPERS).join(', ');
22
+ const VALID_WRAPPERS_LIST = Array.from(_button_group_constants.VALID_WRAPPERS).join(', ');
26
23
  function isCustomComponent(name) {
27
24
  return name[0] === name[0].toUpperCase();
28
25
  }
29
- function collectJsxChildren(node, sourceCode) {
30
- const results = [];
31
- (0, _walk_jsx_children.walkJsxChildren)(node, leaf => {
32
- if (leaf.type === 'JSXElement') {
33
- results.push(leaf);
34
- }
35
- }, {
36
- sourceCode
37
- });
38
- return results;
39
- }
40
26
  function reportInvalidWrapperChildren(wrapper, wrapperName, context, validButtons, allowed, seenButtonTypes) {
41
- const children = (0, _flat_map.flatMap)(wrapper.children, c => collectJsxChildren(c, context.sourceCode));
27
+ const children = (0, _flat_map.flatMap)(wrapper.children, c => (0, _collect_jsx_children.collectJsxChildren)(c, context.sourceCode));
42
28
  for (const wrapperChild of children) {
43
29
  if ((0, _has_spread.hasSpread)(wrapperChild.openingElement.attributes)) continue;
44
30
  const wrapperChildName = (0, _get_element_name.getElementName)(wrapperChild.openingElement);
@@ -49,7 +35,7 @@ function reportInvalidWrapperChildren(wrapper, wrapperName, context, validButton
49
35
  }
50
36
  context.report({
51
37
  node: wrapperChild.openingElement,
52
- messageId: isCustomComponent(wrapperChildName) && !VALID_BUTTONS.has(wrapperChildName) ? 'invalidUnresolvableWrapperChild' : 'invalidWrapperChild',
38
+ messageId: isCustomComponent(wrapperChildName) && !_button_group_constants.VALID_BUTTONS.has(wrapperChildName) ? 'invalidUnresolvableWrapperChild' : 'invalidWrapperChild',
53
39
  data: {
54
40
  name: wrapperChildName,
55
41
  wrapper: wrapperName,
@@ -65,23 +51,24 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
65
51
  const {
66
52
  openingElement
67
53
  } = node;
68
- if (openingElement.name.type !== 'JSXIdentifier' || openingElement.name.name !== BUTTON_GROUP) {
54
+ if (openingElement.name.type !== 'JSXIdentifier' || openingElement.name.name !== _button_group_constants.BUTTON_GROUP) {
69
55
  return;
70
56
  }
71
57
 
72
- // Validate "default" and "segmented" variants.
58
+ // Validate "default", "segmented", and "selection" variants.
73
59
  // Dynamic variant values (variables) are conservatively skipped.
74
60
  const variant = (0, _get_attr_value.findAttrValue)(context, openingElement.attributes, 'variant');
75
- if (variant !== undefined && variant !== 'default' && variant !== 'segmented') return;
61
+ if (variant !== undefined && variant !== 'default' && variant !== 'segmented' && variant !== 'selection') return;
76
62
  const isSegmented = variant === 'segmented';
77
- const validButtons = isSegmented ? SEGMENTED_VALID_BUTTONS : VALID_BUTTONS;
63
+ const isSelection = variant === 'selection';
64
+ const validButtons = isSegmented ? _button_group_constants.SEGMENTED_VALID_BUTTONS : isSelection ? _button_group_constants.SELECTION_VALID_BUTTONS : _button_group_constants.VALID_BUTTONS;
78
65
  const allowed = Array.from(validButtons).join(', ');
79
- const children = (0, _flat_map.flatMap)(node.children, c => collectJsxChildren(c, context.sourceCode));
66
+ const children = (0, _flat_map.flatMap)(node.children, c => (0, _collect_jsx_children.collectJsxChildren)(c, context.sourceCode));
80
67
  if (children.length === 0) return;
81
68
 
82
- // Collect seen button types for the segmented mixed-type check.
69
+ // Collect seen button types for the segmented/selection mixed-type check.
83
70
  // Populated during the main loop to avoid a second traversal.
84
- const seenButtonTypes = isSegmented ? new Set() : null;
71
+ const seenButtonTypes = isSegmented || isSelection ? new Set() : null;
85
72
  for (const child of children) {
86
73
  const name = (0, _get_element_name.getElementName)(child.openingElement);
87
74
  if (name === null) continue;
@@ -89,7 +76,7 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
89
76
  seenButtonTypes?.add(name);
90
77
  continue;
91
78
  }
92
- if (VALID_WRAPPERS.has(name)) {
79
+ if (_button_group_constants.VALID_WRAPPERS.has(name)) {
93
80
  if (name === 'EuiToolTip') {
94
81
  // Validate JSX children (expanding fragments/conditionals).
95
82
  // Also collects button types for the segmented mixed-type check.
@@ -101,7 +88,7 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
101
88
  // EuiToolTip wrapping the trigger button is also supported.
102
89
  const buttonProp = child.openingElement.attributes.find(attr => attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier' && attr.name.name === 'button');
103
90
  if (buttonProp?.value != null) {
104
- const triggerElements = collectJsxChildren(buttonProp.value, context.sourceCode);
91
+ const triggerElements = (0, _collect_jsx_children.collectJsxChildren)(buttonProp.value, context.sourceCode);
105
92
  for (const triggerElement of triggerElements) {
106
93
  if ((0, _has_spread.hasSpread)(triggerElement.openingElement.attributes)) continue;
107
94
  const triggerElementName = (0, _get_element_name.getElementName)(triggerElement.openingElement);
@@ -112,7 +99,7 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
112
99
  }
113
100
  if (triggerElementName === 'EuiToolTip') {
114
101
  // EuiToolTip wrapping the trigger — validate its children.
115
- const tooltipChildren = (0, _flat_map.flatMap)(triggerElement.children, c => collectJsxChildren(c, context.sourceCode));
102
+ const tooltipChildren = (0, _flat_map.flatMap)(triggerElement.children, c => (0, _collect_jsx_children.collectJsxChildren)(c, context.sourceCode));
116
103
  for (const tooltipChild of tooltipChildren) {
117
104
  if ((0, _has_spread.hasSpread)(tooltipChild.openingElement.attributes)) continue;
118
105
  const tooltipChildName = (0, _get_element_name.getElementName)(tooltipChild.openingElement);
@@ -123,7 +110,7 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
123
110
  }
124
111
  context.report({
125
112
  node: tooltipChild.openingElement,
126
- messageId: isCustomComponent(tooltipChildName) && !VALID_BUTTONS.has(tooltipChildName) ? 'invalidUnresolvablePopoverButton' : 'invalidPopoverButton',
113
+ messageId: isCustomComponent(tooltipChildName) && !_button_group_constants.VALID_BUTTONS.has(tooltipChildName) ? 'invalidUnresolvablePopoverButton' : 'invalidPopoverButton',
127
114
  data: {
128
115
  name: tooltipChildName,
129
116
  allowed
@@ -134,7 +121,7 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
134
121
  }
135
122
  context.report({
136
123
  node: triggerElement.openingElement,
137
- messageId: isCustomComponent(triggerElementName) && !VALID_BUTTONS.has(triggerElementName) ? 'invalidUnresolvablePopoverButton' : 'invalidPopoverButton',
124
+ messageId: isCustomComponent(triggerElementName) && !_button_group_constants.VALID_BUTTONS.has(triggerElementName) ? 'invalidUnresolvablePopoverButton' : 'invalidPopoverButton',
138
125
  data: {
139
126
  name: triggerElementName,
140
127
  allowed
@@ -157,7 +144,7 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
157
144
  if ((0, _has_spread.hasSpread)(child.openingElement.attributes)) continue;
158
145
  context.report({
159
146
  node: child.openingElement,
160
- messageId: isCustomComponent(name) && !VALID_BUTTONS.has(name) ? 'invalidUnresolvableChild' : 'invalidChild',
147
+ messageId: isCustomComponent(name) && !_button_group_constants.VALID_BUTTONS.has(name) ? 'invalidUnresolvableChild' : 'invalidChild',
161
148
  data: {
162
149
  name,
163
150
  allowed
@@ -165,13 +152,16 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
165
152
  });
166
153
  }
167
154
 
168
- // For segmented, all children must be the same button type — either
169
- // all EuiButton or all EuiButtonIcon. Types are collected during the
170
- // main loop above, including from EuiToolTip, EuiPopover, and EuiCopy.
155
+ // For segmented/selection, all children must be the same button type —
156
+ // either all EuiButton or all EuiButtonIcon. Types are collected during
157
+ // the main loop above, including from EuiToolTip, EuiPopover, and EuiCopy.
171
158
  if (seenButtonTypes?.has('EuiButton') && seenButtonTypes.has('EuiButtonIcon')) {
172
159
  context.report({
173
160
  node: openingElement,
174
- messageId: 'invalidSegmentedMixedTypes'
161
+ messageId: 'invalidMixedTypes',
162
+ data: {
163
+ variant: isSelection ? 'selection' : 'segmented'
164
+ }
175
165
  });
176
166
  }
177
167
  }
@@ -190,7 +180,7 @@ const ButtonGroupNoInvalidChildren = exports.ButtonGroupNoInvalidChildren = _uti
190
180
  invalidUnresolvablePopoverButton: [`{{ name }} cannot be verified as a valid trigger button for EuiPopover in EuiButtonGroup.`, `The \`button\` prop must be {{ allowed }}.`, `If {{ name }} is a shared button wrapper component only containing`, `valid button children, suppress this rule inline with a comment`, `explaining why it's valid.`, `// eslint-disable-next-line @elastic/eui/button-group-no-invalid-children -- SaveButton only wraps EuiButton`].join(' '),
191
181
  invalidWrapperChild: [`{{ name }} inside {{ wrapper }} is not a valid button for EuiButtonGroup.`, `The wrapper must contain {{ allowed }}.`].join(' '),
192
182
  invalidUnresolvableWrapperChild: [`{{ name }} inside {{ wrapper }} cannot be verified as a valid button for EuiButtonGroup.`, `The wrapper must contain {{ allowed }}.`, `If {{ name }} is a shared button wrapper component, suppress this rule inline`, `with a comment explaining why it renders valid button children:`, `// eslint-disable-next-line @elastic/eui/button-group-no-invalid-children -- SaveButton wraps EuiButton`].join(' '),
193
- invalidSegmentedMixedTypes: [`EuiButtonGroup with variant="segmented" must use a single button type throughout.`, `Use either all EuiButton or all EuiButtonIcon children — not both.`].join(' ')
183
+ invalidMixedTypes: [`EuiButtonGroup with variant="{{ variant }}" must use a single button type throughout.`, `Use either all EuiButton or all EuiButtonIcon children — not both.`].join(' ')
194
184
  }
195
185
  },
196
186
  defaultOptions: []
@@ -0,0 +1,3 @@
1
+ import { type TSESLint } from '@typescript-eslint/utils';
2
+ export declare const ButtonGroupSelectionRequireId: TSESLint.RuleModule<"missingId", [], unknown, TSESLint.RuleListener>;
3
+ //# sourceMappingURL=button_group_selection_require_id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button_group_selection_require_id.d.ts","sourceRoot":"","sources":["../../../src/rules/button_group_selection_require_id.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;AA8BlC,eAAO,MAAM,6BAA6B,sEAiHtC,CAAC"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ButtonGroupSelectionRequireId = void 0;
7
+ var _utils = require("@typescript-eslint/utils");
8
+ var _has_spread = require("../utils/has_spread");
9
+ var _flat_map = require("../utils/flat_map");
10
+ var _get_element_name = require("../utils/get_element_name");
11
+ var _get_attr_value = require("../utils/get_attr_value");
12
+ var _has_meaningful_attr = require("../utils/has_meaningful_attr");
13
+ var _collect_jsx_children = require("../utils/collect_jsx_children");
14
+ var _button_group_constants = require("../utils/button_group_constants");
15
+ /*
16
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
17
+ * or more contributor license agreements. Licensed under the Elastic License
18
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
19
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
20
+ * Side Public License, v 1.
21
+ */
22
+
23
+ function checkButtonForId(element, context) {
24
+ const name = (0, _get_element_name.getElementName)(element.openingElement);
25
+ if (name === null || !_button_group_constants.SELECTION_VALID_BUTTONS.has(name)) return;
26
+ const {
27
+ attributes
28
+ } = element.openingElement;
29
+ if ((0, _has_meaningful_attr.hasMeaningfulAttr)(element.openingElement, 'id')) return;
30
+ if ((0, _has_spread.hasSpread)(attributes)) return;
31
+ context.report({
32
+ node: element.openingElement,
33
+ messageId: 'missingId',
34
+ data: {
35
+ name
36
+ }
37
+ });
38
+ }
39
+ const ButtonGroupSelectionRequireId = exports.ButtonGroupSelectionRequireId = _utils.ESLintUtils.RuleCreator.withoutDocs({
40
+ create(context) {
41
+ return {
42
+ JSXElement(node) {
43
+ const {
44
+ openingElement
45
+ } = node;
46
+ if (openingElement.name.type !== 'JSXIdentifier' || openingElement.name.name !== _button_group_constants.BUTTON_GROUP) {
47
+ return;
48
+ }
49
+
50
+ // Only validate variant="selection". Dynamic or other variants are skipped.
51
+ const variant = (0, _get_attr_value.findAttrValue)(context, openingElement.attributes, 'variant');
52
+ if (variant !== 'selection') return;
53
+ const children = (0, _flat_map.flatMap)(node.children, c => (0, _collect_jsx_children.collectJsxChildren)(c, context.sourceCode));
54
+ if (children.length === 0) return;
55
+ for (const child of children) {
56
+ const name = (0, _get_element_name.getElementName)(child.openingElement);
57
+ if (name === null) continue;
58
+ if (_button_group_constants.SELECTION_VALID_BUTTONS.has(name)) {
59
+ checkButtonForId(child, context);
60
+ continue;
61
+ }
62
+ if (_button_group_constants.VALID_WRAPPERS.has(name)) {
63
+ if (name === 'EuiToolTip') {
64
+ const wrapperChildren = (0, _flat_map.flatMap)(child.children, c => (0, _collect_jsx_children.collectJsxChildren)(c, context.sourceCode));
65
+ for (const wrapperChild of wrapperChildren) {
66
+ checkButtonForId(wrapperChild, context);
67
+ }
68
+ } else if (name === 'EuiPopover') {
69
+ const buttonProp = child.openingElement.attributes.find(attr => attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier' && attr.name.name === 'button');
70
+ if (buttonProp?.value != null) {
71
+ const triggerElements = (0, _collect_jsx_children.collectJsxChildren)(buttonProp.value, context.sourceCode);
72
+ for (const triggerElement of triggerElements) {
73
+ const triggerName = (0, _get_element_name.getElementName)(triggerElement.openingElement);
74
+ if (triggerName === null) continue;
75
+ if (_button_group_constants.SELECTION_VALID_BUTTONS.has(triggerName)) {
76
+ checkButtonForId(triggerElement, context);
77
+ continue;
78
+ }
79
+ if (triggerName === 'EuiToolTip') {
80
+ // EuiToolTip wrapping the popover trigger — check its children.
81
+ const tooltipChildren = (0, _flat_map.flatMap)(triggerElement.children, c => (0, _collect_jsx_children.collectJsxChildren)(c, context.sourceCode));
82
+ for (const tooltipChild of tooltipChildren) {
83
+ checkButtonForId(tooltipChild, context);
84
+ }
85
+ }
86
+ }
87
+ }
88
+ } else if (name === 'EuiCopy') {
89
+ // Children is a render prop; walkJsxChildren expands it.
90
+ const wrapperChildren = (0, _flat_map.flatMap)(child.children, c => (0, _collect_jsx_children.collectJsxChildren)(c, context.sourceCode));
91
+ for (const wrapperChild of wrapperChildren) {
92
+ checkButtonForId(wrapperChild, context);
93
+ }
94
+ }
95
+ continue;
96
+ }
97
+
98
+ // Non-button, non-wrapper children are skipped — the other rule handles those.
99
+ }
100
+ }
101
+ };
102
+ },
103
+ meta: {
104
+ type: 'problem',
105
+ docs: {
106
+ description: 'Enforce that EuiButtonGroup children have an id prop when variant="selection"'
107
+ },
108
+ schema: [],
109
+ messages: {
110
+ missingId: [`{{ name }} inside EuiButtonGroup with variant="selection" is missing a required id prop.`, `Each button must have a unique id so the group can track selection state.`].join(' ')
111
+ }
112
+ },
113
+ defaultOptions: []
114
+ });
@@ -1,7 +1,11 @@
1
1
  import { ESLintUtils } from '@typescript-eslint/utils';
2
2
  export declare const DEPRECATED_ICON_ALIASES: {
3
3
  readonly alert: "warning";
4
+ readonly analyzeEvent: "cube";
4
5
  readonly anomalyChart: "chartAnomaly";
6
+ readonly anomalySwimLane: "chartHeatmap";
7
+ readonly annotation: "flag";
8
+ readonly apps: "grid";
5
9
  readonly apmTrace: "chartWaterfall";
6
10
  readonly arrowDown: "chevronSingleDown";
7
11
  readonly arrowEnd: "chevronLimitRight";
@@ -21,6 +25,9 @@ export declare const DEPRECATED_ICON_ALIASES: {
21
25
  readonly color: "paintBucket";
22
26
  readonly compute: "processor";
23
27
  readonly console: "commandLine";
28
+ readonly container: "package";
29
+ readonly continuityAbove: "upload";
30
+ readonly continuityWithin: "maximize";
24
31
  readonly contrastHigh: "contrastFill";
25
32
  readonly controlsHorizontal: "controls";
26
33
  readonly controlsVertical: "controls";
@@ -67,6 +74,7 @@ export declare const DEPRECATED_ICON_ALIASES: {
67
74
  readonly editorUnorderedList: "listBullet";
68
75
  readonly email: "mail";
69
76
  readonly eql: "query";
77
+ readonly esqlVis: "query";
70
78
  readonly errorFilled: "errorFill";
71
79
  readonly exit: "logOut";
72
80
  readonly expand: "maximize";
@@ -76,15 +84,23 @@ export declare const DEPRECATED_ICON_ALIASES: {
76
84
  readonly eyeClosed: "eyeSlash";
77
85
  readonly fieldStatistics: "tableInfo";
78
86
  readonly filterInCircle: "filter";
87
+ readonly fold: "minimize";
79
88
  readonly folderCheck: "check";
89
+ readonly folderClose: "folder";
90
+ readonly folderClosed: "folder";
80
91
  readonly folderOpened: "folderOpen";
92
+ readonly frameNext: "chevronSingleRight";
93
+ readonly framePrevious: "chevronSingleLeft";
81
94
  readonly glasses: "readOnly";
95
+ readonly help: "question";
82
96
  readonly grab: "dragVertical";
83
97
  readonly grabHorizontal: "dragHorizontal";
84
98
  readonly grabOmnidirectional: "drag";
85
99
  readonly heatmap: "chartHeatmap";
86
100
  readonly importAction: "download";
101
+ readonly index: "table";
87
102
  readonly indexClose: "tableCross";
103
+ readonly ip: "tokenIP";
88
104
  readonly indexEdit: "tablePencil";
89
105
  readonly indexFlush: "chartThreshold";
90
106
  readonly indexMapping: "mapping";
@@ -107,7 +123,10 @@ export declare const DEPRECATED_ICON_ALIASES: {
107
123
  readonly listAdd: "plusCircle";
108
124
  readonly logPatternAnalysis: "pattern";
109
125
  readonly logRateAnalysis: "chartBarVertical";
126
+ readonly logstashFilter: "filter";
110
127
  readonly logstashIf: "if";
128
+ readonly logstashInput: "download";
129
+ readonly logstashOutput: "upload";
111
130
  readonly logstashQueue: "queue";
112
131
  readonly magnifyWithExclamation: "magnifyExclamation";
113
132
  readonly magnifyWithMinus: "magnifyMinus";
@@ -124,6 +143,7 @@ export declare const DEPRECATED_ICON_ALIASES: {
124
143
  readonly offline: "wifiSlash";
125
144
  readonly online: "wifi";
126
145
  readonly pagesSelect: "documentsCheck";
146
+ readonly payment: "money";
127
147
  readonly pinFilled: "pinFill";
128
148
  readonly pipeBreaks: "lineBreak";
129
149
  readonly pipeNoBreaks: "lineBreakSlash";
@@ -136,15 +156,27 @@ export declare const DEPRECATED_ICON_ALIASES: {
136
156
  readonly returnKey: "return";
137
157
  readonly search: "magnify";
138
158
  readonly securitySignal: "radar";
159
+ readonly sessionViewer: "commandLine";
160
+ readonly singleMetricViewer: "chartArea";
161
+ readonly spaces: "grid";
139
162
  readonly starEmpty: "star";
163
+ readonly starEmptySpace: "star";
164
+ readonly starFillSpace: "starFill";
140
165
  readonly starFilled: "starFill";
141
- readonly starFilledSpace: "starFillSpace";
142
- readonly starMinusFilled: "starMinusFill";
143
- readonly starPlusFilled: "starPlusFill";
166
+ readonly starFilledSpace: "starFill";
167
+ readonly starMinusEmpty: "star";
168
+ readonly starMinusFill: "starFill";
169
+ readonly starMinusFilled: "starFill";
170
+ readonly starPlusEmpty: "star";
171
+ readonly starPlusFill: "starFill";
172
+ readonly starPlusFilled: "starFill";
144
173
  readonly stopFilled: "stopFill";
174
+ readonly stats: "chartLine";
145
175
  readonly streamsClassic: "productStreamsClassic";
146
176
  readonly streamsWired: "productStreamsWired";
177
+ readonly string: "tokenString";
147
178
  readonly submodule: "merge";
179
+ readonly tableOfContents: "listBullet";
148
180
  readonly tableDensityCompact: "tableDensityHigh";
149
181
  readonly tableDensityExpanded: "tableDensityLow";
150
182
  readonly tableDensityNormal: "table";
@@ -154,6 +186,7 @@ export declare const DEPRECATED_ICON_ALIASES: {
154
186
  readonly timeslider: "clockControl";
155
187
  readonly tokenDenseVector: "tokenVectorDense";
156
188
  readonly training: "presentation";
189
+ readonly unfold: "maximize";
157
190
  readonly unlink: "linkSlash";
158
191
  readonly userAvatar: "user";
159
192
  readonly vector: "vectorSquare";
@@ -164,6 +197,7 @@ export declare const DEPRECATED_ICON_ALIASES: {
164
197
  readonly visBarVertical: "chartBarVertical";
165
198
  readonly visBarVerticalStacked: "chartBarVerticalStack";
166
199
  readonly visGauge: "chartGauge";
200
+ readonly visGoal: "chartGauge";
167
201
  readonly visLine: "chartLine";
168
202
  readonly visMapCoordinate: "waypoint";
169
203
  readonly visMapRegion: "map";
@@ -176,7 +210,14 @@ export declare const DEPRECATED_ICON_ALIASES: {
176
210
  readonly visVega: "code";
177
211
  readonly visVisualBuilder: "productTSVB";
178
212
  readonly warningFilled: "warningFill";
213
+ readonly wordWrap: "lineBreak";
214
+ readonly wordWrapDisabled: "lineBreakSlash";
179
215
  };
180
216
  export declare const DEPRECATED_ICONS_WITHOUT_REPLACEMENT: ReadonlySet<string>;
181
- export declare const NoDeprecatedIconAliases: ESLintUtils.RuleModule<"deprecatedIcon" | "deprecatedIconAlias", [], unknown, ESLintUtils.RuleListener>;
217
+ export declare const DEPRECATED_ICONS_WITH_GUIDANCE: {
218
+ readonly folderExclamation: "Use `linkSlash` for unlink actions or `hourglass` for Kibana Cases status.";
219
+ readonly stopFill: "Use `EuiColorPickerSwatch` for a color chip or `stop` otherwise.";
220
+ readonly stopSlash: "Use `EuiColorPickerSwatch` for no/transparent color or `stop` otherwise.";
221
+ };
222
+ export declare const NoDeprecatedIconAliases: ESLintUtils.RuleModule<"deprecatedIcon" | "deprecatedIconAlias" | "deprecatedIconGuidance", [], unknown, ESLintUtils.RuleListener>;
182
223
  //# sourceMappingURL=no_deprecated_icon_aliases.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"no_deprecated_icon_aliases.d.ts","sourceRoot":"","sources":["../../../src/rules/no_deprecated_icon_aliases.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,WAAW,EAAY,MAAM,0BAA0B,CAAC;AAEjE,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiL1B,CAAC;AAEX,eAAO,MAAM,oCAAoC,EAAE,WAAW,CAAC,MAAM,CAChD,CAAC;AAwEtB,eAAO,MAAM,uBAAuB,yGAyGlC,CAAC"}
1
+ {"version":3,"file":"no_deprecated_icon_aliases.d.ts","sourceRoot":"","sources":["../../../src/rules/no_deprecated_icon_aliases.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,WAAW,EAAY,MAAM,0BAA0B,CAAC;AAEjE,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqN1B,CAAC;AAEX,eAAO,MAAM,oCAAoC,EAAE,WAAW,CAAC,MAAM,CAQjE,CAAC;AAEL,eAAO,MAAM,8BAA8B;;;;CAOjC,CAAC;AA+EX,eAAO,MAAM,uBAAuB,oIAuHlC,CAAC"}