@proyecto-viviana/solidaria 0.2.2 → 0.2.3

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 (210) hide show
  1. package/dist/autocomplete/createAutocomplete.d.ts +2 -2
  2. package/dist/autocomplete/createAutocomplete.d.ts.map +1 -1
  3. package/dist/index.js +233 -234
  4. package/dist/index.js.map +2 -2
  5. package/dist/index.ssr.js +233 -234
  6. package/dist/index.ssr.js.map +2 -2
  7. package/dist/interactions/PressEvent.d.ts +13 -10
  8. package/dist/interactions/PressEvent.d.ts.map +1 -1
  9. package/dist/interactions/createPress.d.ts.map +1 -1
  10. package/dist/interactions/index.d.ts +1 -1
  11. package/dist/interactions/index.d.ts.map +1 -1
  12. package/dist/select/createHiddenSelect.d.ts.map +1 -1
  13. package/dist/toolbar/createToolbar.d.ts.map +1 -1
  14. package/dist/tooltip/createTooltipTrigger.d.ts.map +1 -1
  15. package/package.json +9 -7
  16. package/src/autocomplete/createAutocomplete.ts +341 -0
  17. package/src/autocomplete/index.ts +9 -0
  18. package/src/breadcrumbs/createBreadcrumbs.ts +196 -0
  19. package/src/breadcrumbs/index.ts +8 -0
  20. package/src/button/createButton.ts +142 -0
  21. package/src/button/createToggleButton.ts +101 -0
  22. package/src/button/index.ts +4 -0
  23. package/src/button/types.ts +78 -0
  24. package/src/calendar/createCalendar.ts +138 -0
  25. package/src/calendar/createCalendarCell.ts +187 -0
  26. package/src/calendar/createCalendarGrid.ts +140 -0
  27. package/src/calendar/createRangeCalendar.ts +136 -0
  28. package/src/calendar/createRangeCalendarCell.ts +186 -0
  29. package/src/calendar/index.ts +34 -0
  30. package/src/checkbox/createCheckbox.ts +135 -0
  31. package/src/checkbox/createCheckboxGroup.ts +137 -0
  32. package/src/checkbox/createCheckboxGroupItem.ts +117 -0
  33. package/src/checkbox/createCheckboxGroupState.ts +193 -0
  34. package/src/checkbox/index.ts +13 -0
  35. package/src/color/createColorArea.ts +314 -0
  36. package/src/color/createColorField.ts +137 -0
  37. package/src/color/createColorSlider.ts +197 -0
  38. package/src/color/createColorSwatch.ts +40 -0
  39. package/src/color/createColorWheel.ts +208 -0
  40. package/src/color/index.ts +24 -0
  41. package/src/color/types.ts +116 -0
  42. package/src/combobox/createComboBox.ts +647 -0
  43. package/src/combobox/index.ts +6 -0
  44. package/src/combobox/intl/en-US.json +7 -0
  45. package/src/combobox/intl/es-ES.json +7 -0
  46. package/src/combobox/intl/index.ts +23 -0
  47. package/src/datepicker/createDateField.ts +154 -0
  48. package/src/datepicker/createDatePicker.ts +206 -0
  49. package/src/datepicker/createDateSegment.ts +229 -0
  50. package/src/datepicker/createTimeField.ts +154 -0
  51. package/src/datepicker/index.ts +28 -0
  52. package/src/dialog/createDialog.ts +120 -0
  53. package/src/dialog/index.ts +2 -0
  54. package/src/dialog/types.ts +19 -0
  55. package/src/disclosure/createDisclosure.ts +131 -0
  56. package/src/disclosure/createDisclosureGroup.ts +62 -0
  57. package/src/disclosure/index.ts +11 -0
  58. package/src/dnd/createDrag.ts +209 -0
  59. package/src/dnd/createDraggableCollection.ts +63 -0
  60. package/src/dnd/createDraggableItem.ts +243 -0
  61. package/src/dnd/createDrop.ts +321 -0
  62. package/src/dnd/createDroppableCollection.ts +293 -0
  63. package/src/dnd/createDroppableItem.ts +213 -0
  64. package/src/dnd/index.ts +47 -0
  65. package/src/dnd/types.ts +89 -0
  66. package/src/dnd/utils.ts +294 -0
  67. package/src/focus/FocusScope.tsx +408 -0
  68. package/src/focus/createAutoFocus.ts +321 -0
  69. package/src/focus/createFocusRestore.ts +313 -0
  70. package/src/focus/createVirtualFocus.ts +396 -0
  71. package/src/focus/index.ts +35 -0
  72. package/src/form/createFormReset.ts +51 -0
  73. package/src/form/createFormValidation.ts +224 -0
  74. package/src/form/index.ts +11 -0
  75. package/src/grid/GridKeyboardDelegate.ts +429 -0
  76. package/src/grid/createGrid.ts +261 -0
  77. package/src/grid/createGridCell.ts +182 -0
  78. package/src/grid/createGridRow.ts +153 -0
  79. package/src/grid/index.ts +18 -0
  80. package/src/grid/types.ts +133 -0
  81. package/src/gridlist/createGridList.ts +185 -0
  82. package/src/gridlist/createGridListItem.ts +180 -0
  83. package/src/gridlist/createGridListSelectionCheckbox.ts +59 -0
  84. package/src/gridlist/index.ts +16 -0
  85. package/src/gridlist/types.ts +81 -0
  86. package/src/i18n/NumberFormatter.ts +266 -0
  87. package/src/i18n/createCollator.ts +79 -0
  88. package/src/i18n/createDateFormatter.ts +83 -0
  89. package/src/i18n/createFilter.ts +131 -0
  90. package/src/i18n/createNumberFormatter.ts +52 -0
  91. package/src/i18n/createStringFormatter.ts +87 -0
  92. package/src/i18n/index.ts +40 -0
  93. package/src/i18n/locale.tsx +188 -0
  94. package/src/i18n/utils.ts +99 -0
  95. package/src/index.ts +670 -0
  96. package/src/interactions/FocusableProvider.tsx +44 -0
  97. package/src/interactions/PressEvent.ts +126 -0
  98. package/src/interactions/createFocus.ts +163 -0
  99. package/src/interactions/createFocusRing.ts +89 -0
  100. package/src/interactions/createFocusWithin.ts +206 -0
  101. package/src/interactions/createFocusable.ts +168 -0
  102. package/src/interactions/createHover.ts +254 -0
  103. package/src/interactions/createInteractionModality.ts +424 -0
  104. package/src/interactions/createKeyboard.ts +82 -0
  105. package/src/interactions/createLongPress.ts +174 -0
  106. package/src/interactions/createMove.ts +289 -0
  107. package/src/interactions/createPress.ts +834 -0
  108. package/src/interactions/index.ts +78 -0
  109. package/src/label/createField.ts +145 -0
  110. package/src/label/createLabel.ts +117 -0
  111. package/src/label/createLabels.ts +50 -0
  112. package/src/label/index.ts +19 -0
  113. package/src/landmark/createLandmark.ts +377 -0
  114. package/src/landmark/index.ts +8 -0
  115. package/src/link/createLink.ts +182 -0
  116. package/src/link/index.ts +1 -0
  117. package/src/listbox/createListBox.ts +269 -0
  118. package/src/listbox/createOption.ts +151 -0
  119. package/src/listbox/index.ts +12 -0
  120. package/src/live-announcer/announce.ts +322 -0
  121. package/src/live-announcer/index.ts +9 -0
  122. package/src/menu/createMenu.ts +396 -0
  123. package/src/menu/createMenuItem.ts +149 -0
  124. package/src/menu/createMenuTrigger.ts +88 -0
  125. package/src/menu/index.ts +18 -0
  126. package/src/meter/createMeter.ts +75 -0
  127. package/src/meter/index.ts +1 -0
  128. package/src/numberfield/createNumberField.ts +268 -0
  129. package/src/numberfield/index.ts +5 -0
  130. package/src/overlays/ariaHideOutside.ts +219 -0
  131. package/src/overlays/createInteractOutside.ts +149 -0
  132. package/src/overlays/createModal.tsx +202 -0
  133. package/src/overlays/createOverlay.ts +155 -0
  134. package/src/overlays/createOverlayTrigger.ts +85 -0
  135. package/src/overlays/createPreventScroll.ts +266 -0
  136. package/src/overlays/index.ts +44 -0
  137. package/src/popover/calculatePosition.ts +766 -0
  138. package/src/popover/createOverlayPosition.ts +356 -0
  139. package/src/popover/createPopover.ts +170 -0
  140. package/src/popover/index.ts +24 -0
  141. package/src/progress/createProgressBar.ts +128 -0
  142. package/src/progress/index.ts +5 -0
  143. package/src/radio/createRadio.ts +287 -0
  144. package/src/radio/createRadioGroup.ts +189 -0
  145. package/src/radio/createRadioGroupState.ts +201 -0
  146. package/src/radio/index.ts +23 -0
  147. package/src/searchfield/createSearchField.ts +186 -0
  148. package/src/searchfield/index.ts +2 -0
  149. package/src/select/createHiddenSelect.tsx +236 -0
  150. package/src/select/createSelect.ts +395 -0
  151. package/src/select/index.ts +14 -0
  152. package/src/selection/createTypeSelect.ts +201 -0
  153. package/src/selection/index.ts +6 -0
  154. package/src/separator/createSeparator.ts +82 -0
  155. package/src/separator/index.ts +6 -0
  156. package/src/slider/createSlider.ts +349 -0
  157. package/src/slider/index.ts +2 -0
  158. package/src/ssr/index.tsx +370 -0
  159. package/src/switch/createSwitch.ts +70 -0
  160. package/src/switch/index.ts +1 -0
  161. package/src/table/createTable.ts +526 -0
  162. package/src/table/createTableCell.ts +147 -0
  163. package/src/table/createTableColumnHeader.ts +115 -0
  164. package/src/table/createTableHeaderRow.ts +40 -0
  165. package/src/table/createTableRow.ts +155 -0
  166. package/src/table/createTableRowGroup.ts +32 -0
  167. package/src/table/createTableSelectAllCheckbox.ts +73 -0
  168. package/src/table/createTableSelectionCheckbox.ts +59 -0
  169. package/src/table/index.ts +30 -0
  170. package/src/table/types.ts +165 -0
  171. package/src/tabs/createTabs.ts +472 -0
  172. package/src/tabs/index.ts +14 -0
  173. package/src/tag/createTag.ts +194 -0
  174. package/src/tag/createTagGroup.ts +154 -0
  175. package/src/tag/index.ts +12 -0
  176. package/src/textfield/createTextField.ts +198 -0
  177. package/src/textfield/index.ts +5 -0
  178. package/src/toast/createToast.ts +118 -0
  179. package/src/toast/createToastRegion.ts +100 -0
  180. package/src/toast/index.ts +11 -0
  181. package/src/toggle/createToggle.ts +223 -0
  182. package/src/toggle/createToggleState.ts +94 -0
  183. package/src/toggle/index.ts +7 -0
  184. package/src/toolbar/createToolbar.ts +369 -0
  185. package/src/toolbar/index.ts +6 -0
  186. package/src/tooltip/createTooltip.ts +79 -0
  187. package/src/tooltip/createTooltipTrigger.ts +222 -0
  188. package/src/tooltip/index.ts +6 -0
  189. package/src/tree/createTree.ts +246 -0
  190. package/src/tree/createTreeItem.ts +233 -0
  191. package/src/tree/createTreeSelectionCheckbox.ts +68 -0
  192. package/src/tree/index.ts +16 -0
  193. package/src/tree/types.ts +87 -0
  194. package/src/utils/createDescription.ts +137 -0
  195. package/src/utils/dom.ts +327 -0
  196. package/src/utils/env.ts +54 -0
  197. package/src/utils/events.ts +106 -0
  198. package/src/utils/filterDOMProps.ts +116 -0
  199. package/src/utils/focus.ts +151 -0
  200. package/src/utils/geometry.ts +115 -0
  201. package/src/utils/globalListeners.ts +142 -0
  202. package/src/utils/index.ts +80 -0
  203. package/src/utils/mergeProps.ts +52 -0
  204. package/src/utils/platform.ts +52 -0
  205. package/src/utils/reactivity.ts +36 -0
  206. package/src/utils/textSelection.ts +114 -0
  207. package/src/visually-hidden/createVisuallyHidden.ts +124 -0
  208. package/src/visually-hidden/index.ts +6 -0
  209. package/dist/index.jsx +0 -15845
  210. package/dist/index.jsx.map +0 -7
