@arbor-education/design-system.components 0.21.1 → 0.23.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 (189) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/component-library.md +77 -14
  3. package/dist/components/articleCard/ArticleCard.d.ts +2 -2
  4. package/dist/components/articleCard/ArticleCard.d.ts.map +1 -1
  5. package/dist/components/articleCard/ArticleCard.js +3 -3
  6. package/dist/components/articleCard/ArticleCard.js.map +1 -1
  7. package/dist/components/articleCard/ArticleCard.stories.d.ts +11 -3
  8. package/dist/components/articleCard/ArticleCard.stories.d.ts.map +1 -1
  9. package/dist/components/articleCard/ArticleCard.stories.js +16 -11
  10. package/dist/components/articleCard/ArticleCard.stories.js.map +1 -1
  11. package/dist/components/combobox/Combobox.js +1 -1
  12. package/dist/components/combobox/Combobox.js.map +1 -1
  13. package/dist/components/combobox/Combobox.stories.d.ts +4 -0
  14. package/dist/components/combobox/Combobox.stories.d.ts.map +1 -1
  15. package/dist/components/combobox/Combobox.stories.js +144 -12
  16. package/dist/components/combobox/Combobox.stories.js.map +1 -1
  17. package/dist/components/combobox/Combobox.test.js +22 -0
  18. package/dist/components/combobox/Combobox.test.js.map +1 -1
  19. package/dist/components/combobox/ComboboxButtonTrigger.d.ts +4 -4
  20. package/dist/components/combobox/ComboboxButtonTrigger.d.ts.map +1 -1
  21. package/dist/components/combobox/ComboboxButtonTrigger.js +35 -40
  22. package/dist/components/combobox/ComboboxButtonTrigger.js.map +1 -1
  23. package/dist/components/combobox/ComboboxTrigger.d.ts.map +1 -1
  24. package/dist/components/combobox/ComboboxTrigger.js +11 -4
  25. package/dist/components/combobox/ComboboxTrigger.js.map +1 -1
  26. package/dist/components/combobox/useVisibleTriggerTags.d.ts +21 -0
  27. package/dist/components/combobox/useVisibleTriggerTags.d.ts.map +1 -0
  28. package/dist/components/combobox/useVisibleTriggerTags.js +46 -0
  29. package/dist/components/combobox/useVisibleTriggerTags.js.map +1 -0
  30. package/dist/components/combobox/useVisibleTriggerTags.test.d.ts +2 -0
  31. package/dist/components/combobox/useVisibleTriggerTags.test.d.ts.map +1 -0
  32. package/dist/components/combobox/useVisibleTriggerTags.test.js +81 -0
  33. package/dist/components/combobox/useVisibleTriggerTags.test.js.map +1 -0
  34. package/dist/components/filterBar/FilterBar.d.ts +71 -0
  35. package/dist/components/filterBar/FilterBar.d.ts.map +1 -0
  36. package/dist/components/filterBar/FilterBar.js +89 -0
  37. package/dist/components/filterBar/FilterBar.js.map +1 -0
  38. package/dist/components/filterBar/FilterBar.stories.d.ts +170 -0
  39. package/dist/components/filterBar/FilterBar.stories.d.ts.map +1 -0
  40. package/dist/components/filterBar/FilterBar.stories.js +894 -0
  41. package/dist/components/filterBar/FilterBar.stories.js.map +1 -0
  42. package/dist/components/filterBar/FilterBar.test.d.ts +2 -0
  43. package/dist/components/filterBar/FilterBar.test.d.ts.map +1 -0
  44. package/dist/components/filterBar/FilterBar.test.js +164 -0
  45. package/dist/components/filterBar/FilterBar.test.js.map +1 -0
  46. package/dist/components/icon/allowedIcons.d.ts +1 -0
  47. package/dist/components/icon/allowedIcons.d.ts.map +1 -1
  48. package/dist/components/icon/allowedIcons.js +2 -1
  49. package/dist/components/icon/allowedIcons.js.map +1 -1
  50. package/dist/components/iconText/IconText.d.ts +43 -0
  51. package/dist/components/iconText/IconText.d.ts.map +1 -0
  52. package/dist/components/iconText/IconText.js +29 -0
  53. package/dist/components/iconText/IconText.js.map +1 -0
  54. package/dist/components/{icoText/IcoText.stories.d.ts → iconText/IconText.stories.d.ts} +8 -9
  55. package/dist/components/iconText/IconText.stories.d.ts.map +1 -0
  56. package/dist/components/{icoText/IcoText.stories.js → iconText/IconText.stories.js} +81 -81
  57. package/dist/components/iconText/IconText.stories.js.map +1 -0
  58. package/dist/components/iconText/IconText.test.d.ts +2 -0
  59. package/dist/components/iconText/IconText.test.d.ts.map +1 -0
  60. package/dist/components/{icoText/IcoText.test.js → iconText/IconText.test.js} +6 -6
  61. package/dist/components/iconText/IconText.test.js.map +1 -0
  62. package/dist/components/modal/Modal.d.ts +1 -0
  63. package/dist/components/modal/Modal.d.ts.map +1 -1
  64. package/dist/components/modal/Modal.js +2 -2
  65. package/dist/components/modal/Modal.js.map +1 -1
  66. package/dist/components/table/cellRenderers/ComboboxCellRenderer.test.d.ts.map +1 -1
  67. package/dist/components/table/cellRenderers/ComboboxCellRenderer.test.js +13 -2
  68. package/dist/components/table/cellRenderers/ComboboxCellRenderer.test.js.map +1 -1
  69. package/dist/components/tag/Tag.d.ts +14 -1
  70. package/dist/components/tag/Tag.d.ts.map +1 -1
  71. package/dist/components/tag/Tag.js +9 -3
  72. package/dist/components/tag/Tag.js.map +1 -1
  73. package/dist/components/tag/Tag.stories.d.ts +1 -1
  74. package/dist/components/tag/Tag.stories.d.ts.map +1 -1
  75. package/dist/components/tag/Tag.stories.js +3 -3
  76. package/dist/components/tag/Tag.stories.js.map +1 -1
  77. package/dist/components/tag/Tag.test.js +36 -5
  78. package/dist/components/tag/Tag.test.js.map +1 -1
  79. package/dist/components/tagList/TagList.d.ts +49 -0
  80. package/dist/components/tagList/TagList.d.ts.map +1 -0
  81. package/dist/components/tagList/TagList.js +114 -0
  82. package/dist/components/tagList/TagList.js.map +1 -0
  83. package/dist/components/tagList/TagList.stories.d.ts +130 -0
  84. package/dist/components/tagList/TagList.stories.d.ts.map +1 -0
  85. package/dist/components/tagList/TagList.stories.js +443 -0
  86. package/dist/components/tagList/TagList.stories.js.map +1 -0
  87. package/dist/components/{icoText/IcoText.test.d.ts → tagList/TagList.test.d.ts} +1 -1
  88. package/dist/components/tagList/TagList.test.d.ts.map +1 -0
  89. package/dist/components/tagList/TagList.test.js +246 -0
  90. package/dist/components/tagList/TagList.test.js.map +1 -0
  91. package/dist/components/tagList/useTagListCollapsedLayout.d.ts +19 -0
  92. package/dist/components/tagList/useTagListCollapsedLayout.d.ts.map +1 -0
  93. package/dist/components/tagList/useTagListCollapsedLayout.js +48 -0
  94. package/dist/components/tagList/useTagListCollapsedLayout.js.map +1 -0
  95. package/dist/components/tagList/useVisibleTags.d.ts +18 -0
  96. package/dist/components/tagList/useVisibleTags.d.ts.map +1 -0
  97. package/dist/components/tagList/useVisibleTags.js +41 -0
  98. package/dist/components/tagList/useVisibleTags.js.map +1 -0
  99. package/dist/index.css +272 -13
  100. package/dist/index.css.map +1 -1
  101. package/dist/index.d.ts +4 -1
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +3 -1
  104. package/dist/index.js.map +1 -1
  105. package/dist/utils/hooks/useElementWidth.d.ts.map +1 -0
  106. package/dist/{components/combobox → utils/hooks}/useElementWidth.js +0 -1
  107. package/dist/utils/hooks/useElementWidth.js.map +1 -0
  108. package/dist/utils/hooks/useMeasuredChildWidths.d.ts +8 -0
  109. package/dist/utils/hooks/useMeasuredChildWidths.d.ts.map +1 -0
  110. package/dist/utils/hooks/useMeasuredChildWidths.js +26 -0
  111. package/dist/utils/hooks/useMeasuredChildWidths.js.map +1 -0
  112. package/dist/utils/hooks/useRovingFocus.d.ts +18 -0
  113. package/dist/utils/hooks/useRovingFocus.d.ts.map +1 -0
  114. package/dist/utils/hooks/useRovingFocus.js +130 -0
  115. package/dist/utils/hooks/useRovingFocus.js.map +1 -0
  116. package/dist/utils/hooks/useRovingFocus.test.d.ts +2 -0
  117. package/dist/utils/hooks/useRovingFocus.test.d.ts.map +1 -0
  118. package/dist/utils/hooks/useRovingFocus.test.js +59 -0
  119. package/dist/utils/hooks/useRovingFocus.test.js.map +1 -0
  120. package/dist/utils/spacedWidths.d.ts +3 -0
  121. package/dist/utils/spacedWidths.d.ts.map +1 -0
  122. package/dist/utils/spacedWidths.js +28 -0
  123. package/dist/utils/spacedWidths.js.map +1 -0
  124. package/dist/utils/spacedWidths.test.d.ts +2 -0
  125. package/dist/utils/spacedWidths.test.d.ts.map +1 -0
  126. package/dist/utils/spacedWidths.test.js +17 -0
  127. package/dist/utils/spacedWidths.test.js.map +1 -0
  128. package/package.json +1 -1
  129. package/src/components/articleCard/ArticleCard.stories.tsx +17 -12
  130. package/src/components/articleCard/ArticleCard.tsx +9 -9
  131. package/src/components/combobox/Combobox.stories.tsx +186 -12
  132. package/src/components/combobox/Combobox.test.tsx +53 -0
  133. package/src/components/combobox/Combobox.tsx +3 -3
  134. package/src/components/combobox/ComboboxButtonTrigger.tsx +52 -56
  135. package/src/components/combobox/ComboboxTrigger.tsx +19 -16
  136. package/src/components/combobox/combobox.scss +8 -3
  137. package/src/components/combobox/useVisibleTriggerTags.test.tsx +91 -0
  138. package/src/components/combobox/useVisibleTriggerTags.ts +83 -0
  139. package/src/components/filterBar/FilterBar.stories.tsx +1199 -0
  140. package/src/components/filterBar/FilterBar.test.tsx +248 -0
  141. package/src/components/filterBar/FilterBar.tsx +298 -0
  142. package/src/components/filterBar/filterBar.scss +143 -0
  143. package/src/components/icon/allowedIcons.tsx +3 -1
  144. package/src/components/{icoText/IcoText.stories.tsx → iconText/IconText.stories.tsx} +112 -112
  145. package/src/components/{icoText/IcoText.test.tsx → iconText/IconText.test.tsx} +10 -10
  146. package/src/components/{icoText/IcoText.tsx → iconText/IconText.tsx} +27 -20
  147. package/src/components/modal/Modal.tsx +5 -1
  148. package/src/components/table/cellRenderers/ComboboxCellRenderer.test.tsx +20 -3
  149. package/src/components/tag/Tag.stories.tsx +4 -4
  150. package/src/components/tag/Tag.test.tsx +62 -5
  151. package/src/components/tag/Tag.tsx +61 -3
  152. package/src/components/tag/tag.scss +80 -9
  153. package/src/components/tagList/TagList.stories.tsx +564 -0
  154. package/src/components/tagList/TagList.test.tsx +342 -0
  155. package/src/components/tagList/TagList.tsx +296 -0
  156. package/src/components/tagList/tagList.scss +56 -0
  157. package/src/components/tagList/useTagListCollapsedLayout.ts +83 -0
  158. package/src/components/tagList/useVisibleTags.ts +74 -0
  159. package/src/index.scss +3 -1
  160. package/src/index.ts +13 -1
  161. package/src/tokens.scss +3 -1
  162. package/src/{components/combobox → utils/hooks}/useElementWidth.ts +0 -1
  163. package/src/utils/hooks/useMeasuredChildWidths.ts +39 -0
  164. package/src/utils/hooks/useRovingFocus.test.tsx +105 -0
  165. package/src/utils/hooks/useRovingFocus.ts +163 -0
  166. package/src/utils/spacedWidths.test.ts +20 -0
  167. package/src/utils/spacedWidths.ts +37 -0
  168. package/dist/components/combobox/useElementWidth.d.ts.map +0 -1
  169. package/dist/components/combobox/useElementWidth.js.map +0 -1
  170. package/dist/components/combobox/useVisibleChips.d.ts +0 -21
  171. package/dist/components/combobox/useVisibleChips.d.ts.map +0 -1
  172. package/dist/components/combobox/useVisibleChips.js +0 -59
  173. package/dist/components/combobox/useVisibleChips.js.map +0 -1
  174. package/dist/components/combobox/useVisibleChips.test.d.ts +0 -2
  175. package/dist/components/combobox/useVisibleChips.test.d.ts.map +0 -1
  176. package/dist/components/combobox/useVisibleChips.test.js +0 -81
  177. package/dist/components/combobox/useVisibleChips.test.js.map +0 -1
  178. package/dist/components/icoText/IcoText.d.ts +0 -37
  179. package/dist/components/icoText/IcoText.d.ts.map +0 -1
  180. package/dist/components/icoText/IcoText.js +0 -29
  181. package/dist/components/icoText/IcoText.js.map +0 -1
  182. package/dist/components/icoText/IcoText.stories.d.ts.map +0 -1
  183. package/dist/components/icoText/IcoText.stories.js.map +0 -1
  184. package/dist/components/icoText/IcoText.test.d.ts.map +0 -1
  185. package/dist/components/icoText/IcoText.test.js.map +0 -1
  186. package/src/components/combobox/useVisibleChips.test.tsx +0 -91
  187. package/src/components/combobox/useVisibleChips.ts +0 -100
  188. /package/dist/{components/combobox → utils/hooks}/useElementWidth.d.ts +0 -0
  189. /package/src/components/{icoText/icoText.scss → iconText/iconText.scss} +0 -0
