@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.
- package/dist/autocomplete/createAutocomplete.d.ts +2 -2
- package/dist/autocomplete/createAutocomplete.d.ts.map +1 -1
- package/dist/index.js +233 -234
- package/dist/index.js.map +2 -2
- package/dist/index.ssr.js +233 -234
- package/dist/index.ssr.js.map +2 -2
- package/dist/interactions/PressEvent.d.ts +13 -10
- package/dist/interactions/PressEvent.d.ts.map +1 -1
- package/dist/interactions/createPress.d.ts.map +1 -1
- package/dist/interactions/index.d.ts +1 -1
- package/dist/interactions/index.d.ts.map +1 -1
- package/dist/select/createHiddenSelect.d.ts.map +1 -1
- package/dist/toolbar/createToolbar.d.ts.map +1 -1
- package/dist/tooltip/createTooltipTrigger.d.ts.map +1 -1
- package/package.json +9 -7
- package/src/autocomplete/createAutocomplete.ts +341 -0
- package/src/autocomplete/index.ts +9 -0
- package/src/breadcrumbs/createBreadcrumbs.ts +196 -0
- package/src/breadcrumbs/index.ts +8 -0
- package/src/button/createButton.ts +142 -0
- package/src/button/createToggleButton.ts +101 -0
- package/src/button/index.ts +4 -0
- package/src/button/types.ts +78 -0
- package/src/calendar/createCalendar.ts +138 -0
- package/src/calendar/createCalendarCell.ts +187 -0
- package/src/calendar/createCalendarGrid.ts +140 -0
- package/src/calendar/createRangeCalendar.ts +136 -0
- package/src/calendar/createRangeCalendarCell.ts +186 -0
- package/src/calendar/index.ts +34 -0
- package/src/checkbox/createCheckbox.ts +135 -0
- package/src/checkbox/createCheckboxGroup.ts +137 -0
- package/src/checkbox/createCheckboxGroupItem.ts +117 -0
- package/src/checkbox/createCheckboxGroupState.ts +193 -0
- package/src/checkbox/index.ts +13 -0
- package/src/color/createColorArea.ts +314 -0
- package/src/color/createColorField.ts +137 -0
- package/src/color/createColorSlider.ts +197 -0
- package/src/color/createColorSwatch.ts +40 -0
- package/src/color/createColorWheel.ts +208 -0
- package/src/color/index.ts +24 -0
- package/src/color/types.ts +116 -0
- package/src/combobox/createComboBox.ts +647 -0
- package/src/combobox/index.ts +6 -0
- package/src/combobox/intl/en-US.json +7 -0
- package/src/combobox/intl/es-ES.json +7 -0
- package/src/combobox/intl/index.ts +23 -0
- package/src/datepicker/createDateField.ts +154 -0
- package/src/datepicker/createDatePicker.ts +206 -0
- package/src/datepicker/createDateSegment.ts +229 -0
- package/src/datepicker/createTimeField.ts +154 -0
- package/src/datepicker/index.ts +28 -0
- package/src/dialog/createDialog.ts +120 -0
- package/src/dialog/index.ts +2 -0
- package/src/dialog/types.ts +19 -0
- package/src/disclosure/createDisclosure.ts +131 -0
- package/src/disclosure/createDisclosureGroup.ts +62 -0
- package/src/disclosure/index.ts +11 -0
- package/src/dnd/createDrag.ts +209 -0
- package/src/dnd/createDraggableCollection.ts +63 -0
- package/src/dnd/createDraggableItem.ts +243 -0
- package/src/dnd/createDrop.ts +321 -0
- package/src/dnd/createDroppableCollection.ts +293 -0
- package/src/dnd/createDroppableItem.ts +213 -0
- package/src/dnd/index.ts +47 -0
- package/src/dnd/types.ts +89 -0
- package/src/dnd/utils.ts +294 -0
- package/src/focus/FocusScope.tsx +408 -0
- package/src/focus/createAutoFocus.ts +321 -0
- package/src/focus/createFocusRestore.ts +313 -0
- package/src/focus/createVirtualFocus.ts +396 -0
- package/src/focus/index.ts +35 -0
- package/src/form/createFormReset.ts +51 -0
- package/src/form/createFormValidation.ts +224 -0
- package/src/form/index.ts +11 -0
- package/src/grid/GridKeyboardDelegate.ts +429 -0
- package/src/grid/createGrid.ts +261 -0
- package/src/grid/createGridCell.ts +182 -0
- package/src/grid/createGridRow.ts +153 -0
- package/src/grid/index.ts +18 -0
- package/src/grid/types.ts +133 -0
- package/src/gridlist/createGridList.ts +185 -0
- package/src/gridlist/createGridListItem.ts +180 -0
- package/src/gridlist/createGridListSelectionCheckbox.ts +59 -0
- package/src/gridlist/index.ts +16 -0
- package/src/gridlist/types.ts +81 -0
- package/src/i18n/NumberFormatter.ts +266 -0
- package/src/i18n/createCollator.ts +79 -0
- package/src/i18n/createDateFormatter.ts +83 -0
- package/src/i18n/createFilter.ts +131 -0
- package/src/i18n/createNumberFormatter.ts +52 -0
- package/src/i18n/createStringFormatter.ts +87 -0
- package/src/i18n/index.ts +40 -0
- package/src/i18n/locale.tsx +188 -0
- package/src/i18n/utils.ts +99 -0
- package/src/index.ts +670 -0
- package/src/interactions/FocusableProvider.tsx +44 -0
- package/src/interactions/PressEvent.ts +126 -0
- package/src/interactions/createFocus.ts +163 -0
- package/src/interactions/createFocusRing.ts +89 -0
- package/src/interactions/createFocusWithin.ts +206 -0
- package/src/interactions/createFocusable.ts +168 -0
- package/src/interactions/createHover.ts +254 -0
- package/src/interactions/createInteractionModality.ts +424 -0
- package/src/interactions/createKeyboard.ts +82 -0
- package/src/interactions/createLongPress.ts +174 -0
- package/src/interactions/createMove.ts +289 -0
- package/src/interactions/createPress.ts +834 -0
- package/src/interactions/index.ts +78 -0
- package/src/label/createField.ts +145 -0
- package/src/label/createLabel.ts +117 -0
- package/src/label/createLabels.ts +50 -0
- package/src/label/index.ts +19 -0
- package/src/landmark/createLandmark.ts +377 -0
- package/src/landmark/index.ts +8 -0
- package/src/link/createLink.ts +182 -0
- package/src/link/index.ts +1 -0
- package/src/listbox/createListBox.ts +269 -0
- package/src/listbox/createOption.ts +151 -0
- package/src/listbox/index.ts +12 -0
- package/src/live-announcer/announce.ts +322 -0
- package/src/live-announcer/index.ts +9 -0
- package/src/menu/createMenu.ts +396 -0
- package/src/menu/createMenuItem.ts +149 -0
- package/src/menu/createMenuTrigger.ts +88 -0
- package/src/menu/index.ts +18 -0
- package/src/meter/createMeter.ts +75 -0
- package/src/meter/index.ts +1 -0
- package/src/numberfield/createNumberField.ts +268 -0
- package/src/numberfield/index.ts +5 -0
- package/src/overlays/ariaHideOutside.ts +219 -0
- package/src/overlays/createInteractOutside.ts +149 -0
- package/src/overlays/createModal.tsx +202 -0
- package/src/overlays/createOverlay.ts +155 -0
- package/src/overlays/createOverlayTrigger.ts +85 -0
- package/src/overlays/createPreventScroll.ts +266 -0
- package/src/overlays/index.ts +44 -0
- package/src/popover/calculatePosition.ts +766 -0
- package/src/popover/createOverlayPosition.ts +356 -0
- package/src/popover/createPopover.ts +170 -0
- package/src/popover/index.ts +24 -0
- package/src/progress/createProgressBar.ts +128 -0
- package/src/progress/index.ts +5 -0
- package/src/radio/createRadio.ts +287 -0
- package/src/radio/createRadioGroup.ts +189 -0
- package/src/radio/createRadioGroupState.ts +201 -0
- package/src/radio/index.ts +23 -0
- package/src/searchfield/createSearchField.ts +186 -0
- package/src/searchfield/index.ts +2 -0
- package/src/select/createHiddenSelect.tsx +236 -0
- package/src/select/createSelect.ts +395 -0
- package/src/select/index.ts +14 -0
- package/src/selection/createTypeSelect.ts +201 -0
- package/src/selection/index.ts +6 -0
- package/src/separator/createSeparator.ts +82 -0
- package/src/separator/index.ts +6 -0
- package/src/slider/createSlider.ts +349 -0
- package/src/slider/index.ts +2 -0
- package/src/ssr/index.tsx +370 -0
- package/src/switch/createSwitch.ts +70 -0
- package/src/switch/index.ts +1 -0
- package/src/table/createTable.ts +526 -0
- package/src/table/createTableCell.ts +147 -0
- package/src/table/createTableColumnHeader.ts +115 -0
- package/src/table/createTableHeaderRow.ts +40 -0
- package/src/table/createTableRow.ts +155 -0
- package/src/table/createTableRowGroup.ts +32 -0
- package/src/table/createTableSelectAllCheckbox.ts +73 -0
- package/src/table/createTableSelectionCheckbox.ts +59 -0
- package/src/table/index.ts +30 -0
- package/src/table/types.ts +165 -0
- package/src/tabs/createTabs.ts +472 -0
- package/src/tabs/index.ts +14 -0
- package/src/tag/createTag.ts +194 -0
- package/src/tag/createTagGroup.ts +154 -0
- package/src/tag/index.ts +12 -0
- package/src/textfield/createTextField.ts +198 -0
- package/src/textfield/index.ts +5 -0
- package/src/toast/createToast.ts +118 -0
- package/src/toast/createToastRegion.ts +100 -0
- package/src/toast/index.ts +11 -0
- package/src/toggle/createToggle.ts +223 -0
- package/src/toggle/createToggleState.ts +94 -0
- package/src/toggle/index.ts +7 -0
- package/src/toolbar/createToolbar.ts +369 -0
- package/src/toolbar/index.ts +6 -0
- package/src/tooltip/createTooltip.ts +79 -0
- package/src/tooltip/createTooltipTrigger.ts +222 -0
- package/src/tooltip/index.ts +6 -0
- package/src/tree/createTree.ts +246 -0
- package/src/tree/createTreeItem.ts +233 -0
- package/src/tree/createTreeSelectionCheckbox.ts +68 -0
- package/src/tree/index.ts +16 -0
- package/src/tree/types.ts +87 -0
- package/src/utils/createDescription.ts +137 -0
- package/src/utils/dom.ts +327 -0
- package/src/utils/env.ts +54 -0
- package/src/utils/events.ts +106 -0
- package/src/utils/filterDOMProps.ts +116 -0
- package/src/utils/focus.ts +151 -0
- package/src/utils/geometry.ts +115 -0
- package/src/utils/globalListeners.ts +142 -0
- package/src/utils/index.ts +80 -0
- package/src/utils/mergeProps.ts +52 -0
- package/src/utils/platform.ts +52 -0
- package/src/utils/reactivity.ts +36 -0
- package/src/utils/textSelection.ts +114 -0
- package/src/visually-hidden/createVisuallyHidden.ts +124 -0
- package/src/visually-hidden/index.ts +6 -0
- package/dist/index.jsx +0 -15845
- package/dist/index.jsx.map +0 -7
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live announcer for solidaria
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to make announcements to screen readers using
|
|
5
|
+
* ARIA live regions. Useful for announcing dynamic content changes.
|
|
6
|
+
*
|
|
7
|
+
* Port of react-aria's @react-aria/live-announcer.
|
|
8
|
+
*
|
|
9
|
+
* SSR Safety: All functions are safe to call during SSR. The announcer
|
|
10
|
+
* will only be created when running in the browser.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { onCleanup, createEffect } from 'solid-js';
|
|
14
|
+
import { isServer } from 'solid-js/web';
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// TYPES
|
|
18
|
+
// ============================================
|
|
19
|
+
|
|
20
|
+
export type Assertiveness = 'assertive' | 'polite';
|
|
21
|
+
|
|
22
|
+
export type Message = string | { 'aria-labelledby': string };
|
|
23
|
+
|
|
24
|
+
// ============================================
|
|
25
|
+
// CONSTANTS
|
|
26
|
+
// ============================================
|
|
27
|
+
|
|
28
|
+
const LIVEREGION_TIMEOUT_DELAY = 7000;
|
|
29
|
+
|
|
30
|
+
// ============================================
|
|
31
|
+
// LIVE ANNOUNCER CLASS
|
|
32
|
+
// ============================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Singleton class that manages live region announcements.
|
|
36
|
+
* Implemented using vanilla DOM for simplicity and framework independence.
|
|
37
|
+
*/
|
|
38
|
+
class LiveAnnouncer {
|
|
39
|
+
node: HTMLElement | null = null;
|
|
40
|
+
assertiveLog: HTMLElement | null = null;
|
|
41
|
+
politeLog: HTMLElement | null = null;
|
|
42
|
+
|
|
43
|
+
constructor() {
|
|
44
|
+
if (typeof document !== 'undefined') {
|
|
45
|
+
this.node = document.createElement('div');
|
|
46
|
+
this.node.dataset.liveAnnouncer = 'true';
|
|
47
|
+
// Visually hidden styles
|
|
48
|
+
Object.assign(this.node.style, {
|
|
49
|
+
border: '0',
|
|
50
|
+
clip: 'rect(0 0 0 0)',
|
|
51
|
+
clipPath: 'inset(50%)',
|
|
52
|
+
height: '1px',
|
|
53
|
+
margin: '-1px',
|
|
54
|
+
overflow: 'hidden',
|
|
55
|
+
padding: '0',
|
|
56
|
+
position: 'absolute',
|
|
57
|
+
width: '1px',
|
|
58
|
+
whiteSpace: 'nowrap',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this.assertiveLog = this.createLog('assertive');
|
|
62
|
+
this.node.appendChild(this.assertiveLog);
|
|
63
|
+
|
|
64
|
+
this.politeLog = this.createLog('polite');
|
|
65
|
+
this.node.appendChild(this.politeLog);
|
|
66
|
+
|
|
67
|
+
document.body.prepend(this.node);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
isAttached(): boolean {
|
|
72
|
+
return this.node?.isConnected ?? false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
createLog(ariaLive: string): HTMLElement {
|
|
76
|
+
const node = document.createElement('div');
|
|
77
|
+
node.setAttribute('role', 'log');
|
|
78
|
+
node.setAttribute('aria-live', ariaLive);
|
|
79
|
+
node.setAttribute('aria-relevant', 'additions');
|
|
80
|
+
return node;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
destroy(): void {
|
|
84
|
+
if (!this.node) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
document.body.removeChild(this.node);
|
|
89
|
+
this.node = null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
announce(
|
|
93
|
+
message: Message,
|
|
94
|
+
assertiveness: Assertiveness = 'assertive',
|
|
95
|
+
timeout: number = LIVEREGION_TIMEOUT_DELAY
|
|
96
|
+
): void {
|
|
97
|
+
if (!this.node) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const node = document.createElement('div');
|
|
102
|
+
if (typeof message === 'object') {
|
|
103
|
+
// To read an aria-labelledby, the element must have an appropriate role, such as img.
|
|
104
|
+
node.setAttribute('role', 'img');
|
|
105
|
+
node.setAttribute('aria-labelledby', message['aria-labelledby']);
|
|
106
|
+
} else {
|
|
107
|
+
node.textContent = message;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (assertiveness === 'assertive') {
|
|
111
|
+
this.assertiveLog?.appendChild(node);
|
|
112
|
+
} else {
|
|
113
|
+
this.politeLog?.appendChild(node);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (message !== '') {
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
node.remove();
|
|
119
|
+
}, timeout);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
clear(assertiveness?: Assertiveness): void {
|
|
124
|
+
if (!this.node) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) {
|
|
129
|
+
this.assertiveLog.innerHTML = '';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if ((!assertiveness || assertiveness === 'polite') && this.politeLog) {
|
|
133
|
+
this.politeLog.innerHTML = '';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ============================================
|
|
139
|
+
// SINGLETON INSTANCE
|
|
140
|
+
// ============================================
|
|
141
|
+
|
|
142
|
+
let liveAnnouncer: LiveAnnouncer | null = null;
|
|
143
|
+
|
|
144
|
+
// ============================================
|
|
145
|
+
// PUBLIC API
|
|
146
|
+
// ============================================
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Announces a message to screen readers using ARIA live regions.
|
|
150
|
+
*
|
|
151
|
+
* @param message - The message to announce, or an object with aria-labelledby
|
|
152
|
+
* @param assertiveness - 'assertive' interrupts, 'polite' waits for a pause
|
|
153
|
+
* @param timeout - How long to keep the message in the DOM (default 7000ms)
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```tsx
|
|
157
|
+
* // Simple announcement
|
|
158
|
+
* announce('Item added to cart');
|
|
159
|
+
*
|
|
160
|
+
* // Polite announcement (won't interrupt)
|
|
161
|
+
* announce('3 results found', 'polite');
|
|
162
|
+
*
|
|
163
|
+
* // Using aria-labelledby for complex content
|
|
164
|
+
* announce({ 'aria-labelledby': 'my-element-id' });
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export function announce(
|
|
168
|
+
message: Message,
|
|
169
|
+
assertiveness: Assertiveness = 'assertive',
|
|
170
|
+
timeout: number = LIVEREGION_TIMEOUT_DELAY
|
|
171
|
+
): void {
|
|
172
|
+
if (!liveAnnouncer) {
|
|
173
|
+
liveAnnouncer = new LiveAnnouncer();
|
|
174
|
+
// Wait for the live announcer regions to be added to the DOM, then announce.
|
|
175
|
+
// Otherwise Safari won't announce the message if it's added too quickly.
|
|
176
|
+
// Found most times less than 100ms were not consistent when announcing with Safari.
|
|
177
|
+
|
|
178
|
+
// Check for test environment
|
|
179
|
+
const isTestEnv = typeof (globalThis as Record<string, unknown>).IS_SOLIDARIA_TEST === 'boolean'
|
|
180
|
+
? (globalThis as Record<string, unknown>).IS_SOLIDARIA_TEST
|
|
181
|
+
: typeof (globalThis as Record<string, unknown>).vitest !== 'undefined';
|
|
182
|
+
|
|
183
|
+
if (!isTestEnv) {
|
|
184
|
+
setTimeout(() => {
|
|
185
|
+
if (liveAnnouncer?.isAttached()) {
|
|
186
|
+
liveAnnouncer?.announce(message, assertiveness, timeout);
|
|
187
|
+
}
|
|
188
|
+
}, 100);
|
|
189
|
+
} else {
|
|
190
|
+
liveAnnouncer.announce(message, assertiveness, timeout);
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
liveAnnouncer.announce(message, assertiveness, timeout);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Clears all queued announcements for the given assertiveness level.
|
|
199
|
+
*
|
|
200
|
+
* @param assertiveness - Which log to clear ('assertive' or 'polite')
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```tsx
|
|
204
|
+
* // Clear assertive announcements
|
|
205
|
+
* clearAnnouncer('assertive');
|
|
206
|
+
*
|
|
207
|
+
* // Clear polite announcements
|
|
208
|
+
* clearAnnouncer('polite');
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
export function clearAnnouncer(assertiveness?: Assertiveness): void {
|
|
212
|
+
if (liveAnnouncer) {
|
|
213
|
+
liveAnnouncer.clear(assertiveness);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Removes the live announcer from the DOM entirely.
|
|
219
|
+
* Call this when unmounting your app or when announcements are no longer needed.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```tsx
|
|
223
|
+
* // Clean up on app unmount
|
|
224
|
+
* onCleanup(() => {
|
|
225
|
+
* destroyAnnouncer();
|
|
226
|
+
* });
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
export function destroyAnnouncer(): void {
|
|
230
|
+
if (liveAnnouncer) {
|
|
231
|
+
liveAnnouncer.destroy();
|
|
232
|
+
liveAnnouncer = null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ============================================
|
|
237
|
+
// HOOK-BASED API
|
|
238
|
+
// ============================================
|
|
239
|
+
|
|
240
|
+
export interface UseAnnouncerResult {
|
|
241
|
+
/** Announce a message to screen readers. */
|
|
242
|
+
announce: (
|
|
243
|
+
message: Message,
|
|
244
|
+
assertiveness?: Assertiveness,
|
|
245
|
+
timeout?: number
|
|
246
|
+
) => void;
|
|
247
|
+
/** Clear announcements for the given assertiveness level. */
|
|
248
|
+
clear: (assertiveness?: Assertiveness) => void;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Hook that provides access to the live announcer with automatic cleanup.
|
|
253
|
+
*
|
|
254
|
+
* This is the recommended way to use the announcer in SolidJS components.
|
|
255
|
+
* It ensures the announcer is created only on the client and provides
|
|
256
|
+
* type-safe methods for announcing and clearing messages.
|
|
257
|
+
*
|
|
258
|
+
* SSR Safety: Returns no-op functions during SSR. The announcer is only
|
|
259
|
+
* created when the component mounts on the client.
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* ```tsx
|
|
263
|
+
* function SearchResults(props) {
|
|
264
|
+
* const announcer = useAnnouncer();
|
|
265
|
+
*
|
|
266
|
+
* createEffect(() => {
|
|
267
|
+
* const count = props.results.length;
|
|
268
|
+
* announcer.announce(`${count} results found`, 'polite');
|
|
269
|
+
* });
|
|
270
|
+
*
|
|
271
|
+
* return <ul>...</ul>;
|
|
272
|
+
* }
|
|
273
|
+
* ```
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```tsx
|
|
277
|
+
* function Form() {
|
|
278
|
+
* const announcer = useAnnouncer();
|
|
279
|
+
*
|
|
280
|
+
* const onSubmit = async () => {
|
|
281
|
+
* try {
|
|
282
|
+
* await submitForm();
|
|
283
|
+
* announcer.announce('Form submitted successfully');
|
|
284
|
+
* } catch (error) {
|
|
285
|
+
* announcer.announce('Error submitting form', 'assertive');
|
|
286
|
+
* }
|
|
287
|
+
* };
|
|
288
|
+
*
|
|
289
|
+
* return <form onSubmit={onSubmit}>...</form>;
|
|
290
|
+
* }
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
export function useAnnouncer(): UseAnnouncerResult {
|
|
294
|
+
// During SSR, return no-op functions
|
|
295
|
+
if (isServer) {
|
|
296
|
+
return {
|
|
297
|
+
announce: () => {},
|
|
298
|
+
clear: () => {},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Ensure the announcer is initialized
|
|
303
|
+
createEffect(() => {
|
|
304
|
+
// Initialize on first use
|
|
305
|
+
if (!liveAnnouncer) {
|
|
306
|
+
liveAnnouncer = new LiveAnnouncer();
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
announce: (
|
|
312
|
+
message: Message,
|
|
313
|
+
assertiveness: Assertiveness = 'assertive',
|
|
314
|
+
timeout: number = LIVEREGION_TIMEOUT_DELAY
|
|
315
|
+
) => {
|
|
316
|
+
announce(message, assertiveness, timeout);
|
|
317
|
+
},
|
|
318
|
+
clear: (assertiveness?: Assertiveness) => {
|
|
319
|
+
clearAnnouncer(assertiveness);
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
}
|