@@ -0,0 +1,182 @@
1
+ /**
2
+ * createGridCell - Provides accessibility for a grid cell.
3
+ * Based on @react-aria/grid/useGridCell.
4
+ */
5
+
6
+ import { createMemo, createSignal, type Accessor } from 'solid-js';
7
+ import type { JSX } from 'solid-js';
8
+ import type { GridState, GridCollection } from '@proyecto-viviana/solid-stately';
9
+ import type { GridCellProps, GridCellAria } from './types';
10
+ import { getGridData } from './createGrid';
11
+
12
+ /**
13
+ * Creates accessibility props for a grid cell.
14
+ */
15
+ export function createGridCell<T extends object>(
16
+ props: Accessor<GridCellProps>,
17
+ state: Accessor<GridState<T, GridCollection<T>>>,
18
+ _ref: Accessor<HTMLElement | null>
19
+ ): GridCellAria {
20
+ const [isPressed, setIsPressed] = createSignal(false);
21
+
22
+ const isSelected = createMemo(() => {
23
+ const s = state();
24
+ const p = props();
25
+ // Check if parent row is selected
26
+ const node = s.collection.getItem(p.key);
27
+ if (node?.parentKey != null) {
28
+ return s.isSelected(node.parentKey);
29
+ }
30
+ return false;
31
+ });
32
+
33
+ const isDisabled = createMemo(() => {
34
+ const s = state();
35
+ const p = props();
36
+ // Check if parent row is disabled
37
+ const node = s.collection.getItem(p.key);
38
+ if (node?.parentKey != null) {
39
+ return s.isDisabled(node.parentKey);
40
+ }
41
+ return false;
42
+ });
43
+
44
+ const isFocused = createMemo(() => {
45
+ const s = state();
46
+ const p = props();
47
+ return s.focusedKey === p.key;
48
+ });
49
+
50
+ // Handle click/press for cell actions
51
+ const onClick = (e: MouseEvent) => {
52
+ const s = state();
53
+ const p = props();
54
+
55
+ if (isDisabled()) return;
56
+
57
+ // Get grid metadata for actions
58
+ const gridData = getGridData(s);
59
+ const onCellAction = gridData?.actions.onCellAction;
60
+
61
+ // Get parent row key for selection
62
+ const node = s.collection.getItem(p.key);
63
+ const rowKey = node?.parentKey;
64
+
65
+ // Handle selection on parent row
66
+ if (rowKey != null && s.selectionMode !== 'none') {
67
+ if (e.shiftKey && s.selectionMode === 'multiple') {
68
+ s.extendSelection(rowKey);
69
+ } else if (e.ctrlKey || e.metaKey) {
70
+ s.toggleSelection(rowKey);
71
+ } else {
72
+ // Replace selection
73
+ s.replaceSelection(rowKey);
74
+ }
75
+ }
76
+
77
+ // Call cell action handler
78
+ if (onCellAction) {
79
+ onCellAction(p.key);
80
+ }
81
+
82
+ if (p.onAction) {
83
+ p.onAction();
84
+ }
85
+ };
86
+
87
+ const onKeyDown = (e: KeyboardEvent) => {
88
+ const s = state();
89
+ const p = props();
90
+
91
+ if (isDisabled()) return;
92
+
93
+ // Enter or Space triggers cell action
94
+ if (e.key === 'Enter' || e.key === ' ') {
95
+ // Only handle if there's an action to trigger
96
+ const gridData = getGridData(s);
97
+ const onCellAction = gridData?.actions.onCellAction;
98
+
99
+ if (onCellAction || p.onAction) {
100
+ e.preventDefault();
101
+
102
+ if (onCellAction) {
103
+ onCellAction(p.key);
104
+ }
105
+
106
+ if (p.onAction) {
107
+ p.onAction();
108
+ }
109
+ }
110
+ }
111
+ };
112
+
113
+ const onFocus = () => {
114
+ const s = state();
115
+ const p = props();
116
+ s.setFocusedKey(p.key);
117
+ };
118
+
119
+ const onPointerDown = () => {
120
+ setIsPressed(true);
121
+ };
122
+
123
+ const onPointerUp = () => {
124
+ setIsPressed(false);
125
+ };
126
+
127
+ const cellProps = createMemo(() => {
128
+ const s = state();
129
+ const p = props();
130
+ const node = s.collection.getItem(p.key);
131
+
132
+ // Determine the role based on node type
133
+ let role: string = 'gridcell';
134
+ if (node?.type === 'rowheader') {
135
+ role = 'rowheader';
136
+ } else if (node?.type === 'column') {
137
+ role = 'columnheader';
138
+ }
139
+
140
+ const baseProps: Record<string, unknown> = {
141
+ role,
142
+ 'aria-disabled': isDisabled() || undefined,
143
+ 'aria-selected': s.selectionMode !== 'none' ? isSelected() : undefined,
144
+ tabIndex: isFocused() ? 0 : -1,
145
+ onClick,
146
+ onKeyDown,
147
+ onFocus,
148
+ onPointerDown,
149
+ onPointerUp,
150
+ };
151
+
152
+ // Add column index for virtualized grids
153
+ if (p.isVirtualized && node?.column != null) {
154
+ baseProps['aria-colindex'] = node.column + 1; // aria-colindex is 1-based
155
+ }
156
+
157
+ // Add colspan if present
158
+ if (node?.colspan != null && node.colspan > 1) {
159
+ baseProps['aria-colspan'] = node.colspan;
160
+ }
161
+
162
+ return baseProps as JSX.HTMLAttributes<HTMLElement>;
163
+ });
164
+
165
+ return {
166
+ get cellProps() {
167
+ return cellProps();
168
+ },
169
+ get isSelected() {
170
+ return isSelected();
171
+ },
172
+ get isDisabled() {
173
+ return isDisabled();
174
+ },
175
+ get isPressed() {
176
+ return isPressed();
177
+ },
178
+ get isFocused() {
179
+ return isFocused();
180
+ },
181
+ };
182
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * createGridRow - Provides accessibility for a grid row.
3
+ * Based on @react-aria/grid/useGridRow.
4
+ */
5
+
6
+ import { createMemo, createSignal, type Accessor } from 'solid-js';
7
+ import type { JSX } from 'solid-js';
8
+ import type { GridState, GridCollection } from '@proyecto-viviana/solid-stately';
9
+ import type { GridRowProps, GridRowAria } from './types';
10
+ import { getGridData } from './createGrid';
11
+
12
+ /**
13
+ * Creates accessibility props for a grid row.
14
+ */
15
+ export function createGridRow<T extends object>(
16
+ props: Accessor<GridRowProps>,
17
+ state: Accessor<GridState<T, GridCollection<T>>>,
18
+ _ref: Accessor<HTMLElement | null>
19
+ ): GridRowAria {
20
+ const [isPressed, setIsPressed] = createSignal(false);
21
+
22
+ const isSelected = createMemo(() => {
23
+ const s = state();
24
+ const p = props();
25
+ return s.isSelected(p.key);
26
+ });
27
+
28
+ const isDisabled = createMemo(() => {
29
+ const s = state();
30
+ const p = props();
31
+ return s.isDisabled(p.key);
32
+ });
33
+
34
+ const isFocused = createMemo(() => {
35
+ const s = state();
36
+ const p = props();
37
+ return s.focusedKey === p.key;
38
+ });
39
+
40
+ // Handle click/press for selection
41
+ const onClick = (e: MouseEvent) => {
42
+ const s = state();
43
+ const p = props();
44
+
45
+ if (isDisabled()) return;
46
+
47
+ // Get grid metadata for actions
48
+ const gridData = getGridData(s);
49
+ const onRowAction = gridData?.actions.onRowAction;
50
+
51
+ // Handle selection
52
+ if (s.selectionMode !== 'none') {
53
+ if (e.shiftKey && s.selectionMode === 'multiple') {
54
+ s.extendSelection(p.key);
55
+ } else if (e.ctrlKey || e.metaKey) {
56
+ s.toggleSelection(p.key);
57
+ } else {
58
+ // Replace selection
59
+ s.replaceSelection(p.key);
60
+ }
61
+ }
62
+
63
+ // Call action handler
64
+ if (onRowAction) {
65
+ onRowAction(p.key);
66
+ }
67
+
68
+ if (p.onAction) {
69
+ p.onAction();
70
+ }
71
+ };
72
+
73
+ const onKeyDown = (e: KeyboardEvent) => {
74
+ const s = state();
75
+ const p = props();
76
+
77
+ if (isDisabled()) return;
78
+
79
+ if (e.key === 'Enter' || e.key === ' ') {
80
+ e.preventDefault();
81
+
82
+ // Get grid metadata for actions
83
+ const gridData = getGridData(s);
84
+ const onRowAction = gridData?.actions.onRowAction;
85
+
86
+ // Handle selection
87
+ if (s.selectionMode !== 'none') {
88
+ s.toggleSelection(p.key);
89
+ }
90
+
91
+ // Call action handler
92
+ if (onRowAction) {
93
+ onRowAction(p.key);
94
+ }
95
+
96
+ if (p.onAction) {
97
+ p.onAction();
98
+ }
99
+ }
100
+ };
101
+
102
+ const onFocus = () => {
103
+ const s = state();
104
+ const p = props();
105
+ s.setFocusedKey(p.key);
106
+ };
107
+
108
+ const onPointerDown = () => {
109
+ setIsPressed(true);
110
+ };
111
+
112
+ const onPointerUp = () => {
113
+ setIsPressed(false);
114
+ };
115
+
116
+ const rowProps = createMemo(() => {
117
+ const s = state();
118
+ const p = props();
119
+
120
+ const baseProps: Record<string, unknown> = {
121
+ role: 'row',
122
+ 'aria-selected': s.selectionMode !== 'none' ? isSelected() : undefined,
123
+ 'aria-disabled': isDisabled() || undefined,
124
+ tabIndex: isFocused() ? 0 : -1,
125
+ onClick,
126
+ onKeyDown,
127
+ onFocus,
128
+ onPointerDown,
129
+ onPointerUp,
130
+ };
131
+
132
+ if (p.isVirtualized && p.index != null) {
133
+ baseProps['aria-rowindex'] = p.index + 1; // aria-rowindex is 1-based
134
+ }
135
+
136
+ return baseProps as JSX.HTMLAttributes<HTMLElement>;
137
+ });
138
+
139
+ return {
140
+ get rowProps() {
141
+ return rowProps();
142
+ },
143
+ get isSelected() {
144
+ return isSelected();
145
+ },
146
+ get isDisabled() {
147
+ return isDisabled();
148
+ },
149
+ get isPressed() {
150
+ return isPressed();
151
+ },
152
+ };
153
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Grid accessibility primitives for Table and GridList components.
3
+ * Based on @react-aria/grid.
4
+ */
5
+
6
+ export { createGrid, getGridData } from './createGrid';
7
+ export { createGridRow } from './createGridRow';
8
+ export { createGridCell } from './createGridCell';
9
+ export { GridKeyboardDelegate } from './GridKeyboardDelegate';
10
+ export type {
11
+ KeyboardDelegate,
12
+ GridProps,
13
+ GridAria,
14
+ GridRowProps,
15
+ GridRowAria,
16
+ GridCellProps,
17
+ GridCellAria,
18
+ } from './types';
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Grid ARIA types for Table and GridList components.
3
+ * Based on @react-aria/grid types.
4
+ */
5
+
6
+ import type { JSX } from 'solid-js';
7
+ import type { Key } from '@proyecto-viviana/solid-stately';
8
+
9
+ /**
10
+ * Keyboard delegate interface for grid navigation.
11
+ */
12
+ export interface KeyboardDelegate {
13
+ /** Get the key above the given key. */
14
+ getKeyAbove?(key: Key): Key | null;
15
+ /** Get the key below the given key. */
16
+ getKeyBelow?(key: Key): Key | null;
17
+ /** Get the key to the left of the given key. */
18
+ getKeyLeftOf?(key: Key): Key | null;
19
+ /** Get the key to the right of the given key. */
20
+ getKeyRightOf?(key: Key): Key | null;
21
+ /** Get the first key in the collection. */
22
+ getFirstKey?(key?: Key, global?: boolean): Key | null;
23
+ /** Get the last key in the collection. */
24
+ getLastKey?(key?: Key, global?: boolean): Key | null;
25
+ /** Get the key for a page up action. */
26
+ getKeyPageAbove?(key: Key): Key | null;
27
+ /** Get the key for a page down action. */
28
+ getKeyPageBelow?(key: Key): Key | null;
29
+ /** Get the key that matches the search string. */
30
+ getKeyForSearch?(search: string, fromKey?: Key): Key | null;
31
+ }
32
+
33
+ /**
34
+ * Props for the createGrid hook.
35
+ */
36
+ export interface GridProps {
37
+ /** ID for the grid element. */
38
+ id?: string;
39
+ /** Whether the grid uses virtual scrolling. */
40
+ isVirtualized?: boolean;
41
+ /** Whether typeahead navigation is disabled. */
42
+ disallowTypeAhead?: boolean;
43
+ /** Custom keyboard delegate for navigation. */
44
+ keyboardDelegate?: KeyboardDelegate;
45
+ /** Whether focus should be on row or cell. */
46
+ focusMode?: 'row' | 'cell';
47
+ /** Handler for row actions. */
48
+ onRowAction?: (key: Key) => void;
49
+ /** Handler for cell actions. */
50
+ onCellAction?: (key: Key) => void;
51
+ /** Escape key behavior. */
52
+ escapeKeyBehavior?: 'clearSelection' | 'none';
53
+ /** Whether selection should occur on press up. */
54
+ shouldSelectOnPressUp?: boolean;
55
+ /** ARIA label for the grid. */
56
+ 'aria-label'?: string;
57
+ /** ARIA labelledby for the grid. */
58
+ 'aria-labelledby'?: string;
59
+ /** ARIA describedby for the grid. */
60
+ 'aria-describedby'?: string;
61
+ }
62
+
63
+ /**
64
+ * Return value from createGrid.
65
+ */
66
+ export interface GridAria {
67
+ /** Props to spread on the grid element. */
68
+ gridProps: JSX.HTMLAttributes<HTMLElement>;
69
+ }
70
+
71
+ /**
72
+ * Props for the createGridRow hook.
73
+ */
74
+ export interface GridRowProps {
75
+ /** The key of the row. */
76
+ key: Key;
77
+ /** The index of the row (for virtualized grids). */
78
+ index?: number;
79
+ /** Whether the grid is virtualized. */
80
+ isVirtualized?: boolean;
81
+ /** Handler for row action. */
82
+ onAction?: () => void;
83
+ }
84
+
85
+ /**
86
+ * Return value from createGridRow.
87
+ */
88
+ export interface GridRowAria {
89
+ /** Props to spread on the row element. */
90
+ rowProps: JSX.HTMLAttributes<HTMLElement>;
91
+ /** Whether the row is selected. */
92
+ isSelected: boolean;
93
+ /** Whether the row is disabled. */
94
+ isDisabled: boolean;
95
+ /** Whether the row is pressed. */
96
+ isPressed: boolean;
97
+ }
98
+
99
+ /**
100
+ * Props for the createGridCell hook.
101
+ */
102
+ export interface GridCellProps {
103
+ /** The key of the cell. */
104
+ key: Key;
105
+ /** The key of the parent row. */
106
+ parentKey: Key;
107
+ /** The column index of the cell. */
108
+ colIndex?: number;
109
+ /** Column span. */
110
+ colSpan?: number;
111
+ /** Whether the grid is virtualized. */
112
+ isVirtualized?: boolean;
113
+ /** Whether to focus cell or child element. */
114
+ focusMode?: 'child' | 'cell';
115
+ /** Handler for cell action. */
116
+ onAction?: () => void;
117
+ }
118
+
119
+ /**
120
+ * Return value from createGridCell.
121
+ */
122
+ export interface GridCellAria {
123
+ /** Props to spread on the cell element. */
124
+ cellProps: JSX.HTMLAttributes<HTMLElement>;
125
+ /** Whether the cell's row is selected. */
126
+ isSelected: boolean;
127
+ /** Whether the cell's row is disabled. */
128
+ isDisabled: boolean;
129
+ /** Whether the cell is pressed. */
130
+ isPressed: boolean;
131
+ /** Whether the cell is focused. */
132
+ isFocused: boolean;
133
+ }
@@ -0,0 +1,185 @@
1
+ /**
2
+ * createGridList - Provides accessibility for a grid list.
3
+ * Based on @react-aria/gridlist/useGridList.
4
+ */
5
+
6
+ import { createMemo, type Accessor } from 'solid-js';
7
+ import type { JSX } from 'solid-js';
8
+ import { createId } from '@proyecto-viviana/solid-stately';
9
+ import type { GridState, GridCollection, Key } from '@proyecto-viviana/solid-stately';
10
+ import type { AriaGridListProps, GridListAria } from './types';
11
+
12
+ /**
13
+ * Metadata stored for a grid list instance.
14
+ */
15
+ interface GridListData {
16
+ /** The generated ID for the grid list. */
17
+ gridListId: string;
18
+ /** Actions registered for the grid list. */
19
+ actions: {
20
+ onAction?: (key: Key) => void;
21
+ };
22
+ }
23
+
24
+ /**
25
+ * WeakMap to store grid list data for child components to access.
26
+ */
27
+ const gridListDataMap = new WeakMap<object, GridListData>();
28
+
29
+ /**
30
+ * Gets the grid list data for a given state.
31
+ */
32
+ export function getGridListData<T extends object, C extends GridCollection<T>>(
33
+ state: GridState<T, C>
34
+ ): GridListData | undefined {
35
+ return gridListDataMap.get(state);
36
+ }
37
+
38
+ /**
39
+ * Creates accessibility props for a grid list.
40
+ */
41
+ export function createGridList<T extends object, C extends GridCollection<T> = GridCollection<T>>(
42
+ props: Accessor<AriaGridListProps>,
43
+ state: Accessor<GridState<T, C>>,
44
+ _ref: Accessor<HTMLUListElement | null>
45
+ ): GridListAria {
46
+ // Generate a unique ID for the grid list
47
+ const gridListId = props().id ?? createId();
48
+
49
+ // Store grid list data for child components
50
+ const gridListData: GridListData = {
51
+ gridListId,
52
+ actions: {
53
+ get onAction() {
54
+ return props().onAction;
55
+ },
56
+ },
57
+ };
58
+
59
+ // Store in WeakMap using the state as key
60
+ gridListDataMap.set(state(), gridListData);
61
+
62
+ // Handle keyboard navigation
63
+ const onKeyDown = (e: KeyboardEvent) => {
64
+ const s = state();
65
+ const p = props();
66
+ const collection = s.collection;
67
+ const focusedKey = s.focusedKey;
68
+
69
+ if (p.isDisabled) return;
70
+
71
+ switch (e.key) {
72
+ case 'ArrowDown': {
73
+ e.preventDefault();
74
+ if (focusedKey != null) {
75
+ const nextKey = collection.getKeyAfter(focusedKey);
76
+ if (nextKey != null) {
77
+ s.setFocusedKey(nextKey);
78
+ }
79
+ } else {
80
+ const firstKey = collection.getFirstKey();
81
+ if (firstKey != null) {
82
+ s.setFocusedKey(firstKey);
83
+ }
84
+ }
85
+ break;
86
+ }
87
+ case 'ArrowUp': {
88
+ e.preventDefault();
89
+ if (focusedKey != null) {
90
+ const prevKey = collection.getKeyBefore(focusedKey);
91
+ if (prevKey != null) {
92
+ s.setFocusedKey(prevKey);
93
+ }
94
+ } else {
95
+ const lastKey = collection.getLastKey();
96
+ if (lastKey != null) {
97
+ s.setFocusedKey(lastKey);
98
+ }
99
+ }
100
+ break;
101
+ }
102
+ case 'Home': {
103
+ e.preventDefault();
104
+ const firstKey = collection.getFirstKey();
105
+ if (firstKey != null) {
106
+ s.setFocusedKey(firstKey);
107
+ }
108
+ break;
109
+ }
110
+ case 'End': {
111
+ e.preventDefault();
112
+ const lastKey = collection.getLastKey();
113
+ if (lastKey != null) {
114
+ s.setFocusedKey(lastKey);
115
+ }
116
+ break;
117
+ }
118
+ case 'a':
119
+ case 'A': {
120
+ if ((e.ctrlKey || e.metaKey) && s.selectionMode === 'multiple') {
121
+ e.preventDefault();
122
+ s.selectAll();
123
+ }
124
+ break;
125
+ }
126
+ case 'Escape': {
127
+ if (s.selectionMode !== 'none') {
128
+ e.preventDefault();
129
+ s.clearSelection();
130
+ }
131
+ break;
132
+ }
133
+ }
134
+ };
135
+
136
+ const onFocus = () => {
137
+ const s = state();
138
+ s.setFocused(true);
139
+
140
+ // If nothing is focused, focus the first item
141
+ if (s.focusedKey == null) {
142
+ const firstKey = s.collection.getFirstKey();
143
+ if (firstKey != null) {
144
+ s.setFocusedKey(firstKey);
145
+ }
146
+ }
147
+ };
148
+
149
+ const onBlur = () => {
150
+ const s = state();
151
+ s.setFocused(false);
152
+ };
153
+
154
+ const gridProps = createMemo(() => {
155
+ const p = props();
156
+ const s = state();
157
+
158
+ const baseProps: Record<string, unknown> = {
159
+ role: 'grid',
160
+ id: gridListId,
161
+ 'aria-label': p['aria-label'],
162
+ 'aria-labelledby': p['aria-labelledby'],
163
+ 'aria-describedby': p['aria-describedby'],
164
+ 'aria-multiselectable': s.selectionMode === 'multiple' ? true : undefined,
165
+ 'aria-disabled': p.isDisabled || undefined,
166
+ tabIndex: p.isDisabled ? undefined : 0,
167
+ onKeyDown,
168
+ onFocus,
169
+ onBlur,
170
+ };
171
+
172
+ // Add row count for virtualized lists
173
+ if (p.isVirtualized) {
174
+ baseProps['aria-rowcount'] = s.collection.rowCount;
175
+ }
176
+
177
+ return baseProps as JSX.HTMLAttributes<HTMLUListElement>;
178
+ });
179
+
180
+ return {
181
+ get gridProps() {
182
+ return gridProps();
183
+ },
184
+ };
185
+ }