@proyecto-viviana/solidaria-components 0.2.5 → 0.3.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 (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -272
  3. package/dist/ActionBar.d.ts +79 -0
  4. package/dist/ActionBar.d.ts.map +1 -0
  5. package/dist/ActionGroup.d.ts +74 -0
  6. package/dist/ActionGroup.d.ts.map +1 -0
  7. package/dist/Alert.d.ts +70 -0
  8. package/dist/Alert.d.ts.map +1 -0
  9. package/dist/Autocomplete.d.ts +5 -5
  10. package/dist/Autocomplete.d.ts.map +1 -1
  11. package/dist/Breadcrumbs.d.ts +27 -8
  12. package/dist/Breadcrumbs.d.ts.map +1 -1
  13. package/dist/Button.d.ts +28 -5
  14. package/dist/Button.d.ts.map +1 -1
  15. package/dist/Calendar.d.ts +51 -7
  16. package/dist/Calendar.d.ts.map +1 -1
  17. package/dist/Checkbox.d.ts +33 -8
  18. package/dist/Checkbox.d.ts.map +1 -1
  19. package/dist/Collection.d.ts +130 -0
  20. package/dist/Collection.d.ts.map +1 -0
  21. package/dist/Color.d.ts +210 -9
  22. package/dist/Color.d.ts.map +1 -1
  23. package/dist/ColorEditor.d.ts +42 -0
  24. package/dist/ColorEditor.d.ts.map +1 -0
  25. package/dist/ComboBox.d.ts +146 -16
  26. package/dist/ComboBox.d.ts.map +1 -1
  27. package/dist/ContextualHelpTrigger.d.ts +40 -0
  28. package/dist/ContextualHelpTrigger.d.ts.map +1 -0
  29. package/dist/DateField.d.ts +35 -8
  30. package/dist/DateField.d.ts.map +1 -1
  31. package/dist/DatePicker.d.ts +101 -5
  32. package/dist/DatePicker.d.ts.map +1 -1
  33. package/dist/DateRangePickerContext.d.ts +30 -0
  34. package/dist/DateRangePickerContext.d.ts.map +1 -0
  35. package/dist/Dialog.d.ts +5 -5
  36. package/dist/Dialog.d.ts.map +1 -1
  37. package/dist/Disclosure.d.ts +25 -5
  38. package/dist/Disclosure.d.ts.map +1 -1
  39. package/dist/DragAndDrop.d.ts +80 -0
  40. package/dist/DragAndDrop.d.ts.map +1 -0
  41. package/dist/DragPreview.d.ts +14 -0
  42. package/dist/DragPreview.d.ts.map +1 -0
  43. package/dist/DropZone.d.ts +27 -0
  44. package/dist/DropZone.d.ts.map +1 -0
  45. package/dist/FieldError.d.ts +27 -0
  46. package/dist/FieldError.d.ts.map +1 -0
  47. package/dist/FileTrigger.d.ts +26 -0
  48. package/dist/FileTrigger.d.ts.map +1 -0
  49. package/dist/Focusable.d.ts +27 -0
  50. package/dist/Focusable.d.ts.map +1 -0
  51. package/dist/Form.d.ts +41 -0
  52. package/dist/Form.d.ts.map +1 -0
  53. package/dist/GridList.d.ts +69 -10
  54. package/dist/GridList.d.ts.map +1 -1
  55. package/dist/HiddenDateInput.d.ts +26 -0
  56. package/dist/HiddenDateInput.d.ts.map +1 -0
  57. package/dist/HiddenTimeInput.d.ts +25 -0
  58. package/dist/HiddenTimeInput.d.ts.map +1 -0
  59. package/dist/Icon.d.ts +57 -0
  60. package/dist/Icon.d.ts.map +1 -0
  61. package/dist/Keyboard.d.ts +13 -0
  62. package/dist/Keyboard.d.ts.map +1 -0
  63. package/dist/Landmark.d.ts +3 -3
  64. package/dist/Landmark.d.ts.map +1 -1
  65. package/dist/Link.d.ts +10 -4
  66. package/dist/Link.d.ts.map +1 -1
  67. package/dist/ListBox.d.ts +73 -11
  68. package/dist/ListBox.d.ts.map +1 -1
  69. package/dist/ListDropTargetDelegate.d.ts +38 -0
  70. package/dist/ListDropTargetDelegate.d.ts.map +1 -0
  71. package/dist/Menu.d.ts +79 -10
  72. package/dist/Menu.d.ts.map +1 -1
  73. package/dist/Meter.d.ts +4 -4
  74. package/dist/Meter.d.ts.map +1 -1
  75. package/dist/Modal.d.ts +6 -4
  76. package/dist/Modal.d.ts.map +1 -1
  77. package/dist/NumberField.d.ts +10 -12
  78. package/dist/NumberField.d.ts.map +1 -1
  79. package/dist/Popover.d.ts +32 -7
  80. package/dist/Popover.d.ts.map +1 -1
  81. package/dist/Pressable.d.ts +27 -0
  82. package/dist/Pressable.d.ts.map +1 -0
  83. package/dist/ProgressBar.d.ts +6 -4
  84. package/dist/ProgressBar.d.ts.map +1 -1
  85. package/dist/RadioGroup.d.ts +43 -9
  86. package/dist/RadioGroup.d.ts.map +1 -1
  87. package/dist/RangeCalendar.d.ts +39 -7
  88. package/dist/RangeCalendar.d.ts.map +1 -1
  89. package/dist/RouterProvider.d.ts +75 -0
  90. package/dist/RouterProvider.d.ts.map +1 -0
  91. package/dist/SearchField.d.ts +23 -21
  92. package/dist/SearchField.d.ts.map +1 -1
  93. package/dist/Select.d.ts +48 -7
  94. package/dist/Select.d.ts.map +1 -1
  95. package/dist/SelectionIndicator.d.ts +30 -0
  96. package/dist/SelectionIndicator.d.ts.map +1 -0
  97. package/dist/Separator.d.ts +9 -3
  98. package/dist/Separator.d.ts.map +1 -1
  99. package/dist/SharedElementTransition.d.ts +41 -0
  100. package/dist/SharedElementTransition.d.ts.map +1 -0
  101. package/dist/Slider.d.ts +15 -8
  102. package/dist/Slider.d.ts.map +1 -1
  103. package/dist/StepList.d.ts +90 -0
  104. package/dist/StepList.d.ts.map +1 -0
  105. package/dist/Switch.d.ts +11 -5
  106. package/dist/Switch.d.ts.map +1 -1
  107. package/dist/Table.d.ts +222 -19
  108. package/dist/Table.d.ts.map +1 -1
  109. package/dist/Tabs.d.ts +47 -10
  110. package/dist/Tabs.d.ts.map +1 -1
  111. package/dist/TagGroup.d.ts +22 -10
  112. package/dist/TagGroup.d.ts.map +1 -1
  113. package/dist/Text.d.ts +10 -0
  114. package/dist/Text.d.ts.map +1 -0
  115. package/dist/TextField.d.ts +19 -11
  116. package/dist/TextField.d.ts.map +1 -1
  117. package/dist/TimeField.d.ts +32 -7
  118. package/dist/TimeField.d.ts.map +1 -1
  119. package/dist/Toast.d.ts +29 -14
  120. package/dist/Toast.d.ts.map +1 -1
  121. package/dist/ToggleButton.d.ts +36 -0
  122. package/dist/ToggleButton.d.ts.map +1 -0
  123. package/dist/ToggleButtonGroup.d.ts +33 -0
  124. package/dist/ToggleButtonGroup.d.ts.map +1 -0
  125. package/dist/Toolbar.d.ts +7 -3
  126. package/dist/Toolbar.d.ts.map +1 -1
  127. package/dist/Tooltip.d.ts +58 -7
  128. package/dist/Tooltip.d.ts.map +1 -1
  129. package/dist/Tree.d.ts +102 -11
  130. package/dist/Tree.d.ts.map +1 -1
  131. package/dist/Virtualizer.d.ts +61 -0
  132. package/dist/Virtualizer.d.ts.map +1 -0
  133. package/dist/VirtualizerLayouts.d.ts +82 -0
  134. package/dist/VirtualizerLayouts.d.ts.map +1 -0
  135. package/dist/VisuallyHidden.d.ts +4 -2
  136. package/dist/VisuallyHidden.d.ts.map +1 -1
  137. package/dist/contexts.d.ts +6 -1
  138. package/dist/contexts.d.ts.map +1 -1
  139. package/dist/index.d.ts +73 -39
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +23342 -10644
  142. package/dist/index.js.map +1 -7
  143. package/dist/index.jsx +18110 -0
  144. package/dist/index.jsx.map +1 -0
  145. package/dist/useDragAndDrop.d.ts +93 -0
  146. package/dist/useDragAndDrop.d.ts.map +1 -0
  147. package/dist/utils.d.ts +8 -2
  148. package/dist/utils.d.ts.map +1 -1
  149. package/dist/virtualizer/Layout.d.ts +79 -0
  150. package/dist/virtualizer/Layout.d.ts.map +1 -0
  151. package/package.json +33 -32
  152. package/src/ActionBar.tsx +251 -0
  153. package/src/ActionGroup.tsx +277 -0
  154. package/src/Alert.tsx +152 -0
  155. package/src/Autocomplete.tsx +39 -44
  156. package/src/Breadcrumbs.tsx +227 -72
  157. package/src/Button.tsx +315 -74
  158. package/src/Calendar.tsx +347 -141
  159. package/src/Checkbox.tsx +414 -123
  160. package/src/Collection.tsx +350 -0
  161. package/src/Color.tsx +1325 -284
  162. package/src/ColorEditor.tsx +213 -0
  163. package/src/ComboBox.tsx +644 -245
  164. package/src/ContextualHelpTrigger.tsx +195 -0
  165. package/src/DateField.tsx +274 -106
  166. package/src/DatePicker.tsx +892 -111
  167. package/src/DateRangePickerContext.tsx +44 -0
  168. package/src/Dialog.tsx +173 -104
  169. package/src/Disclosure.tsx +158 -105
  170. package/src/DragAndDrop.tsx +340 -0
  171. package/src/DragPreview.tsx +47 -0
  172. package/src/DropZone.tsx +233 -0
  173. package/src/FieldError.tsx +89 -0
  174. package/src/FileTrigger.tsx +83 -0
  175. package/src/Focusable.tsx +103 -0
  176. package/src/Form.tsx +140 -0
  177. package/src/GridList.tsx +542 -128
  178. package/src/HiddenDateInput.tsx +153 -0
  179. package/src/HiddenTimeInput.tsx +133 -0
  180. package/src/Icon.tsx +133 -0
  181. package/src/Keyboard.tsx +26 -0
  182. package/src/Landmark.tsx +37 -63
  183. package/src/Link.tsx +132 -69
  184. package/src/ListBox.tsx +656 -106
  185. package/src/ListDropTargetDelegate.ts +283 -0
  186. package/src/Menu.tsx +1234 -132
  187. package/src/Meter.tsx +44 -58
  188. package/src/Modal.tsx +262 -166
  189. package/src/NumberField.tsx +267 -151
  190. package/src/Popover.tsx +452 -343
  191. package/src/Pressable.tsx +108 -0
  192. package/src/ProgressBar.tsx +54 -59
  193. package/src/RadioGroup.tsx +533 -121
  194. package/src/RangeCalendar.tsx +249 -150
  195. package/src/RouterProvider.tsx +223 -0
  196. package/src/SearchField.tsx +460 -133
  197. package/src/Select.tsx +804 -233
  198. package/src/SelectionIndicator.tsx +108 -0
  199. package/src/Separator.tsx +47 -49
  200. package/src/SharedElementTransition.tsx +264 -0
  201. package/src/Slider.tsx +148 -98
  202. package/src/StepList.tsx +272 -0
  203. package/src/Switch.tsx +93 -46
  204. package/src/Table.tsx +1551 -225
  205. package/src/Tabs.tsx +377 -123
  206. package/src/TagGroup.tsx +233 -135
  207. package/src/Text.tsx +18 -0
  208. package/src/TextField.tsx +413 -86
  209. package/src/TimeField.tsx +232 -222
  210. package/src/Toast.tsx +306 -160
  211. package/src/ToggleButton.tsx +169 -0
  212. package/src/ToggleButtonGroup.tsx +141 -0
  213. package/src/Toolbar.tsx +61 -70
  214. package/src/Tooltip.tsx +473 -116
  215. package/src/Tree.tsx +1514 -175
  216. package/src/Virtualizer.tsx +730 -0
  217. package/src/VirtualizerLayouts.ts +280 -0
  218. package/src/VisuallyHidden.tsx +32 -38
  219. package/src/contexts.ts +29 -36
  220. package/src/index.ts +972 -620
  221. package/src/useDragAndDrop.ts +367 -0
  222. package/src/utils.tsx +69 -50
  223. package/src/virtualizer/Layout.ts +192 -0
  224. package/dist/index.ssr.js +0 -9785
  225. package/dist/index.ssr.js.map +0 -7
package/src/TagGroup.tsx CHANGED
@@ -17,19 +17,15 @@ import {
17
17
  useContext,
18
18
  For,
19
19
  Show,
20
- } from 'solid-js';
21
- import {
22
- createTagGroup,
23
- createTag,
24
- type AriaTagGroupProps,
25
- } from '@proyecto-viviana/solidaria';
20
+ } from "solid-js";
21
+ import { createTagGroup, createTag, type AriaTagGroupProps } from "@proyecto-viviana/solidaria";
26
22
  import {
27
23
  createListState,
28
24
  type ListState,
29
25
  type Key,
30
26
  type SelectionMode,
31
27
  type SelectionBehavior,
32
- } from '@proyecto-viviana/solid-stately';
28
+ } from "@proyecto-viviana/solid-stately";
33
29
  import {
34
30
  type RenderChildren,
35
31
  type ClassNameOrFunction,
@@ -38,11 +34,12 @@ import {
38
34
  useRenderProps,
39
35
  filterDOMProps,
40
36
  dataAttr,
41
- } from './utils';
42
-
43
- // ============================================
44
- // TYPES
45
- // ============================================
37
+ } from "./utils";
38
+ import { SharedElementTransition } from "./SharedElementTransition";
39
+ import {
40
+ SelectionIndicatorContext,
41
+ type SelectionIndicatorContextValue,
42
+ } from "./SelectionIndicator";
46
43
 
