aac-board-viewer 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/README.md +69 -2
- package/dist/index.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +50 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +49 -28
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ Universal AAC (Augmentative and Alternative Communication) board viewer componen
|
|
|
14
14
|
- **Excel** (`.xlsx` boards)
|
|
15
15
|
- **DOT files** (`.dot` visualizations)
|
|
16
16
|
|
|
17
|
+
Note: In-browser loading of SQLite-backed formats (`.sps`, `.spb`, `.ce`) requires SQL.js configuration.
|
|
18
|
+
|
|
17
19
|
## Features
|
|
18
20
|
|
|
19
21
|
- 🎯 **Universal Support** - Works with all major AAC file formats
|
|
@@ -40,9 +42,36 @@ yarn add aac-board-viewer
|
|
|
40
42
|
|
|
41
43
|
## Quick Start
|
|
42
44
|
|
|
43
|
-
###
|
|
45
|
+
### Browser Usage
|
|
46
|
+
|
|
47
|
+
SQLite-backed formats (Snap `.sps`/`.spb` and TouchChat `.ce`) require SQL.js to be configured in your bundler before loading files:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { configureBrowserSqlJs, loadAACFile, BoardViewer } from 'aac-board-viewer';
|
|
51
|
+
import sqlWasmUrl from 'sql.js/dist/sql-wasm.wasm?url';
|
|
52
|
+
import 'aac-board-viewer/styles';
|
|
53
|
+
|
|
54
|
+
configureBrowserSqlJs({
|
|
55
|
+
locateFile: () => sqlWasmUrl,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
function MyViewer({ file }: { file: File }) {
|
|
59
|
+
const [tree, setTree] = useState(null);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
async function load() {
|
|
63
|
+
const loadedTree = await loadAACFile(file);
|
|
64
|
+
setTree(loadedTree);
|
|
65
|
+
}
|
|
66
|
+
load();
|
|
67
|
+
}, [file]);
|
|
44
68
|
|
|
45
|
-
|
|
69
|
+
if (!tree) return <div>Loading...</div>;
|
|
70
|
+
return <BoardViewer tree={tree} />;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Server-Side / API Usage
|
|
46
75
|
|
|
47
76
|
```tsx
|
|
48
77
|
import { BoardViewer } from 'aac-board-viewer';
|
|
@@ -60,6 +89,44 @@ function MyViewer({ treeData }) {
|
|
|
60
89
|
}
|
|
61
90
|
```
|
|
62
91
|
|
|
92
|
+
### Client/Server Split (Lightweight Frontend)
|
|
93
|
+
|
|
94
|
+
Parse boards on the server and send the `AACTree` JSON to the browser for rendering. This keeps the frontend lightweight while the backend handles heavy formats.
|
|
95
|
+
|
|
96
|
+
Server (Node/Express):
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import express from 'express';
|
|
100
|
+
import { loadAACFile } from 'aac-board-viewer';
|
|
101
|
+
|
|
102
|
+
const app = express();
|
|
103
|
+
|
|
104
|
+
app.get('/api/boards/:id', async (req, res) => {
|
|
105
|
+
const tree = await loadAACFile(`/data/boards/${req.params.id}.sps`);
|
|
106
|
+
res.json(tree);
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Client (React):
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { BoardViewer } from 'aac-board-viewer';
|
|
114
|
+
import 'aac-board-viewer/styles';
|
|
115
|
+
|
|
116
|
+
function RemoteBoard({ id }: { id: string }) {
|
|
117
|
+
const [tree, setTree] = useState(null);
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
fetch(`/api/boards/${id}`)
|
|
121
|
+
.then((res) => res.json())
|
|
122
|
+
.then(setTree);
|
|
123
|
+
}, [id]);
|
|
124
|
+
|
|
125
|
+
if (!tree) return <div>Loading...</div>;
|
|
126
|
+
return <BoardViewer tree={tree} />;
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
63
130
|
### With Metrics
|
|
64
131
|
|
|
65
132
|
```tsx
|
package/dist/index.d.mts
CHANGED
|
@@ -271,11 +271,19 @@ declare function useSentenceBuilder(): {
|
|
|
271
271
|
* Provides utilities for loading AAC files from various sources
|
|
272
272
|
* (File/Blob objects, file paths, URLs) in both browser and server contexts.
|
|
273
273
|
*
|
|
274
|
-
* Browser: Supports
|
|
275
|
-
* Node.js: Supports all formats including
|
|
274
|
+
* Browser: Supports all formats. SQLite-backed formats (.sps, .spb, .ce) require SQL.js configuration.
|
|
275
|
+
* Node.js: Supports all formats including filesystem access and SQLite-backed formats.
|
|
276
276
|
*/
|
|
277
277
|
|
|
278
278
|
type ProcessorOptions = Record<string, unknown> | undefined;
|
|
279
|
+
type SqlJsConfig = {
|
|
280
|
+
locateFile: (file: string) => string;
|
|
281
|
+
[key: string]: unknown;
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Configure SQL.js for browser-only SQLite-backed formats (.sps/.spb/.ce).
|
|
285
|
+
*/
|
|
286
|
+
declare function configureBrowserSqlJs(config: SqlJsConfig): Promise<void>;
|
|
279
287
|
/**
|
|
280
288
|
* Load an AAC file from a file path (Node.js only)
|
|
281
289
|
*
|
|
@@ -403,4 +411,4 @@ declare function getBrowserExtensions(): string[];
|
|
|
403
411
|
*/
|
|
404
412
|
declare function getNodeOnlyExtensions(): string[];
|
|
405
413
|
|
|
406
|
-
export { BoardViewer, type BoardViewerProps, type ButtonMetric, type LoadAACFileResult, type MetricsOptions, calculateMetrics, getBrowserExtensions, getNodeOnlyExtensions, getSupportedFormats, isBrowserCompatible, loadAACFile, loadAACFileFromURL, loadAACFileWithMetadata, useAACFile, useAACFileFromFile, useAACFileFromFileWithMetrics, useAACFileWithMetrics, useMetrics, useSentenceBuilder };
|
|
414
|
+
export { BoardViewer, type BoardViewerProps, type ButtonMetric, type LoadAACFileResult, type MetricsOptions, calculateMetrics, configureBrowserSqlJs, getBrowserExtensions, getNodeOnlyExtensions, getSupportedFormats, isBrowserCompatible, loadAACFile, loadAACFileFromURL, loadAACFileWithMetadata, useAACFile, useAACFileFromFile, useAACFileFromFileWithMetrics, useAACFileWithMetrics, useMetrics, useSentenceBuilder };
|
package/dist/index.d.ts
CHANGED
|
@@ -271,11 +271,19 @@ declare function useSentenceBuilder(): {
|
|
|
271
271
|
* Provides utilities for loading AAC files from various sources
|
|
272
272
|
* (File/Blob objects, file paths, URLs) in both browser and server contexts.
|
|
273
273
|
*
|
|
274
|
-
* Browser: Supports
|
|
275
|
-
* Node.js: Supports all formats including
|
|
274
|
+
* Browser: Supports all formats. SQLite-backed formats (.sps, .spb, .ce) require SQL.js configuration.
|
|
275
|
+
* Node.js: Supports all formats including filesystem access and SQLite-backed formats.
|
|
276
276
|
*/
|
|
277
277
|
|
|
278
278
|
type ProcessorOptions = Record<string, unknown> | undefined;
|
|
279
|
+
type SqlJsConfig = {
|
|
280
|
+
locateFile: (file: string) => string;
|
|
281
|
+
[key: string]: unknown;
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Configure SQL.js for browser-only SQLite-backed formats (.sps/.spb/.ce).
|
|
285
|
+
*/
|
|
286
|
+
declare function configureBrowserSqlJs(config: SqlJsConfig): Promise<void>;
|
|
279
287
|
/**
|
|
280
288
|
* Load an AAC file from a file path (Node.js only)
|
|
281
289
|
*
|
|
@@ -403,4 +411,4 @@ declare function getBrowserExtensions(): string[];
|
|
|
403
411
|
*/
|
|
404
412
|
declare function getNodeOnlyExtensions(): string[];
|
|
405
413
|
|
|
406
|
-
export { BoardViewer, type BoardViewerProps, type ButtonMetric, type LoadAACFileResult, type MetricsOptions, calculateMetrics, getBrowserExtensions, getNodeOnlyExtensions, getSupportedFormats, isBrowserCompatible, loadAACFile, loadAACFileFromURL, loadAACFileWithMetadata, useAACFile, useAACFileFromFile, useAACFileFromFileWithMetrics, useAACFileWithMetrics, useMetrics, useSentenceBuilder };
|
|
414
|
+
export { BoardViewer, type BoardViewerProps, type ButtonMetric, type LoadAACFileResult, type MetricsOptions, calculateMetrics, configureBrowserSqlJs, getBrowserExtensions, getNodeOnlyExtensions, getSupportedFormats, isBrowserCompatible, loadAACFile, loadAACFileFromURL, loadAACFileWithMetadata, useAACFile, useAACFileFromFile, useAACFileFromFileWithMetrics, useAACFileWithMetrics, useMetrics, useSentenceBuilder };
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
BoardViewer: () => BoardViewer,
|
|
34
34
|
calculateMetrics: () => calculateMetrics,
|
|
35
|
+
configureBrowserSqlJs: () => configureBrowserSqlJs,
|
|
35
36
|
getBrowserExtensions: () => getBrowserExtensions,
|
|
36
37
|
getNodeOnlyExtensions: () => getNodeOnlyExtensions,
|
|
37
38
|
getSupportedFormats: () => getSupportedFormats,
|
|
@@ -288,16 +289,16 @@ function BoardViewer({
|
|
|
288
289
|
}
|
|
289
290
|
};
|
|
290
291
|
const getTextColor = (backgroundColor) => {
|
|
291
|
-
if (!backgroundColor) return "
|
|
292
|
+
if (!backgroundColor) return "#111827";
|
|
292
293
|
const hex = backgroundColor.replace("#", "");
|
|
293
294
|
if (hex.length === 6) {
|
|
294
295
|
const r = parseInt(hex.substring(0, 2), 16);
|
|
295
296
|
const g = parseInt(hex.substring(2, 4), 16);
|
|
296
297
|
const b = parseInt(hex.substring(4, 6), 16);
|
|
297
298
|
const brightness = (r * 299 + g * 587 + b * 114) / 1e3;
|
|
298
|
-
return brightness >= 128 ? "
|
|
299
|
+
return brightness >= 128 ? "#111827" : "#f9fafb";
|
|
299
300
|
}
|
|
300
|
-
return "
|
|
301
|
+
return "#111827";
|
|
301
302
|
};
|
|
302
303
|
if (!currentPage) {
|
|
303
304
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `flex items-center justify-center h-96 bg-gray-100 dark:bg-gray-800 rounded-lg ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-gray-600 dark:text-gray-400", children: "No pages available" }) }) });
|
|
@@ -370,7 +371,8 @@ function BoardViewer({
|
|
|
370
371
|
className: "aspect-square p-1 rounded border border-gray-200 dark:border-gray-700 transition flex flex-col items-center justify-center gap-0.5 hover:bg-gray-200 dark:hover:bg-gray-700 relative",
|
|
371
372
|
style: {
|
|
372
373
|
backgroundColor: button.style?.backgroundColor || "#f3f4f6",
|
|
373
|
-
borderColor: button.style?.borderColor || "#e5e7eb"
|
|
374
|
+
borderColor: button.style?.borderColor || "#e5e7eb",
|
|
375
|
+
color: button.style?.fontColor || getTextColor(button.style?.backgroundColor)
|
|
374
376
|
},
|
|
375
377
|
title: `${button.label}
|
|
376
378
|
${button.message || ""}`,
|
|
@@ -379,9 +381,7 @@ ${button.message || ""}`,
|
|
|
379
381
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
380
382
|
"span",
|
|
381
383
|
{
|
|
382
|
-
className:
|
|
383
|
-
button.style?.backgroundColor
|
|
384
|
-
)}`,
|
|
384
|
+
className: "text-[8px] sm:text-[9px] text-center font-medium leading-tight line-clamp-2",
|
|
385
385
|
children: button.label
|
|
386
386
|
}
|
|
387
387
|
)
|
|
@@ -495,7 +495,7 @@ ${button.message || ""}`,
|
|
|
495
495
|
style: {
|
|
496
496
|
backgroundColor: button.style?.backgroundColor || "#f3f4f6",
|
|
497
497
|
borderColor: button.style?.borderColor || "#e5e7eb",
|
|
498
|
-
color: button.style?.fontColor ||
|
|
498
|
+
color: button.style?.fontColor || getTextColor(button.style?.backgroundColor),
|
|
499
499
|
gridColumn: `${colIndex + 1} / span ${colSpan}`,
|
|
500
500
|
gridRow: `${rowIndex + 1} / span ${rowSpan}`
|
|
501
501
|
},
|
|
@@ -523,9 +523,7 @@ ${button.message || ""}`,
|
|
|
523
523
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
524
524
|
"span",
|
|
525
525
|
{
|
|
526
|
-
className:
|
|
527
|
-
button.style?.backgroundColor
|
|
528
|
-
)}`,
|
|
526
|
+
className: "text-xs sm:text-sm text-center font-medium leading-tight line-clamp-3",
|
|
529
527
|
children: button.label
|
|
530
528
|
}
|
|
531
529
|
),
|
|
@@ -537,9 +535,7 @@ ${button.message || ""}`,
|
|
|
537
535
|
button.message && button.message !== button.label && !isPredictionCell && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
538
536
|
"span",
|
|
539
537
|
{
|
|
540
|
-
className:
|
|
541
|
-
button.style?.backgroundColor
|
|
542
|
-
)}`,
|
|
538
|
+
className: "text-[10px] sm:text-xs text-center opacity-75 line-clamp-2",
|
|
543
539
|
children: button.message
|
|
544
540
|
}
|
|
545
541
|
)
|
|
@@ -576,14 +572,38 @@ ${button.message || ""}`,
|
|
|
576
572
|
var import_react2 = require("react");
|
|
577
573
|
|
|
578
574
|
// src/utils/loaders.ts
|
|
579
|
-
var NODE_ONLY_EXTENSIONS = [".
|
|
580
|
-
var BROWSER_EXTENSIONS = [
|
|
575
|
+
var NODE_ONLY_EXTENSIONS = [".xlsx", ".xls"];
|
|
576
|
+
var BROWSER_EXTENSIONS = [
|
|
577
|
+
".obf",
|
|
578
|
+
".obz",
|
|
579
|
+
".gridset",
|
|
580
|
+
".plist",
|
|
581
|
+
".grd",
|
|
582
|
+
".opml",
|
|
583
|
+
".dot",
|
|
584
|
+
".sps",
|
|
585
|
+
".spb",
|
|
586
|
+
".ce"
|
|
587
|
+
];
|
|
581
588
|
function isBrowserEnvironment() {
|
|
582
589
|
return typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
583
590
|
}
|
|
584
591
|
async function importProcessors() {
|
|
592
|
+
if (isBrowserEnvironment()) {
|
|
593
|
+
return import("@willwade/aac-processors/browser");
|
|
594
|
+
}
|
|
585
595
|
return import("@willwade/aac-processors");
|
|
586
596
|
}
|
|
597
|
+
async function configureBrowserSqlJs(config) {
|
|
598
|
+
if (!isBrowserEnvironment()) {
|
|
599
|
+
throw new Error("configureBrowserSqlJs can only be used in a browser environment.");
|
|
600
|
+
}
|
|
601
|
+
const processors = await import("@willwade/aac-processors/browser");
|
|
602
|
+
if (typeof processors.configureSqlJs !== "function") {
|
|
603
|
+
throw new Error("configureSqlJs is not available in this build of @willwade/aac-processors.");
|
|
604
|
+
}
|
|
605
|
+
processors.configureSqlJs(config);
|
|
606
|
+
}
|
|
587
607
|
async function getProcessorForFile(filepath, options) {
|
|
588
608
|
const { getProcessor } = await importProcessors();
|
|
589
609
|
const ext = filepath.toLowerCase().split(".").pop();
|
|
@@ -601,11 +621,6 @@ async function getProcessorForFile(filepath, options) {
|
|
|
601
621
|
throw new Error(`Unsupported file type: ${extension}`);
|
|
602
622
|
}
|
|
603
623
|
if (extension === ".sps" || extension === ".spb") {
|
|
604
|
-
if (isBrowserEnvironment()) {
|
|
605
|
-
throw new Error(
|
|
606
|
-
`SNAP files (.sps, .spb) require server-side processing. Please use the server API or upload a browser-compatible format. Browser supports: ${BROWSER_EXTENSIONS.join(", ")}`
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
624
|
const { SnapProcessor } = await importProcessors();
|
|
610
625
|
return {
|
|
611
626
|
processor: options ? new SnapProcessor(null, options) : new SnapProcessor(),
|
|
@@ -659,7 +674,12 @@ async function loadAACFileFromURL(url, options) {
|
|
|
659
674
|
return loadAACFileFromFile(blob, filename, options);
|
|
660
675
|
}
|
|
661
676
|
async function loadAACFileWithMetadata(input, options) {
|
|
662
|
-
|
|
677
|
+
let tree;
|
|
678
|
+
if (typeof input === "string") {
|
|
679
|
+
tree = await loadAACFile(input, options);
|
|
680
|
+
} else {
|
|
681
|
+
tree = await loadAACFile(input, options);
|
|
682
|
+
}
|
|
663
683
|
let filepath = "";
|
|
664
684
|
if (typeof input === "string") {
|
|
665
685
|
filepath = input;
|
|
@@ -695,8 +715,9 @@ function getFilenameFromURL(url) {
|
|
|
695
715
|
}
|
|
696
716
|
}
|
|
697
717
|
async function calculateMetrics(tree, options = {}) {
|
|
698
|
-
const aacProcessors = await
|
|
699
|
-
|
|
718
|
+
const aacProcessors = await importProcessors();
|
|
719
|
+
const hasMetricsCalculator = typeof aacProcessors.MetricsCalculator === "function";
|
|
720
|
+
if (!hasMetricsCalculator) {
|
|
700
721
|
console.warn("MetricsCalculator not available in this environment");
|
|
701
722
|
return [];
|
|
702
723
|
}
|
|
@@ -751,14 +772,14 @@ function getSupportedFormats() {
|
|
|
751
772
|
{
|
|
752
773
|
name: "TD Snap",
|
|
753
774
|
extensions: [".sps", ".spb"],
|
|
754
|
-
description: "Tobii Dynavox Snap files",
|
|
755
|
-
browserCompatible:
|
|
775
|
+
description: "Tobii Dynavox Snap files (requires SQL.js in browser)",
|
|
776
|
+
browserCompatible: true
|
|
756
777
|
},
|
|
757
778
|
{
|
|
758
779
|
name: "TouchChat",
|
|
759
780
|
extensions: [".ce"],
|
|
760
|
-
description: "Saltillo TouchChat files",
|
|
761
|
-
browserCompatible:
|
|
781
|
+
description: "Saltillo TouchChat files (requires SQL.js in browser)",
|
|
782
|
+
browserCompatible: true
|
|
762
783
|
},
|
|
763
784
|
{
|
|
764
785
|
name: "OpenBoard",
|
|
@@ -996,6 +1017,7 @@ function useSentenceBuilder() {
|
|
|
996
1017
|
0 && (module.exports = {
|
|
997
1018
|
BoardViewer,
|
|
998
1019
|
calculateMetrics,
|
|
1020
|
+
configureBrowserSqlJs,
|
|
999
1021
|
getBrowserExtensions,
|
|
1000
1022
|
getNodeOnlyExtensions,
|
|
1001
1023
|
getSupportedFormats,
|