aac-board-viewer 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Will Wade
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,301 @@
1
+ # AAC Board Viewer
2
+
3
+ Universal AAC (Augmentative and Alternative Communication) board viewer component for React. Display and interact with communication boards from multiple AAC systems.
4
+
5
+ ## Supported Formats
6
+
7
+ - **Grid 3** (`.gridset` files)
8
+ - **TouchChat** (`.ce` files)
9
+ - **TD Snap** (`.sps`, `.spb` files)
10
+ - **OpenBoard** (`.obf`, `.obz` files)
11
+ - **Asterics Grid** (`.grd` files)
12
+ - **Apple Panels** (`.plist` files)
13
+ - **OPML** (`.opml` files)
14
+ - **Excel** (`.xlsx` boards)
15
+ - **DOT files** (`.dot` visualizations)
16
+
17
+ ## Features
18
+
19
+ - 🎯 **Universal Support** - Works with all major AAC file formats
20
+ - 📱 **Responsive Design** - Mobile-friendly with touch support
21
+ - 🎨 **Preserves Styling** - Maintains original colors, fonts, and layouts
22
+ - 🔗 **Interactive Navigation** - Click buttons to navigate between pages
23
+ - 🗣️ **Sentence Building** - Tap buttons to build sentences
24
+ - 🔧 **Customizable** - Flexible styling and behavior options (toggle message bar, link indicators, effort badges)
25
+ - 🌙 **Dark-mode Friendly** - Inherits host app theme when a parent adds the `dark` class
26
+
27
+ ## Installation
28
+
29
+ Requires Node 20+.
30
+
31
+ ```bash
32
+ npm install aac-board-viewer
33
+ ```
34
+
35
+ Or with yarn:
36
+
37
+ ```bash
38
+ yarn add aac-board-viewer
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ### Client-Side Usage
44
+
45
+ ```tsx
46
+ import { BoardViewer, useAACFile } from 'aac-board-viewer';
47
+ import 'aac-board-viewer/styles';
48
+
49
+ function MyViewer() {
50
+ const { tree, loading, error } = useAACFile('/path/to/file.sps');
51
+
52
+ if (loading) return <div>Loading...</div>;
53
+ if (error) return <div>Error: {error.message}</div>;
54
+
55
+ return <BoardViewer tree={tree} />;
56
+ }
57
+ ```
58
+
59
+ ### Server-Side / API Usage
60
+
61
+ ```tsx
62
+ import { BoardViewer } from 'aac-board-viewer';
63
+ import 'aac-board-viewer/styles';
64
+
65
+ function MyViewer({ treeData }) {
66
+ return (
67
+ <BoardViewer
68
+ tree={treeData}
69
+ buttonMetrics={metricsData}
70
+ showMessageBar={true}
71
+ showEffortBadges={true}
72
+ />
73
+ );
74
+ }
75
+ ```
76
+
77
+ ### With Metrics
78
+
79
+ ```tsx
80
+ import { BoardViewer, loadAACFile, calculateMetrics } from 'aac-board-viewer';
81
+
82
+ function MetricsViewer({ filePath }) {
83
+ const [tree, setTree] = useState(null);
84
+ const [metrics, setMetrics] = useState(null);
85
+
86
+ useEffect(() => {
87
+ async function load() {
88
+ const loadedTree = await loadAACFile(filePath);
89
+ const calculatedMetrics = await calculateMetrics(loadedTree);
90
+
91
+ setTree(loadedTree);
92
+ setMetrics(calculatedMetrics);
93
+ }
94
+ load();
95
+ }, [filePath]);
96
+
97
+ if (!tree) return <div>Loading...</div>;
98
+
99
+ return (
100
+ <BoardViewer
101
+ tree={tree}
102
+ buttonMetrics={metrics}
103
+ showEffortBadges={true}
104
+ />
105
+ );
106
+ }
107
+ ```
108
+
109
+ ## Props
110
+
111
+ ### BoardViewer
112
+
113
+ ```typescript
114
+ interface BoardViewerProps {
115
+ tree: AACTree;
116
+ buttonMetrics?: ButtonMetric[] | null;
117
+ showMessageBar?: boolean;
118
+ showEffortBadges?: boolean;
119
+ showLinkIndicators?: boolean;
120
+ onButtonClick?: (button: AACButton) => void;
121
+ onPageChange?: (pageId: string) => void;
122
+ className?: string;
123
+ }
124
+ ```
125
+
126
+ ### AACTree
127
+
128
+ ```typescript
129
+ interface AACTree {
130
+ pages: { [key: string]: AACPage };
131
+ rootId?: string;
132
+ toolbarId?: string;
133
+ metadata?: {
134
+ format?: string;
135
+ name?: string;
136
+ description?: string;
137
+ [key: string]: any;
138
+ };
139
+ }
140
+ ```
141
+
142
+ ## Advanced Usage
143
+
144
+ ### Custom Styling
145
+
146
+ ```tsx
147
+ <BoardViewer
148
+ tree={tree}
149
+ className="my-custom-board"
150
+ />
151
+ ```
152
+
153
+ ### Event Handling
154
+
155
+ ```tsx
156
+ <BoardViewer
157
+ tree={tree}
158
+ onButtonClick={(button) => {
159
+ console.log('Button clicked:', button.label);
160
+ // Track analytics, play sound, etc.
161
+ }}
162
+ onPageChange={(pageId) => {
163
+ console.log('Page changed to:', pageId);
164
+ // Track navigation
165
+ }}
166
+ />
167
+ ```
168
+
169
+ ### Hide Message Bar
170
+
171
+ ```tsx
172
+ <BoardViewer
173
+ tree={tree}
174
+ showMessageBar={false}
175
+ />
176
+ ```
177
+
178
+ ## File Loading
179
+
180
+ The library provides utilities for loading AAC files:
181
+
182
+ ### Client-Side Loading
183
+
184
+ ```tsx
185
+ import { useAACFile } from 'aac-board-viewer';
186
+
187
+ function Viewer({ fileUrl }) {
188
+ const { tree, loading, error } = useAACFile(fileUrl);
189
+
190
+ // ...
191
+ }
192
+ ```
193
+
194
+ ### Programmatic Loading
195
+
196
+ ```tsx
197
+ import { loadAACFile } from 'aac-board-viewer';
198
+
199
+ const tree = await loadAACFile('/path/to/file.gridset');
200
+ ```
201
+
202
+ ### From File Input
203
+
204
+ ```tsx
205
+ import { loadAACFileFromFile } from 'aac-board-viewer';
206
+
207
+ function FileInput() {
208
+ const handleChange = async (e) => {
209
+ const file = e.target.files[0];
210
+ const tree = await loadAACFileFromFile(file);
211
+ // Use tree...
212
+ };
213
+
214
+ return <input type="file" onChange={handleChange} />;
215
+ }
216
+ ```
217
+
218
+ ## Metrics Calculation
219
+
220
+ Calculate cognitive effort metrics for buttons:
221
+
222
+ ```tsx
223
+ import { calculateMetrics } from 'aac-board-viewer';
224
+
225
+ const metrics = await calculateMetrics(tree, {
226
+ accessMethod: 'direct', // or 'scanning'
227
+ scanningConfig: {
228
+ pattern: 'row-column', // 'linear', 'row-column', 'block'
229
+ selectionMethod: 'auto-1-switch',
230
+ errorCorrection: false,
231
+ },
232
+ });
233
+
234
+ // metrics is an array of ButtonMetric objects:
235
+ // [{ id, label, effort, count, is_word, level }, ...]
236
+ ```
237
+
238
+ ## Format-Specific Notes
239
+
240
+ ### Apple Panels
241
+
242
+ Apple Panels use free-form positioning. The viewer automatically:
243
+ - Converts absolute positioning to grid layout
244
+ - Calculates appropriate grid dimensions
245
+ - Preserves original button placement
246
+
247
+ ### Asterics Grid
248
+
249
+ Asterics files (`.grd`) are automatically detected and processed using the Asterics Grid processor.
250
+
251
+ ### GridSet / SNAP / TouchChat
252
+
253
+ These formats use native grid layouts and are displayed as-is, preserving:
254
+ - Grid dimensions (rows × columns)
255
+ - Button colors and borders
256
+ - Font sizes and styles
257
+ - Navigation links between pages
258
+
259
+ ## Development
260
+
261
+ ```bash
262
+ # Install dependencies
263
+ npm install
264
+
265
+ # Run demo app
266
+ npm run dev
267
+
268
+ # Build library
269
+ npm run build
270
+
271
+ # Type check
272
+ npm run type-check
273
+
274
+ # Lint
275
+ npm run lint
276
+ ```
277
+
278
+ ## Examples
279
+
280
+ See the `/demo` directory for complete examples:
281
+ - Basic viewer
282
+ - With metrics
283
+ - Multiple formats
284
+ - Server-side rendering
285
+
286
+ ## Contributing
287
+
288
+ Contributions are welcome! Please read our contributing guidelines before submitting PRs.
289
+
290
+ ## License
291
+
292
+ MIT License - see LICENSE file for details.
293
+
294
+ ## Related Packages
295
+
296
+ - [@willwade/aac-processors](https://github.com/willwade/AACProcessors-nodejs) - Core AAC file processing library
297
+
298
+ ## Support
299
+
300
+ - Issues: [GitHub Issues](https://github.com/willwade/aac-board-viewer/issues)
301
+ - Documentation: [Full Docs](https://github.com/willwade/aac-board-viewer/wiki)
@@ -0,0 +1,305 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as _willwade_aac_processors from '@willwade/aac-processors';
3
+ import { AACTree } from '@willwade/aac-processors';
4
+ export { AACButton, AACPage, AACSemanticAction, AACSemanticCategory, AACSemanticIntent, AACTree } from '@willwade/aac-processors';
5
+
6
+ /**
7
+ * Button metric information for effort scoring
8
+ */
9
+ interface ButtonMetric {
10
+ /** Button ID */
11
+ id: string;
12
+ /** Button label text */
13
+ label: string;
14
+ /** Cognitive effort score (lower is easier) */
15
+ effort: number;
16
+ /** Usage count */
17
+ count?: number;
18
+ /** Whether the button represents a word */
19
+ is_word?: boolean;
20
+ /** Depth level in navigation tree */
21
+ level?: number;
22
+ }
23
+ /**
24
+ * Props for BoardViewer component
25
+ */
26
+ interface BoardViewerProps {
27
+ /** The AAC tree containing pages and navigation structure */
28
+ tree: _willwade_aac_processors.AACTree;
29
+ /** Optional button metrics to display effort scores */
30
+ buttonMetrics?: ButtonMetric[] | null;
31
+ /** Show the message bar at the top (default: true) */
32
+ showMessageBar?: boolean;
33
+ /** Show effort badges on buttons (default: true if metrics provided) */
34
+ showEffortBadges?: boolean;
35
+ /** Show indicators for buttons that link to other pages (default: true) */
36
+ showLinkIndicators?: boolean;
37
+ /** Start the viewer on this page id (overrides tree.rootId) */
38
+ initialPageId?: string;
39
+ /** Callback when a button is clicked */
40
+ onButtonClick?: (button: _willwade_aac_processors.AACButton) => void;
41
+ /** Callback when page changes */
42
+ onPageChange?: (pageId: string) => void;
43
+ /** Custom CSS class name */
44
+ className?: string;
45
+ }
46
+ /**
47
+ * Result from loading an AAC file
48
+ */
49
+ interface LoadAACFileResult {
50
+ tree: _willwade_aac_processors.AACTree;
51
+ format: string;
52
+ metadata?: {
53
+ [key: string]: unknown;
54
+ };
55
+ }
56
+
57
+ interface MetricsOptions {
58
+ /** Access method: 'direct' or 'scanning' */
59
+ accessMethod?: 'direct' | 'scanning';
60
+ /** Scanning configuration */
61
+ scanningConfig?: {
62
+ /** Scanning pattern: 'linear', 'row-column', or 'block' */
63
+ pattern?: 'linear' | 'row-column' | 'block';
64
+ /** Selection method for scanning */
65
+ selectionMethod?: string;
66
+ /** Enable error correction */
67
+ errorCorrection?: boolean;
68
+ };
69
+ }
70
+
71
+ /**
72
+ * AAC Board Viewer Component
73
+ *
74
+ * Displays AAC boards with interactive navigation, sentence building,
75
+ * and optional effort metrics.
76
+ *
77
+ * @param props - BoardViewerProps
78
+ */
79
+ declare function BoardViewer({ tree, buttonMetrics, showMessageBar, showEffortBadges, showLinkIndicators, initialPageId, onButtonClick, onPageChange, className, }: BoardViewerProps): react_jsx_runtime.JSX.Element;
80
+
81
+ /**
82
+ * React hooks for AAC Board Viewer
83
+ */
84
+
85
+ /**
86
+ * Hook to load an AAC file from a URL
87
+ *
88
+ * @param url - URL to the AAC file
89
+ * @param options - Processor options (e.g., pageLayoutPreference for SNAP)
90
+ * @returns Object with tree, loading state, and error
91
+ *
92
+ * @example
93
+ * ```tsx
94
+ * function MyViewer() {
95
+ * const { tree, loading, error, reload } = useAACFile('/files/board.sps');
96
+ *
97
+ * if (loading) return <div>Loading...</div>;
98
+ * if (error) return <div>Error: {error.message}</div>;
99
+ *
100
+ * return <BoardViewer tree={tree} />;
101
+ * }
102
+ * ```
103
+ */
104
+ declare function useAACFile(url: string, options?: {
105
+ processorOptions?: Record<string, unknown>;
106
+ enabled?: boolean;
107
+ }): {
108
+ tree: AACTree | null;
109
+ loading: boolean;
110
+ error: Error | null;
111
+ reload: () => Promise<void>;
112
+ };
113
+ /**
114
+ * Hook to load an AAC file and calculate metrics
115
+ *
116
+ * @param url - URL to the AAC file
117
+ * @param metricsOptions - Metrics calculation options
118
+ * @returns Object with tree, metrics, loading state, and error
119
+ *
120
+ * @example
121
+ * ```tsx
122
+ * function MyViewer() {
123
+ * const { tree, metrics, loading, error } = useAACFileWithMetrics(
124
+ * '/files/board.sps',
125
+ * { accessMethod: 'direct' }
126
+ * );
127
+ *
128
+ * if (loading) return <div>Loading...</div>;
129
+ * if (error) return <div>Error: {error.message}</div>;
130
+ *
131
+ * return <BoardViewer tree={tree} buttonMetrics={metrics} />;
132
+ * }
133
+ * ```
134
+ */
135
+ declare function useAACFileWithMetrics(url: string, metricsOptions?: MetricsOptions, fileOptions?: {
136
+ processorOptions?: Record<string, unknown>;
137
+ enabled?: boolean;
138
+ }): {
139
+ tree: AACTree | null;
140
+ metrics: ButtonMetric[] | null;
141
+ loading: boolean;
142
+ error: Error | null;
143
+ reload: () => Promise<void>;
144
+ };
145
+ /**
146
+ * Hook to calculate metrics for a tree
147
+ *
148
+ * @param tree - The AAC tree
149
+ * @param options - Metrics calculation options
150
+ * @returns Object with metrics, loading state, and error
151
+ *
152
+ * @example
153
+ * ```tsx
154
+ * function MyViewer({ tree }) {
155
+ * const { metrics, loading } = useMetrics(tree, {
156
+ * accessMethod: 'scanning',
157
+ * scanningConfig: { pattern: 'row-column' }
158
+ * });
159
+ *
160
+ * return <BoardViewer tree={tree} buttonMetrics={metrics} />;
161
+ * }
162
+ * ```
163
+ */
164
+ declare function useMetrics(tree: AACTree | null, options?: MetricsOptions): {
165
+ metrics: ButtonMetric[] | null;
166
+ loading: boolean;
167
+ error: Error | null;
168
+ recalculate: () => Promise<void>;
169
+ };
170
+ /**
171
+ * Hook for sentence building state
172
+ *
173
+ * @returns Object with message state and handlers
174
+ *
175
+ * @example
176
+ * ```tsx
177
+ * function MyComponent() {
178
+ * const { message, wordCount, effort, addWord, clear } = useSentenceBuilder();
179
+ *
180
+ * return (
181
+ * <div>
182
+ * <p>{message || 'Start building...'}</p>
183
+ * <p>{wordCount} words, {effort.toFixed(2)} effort</p>
184
+ * <button onClick={clear}>Clear</button>
185
+ * </div>
186
+ * );
187
+ * }
188
+ * ```
189
+ */
190
+ declare function useSentenceBuilder(): {
191
+ message: string;
192
+ wordCount: number;
193
+ effort: number;
194
+ addWord: (word: string, wordEffort?: number) => void;
195
+ clear: () => void;
196
+ };
197
+
198
+ /**
199
+ * AAC File Loading Utilities
200
+ *
201
+ * Provides utilities for loading AAC files from various sources
202
+ * (URLs, File objects, file paths) in both client and server contexts.
203
+ */
204
+
205
+ type ProcessorOptions = Record<string, unknown> | undefined;
206
+ /**
207
+ * Load an AAC file from a file path (server-side only)
208
+ *
209
+ * @param filepath - Path to the AAC file
210
+ * @param options - Processor options (e.g., pageLayoutPreference for SNAP)
211
+ * @returns Promise resolving to AACTree
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * const tree = await loadAACFile('/path/to/file.sps');
216
+ * ```
217
+ */
218
+ declare function loadAACFile(filepath: string, options?: ProcessorOptions): Promise<AACTree>;
219
+ /**
220
+ * Load an AAC file and return extended result with format info
221
+ *
222
+ * @param filepath - Path to the AAC file
223
+ * @param options - Processor options
224
+ * @returns Promise resolving to LoadAACFileResult
225
+ */
226
+ declare function loadAACFileWithMetadata(filepath: string, options?: ProcessorOptions): Promise<LoadAACFileResult>;
227
+ /**
228
+ * Load an AAC file from a URL (client-side)
229
+ *
230
+ * Note: This requires the server to provide the file with appropriate CORS headers.
231
+ * For better performance, consider server-side loading instead.
232
+ *
233
+ * @param url - URL to the AAC file
234
+ * @param options - Processor options
235
+ * @returns Promise resolving to AACTree
236
+ *
237
+ * @example
238
+ * ```ts
239
+ * const tree = await loadAACFileFromURL('https://example.com/file.sps');
240
+ * ```
241
+ */
242
+ declare function loadAACFileFromURL(url: string, options?: ProcessorOptions): Promise<AACTree>;
243
+ /**
244
+ * Load an AAC file from a File object (client-side file input)
245
+ *
246
+ * @param file - File object from file input
247
+ * @param options - Processor options
248
+ * @returns Promise resolving to AACTree
249
+ *
250
+ * @example
251
+ * ```ts
252
+ * const input = document.querySelector('input[type="file"]');
253
+ * input.onchange = async (e) => {
254
+ * const file = e.target.files[0];
255
+ * const tree = await loadAACFileFromFile(file);
256
+ * // Use tree...
257
+ * };
258
+ * ```
259
+ */
260
+ declare function loadAACFileFromFile(_file: File | Blob, _filename?: string, _options?: unknown): Promise<AACTree>;
261
+ /**
262
+ * Calculate cognitive effort metrics for an AAC tree
263
+ *
264
+ * @param tree - The AAC tree
265
+ * @param options - Metrics calculation options
266
+ * @returns Promise resolving to array of ButtonMetrics
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * import { calculateMetrics } from 'aac-board-viewer';
271
+ *
272
+ * const metrics = await calculateMetrics(tree, {
273
+ * accessMethod: 'direct',
274
+ * });
275
+ * ```
276
+ */
277
+ declare function calculateMetrics(tree: AACTree, options?: {
278
+ accessMethod?: 'direct' | 'scanning';
279
+ scanningConfig?: {
280
+ pattern?: 'linear' | 'row-column' | 'block';
281
+ selectionMethod?: string;
282
+ errorCorrection?: boolean;
283
+ };
284
+ }): Promise<{
285
+ id: string;
286
+ label: string;
287
+ effort: number;
288
+ count: number;
289
+ is_word: boolean;
290
+ level: number | undefined;
291
+ semantic_id: string | undefined;
292
+ clone_id: string | undefined;
293
+ }[]>;
294
+ /**
295
+ * Get a list of supported file formats
296
+ *
297
+ * @returns Array of format information
298
+ */
299
+ declare function getSupportedFormats(): Array<{
300
+ name: string;
301
+ extensions: string[];
302
+ description: string;
303
+ }>;
304
+
305
+ export { BoardViewer, type BoardViewerProps, type ButtonMetric, type LoadAACFileResult, type MetricsOptions, calculateMetrics, getSupportedFormats, loadAACFile, loadAACFileFromFile, loadAACFileFromURL, loadAACFileWithMetadata, useAACFile, useAACFileWithMetrics, useMetrics, useSentenceBuilder };