@theaccessibleteam/a11y-feedback-react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # @theaccessibleteam/a11y-feedback-react
2
+
3
+ React bindings for [a11y-feedback](https://www.npmjs.com/package/@theaccessibleteam/a11y-feedback) - the accessibility-first feedback library.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @theaccessibleteam/a11y-feedback @theaccessibleteam/a11y-feedback-react
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### Option 1: Using the Hook (Simple)
14
+
15
+ ```tsx
16
+ import { useA11yFeedback } from '@theaccessibleteam/a11y-feedback-react'
17
+ import { configureFeedback } from '@theaccessibleteam/a11y-feedback'
18
+
19
+ // Configure once at app startup
20
+ configureFeedback({ visual: true })
21
+
22
+ function SaveButton() {
23
+ const feedback = useA11yFeedback()
24
+
25
+ const handleSave = async () => {
26
+ feedback.loading('Saving...', { id: 'save' })
27
+
28
+ try {
29
+ await saveData()
30
+ feedback.success('Saved!', { id: 'save' })
31
+ } catch (e) {
32
+ feedback.error('Failed to save', { id: 'save', focus: '#save-btn' })
33
+ }
34
+ }
35
+
36
+ return <button id="save-btn" onClick={handleSave}>Save</button>
37
+ }
38
+ ```
39
+
40
+ ### Option 2: Using the Provider (Recommended for Apps)
41
+
42
+ ```tsx
43
+ import { A11yFeedbackProvider, useA11yFeedbackContext } from '@theaccessibleteam/a11y-feedback-react'
44
+
45
+ function App() {
46
+ return (
47
+ <A11yFeedbackProvider config={{ visual: true }} debug>
48
+ <MyApp />
49
+ </A11yFeedbackProvider>
50
+ )
51
+ }
52
+
53
+ function MyComponent() {
54
+ const { success, error } = useA11yFeedbackContext()
55
+
56
+ const handleAction = async () => {
57
+ try {
58
+ await performAction()
59
+ success('Action completed!')
60
+ } catch (e) {
61
+ error('Action failed')
62
+ }
63
+ }
64
+
65
+ return <button onClick={handleAction}>Do Something</button>
66
+ }
67
+ ```
68
+
69
+ ## Hooks
70
+
71
+ ### `useA11yFeedback()`
72
+
73
+ Main hook providing all feedback methods. Can be used without a provider.
74
+
75
+ ```tsx
76
+ const { success, error, warning, info, loading, dismiss, dismissAll } = useA11yFeedback()
77
+ ```
78
+
79
+ ### `useA11yAnnounce()`
80
+
81
+ Lightweight hook for screen reader announcements only.
82
+
83
+ ```tsx
84
+ const { announcePolite, announceAssertive } = useA11yAnnounce()
85
+
86
+ // Polite announcements wait for current speech to finish
87
+ announcePolite('Results updated')
88
+
89
+ // Assertive announcements interrupt immediately
90
+ announceAssertive('Error: Please fix the form')
91
+ ```
92
+
93
+ ### `useFeedbackConfig()`
94
+
95
+ Hook for managing configuration reactively.
96
+
97
+ ```tsx
98
+ const { config, updateConfig, enableVisual, disableVisual } = useFeedbackConfig()
99
+ ```
100
+
101
+ ### `useA11yFeedbackContext()`
102
+
103
+ Access the provider context. Must be used inside `A11yFeedbackProvider`.
104
+
105
+ ```tsx
106
+ const ctx = useA11yFeedbackContext()
107
+ ```
108
+
109
+ ## API
110
+
111
+ ### `A11yFeedbackProvider`
112
+
113
+ | Prop | Type | Description |
114
+ |------|------|-------------|
115
+ | `config` | `Partial<FeedbackConfig>` | Configuration options |
116
+ | `debug` | `boolean` | Enable debug mode |
117
+ | `children` | `ReactNode` | Child components |
118
+
119
+ ### `useA11yFeedback()` Return
120
+
121
+ | Method | Description |
122
+ |--------|-------------|
123
+ | `success(message, options?)` | Send success notification |
124
+ | `error(message, options?)` | Send error notification |
125
+ | `warning(message, options?)` | Send warning notification |
126
+ | `info(message, options?)` | Send info notification |
127
+ | `loading(message, options?)` | Send loading notification |
128
+ | `dismiss(id)` | Dismiss specific notification |
129
+ | `dismissAll()` | Dismiss all notifications |
130
+
131
+ ## TypeScript
132
+
133
+ Full TypeScript support with exported types:
134
+
135
+ ```tsx
136
+ import type {
137
+ FeedbackType,
138
+ FeedbackOptions,
139
+ FeedbackEvent,
140
+ FeedbackConfig
141
+ } from '@theaccessibleteam/a11y-feedback-react'
142
+ ```
143
+
144
+ ## License
145
+
146
+ MIT
147
+
package/dist/index.cjs ADDED
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ A11yFeedbackProvider: () => A11yFeedbackProvider,
24
+ useA11yAnnounce: () => useA11yAnnounce,
25
+ useA11yFeedback: () => useA11yFeedback,
26
+ useA11yFeedbackContext: () => useA11yFeedbackContext,
27
+ useFeedbackConfig: () => useFeedbackConfig
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/provider.tsx
32
+ var import_react = require("react");
33
+ var import_a11y_feedback = require("@theaccessibleteam/a11y-feedback");
34
+ var import_jsx_runtime = require("react/jsx-runtime");
35
+ var A11yFeedbackContext = (0, import_react.createContext)(null);
36
+ function A11yFeedbackProvider({
37
+ children,
38
+ config,
39
+ debug = false
40
+ }) {
41
+ (0, import_react.useEffect)(() => {
42
+ if (config) {
43
+ (0, import_a11y_feedback.configureFeedback)(config);
44
+ }
45
+ if (debug) {
46
+ (0, import_a11y_feedback.enableFeedbackDebug)();
47
+ }
48
+ return () => {
49
+ (0, import_a11y_feedback.resetConfig)();
50
+ (0, import_a11y_feedback.disableFeedbackDebug)();
51
+ (0, import_a11y_feedback.dismissAllVisualFeedback)();
52
+ };
53
+ }, []);
54
+ (0, import_react.useEffect)(() => {
55
+ if (config) {
56
+ (0, import_a11y_feedback.configureFeedback)(config);
57
+ }
58
+ }, [config]);
59
+ (0, import_react.useEffect)(() => {
60
+ if (debug) {
61
+ (0, import_a11y_feedback.enableFeedbackDebug)();
62
+ } else {
63
+ (0, import_a11y_feedback.disableFeedbackDebug)();
64
+ }
65
+ }, [debug]);
66
+ const contextValue = (0, import_react.useMemo)(
67
+ () => ({
68
+ success: (message, options) => import_a11y_feedback.notify.success(message, options),
69
+ error: (message, options) => import_a11y_feedback.notify.error(message, options),
70
+ warning: (message, options) => import_a11y_feedback.notify.warning(message, options),
71
+ info: (message, options) => import_a11y_feedback.notify.info(message, options),
72
+ loading: (message, options) => import_a11y_feedback.notify.loading(message, options),
73
+ notify: import_a11y_feedback.notify,
74
+ dismissAll: import_a11y_feedback.dismissAllVisualFeedback,
75
+ getLog: () => [...(0, import_a11y_feedback.getFeedbackLog)()],
76
+ clearLog: import_a11y_feedback.clearFeedbackLog
77
+ }),
78
+ []
79
+ );
80
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(A11yFeedbackContext.Provider, { value: contextValue, children });
81
+ }
82
+ function useA11yFeedbackContext() {
83
+ const context = (0, import_react.useContext)(A11yFeedbackContext);
84
+ if (context === null) {
85
+ throw new Error(
86
+ "useA11yFeedbackContext must be used within an A11yFeedbackProvider"
87
+ );
88
+ }
89
+ return context;
90
+ }
91
+
92
+ // src/useA11yFeedback.ts
93
+ var import_react2 = require("react");
94
+ var import_a11y_feedback2 = require("@theaccessibleteam/a11y-feedback");
95
+ function useA11yFeedback() {
96
+ const success = (0, import_react2.useCallback)(
97
+ (message, options) => import_a11y_feedback2.notify.success(message, options),
98
+ []
99
+ );
100
+ const error = (0, import_react2.useCallback)(
101
+ (message, options) => import_a11y_feedback2.notify.error(message, options),
102
+ []
103
+ );
104
+ const warning = (0, import_react2.useCallback)(
105
+ (message, options) => import_a11y_feedback2.notify.warning(message, options),
106
+ []
107
+ );
108
+ const info = (0, import_react2.useCallback)(
109
+ (message, options) => import_a11y_feedback2.notify.info(message, options),
110
+ []
111
+ );
112
+ const loading = (0, import_react2.useCallback)(
113
+ (message, options) => import_a11y_feedback2.notify.loading(message, options),
114
+ []
115
+ );
116
+ const dismiss = (0, import_react2.useCallback)((id) => {
117
+ (0, import_a11y_feedback2.dismissVisualFeedback)(id);
118
+ }, []);
119
+ const dismissAll = (0, import_react2.useCallback)(() => {
120
+ (0, import_a11y_feedback2.dismissAllVisualFeedback)();
121
+ }, []);
122
+ return (0, import_react2.useMemo)(
123
+ () => ({
124
+ success,
125
+ error,
126
+ warning,
127
+ info,
128
+ loading,
129
+ dismiss,
130
+ dismissAll
131
+ }),
132
+ [success, error, warning, info, loading, dismiss, dismissAll]
133
+ );
134
+ }
135
+
136
+ // src/useA11yAnnounce.ts
137
+ var import_react3 = require("react");
138
+ var import_a11y_feedback3 = require("@theaccessibleteam/a11y-feedback");
139
+ function useA11yAnnounce() {
140
+ const announcePolite = (0, import_react3.useCallback)(
141
+ async (message, options) => {
142
+ await import_a11y_feedback3.notify.info(message, options);
143
+ },
144
+ []
145
+ );
146
+ const announceAssertive = (0, import_react3.useCallback)(
147
+ async (message, options) => {
148
+ await import_a11y_feedback3.notify.warning(message, options);
149
+ },
150
+ []
151
+ );
152
+ const announce = (0, import_react3.useCallback)(
153
+ async (message, politeness, options) => {
154
+ if (politeness === "assertive") {
155
+ await import_a11y_feedback3.notify.warning(message, options);
156
+ } else {
157
+ await import_a11y_feedback3.notify.info(message, options);
158
+ }
159
+ },
160
+ []
161
+ );
162
+ return (0, import_react3.useMemo)(
163
+ () => ({
164
+ announcePolite,
165
+ announceAssertive,
166
+ announce
167
+ }),
168
+ [announcePolite, announceAssertive, announce]
169
+ );
170
+ }
171
+
172
+ // src/useFeedbackConfig.ts
173
+ var import_react4 = require("react");
174
+ var import_a11y_feedback4 = require("@theaccessibleteam/a11y-feedback");
175
+ function useFeedbackConfig() {
176
+ const [config, setConfig] = (0, import_react4.useState)(() => (0, import_a11y_feedback4.getConfig)());
177
+ const syncConfig = (0, import_react4.useCallback)(() => {
178
+ setConfig((0, import_a11y_feedback4.getConfig)());
179
+ }, []);
180
+ const updateConfig = (0, import_react4.useCallback)(
181
+ (updates) => {
182
+ (0, import_a11y_feedback4.configureFeedback)(updates);
183
+ syncConfig();
184
+ },
185
+ [syncConfig]
186
+ );
187
+ const reset = (0, import_react4.useCallback)(() => {
188
+ (0, import_a11y_feedback4.resetConfig)();
189
+ syncConfig();
190
+ }, [syncConfig]);
191
+ const enableVisual = (0, import_react4.useCallback)(() => {
192
+ updateConfig({ visual: true });
193
+ }, [updateConfig]);
194
+ const disableVisual = (0, import_react4.useCallback)(() => {
195
+ updateConfig({ visual: false });
196
+ }, [updateConfig]);
197
+ (0, import_react4.useEffect)(() => {
198
+ syncConfig();
199
+ }, [syncConfig]);
200
+ return {
201
+ config,
202
+ updateConfig,
203
+ resetConfig: reset,
204
+ enableVisual,
205
+ disableVisual
206
+ };
207
+ }
208
+ // Annotate the CommonJS export names for ESM import in node:
209
+ 0 && (module.exports = {
210
+ A11yFeedbackProvider,
211
+ useA11yAnnounce,
212
+ useA11yFeedback,
213
+ useA11yFeedbackContext,
214
+ useFeedbackConfig
215
+ });
@@ -0,0 +1,241 @@
1
+ import { ReactNode } from 'react';
2
+ import { FeedbackConfig, FeedbackOptions, FeedbackEvent, notify, FeedbackLogEntry } from '@theaccessibleteam/a11y-feedback';
3
+ export { FeedbackConfig, FeedbackEvent, FeedbackOptions, FeedbackType } from '@theaccessibleteam/a11y-feedback';
4
+
5
+ /**
6
+ * React Context Provider for a11y-feedback
7
+ */
8
+
9
+ /**
10
+ * Context value interface
11
+ */
12
+ interface A11yFeedbackContextValue {
13
+ /** Send a success notification */
14
+ success: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
15
+ /** Send an error notification */
16
+ error: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
17
+ /** Send a warning notification */
18
+ warning: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
19
+ /** Send an info notification */
20
+ info: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
21
+ /** Send a loading notification */
22
+ loading: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
23
+ /** Generic notify function */
24
+ notify: typeof notify;
25
+ /** Dismiss all visual feedback */
26
+ dismissAll: () => void;
27
+ /** Get the feedback log (when debug is enabled) */
28
+ getLog: () => FeedbackLogEntry[];
29
+ /** Clear the feedback log */
30
+ clearLog: () => void;
31
+ }
32
+ /**
33
+ * Provider props
34
+ */
35
+ interface A11yFeedbackProviderProps {
36
+ /** React children */
37
+ children: ReactNode;
38
+ /** Configuration options */
39
+ config?: Partial<FeedbackConfig>;
40
+ /** Enable debug mode */
41
+ debug?: boolean;
42
+ }
43
+ /**
44
+ * Provider component for a11y-feedback
45
+ *
46
+ * @example
47
+ * ```tsx
48
+ * import { A11yFeedbackProvider } from '@theaccessibleteam/a11y-feedback-react'
49
+ *
50
+ * function App() {
51
+ * return (
52
+ * <A11yFeedbackProvider config={{ visual: true }}>
53
+ * <MyApp />
54
+ * </A11yFeedbackProvider>
55
+ * )
56
+ * }
57
+ * ```
58
+ */
59
+ declare function A11yFeedbackProvider({ children, config, debug, }: A11yFeedbackProviderProps): JSX.Element;
60
+ /**
61
+ * Hook to access the a11y-feedback context
62
+ *
63
+ * @throws Error if used outside of A11yFeedbackProvider
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * function MyComponent() {
68
+ * const { success, error } = useA11yFeedbackContext()
69
+ *
70
+ * const handleSave = async () => {
71
+ * try {
72
+ * await saveData()
73
+ * success('Data saved successfully')
74
+ * } catch (e) {
75
+ * error('Failed to save data')
76
+ * }
77
+ * }
78
+ *
79
+ * return <button onClick={handleSave}>Save</button>
80
+ * }
81
+ * ```
82
+ */
83
+ declare function useA11yFeedbackContext(): A11yFeedbackContextValue;
84
+
85
+ /**
86
+ * Return type for useA11yFeedback hook
87
+ */
88
+ interface UseA11yFeedbackReturn {
89
+ /** Send a success notification */
90
+ success: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
91
+ /** Send an error notification */
92
+ error: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
93
+ /** Send a warning notification */
94
+ warning: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
95
+ /** Send an info notification */
96
+ info: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
97
+ /** Send a loading notification */
98
+ loading: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
99
+ /** Dismiss a specific visual feedback item */
100
+ dismiss: (id: string) => void;
101
+ /** Dismiss all visual feedback items */
102
+ dismissAll: () => void;
103
+ }
104
+ /**
105
+ * Main hook for sending accessible feedback notifications
106
+ *
107
+ * Can be used without a provider for simple use cases.
108
+ * For app-wide configuration, use with A11yFeedbackProvider.
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * function SaveButton() {
113
+ * const feedback = useA11yFeedback()
114
+ *
115
+ * const handleSave = async () => {
116
+ * feedback.loading('Saving...', { id: 'save' })
117
+ *
118
+ * try {
119
+ * await saveData()
120
+ * feedback.success('Saved successfully!', { id: 'save' })
121
+ * } catch (e) {
122
+ * feedback.error('Failed to save', { id: 'save', focus: '#save-btn' })
123
+ * }
124
+ * }
125
+ *
126
+ * return <button id="save-btn" onClick={handleSave}>Save</button>
127
+ * }
128
+ * ```
129
+ */
130
+ declare function useA11yFeedback(): UseA11yFeedbackReturn;
131
+
132
+ /**
133
+ * Return type for useA11yAnnounce hook
134
+ */
135
+ interface UseA11yAnnounceReturn {
136
+ /**
137
+ * Announce a message politely (for non-urgent updates)
138
+ * Screen reader will wait for current speech to finish
139
+ */
140
+ announcePolite: (message: string, options?: FeedbackOptions) => Promise<void>;
141
+ /**
142
+ * Announce a message assertively (for urgent updates)
143
+ * Screen reader will interrupt current speech
144
+ */
145
+ announceAssertive: (message: string, options?: FeedbackOptions) => Promise<void>;
146
+ /**
147
+ * Announce with custom options
148
+ */
149
+ announce: (message: string, politeness: 'polite' | 'assertive', options?: FeedbackOptions) => Promise<void>;
150
+ }
151
+ /**
152
+ * Simple hook for making screen reader announcements
153
+ *
154
+ * This is a lightweight alternative to useA11yFeedback when you only
155
+ * need to announce messages without visual feedback or complex options.
156
+ *
157
+ * @example
158
+ * ```tsx
159
+ * function SearchResults({ count }: { count: number }) {
160
+ * const { announcePolite } = useA11yAnnounce()
161
+ *
162
+ * useEffect(() => {
163
+ * announcePolite(`Found ${count} results`)
164
+ * }, [count, announcePolite])
165
+ *
166
+ * return <div>{count} results found</div>
167
+ * }
168
+ * ```
169
+ *
170
+ * @example
171
+ * ```tsx
172
+ * function Timer({ secondsLeft }: { secondsLeft: number }) {
173
+ * const { announceAssertive } = useA11yAnnounce()
174
+ *
175
+ * useEffect(() => {
176
+ * if (secondsLeft <= 10) {
177
+ * announceAssertive(`${secondsLeft} seconds remaining`)
178
+ * }
179
+ * }, [secondsLeft, announceAssertive])
180
+ *
181
+ * return <div>{secondsLeft}s</div>
182
+ * }
183
+ * ```
184
+ */
185
+ declare function useA11yAnnounce(): UseA11yAnnounceReturn;
186
+
187
+ /**
188
+ * Return type for useFeedbackConfig hook
189
+ */
190
+ interface UseFeedbackConfigReturn {
191
+ /** Current configuration */
192
+ config: FeedbackConfig;
193
+ /** Update configuration (merges with existing) */
194
+ updateConfig: (updates: Partial<FeedbackConfig>) => void;
195
+ /** Reset configuration to defaults */
196
+ resetConfig: () => void;
197
+ /** Enable visual feedback */
198
+ enableVisual: () => void;
199
+ /** Disable visual feedback */
200
+ disableVisual: () => void;
201
+ }
202
+ /**
203
+ * Hook for managing a11y-feedback configuration
204
+ *
205
+ * Provides reactive access to the configuration and methods to update it.
206
+ *
207
+ * @example
208
+ * ```tsx
209
+ * function SettingsPanel() {
210
+ * const { config, updateConfig, enableVisual, disableVisual } = useFeedbackConfig()
211
+ *
212
+ * return (
213
+ * <div>
214
+ * <label>
215
+ * <input
216
+ * type="checkbox"
217
+ * checked={config.visual}
218
+ * onChange={(e) =>
219
+ * e.target.checked ? enableVisual() : disableVisual()
220
+ * }
221
+ * />
222
+ * Show visual notifications
223
+ * </label>
224
+ *
225
+ * <select
226
+ * value={config.visualPosition}
227
+ * onChange={(e) =>
228
+ * updateConfig({ visualPosition: e.target.value as any })
229
+ * }
230
+ * >
231
+ * <option value="top-right">Top Right</option>
232
+ * <option value="bottom-right">Bottom Right</option>
233
+ * </select>
234
+ * </div>
235
+ * )
236
+ * }
237
+ * ```
238
+ */
239
+ declare function useFeedbackConfig(): UseFeedbackConfigReturn;
240
+
241
+ export { A11yFeedbackProvider, useA11yAnnounce, useA11yFeedback, useA11yFeedbackContext, useFeedbackConfig };
@@ -0,0 +1,241 @@
1
+ import { ReactNode } from 'react';
2
+ import { FeedbackConfig, FeedbackOptions, FeedbackEvent, notify, FeedbackLogEntry } from '@theaccessibleteam/a11y-feedback';
3
+ export { FeedbackConfig, FeedbackEvent, FeedbackOptions, FeedbackType } from '@theaccessibleteam/a11y-feedback';
4
+
5
+ /**
6
+ * React Context Provider for a11y-feedback
7
+ */
8
+
9
+ /**
10
+ * Context value interface
11
+ */
12
+ interface A11yFeedbackContextValue {
13
+ /** Send a success notification */
14
+ success: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
15
+ /** Send an error notification */
16
+ error: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
17
+ /** Send a warning notification */
18
+ warning: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
19
+ /** Send an info notification */
20
+ info: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
21
+ /** Send a loading notification */
22
+ loading: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
23
+ /** Generic notify function */
24
+ notify: typeof notify;
25
+ /** Dismiss all visual feedback */
26
+ dismissAll: () => void;
27
+ /** Get the feedback log (when debug is enabled) */
28
+ getLog: () => FeedbackLogEntry[];
29
+ /** Clear the feedback log */
30
+ clearLog: () => void;
31
+ }
32
+ /**
33
+ * Provider props
34
+ */
35
+ interface A11yFeedbackProviderProps {
36
+ /** React children */
37
+ children: ReactNode;
38
+ /** Configuration options */
39
+ config?: Partial<FeedbackConfig>;
40
+ /** Enable debug mode */
41
+ debug?: boolean;
42
+ }
43
+ /**
44
+ * Provider component for a11y-feedback
45
+ *
46
+ * @example
47
+ * ```tsx
48
+ * import { A11yFeedbackProvider } from '@theaccessibleteam/a11y-feedback-react'
49
+ *
50
+ * function App() {
51
+ * return (
52
+ * <A11yFeedbackProvider config={{ visual: true }}>
53
+ * <MyApp />
54
+ * </A11yFeedbackProvider>
55
+ * )
56
+ * }
57
+ * ```
58
+ */
59
+ declare function A11yFeedbackProvider({ children, config, debug, }: A11yFeedbackProviderProps): JSX.Element;
60
+ /**
61
+ * Hook to access the a11y-feedback context
62
+ *
63
+ * @throws Error if used outside of A11yFeedbackProvider
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * function MyComponent() {
68
+ * const { success, error } = useA11yFeedbackContext()
69
+ *
70
+ * const handleSave = async () => {
71
+ * try {
72
+ * await saveData()
73
+ * success('Data saved successfully')
74
+ * } catch (e) {
75
+ * error('Failed to save data')
76
+ * }
77
+ * }
78
+ *
79
+ * return <button onClick={handleSave}>Save</button>
80
+ * }
81
+ * ```
82
+ */
83
+ declare function useA11yFeedbackContext(): A11yFeedbackContextValue;
84
+
85
+ /**
86
+ * Return type for useA11yFeedback hook
87
+ */
88
+ interface UseA11yFeedbackReturn {
89
+ /** Send a success notification */
90
+ success: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
91
+ /** Send an error notification */
92
+ error: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
93
+ /** Send a warning notification */
94
+ warning: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
95
+ /** Send an info notification */
96
+ info: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
97
+ /** Send a loading notification */
98
+ loading: (message: string, options?: FeedbackOptions) => Promise<FeedbackEvent>;
99
+ /** Dismiss a specific visual feedback item */
100
+ dismiss: (id: string) => void;
101
+ /** Dismiss all visual feedback items */
102
+ dismissAll: () => void;
103
+ }
104
+ /**
105
+ * Main hook for sending accessible feedback notifications
106
+ *
107
+ * Can be used without a provider for simple use cases.
108
+ * For app-wide configuration, use with A11yFeedbackProvider.
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * function SaveButton() {
113
+ * const feedback = useA11yFeedback()
114
+ *
115
+ * const handleSave = async () => {
116
+ * feedback.loading('Saving...', { id: 'save' })
117
+ *
118
+ * try {
119
+ * await saveData()
120
+ * feedback.success('Saved successfully!', { id: 'save' })
121
+ * } catch (e) {
122
+ * feedback.error('Failed to save', { id: 'save', focus: '#save-btn' })
123
+ * }
124
+ * }
125
+ *
126
+ * return <button id="save-btn" onClick={handleSave}>Save</button>
127
+ * }
128
+ * ```
129
+ */
130
+ declare function useA11yFeedback(): UseA11yFeedbackReturn;
131
+
132
+ /**
133
+ * Return type for useA11yAnnounce hook
134
+ */
135
+ interface UseA11yAnnounceReturn {
136
+ /**
137
+ * Announce a message politely (for non-urgent updates)
138
+ * Screen reader will wait for current speech to finish
139
+ */
140
+ announcePolite: (message: string, options?: FeedbackOptions) => Promise<void>;
141
+ /**
142
+ * Announce a message assertively (for urgent updates)
143
+ * Screen reader will interrupt current speech
144
+ */
145
+ announceAssertive: (message: string, options?: FeedbackOptions) => Promise<void>;
146
+ /**
147
+ * Announce with custom options
148
+ */
149
+ announce: (message: string, politeness: 'polite' | 'assertive', options?: FeedbackOptions) => Promise<void>;
150
+ }
151
+ /**
152
+ * Simple hook for making screen reader announcements
153
+ *
154
+ * This is a lightweight alternative to useA11yFeedback when you only
155
+ * need to announce messages without visual feedback or complex options.
156
+ *
157
+ * @example
158
+ * ```tsx
159
+ * function SearchResults({ count }: { count: number }) {
160
+ * const { announcePolite } = useA11yAnnounce()
161
+ *
162
+ * useEffect(() => {
163
+ * announcePolite(`Found ${count} results`)
164
+ * }, [count, announcePolite])
165
+ *
166
+ * return <div>{count} results found</div>
167
+ * }
168
+ * ```
169
+ *
170
+ * @example
171
+ * ```tsx
172
+ * function Timer({ secondsLeft }: { secondsLeft: number }) {
173
+ * const { announceAssertive } = useA11yAnnounce()
174
+ *
175
+ * useEffect(() => {
176
+ * if (secondsLeft <= 10) {
177
+ * announceAssertive(`${secondsLeft} seconds remaining`)
178
+ * }
179
+ * }, [secondsLeft, announceAssertive])
180
+ *
181
+ * return <div>{secondsLeft}s</div>
182
+ * }
183
+ * ```
184
+ */
185
+ declare function useA11yAnnounce(): UseA11yAnnounceReturn;
186
+
187
+ /**
188
+ * Return type for useFeedbackConfig hook
189
+ */
190
+ interface UseFeedbackConfigReturn {
191
+ /** Current configuration */
192
+ config: FeedbackConfig;
193
+ /** Update configuration (merges with existing) */
194
+ updateConfig: (updates: Partial<FeedbackConfig>) => void;
195
+ /** Reset configuration to defaults */
196
+ resetConfig: () => void;
197
+ /** Enable visual feedback */
198
+ enableVisual: () => void;
199
+ /** Disable visual feedback */
200
+ disableVisual: () => void;
201
+ }
202
+ /**
203
+ * Hook for managing a11y-feedback configuration
204
+ *
205
+ * Provides reactive access to the configuration and methods to update it.
206
+ *
207
+ * @example
208
+ * ```tsx
209
+ * function SettingsPanel() {
210
+ * const { config, updateConfig, enableVisual, disableVisual } = useFeedbackConfig()
211
+ *
212
+ * return (
213
+ * <div>
214
+ * <label>
215
+ * <input
216
+ * type="checkbox"
217
+ * checked={config.visual}
218
+ * onChange={(e) =>
219
+ * e.target.checked ? enableVisual() : disableVisual()
220
+ * }
221
+ * />
222
+ * Show visual notifications
223
+ * </label>
224
+ *
225
+ * <select
226
+ * value={config.visualPosition}
227
+ * onChange={(e) =>
228
+ * updateConfig({ visualPosition: e.target.value as any })
229
+ * }
230
+ * >
231
+ * <option value="top-right">Top Right</option>
232
+ * <option value="bottom-right">Bottom Right</option>
233
+ * </select>
234
+ * </div>
235
+ * )
236
+ * }
237
+ * ```
238
+ */
239
+ declare function useFeedbackConfig(): UseFeedbackConfigReturn;
240
+
241
+ export { A11yFeedbackProvider, useA11yAnnounce, useA11yFeedback, useA11yFeedbackContext, useFeedbackConfig };
package/dist/index.js ADDED
@@ -0,0 +1,206 @@
1
+ // src/provider.tsx
2
+ import {
3
+ createContext,
4
+ useContext,
5
+ useEffect,
6
+ useMemo
7
+ } from "react";
8
+ import {
9
+ notify,
10
+ configureFeedback,
11
+ resetConfig,
12
+ enableFeedbackDebug,
13
+ disableFeedbackDebug,
14
+ getFeedbackLog,
15
+ clearFeedbackLog,
16
+ dismissAllVisualFeedback
17
+ } from "@theaccessibleteam/a11y-feedback";
18
+ import { jsx } from "react/jsx-runtime";
19
+ var A11yFeedbackContext = createContext(null);
20
+ function A11yFeedbackProvider({
21
+ children,
22
+ config,
23
+ debug = false
24
+ }) {
25
+ useEffect(() => {
26
+ if (config) {
27
+ configureFeedback(config);
28
+ }
29
+ if (debug) {
30
+ enableFeedbackDebug();
31
+ }
32
+ return () => {
33
+ resetConfig();
34
+ disableFeedbackDebug();
35
+ dismissAllVisualFeedback();
36
+ };
37
+ }, []);
38
+ useEffect(() => {
39
+ if (config) {
40
+ configureFeedback(config);
41
+ }
42
+ }, [config]);
43
+ useEffect(() => {
44
+ if (debug) {
45
+ enableFeedbackDebug();
46
+ } else {
47
+ disableFeedbackDebug();
48
+ }
49
+ }, [debug]);
50
+ const contextValue = useMemo(
51
+ () => ({
52
+ success: (message, options) => notify.success(message, options),
53
+ error: (message, options) => notify.error(message, options),
54
+ warning: (message, options) => notify.warning(message, options),
55
+ info: (message, options) => notify.info(message, options),
56
+ loading: (message, options) => notify.loading(message, options),
57
+ notify,
58
+ dismissAll: dismissAllVisualFeedback,
59
+ getLog: () => [...getFeedbackLog()],
60
+ clearLog: clearFeedbackLog
61
+ }),
62
+ []
63
+ );
64
+ return /* @__PURE__ */ jsx(A11yFeedbackContext.Provider, { value: contextValue, children });
65
+ }
66
+ function useA11yFeedbackContext() {
67
+ const context = useContext(A11yFeedbackContext);
68
+ if (context === null) {
69
+ throw new Error(
70
+ "useA11yFeedbackContext must be used within an A11yFeedbackProvider"
71
+ );
72
+ }
73
+ return context;
74
+ }
75
+
76
+ // src/useA11yFeedback.ts
77
+ import { useCallback, useMemo as useMemo2 } from "react";
78
+ import {
79
+ notify as notify2,
80
+ dismissVisualFeedback,
81
+ dismissAllVisualFeedback as dismissAllVisualFeedback2
82
+ } from "@theaccessibleteam/a11y-feedback";
83
+ function useA11yFeedback() {
84
+ const success = useCallback(
85
+ (message, options) => notify2.success(message, options),
86
+ []
87
+ );
88
+ const error = useCallback(
89
+ (message, options) => notify2.error(message, options),
90
+ []
91
+ );
92
+ const warning = useCallback(
93
+ (message, options) => notify2.warning(message, options),
94
+ []
95
+ );
96
+ const info = useCallback(
97
+ (message, options) => notify2.info(message, options),
98
+ []
99
+ );
100
+ const loading = useCallback(
101
+ (message, options) => notify2.loading(message, options),
102
+ []
103
+ );
104
+ const dismiss = useCallback((id) => {
105
+ dismissVisualFeedback(id);
106
+ }, []);
107
+ const dismissAll = useCallback(() => {
108
+ dismissAllVisualFeedback2();
109
+ }, []);
110
+ return useMemo2(
111
+ () => ({
112
+ success,
113
+ error,
114
+ warning,
115
+ info,
116
+ loading,
117
+ dismiss,
118
+ dismissAll
119
+ }),
120
+ [success, error, warning, info, loading, dismiss, dismissAll]
121
+ );
122
+ }
123
+
124
+ // src/useA11yAnnounce.ts
125
+ import { useCallback as useCallback2, useMemo as useMemo3 } from "react";
126
+ import { notify as notify3 } from "@theaccessibleteam/a11y-feedback";
127
+ function useA11yAnnounce() {
128
+ const announcePolite = useCallback2(
129
+ async (message, options) => {
130
+ await notify3.info(message, options);
131
+ },
132
+ []
133
+ );
134
+ const announceAssertive = useCallback2(
135
+ async (message, options) => {
136
+ await notify3.warning(message, options);
137
+ },
138
+ []
139
+ );
140
+ const announce = useCallback2(
141
+ async (message, politeness, options) => {
142
+ if (politeness === "assertive") {
143
+ await notify3.warning(message, options);
144
+ } else {
145
+ await notify3.info(message, options);
146
+ }
147
+ },
148
+ []
149
+ );
150
+ return useMemo3(
151
+ () => ({
152
+ announcePolite,
153
+ announceAssertive,
154
+ announce
155
+ }),
156
+ [announcePolite, announceAssertive, announce]
157
+ );
158
+ }
159
+
160
+ // src/useFeedbackConfig.ts
161
+ import { useCallback as useCallback3, useEffect as useEffect2, useState } from "react";
162
+ import {
163
+ configureFeedback as configureFeedback2,
164
+ getConfig,
165
+ resetConfig as resetConfig2
166
+ } from "@theaccessibleteam/a11y-feedback";
167
+ function useFeedbackConfig() {
168
+ const [config, setConfig] = useState(() => getConfig());
169
+ const syncConfig = useCallback3(() => {
170
+ setConfig(getConfig());
171
+ }, []);
172
+ const updateConfig = useCallback3(
173
+ (updates) => {
174
+ configureFeedback2(updates);
175
+ syncConfig();
176
+ },
177
+ [syncConfig]
178
+ );
179
+ const reset = useCallback3(() => {
180
+ resetConfig2();
181
+ syncConfig();
182
+ }, [syncConfig]);
183
+ const enableVisual = useCallback3(() => {
184
+ updateConfig({ visual: true });
185
+ }, [updateConfig]);
186
+ const disableVisual = useCallback3(() => {
187
+ updateConfig({ visual: false });
188
+ }, [updateConfig]);
189
+ useEffect2(() => {
190
+ syncConfig();
191
+ }, [syncConfig]);
192
+ return {
193
+ config,
194
+ updateConfig,
195
+ resetConfig: reset,
196
+ enableVisual,
197
+ disableVisual
198
+ };
199
+ }
200
+ export {
201
+ A11yFeedbackProvider,
202
+ useA11yAnnounce,
203
+ useA11yFeedback,
204
+ useA11yFeedbackContext,
205
+ useFeedbackConfig
206
+ };
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@theaccessibleteam/a11y-feedback-react",
3
+ "version": "1.0.0",
4
+ "description": "React bindings for a11y-feedback - accessible notifications and screen reader announcements",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "sideEffects": false,
26
+ "scripts": {
27
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
28
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
29
+ "typecheck": "tsc --noEmit",
30
+ "lint": "eslint src --ext .ts,.tsx"
31
+ },
32
+ "keywords": [
33
+ "react",
34
+ "accessibility",
35
+ "a11y",
36
+ "aria-live",
37
+ "screen-reader",
38
+ "hooks",
39
+ "notifications",
40
+ "toast"
41
+ ],
42
+ "author": "The Accessible Team <theaccessibleteam@gmail.com>",
43
+ "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/WOLFIEEEE/a11y-feedback.git",
47
+ "directory": "packages/react"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/WOLFIEEEE/a11y-feedback/issues"
51
+ },
52
+ "homepage": "https://github.com/WOLFIEEEE/a11y-feedback/tree/main/packages/react#readme",
53
+ "peerDependencies": {
54
+ "@theaccessibleteam/a11y-feedback": "workspace:^",
55
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/react": "^18.2.0",
59
+ "react": "^18.2.0",
60
+ "tsup": "^8.0.0",
61
+ "typescript": "^5.4.0"
62
+ }
63
+ }
64
+