@@ -1,11 +1,11 @@
1
- import { describe, expect, test, vi, afterEach } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
1
  import '@testing-library/jest-dom/vitest';
2
+ import { render, screen } from '@testing-library/react';
4
3
  import userEvent from '@testing-library/user-event';
5
4
  import type { SuppressKeyboardEventParams } from 'ag-grid-community';
6
5
  import type { CustomCellRendererProps } from 'ag-grid-react';
7
- import { ComboboxCellRenderer } from './ComboboxCellRenderer.js';
8
6
  import type { ComboboxOption, ComboboxProps } from 'Components/combobox/types';
7
+ import { afterEach, describe, expect, test, vi } from 'vitest';
8
+ import { ComboboxCellRenderer } from './ComboboxCellRenderer.js';
9
9
 
10
10
  const options: ComboboxOption[] = [
11
11
  { value: 'opt1', label: 'Option 1' },
@@ -104,6 +104,23 @@ describe('ComboboxCellRenderer', () => {
104
104
  expect(screen.getByRole('combobox')).toBeInTheDocument();
105
105
  });
106
106
 
107
+ test('renders selected tags for multiple button-trigger values', () => {
108
+ const { container } = render(
109
+ <ComboboxCellRenderer
110
+ {...createMockProps({
111
+ 'value': ['opt1', 'opt2'],
112
+ 'multiple': true,
113
+ 'triggerVariant': 'button',
114
+ 'aria-label': 'Choose tags',
115
+ })}
116
+ />,
117
+ );
118
+
119
+ expect(screen.getByRole('button', { name: 'Choose tags' })).toBeInTheDocument();
120
+ expect(container.querySelector('.ds-combobox__button-tags-viewport .ds-tag-list')).toBeInTheDocument();
121
+ expect(container.querySelectorAll('.ds-combobox__button-tags-viewport .ds-tag')).toHaveLength(2);
122
+ });
123
+
107
124
  test('registers cellKeyDown listener on mount', () => {
108
125
  const addEventListener = vi.fn();
109
126
  const removeEventListener = vi.fn();
@@ -1,17 +1,17 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
1
  import {
3
2
  Controls,
4
3
  Heading as DocHeading,
5
- Markdown,
6
4
  Primary as DocPrimary,
5
+ Markdown,
7
6
  Stories,
8
7
  Subtitle,
9
8
  Title,
10
9
  } from '@storybook/addon-docs/blocks';
11
- import { useState } from 'react';
12
- import { fn } from 'storybook/test';
10
+ import type { Meta, StoryObj } from '@storybook/react-vite';
13
11
  import { Dot } from 'Components/dot/Dot';
14
12
  import { Icon } from 'Components/icon/Icon';
13
+ import { useState } from 'react';
14
+ import { fn } from 'storybook/test';
15
15
  import { Tag, type TagColor } from './Tag.js';
16
16
 
17
17
  // ---------------------------------------------------------------------------
@@ -108,8 +108,48 @@ describe('Tag', () => {
108
108
  });
109
109
  });
110
110
 
111
+ describe('onClick', () => {
112
+ test('renders a primary action button when onClick is provided', () => {
113
+ render(<Tag onClick={() => {}}>Clickable</Tag>);
114
+ expect(screen.getByRole('button', { name: 'Clickable' })).toBeInTheDocument();
115
+ });
116
+
117
+ test('uses a custom action label when provided', () => {
118
+ render(<Tag onClick={() => {}} actionLabel="Open filter for Alice Johnson">Alice Johnson</Tag>);
119
+ expect(screen.getByRole('button', { name: 'Open filter for Alice Johnson' })).toBeInTheDocument();
120
+ });
121
+
122
+ test('allows composite parents to remove the primary action from the tab order', () => {
123
+ render(
124
+ <Tag onClick={() => {}} actionButtonTabIndex={-1}>
125
+ Clickable
126
+ </Tag>,
127
+ );
128
+ expect(screen.getByRole('button', { name: 'Clickable' })).toHaveAttribute('tabindex', '-1');
129
+ });
130
+
131
+ test('fires onClick callback when the primary action is clicked', async () => {
132
+ const onClick = vi.fn();
133
+ render(<Tag onClick={onClick}>Clickable</Tag>);
134
+
135
+ await userEvent.click(screen.getByRole('button', { name: 'Clickable' }));
136
+ expect(onClick).toHaveBeenCalledOnce();
137
+ });
138
+
139
+ test('forwards aria-controls and aria-expanded to the primary action button', () => {
140
+ render(
141
+ <Tag onClick={() => {}} ariaControls="filter-modal" ariaExpanded={true}>
142
+ Clickable
143
+ </Tag>,
144
+ );
145
+
146
+ expect(screen.getByRole('button', { name: 'Clickable' })).toHaveAttribute('aria-controls', 'filter-modal');
147
+ expect(screen.getByRole('button', { name: 'Clickable' })).toHaveAttribute('aria-expanded', 'true');
148
+ });
149
+ });
150
+
111
151
  describe('combined slots', () => {
112
- test('renders slotStart, children, slotEnd, and remove button in correct order', () => {
152
+ test('renders non-clickable removable tags through the shared content wrapper', () => {
113
153
  const { container } = render(
114
154
  <Tag
115
155
  slotStart={<span>S</span>}
@@ -122,10 +162,27 @@ describe('Tag', () => {
122
162
 
123
163
  const tag = container.querySelector('.ds-tag')!;
124
164
  const children = Array.from(tag.children);
125
- expect(children[0]).toHaveClass('ds-tag__slot-start');
126
- expect(children[1]).toHaveClass('ds-tag__label');
127
- expect(children[2]).toHaveClass('ds-tag__slot-end');
128
- expect(children[3]).toHaveClass('ds-tag__remove');
165
+ expect(children[0]).toHaveClass('ds-tag__content');
166
+ expect(children[1]).toHaveClass('ds-tag__remove');
167
+
168
+ const contentChildren = Array.from(children[0]!.children);
169
+ expect(contentChildren[0]).toHaveClass('ds-tag__slot-start');
170
+ expect(contentChildren[1]).toHaveClass('ds-tag__label');
171
+ expect(contentChildren[2]).toHaveClass('ds-tag__slot-end');
172
+ });
173
+
174
+ test('renders clickable tags through the same shared content wrapper', () => {
175
+ const { container } = render(
176
+ <Tag
177
+ slotStart={<span>S</span>}
178
+ slotEnd={<span>E</span>}
179
+ onClick={() => {}}
180
+ >
181
+ Label
182
+ </Tag>,
183
+ );
184
+
185
+ expect(container.querySelector('.ds-tag__content.ds-tag__action')).toBeInTheDocument();
129
186
  });
130
187
  });
131
188
  });
@@ -1,5 +1,6 @@
1
1
  import classNames from 'classnames';
2
2
  import { Icon } from 'Components/icon/Icon';
3
+ import type { ButtonHTMLAttributes } from 'react';
3
4
 
4
5
  export type TagColor = 'neutral'
5
6
  | 'orange'
@@ -16,9 +17,21 @@ export type TagProps = {
16
17
  selected?: boolean;
17
18
  slotStart?: React.ReactNode;
18
19
  slotEnd?: React.ReactNode;
20
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
21
+ onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
22
+ onFocus?: React.FocusEventHandler<HTMLButtonElement>;
23
+ actionLabel?: string;
24
+ actionButtonTabIndex?: 0 | -1;
25
+ actionRef?: React.Ref<HTMLButtonElement>;
19
26
  onRemove?: () => void;
20
27
  removeLabel?: string;
28
+ onRemoveKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
29
+ onRemoveFocus?: React.FocusEventHandler<HTMLButtonElement>;
21
30
  removeButtonTabIndex?: 0 | -1;
31
+ removeButtonRef?: React.Ref<HTMLButtonElement>;
32
+ disabled?: boolean;
33
+ ariaControls?: string;
34
+ ariaExpanded?: ButtonHTMLAttributes<HTMLButtonElement>['aria-expanded'];
22
35
  };
23
36
 
24
37
  export const Tag = ({
@@ -27,18 +40,59 @@ export const Tag = ({
27
40
  selected = false,
28
41
  slotStart,
29
42
  slotEnd,
43
+ onClick,
44
+ onKeyDown,
45
+ onFocus,
46
+ actionLabel,
47
+ actionButtonTabIndex = 0,
48
+ actionRef,
30
49
  onRemove,
31
50
  removeLabel = 'Remove',
51
+ onRemoveKeyDown,
52
+ onRemoveFocus,
32
53
  removeButtonTabIndex = 0,
54
+ removeButtonRef,
55
+ disabled = false,
56
+ ariaControls,
57
+ ariaExpanded,
33
58
  }: TagProps): React.JSX.Element => {
59
+ const tagContent = onClick
60
+ ? (
61
+ <button
62
+ type="button"
63
+ className="ds-tag__content ds-tag__action"
64
+ aria-label={actionLabel}
65
+ aria-controls={ariaControls}
66
+ aria-expanded={ariaExpanded}
67
+ onClick={onClick}
68
+ onKeyDown={onKeyDown}
69
+ onFocus={onFocus}
70
+ tabIndex={actionButtonTabIndex}
71
+ ref={actionRef}
72
+ disabled={disabled}
73
+ >
74
+ {slotStart && <span className="ds-tag__slot-start">{slotStart}</span>}
75
+ <span className="ds-tag__label">{children}</span>
76
+ {slotEnd && <span className="ds-tag__slot-end">{slotEnd}</span>}
77
+ </button>
78
+ )
79
+ : (
80
+ <span className="ds-tag__content">
81
+ {slotStart && <span className="ds-tag__slot-start">{slotStart}</span>}
82
+ <span className="ds-tag__label">{children}</span>
83
+ {slotEnd && <span className="ds-tag__slot-end">{slotEnd}</span>}
84
+ </span>
85
+ );
86
+
34
87
  return (
35
88
  <span className={classNames('ds-tag', `ds-tag--${color}`, {
36
89
  'ds-tag--selected': selected,
90
+ 'ds-tag--interactive': Boolean(onClick),
91
+ 'ds-tag--removable': Boolean(onRemove),
92
+ 'ds-tag--disabled': disabled,
37
93
  })}
38
94
  >
39
- {slotStart && <span className="ds-tag__slot-start">{slotStart}</span>}
40
- <span className="ds-tag__label">{children}</span>
41
- {slotEnd && <span className="ds-tag__slot-end">{slotEnd}</span>}
95
+ {tagContent}
42
96
  {onRemove && (
43
97
  <button
44
98
  type="button"
@@ -48,7 +102,11 @@ export const Tag = ({
48
102
  e.stopPropagation();
49
103
  onRemove();
50
104
  }}
105
+ onKeyDown={onRemoveKeyDown}
106
+ onFocus={onRemoveFocus}
51
107
  tabIndex={removeButtonTabIndex}
108
+ ref={removeButtonRef}
109
+ disabled={disabled}
52
110
  >
53
111
  <Icon name="x" size={12} />
54
112
  </button>
@@ -1,6 +1,5 @@
1
1
  .ds-tag {
2
2
  display: inline-flex;
3
- padding: 0 var(--tag-spacing-horizontal);
4
3
  align-items: center;
5
4
  gap: var(--tag-spacing-gap-horizontal);
6
5
  border-radius: var(--tag-radius);
@@ -13,6 +12,7 @@
13
12
  height: var(--tag-height);
14
13
  font-style: normal;
15
14
  line-height: 150%;
15
+ overflow: visible;
16
16
 
17
17
  &--neutral {
18
18
  color: var(--tag-neutral-color-text);
@@ -60,6 +60,68 @@
60
60
  border-color: var(--tag-selected-color-border);
61
61
  }
62
62
 
63
+ .ds-tag__label {
64
+ overflow: hidden;
65
+ text-overflow: ellipsis;
66
+ }
67
+
68
+ &--disabled {
69
+ opacity: 0.6;
70
+ }
71
+ }
72
+
73
+ .ds-tag__content {
74
+ display: inline-flex;
75
+ align-items: center;
76
+ gap: inherit;
77
+ min-width: 0;
78
+ height: 100%;
79
+ padding: 0 var(--tag-spacing-horizontal);
80
+ border-radius: inherit;
81
+ box-sizing: border-box;
82
+ }
83
+
84
+ .ds-tag__action {
85
+ border: none;
86
+ background: transparent;
87
+ color: inherit;
88
+ font: inherit;
89
+ cursor: pointer;
90
+
91
+ &:focus {
92
+ outline: none;
93
+ }
94
+
95
+ &:focus-visible {
96
+ outline: none;
97
+ background-color: var(--color-grey-100);
98
+ }
99
+
100
+ &:hover {
101
+ background-color: var(--color-grey-100);
102
+ }
103
+
104
+ &:disabled {
105
+ cursor: not-allowed;
106
+ }
107
+ }
108
+
109
+ .ds-tag--removable {
110
+ gap: 0;
111
+
112
+ .ds-tag__label {
113
+ padding: 0 var(--tag-spacing-horizontal) 0 0;
114
+ }
115
+
116
+ .ds-tag__content {
117
+ gap: var(--tag-spacing-horizontal);
118
+ padding-right: 0;
119
+ }
120
+ }
121
+
122
+ .ds-tag:has(.ds-tag__action:focus-visible) {
123
+ outline: var(--focus-border) solid var(--focus-color-focus);
124
+ outline-offset: 2px;
63
125
  }
64
126
 
65
127
  .ds-tag__slot-start {
@@ -68,11 +130,6 @@
68
130
  flex-shrink: 0;
69
131
  }
70
132
 
71
- .ds-tag__label {
72
- overflow: hidden;
73
- text-overflow: ellipsis;
74
- }
75
-
76
133
  .ds-tag__slot-end {
77
134
  display: flex;
78
135
  align-items: center;
@@ -80,19 +137,33 @@
80
137
  }
81
138
 
82
139
  .ds-tag__remove {
83
- display: flex;
140
+ display: inline-flex;
84
141
  align-items: center;
85
142
  justify-content: center;
86
143
  border: none;
87
144
  background: transparent;
145
+ align-self: stretch;
146
+ min-width: calc(var(--tag-height) - (var(--border-weight) * 2));
88
147
  padding: 0;
89
148
  cursor: pointer;
90
149
  color: inherit;
91
- border-radius: 50%;
150
+ border-radius: var(--tag-radius);
92
151
  flex-shrink: 0;
152
+ line-height: 0;
153
+
154
+ &:focus {
155
+ outline: none;
156
+ }
157
+
158
+ &:focus-visible {
159
+ outline: var(--focus-border) solid var(--focus-color-focus);
160
+ outline-offset: 2px;
161
+ border-radius: var(--tag-radius);
162
+ background-color: var(--color-grey-100);
163
+ }
93
164
 
94
165
  &:hover {
95
- background-color: var(--color-grey-200);
166
+ background-color: var(--color-grey-100);
96
167
  }
97
168
 
98
169
  &:disabled {