47
44
  export interface TagGroupRenderProps {
48
45
  /** Whether the tag group is disabled. */
@@ -52,8 +49,10 @@ export interface TagGroupRenderProps {
52
49
  }
53
50
 
54
51
  export interface TagGroupProps
55
- extends Omit<AriaTagGroupProps, 'id'>,
56
- SlotProps {
52
+ extends
53
+ Omit<AriaTagGroupProps, "id">,
54
+ SlotProps,
55
+ Omit<JSX.HTMLAttributes<HTMLDivElement>, "class" | "style" | "children"> {
57
56
  /** The children of the component. */
58
57
  children?: JSX.Element;
59
58
  /** The CSS className for the element. */
@@ -69,7 +68,10 @@ export interface TagListRenderProps {
69
68
  isFocused: boolean;
70
69
  }
71
70
 
72
- export interface TagListProps<T> extends SlotProps {
71
+ export interface TagListProps<T>
72
+ extends
73
+ SlotProps,
74
+ Omit<JSX.HTMLAttributes<HTMLDivElement>, "class" | "style" | "children" | "onSelectionChange"> {
73
75
  /** The items to display in the tag list. */
74
76
  items: T[];
75
77
  /** Function to render each item. */
@@ -89,7 +91,7 @@ export interface TagListProps<T> extends SlotProps {
89
91
  /** The default selected keys (uncontrolled). */
90
92
  defaultSelectedKeys?: Iterable<Key>;
91
93
  /** Handler called when selection changes. */
92
- onSelectionChange?: (keys: 'all' | Set<Key>) => void;
94
+ onSelectionChange?: (keys: "all" | Set<Key>) => void;
93
95
  /** Keys that are disabled. */
94
96
  disabledKeys?: Iterable<Key>;
95
97
  /** Function to get a unique key from an item. */
@@ -97,11 +99,11 @@ export interface TagListProps<T> extends SlotProps {
97
99
  /** Accessibility label. */
98
100
  label?: string;
99
101
  /** Custom aria-label. */
100
- 'aria-label'?: string;
102
+ "aria-label"?: string;
101
103
  /** Reference to external label element. */
102
- 'aria-labelledby'?: string;
104
+ "aria-labelledby"?: string;
103
105
  /** Reference to description element. */
104
- 'aria-describedby'?: string;
106
+ "aria-describedby"?: string;
105
107
  /** Whether the tag list is disabled. */
106
108
  isDisabled?: boolean;
107
109
  /** Handler called when tags are removed. */
@@ -121,6 +123,8 @@ export interface TagRenderProps {
121
123
  allowsRemoving: boolean;
122
124
  /** The selection mode. */
123
125
  selectionMode: SelectionMode;
126
+ /** Props for the remove button when removal is allowed. */
127
+ removeButtonProps: Record<string, unknown>;
124
128
  }
125
129
 
126
130
  export interface TagProps extends SlotProps {
@@ -136,28 +140,29 @@ export interface TagProps extends SlotProps {
136
140
  class?: ClassNameOrFunction<TagRenderProps>;
137
141
  /** The inline style for the element. */
138
142
  style?: StyleOrFunction<TagRenderProps>;
143
+ /** Handler called when the tag is activated. */
144
+ onAction?: (key: Key) => void;
139
145
  }
140
146
 
141
- // ============================================
142
- // CONTEXT
143
- // ============================================
144
-
145
147
  interface TagGroupContextValue {
146
148
  state: ListState;
147
149
  onRemove?: (keys: Set<Key>) => void;
150
+ isDisabled?: boolean;
151
+ }
152
+
153
+ interface TagContextValue {
154
+ removeButtonProps: Record<string, unknown>;
155
+ allowsRemoving: boolean;
148
156
  }
149
157
 
150
158
  export const TagGroupContext = createContext<TagGroupContextValue | null>(null);
151
159
  export const TagListStateContext = createContext<ListState | null>(null);
160
+ export const TagContext = createContext<TagContextValue | null>(null);
152
161
 
153
162
  export function useTagGroupContext(): TagGroupContextValue | null {
154
163
  return useContext(TagGroupContext);
155
164
  }
156
165
 
157
- // ============================================
158
- // TAG GROUP COMPONENT
159
- // ============================================
160
-
161
166
  /**
162
167
  * A tag group is a focusable list of labels, categories, keywords, filters, or other items,
163
168
  * with support for keyboard navigation, selection, and removal.
@@ -172,17 +177,14 @@ export function useTagGroupContext(): TagGroupContextValue | null {
172
177
  * ```
173
178
  */
174
179
  export function TagGroup(props: TagGroupProps): JSX.Element {
175
- const [local] = splitProps(props, [
176
- 'class',
177
- 'style',
178
- 'slot',
179
- ]);
180
+ const [local, domProps] = splitProps(props, ["class", "style", "slot", "children"]);
180
181
 
181
182
  // We need TagList to provide the state, so TagGroup just provides context
182
183
  return (
183
184
  <div
184
- class={typeof local.class === 'string' ? local.class : 'solidaria-TagGroup'}
185
- style={typeof local.style === 'object' ? local.style : undefined}
185
+ {...domProps}
186
+ class={typeof local.class === "string" ? local.class : "solidaria-TagGroup"}
187
+ style={typeof local.style === "object" ? local.style : undefined}
186
188
  slot={local.slot}
187
189
  >
188
190
  {props.children}
@@ -190,33 +192,30 @@ export function TagGroup(props: TagGroupProps): JSX.Element {
190
192
  );
191
193
  }
192
194
 
193
- // ============================================
194
- // TAG LIST COMPONENT
195
- // ============================================
196
-
197
195
  /**
198
196
  * TagList contains the list of tags within a TagGroup.
199
197
  */
200
198
  export function TagList<T extends { id?: Key; key?: Key }>(props: TagListProps<T>): JSX.Element {
201
- const [local] = splitProps(props, [
202
- 'items',
203
- 'class',
204
- 'style',
205
- 'slot',
206
- 'renderEmptyState',
207
- 'selectionMode',
208
- 'selectionBehavior',
209
- 'selectedKeys',
210
- 'defaultSelectedKeys',
211
- 'onSelectionChange',
212
- 'disabledKeys',
213
- 'getKey',
214
- 'label',
215
- 'aria-label',
216
- 'aria-labelledby',
217
- 'aria-describedby',
218
- 'isDisabled',
219
- 'onRemove',
199
+ const [local, domProps] = splitProps(props, [
200
+ "items",
201
+ "class",
202
+ "style",
203
+ "slot",
204
+ "renderEmptyState",
205
+ "children",
206
+ "selectionMode",
207
+ "selectionBehavior",
208
+ "selectedKeys",
209
+ "defaultSelectedKeys",
210
+ "onSelectionChange",
211
+ "disabledKeys",
212
+ "getKey",
213
+ "label",
214
+ "aria-label",
215
+ "aria-labelledby",
216
+ "aria-describedby",
217
+ "isDisabled",
218
+ "onRemove",
220
219
  ]);
221
220
 
222
221
  // Create a ref for the grid
@@ -230,55 +229,78 @@ export function TagList<T extends { id?: Key; key?: Key }>(props: TagListProps<T
230
229
  return String(item);
231
230
  };
232
231
 
233
- // Create list state
234
232
  const state = createListState({
235
- get items() { return local.items; },
233
+ get items() {
234
+ return local.items;
235
+ },
236
236
  getKey,
237
- get selectionMode() { return local.selectionMode ?? 'none'; },
238
- get selectionBehavior() { return local.selectionBehavior ?? 'toggle'; },
239
- get selectedKeys() { return local.selectedKeys; },
240
- get defaultSelectedKeys() { return local.defaultSelectedKeys; },
241
- get onSelectionChange() { return local.onSelectionChange; },
242
- get disabledKeys() { return local.disabledKeys; },
237
+ get selectionMode() {
238
+ return local.selectionMode ?? "none";
239
+ },
240
+ get selectionBehavior() {
241
+ return local.selectionBehavior ?? "toggle";
242
+ },
243
+ get selectedKeys() {
244
+ return local.selectedKeys;
245
+ },
246
+ get defaultSelectedKeys() {
247
+ return local.defaultSelectedKeys;
248
+ },
249
+ get onSelectionChange() {
250
+ return local.onSelectionChange;
251
+ },
252
+ get disabledKeys() {
253
+ return local.disabledKeys;
254
+ },
243
255
  });
244
256
 
245
257
  // Create tag group accessibility props
246
258
  const tagGroupAria = createTagGroup(
247
259
  {
248
- get label() { return local.label; },
249
- get 'aria-label'() { return local['aria-label']; },
250
- get 'aria-labelledby'() { return local['aria-labelledby']; },
251
- get 'aria-describedby'() { return local['aria-describedby']; },
252
- get isDisabled() { return local.isDisabled; },
253
- get onRemove() { return local.onRemove; },
260
+ get "aria-label"() {
261
+ return local["aria-label"] ?? (!local["aria-labelledby"] ? local.label : undefined);
262
+ },
263
+ get "aria-labelledby"() {
264
+ return local["aria-labelledby"];
265
+ },
266
+ get "aria-describedby"() {
267
+ return local["aria-describedby"];
268
+ },
269
+ get isDisabled() {
270
+ return local.isDisabled;
271
+ },
272
+ get onRemove() {
273
+ return local.onRemove;
274
+ },
254
275
  },
255
276
  state,
256
- gridRef
277
+ gridRef,
257
278
  );
258
279
 
259
- // Track focus
260
280
  const [isFocused, setIsFocused] = createSignal(false);
261
281
 
262
- // Render props values
263
282
  const renderValues = createMemo<TagListRenderProps>(() => ({
264
283
  isEmpty: local.items.length === 0,
265
284
  isFocused: isFocused(),
266
285
  }));
267
286
 
268
- // Resolve render props
269
287
  const renderProps = useRenderProps(
270
288
  {
271
289
  class: local.class,
272
290
  style: local.style,
273
- defaultClassName: 'solidaria-TagList',
291
+ defaultClassName: "solidaria-TagList",
274
292
  },
275
- renderValues
293
+ renderValues,
276
294
  );
277
295
 
278
- // Context value
279
296
  const contextValue: TagGroupContextValue = {
280
297
  state,
281
- get onRemove() { return local.onRemove; },
298
+ get onRemove() {
299
+ return local.onRemove;
300
+ },
301
+ get isDisabled() {
302
+ return local.isDisabled;
303
+ },
282
304
  };
283
305
 
284
306
  return (
@@ -286,46 +308,53 @@ export function TagList<T extends { id?: Key; key?: Key }>(props: TagListProps<T
286
308
  <TagListStateContext.Provider value={state}>
287
309
  <div
288
310
  ref={setGridRef}
311
+ {...domProps}
289
312
  {...tagGroupAria.gridProps}
290
313
  class={renderProps.class()}
291
314
  style={renderProps.style()}
292
- onFocus={() => setIsFocused(true)}
293
- onBlur={() => setIsFocused(false)}
315
+ onFocus={() => {
316
+ setIsFocused(true);
317
+ state.setFocused(true);
318
+ }}
319
+ onBlur={(e) => {
320
+ const nextTarget = e.relatedTarget as Node | null;
321
+ if (nextTarget && e.currentTarget.contains(nextTarget)) {
322
+ return;
323
+ }
324
+
325
+ setIsFocused(false);
326
+ state.setFocused(false);
327
+ }}
294
328
  data-empty={dataAttr(local.items.length === 0)}
295
329
  data-focused={dataAttr(isFocused())}
296
330
  >
297
- <Show
298
- when={local.items.length > 0}
299
- fallback={local.renderEmptyState?.()}
300
- >
301
- <For each={local.items}>
302
- {(item) => props.children(item)}
303
- </For>
304
- </Show>
331
+ <SharedElementTransition>
332
+ <Show when={local.items.length > 0} fallback={local.renderEmptyState?.()}>
333
+ <For each={local.items}>{(item) => props.children(item)}</For>
334
+ </Show>
335
+ </SharedElementTransition>
305
336
  </div>
306
337
  </TagListStateContext.Provider>
307
338
  </TagGroupContext.Provider>
308
339
  );
309
340
  }
310
341
 
311
- // ============================================
312
- // TAG COMPONENT
313
- // ============================================
314
-
315
342
  /**
316
343
  * A Tag is an individual item within a TagList.
317
344
  */
318
345
  export function Tag(props: TagProps): JSX.Element {
319
346
  const [local, rest] = splitProps(props, [
320
- 'id',
321
- 'class',
322
- 'style',
323
- 'slot',
324
- 'isDisabled',
325
- 'textValue',
347
+ "id",
348
+ "class",
349
+ "style",
350
+ "slot",
351
+ "isDisabled",
352
+ "textValue",
353
+ "onAction",
326
354
  ]);
327
355
 
328
356
  const state = useContext(TagListStateContext);
357
+ const groupContext = useContext(TagGroupContext);
329
358
 
330
359
  // Create a ref for the tag
331
360
  const [tagRef, setTagRef] = createSignal<HTMLDivElement | null>(null);
@@ -333,62 +362,104 @@ export function Tag(props: TagProps): JSX.Element {
333
362
  // Create tag accessibility props
334
363
  const tagAria = createTag(
335
364
  {
336
- get key() { return local.id; },
337
- get isDisabled() { return local.isDisabled; },
338
- get textValue() { return local.textValue; },
365
+ get key() {
366
+ return local.id;
367
+ },
368
+ get isDisabled() {
369
+ return local.isDisabled || groupContext?.isDisabled;
370
+ },
371
+ get textValue() {
372
+ return local.textValue;
373
+ },
339
374
  },
340
375
  state!,
341
- tagRef
376
+ tagRef,
342
377
  );
343
378
 
344
- // Render props values
379
+ const normalizedRemoveButtonProps = createMemo<Record<string, unknown>>(() => {
380
+ const raw = tagAria.removeButtonProps;
381
+ const rawHandler = typeof raw.onPress === "function" ? (raw.onPress as () => void) : undefined;
382
+ return {
383
+ ...raw,
384
+ onPress: () => {
385
+ if (!tagAria.isDisabled && groupContext?.onRemove) {
386
+ groupContext.onRemove(new Set([local.id]));
387
+ return;
388
+ }
389
+ rawHandler?.();
390
+ },
391
+ };
392
+ });
393
+
345
394
  const renderValues = createMemo<TagRenderProps>(() => ({
346
395
  isSelected: tagAria.isSelected,
347
396
  isDisabled: tagAria.isDisabled,
348
397
  isFocused: tagAria.isFocused,
349
398
  isPressed: tagAria.isPressed,
350
399
  allowsRemoving: tagAria.allowsRemoving,
351
- selectionMode: state?.selectionMode() ?? 'none',
400
+ selectionMode: state?.selectionMode() ?? "none",
401
+ removeButtonProps: normalizedRemoveButtonProps(),
352
402
  }));
353
403
 
354
- // Resolve render props
355
404
  const renderProps = useRenderProps(
356
405
  {
357
406
  children: props.children,
358
407
  class: local.class,
359
408
  style: local.style,
360
- defaultClassName: 'solidaria-Tag',
409
+ defaultClassName: "solidaria-Tag",
361
410
  },
362
- renderValues
411
+ renderValues,
363
412
  );
364
413
 
365
- // Filter DOM props
414
+ const selectionIndicatorContext = createMemo<SelectionIndicatorContextValue>(() => ({
415
+ isSelected: () => tagAria.isSelected,
416
+ }));
417
+
366
418
  const domProps = createMemo(() => filterDOMProps(rest, { global: true }));
367
419
 
368
420
  return (
369
- <div
370
- ref={setTagRef}
371
- {...domProps()}
372
- {...tagAria.rowProps}
373
- class={renderProps.class()}
374
- style={renderProps.style()}
375
- data-selected={dataAttr(tagAria.isSelected)}
376
- data-disabled={dataAttr(tagAria.isDisabled)}
377
- data-focused={dataAttr(tagAria.isFocused)}
378
- data-pressed={dataAttr(tagAria.isPressed)}
379
- data-allows-removing={dataAttr(tagAria.allowsRemoving)}
380
- >
381
- <div {...tagAria.gridCellProps} style={{ display: 'contents' }}>
382
- {renderProps.renderChildren()}
383
- </div>
384
- </div>
421
+ <SelectionIndicatorContext.Provider value={selectionIndicatorContext()}>
422
+ <TagContext.Provider
423
+ value={{
424
+ get removeButtonProps() {
425
+ return normalizedRemoveButtonProps();
426
+ },
427
+ get allowsRemoving() {
428
+ return tagAria.allowsRemoving;
429
+ },
430
+ }}
431
+ >
432
+ <div
433
+ ref={setTagRef}
434
+ {...domProps()}
435
+ {...tagAria.rowProps}
436
+ class={renderProps.class()}
437
+ style={renderProps.style()}
438
+ onClick={(event) => {
439
+ const rowClick = tagAria.rowProps.onClick;
440
+ if (typeof rowClick === "function") {
441
+ (rowClick as JSX.EventHandler<HTMLDivElement, MouseEvent>)(event);
442
+ }
443
+
444
+ if (!tagAria.isDisabled && !(event.target as Element | null)?.closest("button")) {
445
+ local.onAction?.(local.id);
446
+ }
447
+ }}
448
+ data-selected={dataAttr(tagAria.isSelected)}
449
+ data-disabled={dataAttr(tagAria.isDisabled)}
450
+ data-focused={dataAttr(tagAria.isFocused)}
451
+ data-pressed={dataAttr(tagAria.isPressed)}
452
+ data-allows-removing={dataAttr(tagAria.allowsRemoving)}
453
+ >
454
+ <div {...tagAria.gridCellProps} style={{ display: "contents" }}>
455
+ {renderProps.renderChildren()}
456
+ </div>
457
+ </div>
458
+ </TagContext.Provider>
459
+ </SelectionIndicatorContext.Provider>
385
460
  );
386
461
  }
387
462
 
388
- // ============================================
389
- // TAG REMOVE BUTTON COMPONENT
390
- // ============================================
391
-
392
463
  export interface TagRemoveButtonProps {
393
464
  /** The children of the button (usually an X icon). */
394
465
  children?: JSX.Element;
@@ -396,6 +467,8 @@ export interface TagRemoveButtonProps {
396
467
  class?: string;
397
468
  /** The inline style for the element. */
398
469
  style?: JSX.CSSProperties;
470
+ /** Explicit button props from Tag render props. */
471
+ buttonProps?: Record<string, unknown>;
399
472
  }
400
473
 
401
474
  /**
@@ -403,19 +476,44 @@ export interface TagRemoveButtonProps {
403
476
  * It should be placed inside a Tag component.
404
477
  */
405
478
  export function TagRemoveButton(props: TagRemoveButtonProps): JSX.Element {
406
- // This is a simplified version - in a full implementation,
407
- // we'd get the remove button props from the Tag context
479
+ const tagContext = useContext(TagContext);
480
+ const getRemoveButtonProps = () => props.buttonProps ?? tagContext?.removeButtonProps ?? {};
481
+ const getIsDisabled = () => Boolean(getRemoveButtonProps().isDisabled);
482
+ const rawId = getRemoveButtonProps().id;
483
+ const rawAriaLabel = getRemoveButtonProps()["aria-label"];
484
+ const rawAriaLabelledBy = getRemoveButtonProps()["aria-labelledby"];
485
+ const buttonId: string | undefined = typeof rawId === "string" ? rawId : undefined;
486
+ const ariaLabel: string = typeof rawAriaLabel === "string" ? rawAriaLabel : "Remove";
487
+ const ariaLabelledBy: string | undefined =
488
+ typeof rawAriaLabelledBy === "string" ? rawAriaLabelledBy : undefined;
489
+
490
+ const handleClick: JSX.EventHandler<HTMLButtonElement, MouseEvent> = (event) => {
491
+ event.stopPropagation();
492
+ const handler = getRemoveButtonProps().onPress;
493
+ if (typeof handler === "function" && !getIsDisabled()) {
494
+ (handler as () => void)();
495
+ }
496
+ };
497
+ const stopRowPress: JSX.EventHandler<HTMLButtonElement, PointerEvent> = (event) => {
498
+ event.stopPropagation();
499
+ };
500
+
408
501
  return (
409
502
  <button
410
503
  type="button"
411
- class={props.class ?? 'solidaria-TagRemoveButton'}
504
+ class={props.class ?? "solidaria-TagRemoveButton"}
412
505
  style={props.style}
413
- aria-label="Remove"
506
+ id={buttonId}
507
+ aria-label={ariaLabel}
508
+ aria-labelledby={ariaLabelledBy}
509
+ disabled={getIsDisabled()}
510
+ data-allows-removing={dataAttr(tagContext?.allowsRemoving ?? false)}
511
+ onPointerDown={stopRowPress}
512
+ onClick={handleClick}
414
513
  >
415
- {props.children ?? '×'}
514
+ {props.children ?? "×"}
416
515
  </button>
417
516
  );
418
517
  }
419
518
 
420
- // Re-export types
421
519
  export type { Key, SelectionMode, SelectionBehavior };
package/src/Text.tsx ADDED
@@ -0,0 +1,18 @@
1
+ import { type JSX, createContext } from "solid-js";
2
+ import type { SlotProps } from "./utils";
3
+
4
+ export interface TextProps extends SlotProps {
5
+ children?: JSX.Element;
6
+ class?: string;
7
+ style?: JSX.CSSProperties;
8
+ }
9
+
10
+ export const TextContext = createContext<null>(null);
11
+
12
+ export function Text(props: TextProps): JSX.Element {
13
+ return (
14
+ <span class={props.class ?? "solidaria-Text"} style={props.style}>
15
+ {props.children}
16
+ </span>
17
+ );
18
+ }