@willwade/aac-processors 0.1.20 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/browser/core/baseProcessor.js +4 -0
  2. package/dist/browser/processors/applePanelsProcessor.js +24 -31
  3. package/dist/browser/processors/astericsGridProcessor.js +10 -3
  4. package/dist/browser/processors/dotProcessor.js +5 -2
  5. package/dist/browser/processors/gridset/colorUtils.js +354 -0
  6. package/dist/browser/processors/gridset/helpers.js +49 -45
  7. package/dist/browser/processors/gridset/index.js +61 -0
  8. package/dist/browser/processors/gridset/styleHelpers.js +205 -0
  9. package/dist/browser/processors/gridset/symbolExtractor.js +331 -0
  10. package/dist/browser/processors/gridset/symbolSearch.js +248 -0
  11. package/dist/browser/processors/gridset/symbols.js +35 -68
  12. package/dist/browser/processors/gridsetProcessor.js +32 -41
  13. package/dist/browser/processors/obfProcessor.js +20 -33
  14. package/dist/browser/processors/opmlProcessor.js +5 -2
  15. package/dist/browser/processors/snap/helpers.js +49 -45
  16. package/dist/browser/processors/snapProcessor.js +39 -42
  17. package/dist/browser/processors/touchchatProcessor.js +54 -45
  18. package/dist/browser/utilities/analytics/reference/index.js +27 -19
  19. package/dist/browser/utils/io.js +67 -14
  20. package/dist/browser/utils/sqlite.js +6 -8
  21. package/dist/browser/utils/zip.js +45 -43
  22. package/dist/browser/validation/baseValidator.js +5 -0
  23. package/dist/browser/validation/gridsetValidator.js +12 -20
  24. package/dist/browser/validation/obfValidator.js +5 -4
  25. package/dist/browser/validation/snapValidator.js +9 -5
  26. package/dist/browser/validation/touchChatValidator.js +21 -11
  27. package/dist/cli/index.js +10 -15
  28. package/dist/core/baseProcessor.d.ts +7 -7
  29. package/dist/core/baseProcessor.js +4 -0
  30. package/dist/processors/applePanelsProcessor.js +29 -36
  31. package/dist/processors/astericsGridProcessor.js +20 -13
  32. package/dist/processors/dotProcessor.js +10 -7
  33. package/dist/processors/excelProcessor.js +9 -12
  34. package/dist/processors/gridset/helpers.d.ts +9 -11
  35. package/dist/processors/gridset/helpers.js +49 -71
  36. package/dist/processors/gridset/imageDebug.d.ts +3 -5
  37. package/dist/processors/gridset/imageDebug.js +4 -4
  38. package/dist/processors/gridset/password.d.ts +1 -1
  39. package/dist/processors/gridset/symbolExtractor.d.ts +5 -3
  40. package/dist/processors/gridset/symbolExtractor.js +15 -38
  41. package/dist/processors/gridset/symbolSearch.d.ts +3 -2
  42. package/dist/processors/gridset/symbolSearch.js +12 -34
  43. package/dist/processors/gridset/symbols.d.ts +8 -6
  44. package/dist/processors/gridset/symbols.js +34 -67
  45. package/dist/processors/gridset/wordlistHelpers.d.ts +4 -6
  46. package/dist/processors/gridset/wordlistHelpers.js +15 -74
  47. package/dist/processors/gridsetProcessor.js +36 -68
  48. package/dist/processors/obfProcessor.js +26 -62
  49. package/dist/processors/obfsetProcessor.js +2 -2
  50. package/dist/processors/opmlProcessor.js +10 -7
  51. package/dist/processors/snap/helpers.d.ts +8 -8
  52. package/dist/processors/snap/helpers.js +50 -72
  53. package/dist/processors/snapProcessor.js +38 -41
  54. package/dist/processors/touchchatProcessor.js +54 -45
  55. package/dist/utilities/analytics/index.d.ts +3 -2
  56. package/dist/utilities/analytics/index.js +8 -10
  57. package/dist/utilities/analytics/reference/index.d.ts +5 -3
  58. package/dist/utilities/analytics/reference/index.js +26 -18
  59. package/dist/utilities/symbolTools.d.ts +4 -2
  60. package/dist/utilities/symbolTools.js +16 -15
  61. package/dist/utils/io.d.ts +24 -6
  62. package/dist/utils/io.js +64 -14
  63. package/dist/utils/sqlite.d.ts +2 -0
  64. package/dist/utils/sqlite.js +6 -8
  65. package/dist/utils/zip.d.ts +7 -3
  66. package/dist/utils/zip.js +45 -43
  67. package/dist/validation/applePanelsValidator.d.ts +2 -1
  68. package/dist/validation/applePanelsValidator.js +9 -11
  69. package/dist/validation/astericsValidator.d.ts +2 -1
  70. package/dist/validation/astericsValidator.js +5 -4
  71. package/dist/validation/baseValidator.d.ts +2 -2
  72. package/dist/validation/baseValidator.js +5 -0
  73. package/dist/validation/dotValidator.d.ts +2 -1
  74. package/dist/validation/dotValidator.js +5 -4
  75. package/dist/validation/excelValidator.d.ts +2 -1
  76. package/dist/validation/excelValidator.js +5 -4
  77. package/dist/validation/gridsetValidator.d.ts +2 -1
  78. package/dist/validation/gridsetValidator.js +11 -22
  79. package/dist/validation/index.d.ts +2 -2
  80. package/dist/validation/index.js +5 -4
  81. package/dist/validation/obfValidator.d.ts +2 -1
  82. package/dist/validation/obfValidator.js +5 -4
  83. package/dist/validation/obfsetValidator.d.ts +2 -1
  84. package/dist/validation/obfsetValidator.js +5 -4
  85. package/dist/validation/opmlValidator.d.ts +2 -1
  86. package/dist/validation/opmlValidator.js +5 -4
  87. package/dist/validation/snapValidator.d.ts +2 -1
  88. package/dist/validation/snapValidator.js +9 -5
  89. package/dist/validation/touchChatValidator.d.ts +4 -6
  90. package/dist/validation/touchChatValidator.js +21 -11
  91. package/dist/validation/validationTypes.d.ts +8 -1
  92. package/package.json +1 -1
  93. package/dist/core/fileProcessor.d.ts +0 -7
  94. package/dist/core/fileProcessor.js +0 -57
@@ -1,12 +1,10 @@
1
1
  import { XMLBuilder } from 'fast-xml-parser';
2
2
  import { AACSemanticCategory, AACSemanticIntent, } from '../../core/treeStructure';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import { execSync } from 'child_process';
6
- import Database from 'better-sqlite3';
7
3
  import { dotNetTicksToDate } from '../../utils/dotnetTicks';
8
4
  import { getZipEntriesFromAdapter, resolveGridsetPasswordFromEnv } from './password';
9
- import { openZipFromInput } from '../../utils/zip';
5
+ import { defaultFileAdapter, extname, getNodeRequire, joinWin32, } from '../../utils/io';
6
+ import { getZipAdapter } from '../../utils/zip';
7
+ import { requireBetterSqlite3 } from '../../utils/sqlite';
10
8
  function normalizeZipPath(p) {
11
9
  const unified = p.replace(/\\/g, '/');
12
10
  try {
@@ -52,11 +50,11 @@ export function getAllowedImageEntries(tree) {
52
50
  * @param entryPath Entry name inside the zip
53
51
  * @returns Image data buffer or null if not found
54
52
  */
55
- export async function openImage(gridsetBuffer, entryPath, password = resolveGridsetPasswordFromEnv(), zipAdapter) {
53
+ export async function openImage(gridsetBuffer, entryPath, password = resolveGridsetPasswordFromEnv(), fileAdapter = defaultFileAdapter, zipAdapter) {
56
54
  try {
57
- const { zip } = zipAdapter
55
+ const zip = zipAdapter
58
56
  ? await zipAdapter(gridsetBuffer)
59
- : await openZipFromInput(gridsetBuffer);
57
+ : await getZipAdapter(gridsetBuffer, fileAdapter);
60
58
  const entries = getZipEntriesFromAdapter(zip, password);
61
59
  const want = normalizeZipPath(entryPath);
62
60
  const entry = entries.find((e) => normalizeZipPath(e.entryName) === want);
@@ -149,8 +147,9 @@ export function getCommonDocumentsPath() {
149
147
  }
150
148
  try {
151
149
  // Query registry for Common Documents path
150
+ const child_process = getNodeRequire()('child_process');
152
151
  const command = 'REG.EXE QUERY "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" /V "Common Documents"';
153
- const output = execSync(command, { encoding: 'utf-8', windowsHide: true });
152
+ const output = child_process.execSync(command, { encoding: 'utf-8', windowsHide: true });
154
153
  // Parse the output to extract the path
155
154
  const match = output.match(/Common Documents\s+REG_SZ\s+(.+)/);
156
155
  if (match && match[1]) {
@@ -171,7 +170,8 @@ export function getCommonDocumentsPath() {
171
170
  * C:\Users\Public\Documents\Smartbox\Grid 3\Users\{UserName}\Grid Sets\
172
171
  * @returns Array of Grid3 user path information
173
172
  */
174
- export function findGrid3UserPaths() {
173
+ export function findGrid3UserPaths(fileAdapter = defaultFileAdapter) {
174
+ const { pathExists, listDir, isDirectory } = fileAdapter;
175
175
  const results = [];
176
176
  // Only works on Windows
177
177
  if (process.platform !== 'win32') {
@@ -180,28 +180,28 @@ export function findGrid3UserPaths() {
180
180
  try {
181
181
  const commonDocs = getCommonDocumentsPath();
182
182
  // Use Windows path joining so tests that mock a Windows platform stay consistent even on POSIX runners
183
- const grid3BasePath = path.win32.join(commonDocs, 'Smartbox', 'Grid 3', 'Users');
183
+ const grid3BasePath = joinWin32(commonDocs, 'Smartbox', 'Grid 3', 'Users');
184
184
  // Check if Grid3 Users directory exists
185
- if (!fs.existsSync(grid3BasePath)) {
185
+ if (!pathExists(grid3BasePath)) {
186
186
  return results;
187
187
  }
188
188
  // Enumerate users
189
- const users = fs.readdirSync(grid3BasePath, { withFileTypes: true });
189
+ const users = listDir(grid3BasePath);
190
190
  for (const userDir of users) {
191
- if (!userDir.isDirectory())
191
+ if (!isDirectory(userDir))
192
192
  continue;
193
- const userName = userDir.name;
194
- const userPath = path.win32.join(grid3BasePath, userName);
193
+ const userName = userDir;
194
+ const userPath = joinWin32(grid3BasePath, userName);
195
195
  // Enumerate language codes
196
- const langDirs = fs.readdirSync(userPath, { withFileTypes: true });
196
+ const langDirs = listDir(userPath);
197
197
  for (const langDir of langDirs) {
198
- if (!langDir.isDirectory())
198
+ if (!isDirectory(langDir))
199
199
  continue;
200
- const langCode = langDir.name;
201
- const basePath = path.win32.join(userPath, langCode);
202
- const historyDbPath = path.win32.join(basePath, 'Phrases', 'history.sqlite');
200
+ const langCode = langDir;
201
+ const basePath = joinWin32(userPath, langCode);
202
+ const historyDbPath = joinWin32(basePath, 'Phrases', 'history.sqlite');
203
203
  // Only include if history database exists
204
- if (fs.existsSync(historyDbPath)) {
204
+ if (pathExists(historyDbPath)) {
205
205
  results.push({
206
206
  userName,
207
207
  langCode,
@@ -222,8 +222,8 @@ export function findGrid3UserPaths() {
222
222
  * Convenience method that returns just the database file paths
223
223
  * @returns Array of paths to history.sqlite files
224
224
  */
225
- export function findGrid3HistoryDatabases() {
226
- return findGrid3UserPaths().map((userPath) => userPath.historyDbPath);
225
+ export function findGrid3HistoryDatabases(fileAdapter) {
226
+ return findGrid3UserPaths(fileAdapter).map((userPath) => userPath.historyDbPath);
227
227
  }
228
228
  /**
229
229
  * Get Grid 3 users (alias of findGrid3UserPaths for clarity)
@@ -236,36 +236,37 @@ export function findGrid3Users() {
236
236
  * @param userName Optional user filter; matches case-insensitively
237
237
  * @returns Array of user/gridset path pairs
238
238
  */
239
- export function findGrid3Vocabularies(userName) {
239
+ export function findGrid3Vocabularies(userName, fileAdapter = defaultFileAdapter) {
240
+ const { pathExists, listDir, isDirectory } = fileAdapter;
240
241
  const results = [];
241
242
  if (process.platform !== 'win32') {
242
243
  return results;
243
244
  }
244
245
  const commonDocs = getCommonDocumentsPath();
245
- const grid3BasePath = path.win32.join(commonDocs, 'Smartbox', 'Grid 3', 'Users');
246
- if (!fs.existsSync(grid3BasePath)) {
246
+ const grid3BasePath = joinWin32(commonDocs, 'Smartbox', 'Grid 3', 'Users');
247
+ if (!pathExists(grid3BasePath)) {
247
248
  return results;
248
249
  }
249
250
  const normalizedUser = userName?.toLowerCase();
250
- const users = fs.readdirSync(grid3BasePath, { withFileTypes: true });
251
+ const users = listDir(grid3BasePath);
251
252
  for (const userDir of users) {
252
- if (!userDir.isDirectory())
253
+ if (!isDirectory(userDir))
253
254
  continue;
254
- if (normalizedUser && userDir.name.toLowerCase() !== normalizedUser)
255
+ if (normalizedUser && userDir.toLowerCase() !== normalizedUser)
255
256
  continue;
256
- const userRoot = path.win32.join(grid3BasePath, userDir.name);
257
- const gridSetsDir = path.win32.join(userRoot, 'Grid Sets');
258
- if (!fs.existsSync(gridSetsDir))
257
+ const userRoot = joinWin32(grid3BasePath, userDir);
258
+ const gridSetsDir = joinWin32(userRoot, 'Grid Sets');
259
+ if (!pathExists(gridSetsDir))
259
260
  continue;
260
- const entries = fs.readdirSync(gridSetsDir, { withFileTypes: true });
261
+ const entries = listDir(gridSetsDir);
261
262
  for (const entry of entries) {
262
- if (!entry.isFile())
263
+ if (!pathExists(entry) || isDirectory(entry))
263
264
  continue;
264
- const ext = path.extname(entry.name).toLowerCase();
265
+ const ext = extname(entry).toLowerCase();
265
266
  if (ext === '.gridset' || ext === '.gridsetx' || ext === '.grd' || ext === '.grdl') {
266
267
  results.push({
267
- userName: userDir.name,
268
- gridsetPath: path.win32.join(gridSetsDir, entry.name),
268
+ userName: userDir,
269
+ gridsetPath: joinWin32(gridSetsDir, entry),
269
270
  });
270
271
  }
271
272
  }
@@ -278,26 +279,27 @@ export function findGrid3Vocabularies(userName) {
278
279
  * @param langCode Optional language code filter (case-insensitive)
279
280
  * @returns Path to history.sqlite or null if not found
280
281
  */
281
- export function findGrid3UserHistory(userName, langCode) {
282
+ export function findGrid3UserHistory(userName, langCode, fileAdapter) {
282
283
  if (!userName)
283
284
  return null;
284
285
  const normalizedUser = userName.toLowerCase();
285
286
  const normalizedLang = langCode?.toLowerCase();
286
- const match = findGrid3UserPaths().find((u) => u.userName.toLowerCase() === normalizedUser &&
287
+ const match = findGrid3UserPaths(fileAdapter).find((u) => u.userName.toLowerCase() === normalizedUser &&
287
288
  (!normalizedLang || u.langCode.toLowerCase() === normalizedLang));
288
289
  return match?.historyDbPath ?? null;
289
290
  }
290
291
  /**
291
292
  * Check whether Grid 3 appears to be installed (Windows only)
292
293
  */
293
- export function isGrid3Installed() {
294
+ export function isGrid3Installed(fileAdapter = defaultFileAdapter) {
295
+ const { pathExists } = fileAdapter;
294
296
  if (process.platform !== 'win32')
295
297
  return false;
296
298
  const commonDocs = getCommonDocumentsPath();
297
299
  if (!commonDocs)
298
300
  return false;
299
- const grid3BasePath = path.win32.join(commonDocs, 'Smartbox', 'Grid 3', 'Users');
300
- return fs.existsSync(grid3BasePath);
301
+ const grid3BasePath = joinWin32(commonDocs, 'Smartbox', 'Grid 3', 'Users');
302
+ return pathExists(grid3BasePath);
301
303
  }
302
304
  function parseGrid3ContentXml(xmlContent) {
303
305
  const regex = /<r>(?:<!\[CDATA\[)?(.*?)(?:\]\]>)?<\/r>/gis;
@@ -316,9 +318,11 @@ function parseGrid3ContentXml(xmlContent) {
316
318
  * @param historyDbPath Absolute path to the history database
317
319
  * @returns Parsed history entries grouped by phrase
318
320
  */
319
- export function readGrid3History(historyDbPath) {
320
- if (!fs.existsSync(historyDbPath))
321
+ export function readGrid3History(historyDbPath, fileAdapter = defaultFileAdapter) {
322
+ const { pathExists } = fileAdapter;
323
+ if (!pathExists(historyDbPath))
321
324
  return [];
325
+ const Database = requireBetterSqlite3();
322
326
  const db = new Database(historyDbPath, { readonly: true });
323
327
  const rows = db
324
328
  .prepare(`
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Grid 3 Enhanced Support Module
3
+ *
4
+ * This module exports all enhanced Grid 3 functionality including:
5
+ * - Cell shape detection and support
6
+ * - Plugin cell type detection (Workspace, LiveCell, AutoContent)
7
+ * - Comprehensive command definitions and detection
8
+ * - Color utilities and style helpers
9
+ * - Image resolution helpers
10
+ */
11
+ // Style helpers
12
+ export { CellBackgroundShape, SHAPE_NAMES, DEFAULT_GRID3_STYLES, CATEGORY_STYLES, createDefaultStylesXml, createCategoryStyle, } from './styleHelpers';
13
+ // Plugin cell type detection
14
+ export { detectPluginCellType, Grid3CellType, WORKSPACE_TYPES, LIVECELL_TYPES, AUTOCONTENT_TYPES, getCellTypeDisplayName, isWorkspaceCell, isLiveCell, isAutoContentCell, isRegularCell, } from './pluginTypes';
15
+ // Command definitions and detection
16
+ export { detectCommand, getCommandDefinition, getCommandsByPlugin, getCommandsByCategory, getAllCommandIds, getAllPluginIds, extractCommandParameters, GRID3_COMMANDS, Grid3CommandCategory, } from './commands';
17
+ // Import for local use in constant definitions
18
+ import { getAllCommandIds, getAllPluginIds } from './commands';
19
+ import { CellBackgroundShape } from './styleHelpers';
20
+ import { Grid3CellType } from './pluginTypes';
21
+ import { Grid3CommandCategory } from './commands';
22
+ // Color utilities
23
+ export { ensureAlphaChannel, darkenColor, lightenColor, hexToRgba, rgbaToHex } from './colorUtils';
24
+ // Password handling
25
+ export { resolveGridsetPassword, getZipEntriesWithPassword, getZipEntriesFromAdapter, resolveGridsetPasswordFromEnv, } from './password';
26
+ // Helper functions
27
+ export { getPageTokenImageMap, getAllowedImageEntries, openImage, generateGrid3Guid, createSettingsXml, createFileMapXml, getCommonDocumentsPath, findGrid3UserPaths, findGrid3HistoryDatabases, findGrid3Vocabularies, findGrid3UserHistory, findGrid3Users, isGrid3Installed, readGrid3History, readGrid3HistoryForUser, readAllGrid3History, } from './helpers';
28
+ // Symbol library handling
29
+ export { parseSymbolReference, isSymbolReference, resolveSymbolReference, getAvailableSymbolLibraries, getSymbolLibraryInfo, extractSymbolReferences, analyzeSymbolUsage, createSymbolReference, getSymbolLibraryName, getSymbolPath, isKnownSymbolLibrary, getSymbolLibraryDisplayName, getDefaultGrid3Path, getSymbolLibrariesDir, getSymbolSearchIndexesDir, symbolReferenceToFilename, SYMBOL_LIBRARIES, } from './symbols';
30
+ // Backward compatibility aliases for old function names
31
+ export { getSymbolsDir, getSymbolSearchDir } from './symbols';
32
+ // Image resolution
33
+ export { resolveGrid3CellImage, isSymbolLibraryReference, parseImageSymbolReference, } from './resolver';
34
+ // Symbol extraction and conversion
35
+ export { extractButtonImage, extractSymbolLibraryImage, convertToAstericsImage, analyzeSymbolExtraction, suggestExtractionStrategy, exportSymbolReferencesToCsv, createSymbolManifest, } from './symbolExtractor';
36
+ // Symbol search functionality
37
+ export { parsePixFile, loadSearchIndexes, searchSymbols, searchSymbolsWithReferences, getSymbolFilename, getSymbolDisplayName, getAllSearchTerms, getSearchSuggestions, countLibrarySymbols, getSymbolSearchStats, } from './symbolSearch';
38
+ /**
39
+ * Get all Grid 3 command IDs as a readonly array
40
+ * Useful for validation and autocomplete
41
+ */
42
+ export const GRID3_COMMAND_IDS = Object.freeze(getAllCommandIds());
43
+ /**
44
+ * Get all Grid 3 plugin IDs as a readonly array
45
+ */
46
+ export const GRID3_PLUGIN_IDS = Object.freeze(getAllPluginIds());
47
+ /**
48
+ * Grid 3 cell shapes enum values
49
+ */
50
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
51
+ export const GRID3_CELL_SHAPES = Object.freeze(Object.values(CellBackgroundShape));
52
+ /**
53
+ * Grid 3 cell types enum values
54
+ */
55
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
56
+ export const GRID3_CELL_TYPES = Object.freeze(Object.values(Grid3CellType));
57
+ /**
58
+ * Grid 3 command categories enum values
59
+ */
60
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
61
+ export const GRID3_COMMAND_CATEGORIES = Object.freeze(Object.values(Grid3CommandCategory));
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Grid3 Style Helpers
3
+ *
4
+ * Utilities for creating and managing Grid3 styles, including default styles,
5
+ * style XML generation, and style conversion utilities.
6
+ */
7
+ import { XMLBuilder } from 'fast-xml-parser';
8
+ import { ensureAlphaChannel, darkenColor } from './colorUtils';
9
+ /**
10
+ * Cell background shapes supported by Grid 3
11
+ * Maps to Grid 3's CellBackgroundShape enum
12
+ */
13
+ export var CellBackgroundShape;
14
+ (function (CellBackgroundShape) {
15
+ CellBackgroundShape[CellBackgroundShape["Rectangle"] = 0] = "Rectangle";
16
+ CellBackgroundShape[CellBackgroundShape["RoundedRectangle"] = 1] = "RoundedRectangle";
17
+ CellBackgroundShape[CellBackgroundShape["FoldedCorner"] = 2] = "FoldedCorner";
18
+ CellBackgroundShape[CellBackgroundShape["Octagon"] = 3] = "Octagon";
19
+ CellBackgroundShape[CellBackgroundShape["Folder"] = 4] = "Folder";
20
+ CellBackgroundShape[CellBackgroundShape["Ellipse"] = 5] = "Ellipse";
21
+ CellBackgroundShape[CellBackgroundShape["SpeechBubble"] = 6] = "SpeechBubble";
22
+ CellBackgroundShape[CellBackgroundShape["ThoughtBubble"] = 7] = "ThoughtBubble";
23
+ CellBackgroundShape[CellBackgroundShape["Star"] = 8] = "Star";
24
+ CellBackgroundShape[CellBackgroundShape["Circle"] = 9] = "Circle";
25
+ CellBackgroundShape[CellBackgroundShape["ColouredCorner"] = 10] = "ColouredCorner";
26
+ })(CellBackgroundShape || (CellBackgroundShape = {}));
27
+ /**
28
+ * Human-readable shape names
29
+ */
30
+ export const SHAPE_NAMES = {
31
+ [CellBackgroundShape.Rectangle]: 'Rectangle',
32
+ [CellBackgroundShape.RoundedRectangle]: 'Rounded Rectangle',
33
+ [CellBackgroundShape.FoldedCorner]: 'Folded Corner',
34
+ [CellBackgroundShape.Octagon]: 'Octagon',
35
+ [CellBackgroundShape.Folder]: 'Folder',
36
+ [CellBackgroundShape.Ellipse]: 'Ellipse',
37
+ [CellBackgroundShape.SpeechBubble]: 'Speech Bubble',
38
+ [CellBackgroundShape.ThoughtBubble]: 'Thought Bubble',
39
+ [CellBackgroundShape.Star]: 'Star',
40
+ [CellBackgroundShape.Circle]: 'Circle',
41
+ [CellBackgroundShape.ColouredCorner]: 'Coloured Corner',
42
+ };
43
+ /**
44
+ * Default Grid3 styles for common use cases
45
+ * Colors are in 8-digit ARGB hex format (#AARRGGBBFF)
46
+ */
47
+ export const DEFAULT_GRID3_STYLES = {
48
+ Default: {
49
+ BackColour: '#E2EDF8FF',
50
+ TileColour: '#FFFFFFFF',
51
+ BorderColour: '#000000FF',
52
+ FontColour: '#000000FF',
53
+ FontName: 'Arial',
54
+ FontSize: '16',
55
+ },
56
+ Workspace: {
57
+ BackColour: '#FFFFFFFF',
58
+ TileColour: '#FFFFFFFF',
59
+ BorderColour: '#CCCCCCFF',
60
+ FontColour: '#000000FF',
61
+ FontName: 'Arial',
62
+ FontSize: '14',
63
+ },
64
+ 'Auto content': {
65
+ BackColour: '#E8F4F8FF',
66
+ TileColour: '#E8F4F8FF',
67
+ BorderColour: '#2C82C9FF',
68
+ FontColour: '#000000FF',
69
+ FontName: 'Arial',
70
+ FontSize: '14',
71
+ },
72
+ 'Vocab cell': {
73
+ BackColour: '#E8F4F8FF',
74
+ TileColour: '#E8F4F8FF',
75
+ BorderColour: '#2C82C9FF',
76
+ FontColour: '#000000FF',
77
+ FontName: 'Arial',
78
+ FontSize: '14',
79
+ },
80
+ 'Keyboard key': {
81
+ BackColour: '#F0F0F0FF',
82
+ TileColour: '#F0F0F0FF',
83
+ BorderColour: '#808080FF',
84
+ FontColour: '#000000FF',
85
+ FontName: 'Arial',
86
+ FontSize: '12',
87
+ },
88
+ };
89
+ /**
90
+ * Category-specific styles for navigation and organization
91
+ */
92
+ export const CATEGORY_STYLES = {
93
+ 'Actions category style': {
94
+ BackColour: '#4472C4FF',
95
+ TileColour: '#4472C4FF',
96
+ BorderColour: '#2F5496FF',
97
+ FontColour: '#FFFFFFFF',
98
+ FontName: 'Arial',
99
+ FontSize: '16',
100
+ },
101
+ 'People category style': {
102
+ BackColour: '#ED7D31FF',
103
+ TileColour: '#ED7D31FF',
104
+ BorderColour: '#C65911FF',
105
+ FontColour: '#FFFFFFFF',
106
+ FontName: 'Arial',
107
+ FontSize: '16',
108
+ },
109
+ 'Places category style': {
110
+ BackColour: '#A5A5A5FF',
111
+ TileColour: '#A5A5A5FF',
112
+ BorderColour: '#595959FF',
113
+ FontColour: '#FFFFFFFF',
114
+ FontName: 'Arial',
115
+ FontSize: '16',
116
+ },
117
+ 'Descriptive category style': {
118
+ BackColour: '#70AD47FF',
119
+ TileColour: '#70AD47FF',
120
+ BorderColour: '#4F7C2FFF',
121
+ FontColour: '#FFFFFFFF',
122
+ FontName: 'Arial',
123
+ FontSize: '16',
124
+ },
125
+ 'Social category style': {
126
+ BackColour: '#FFC000FF',
127
+ TileColour: '#FFC000FF',
128
+ BorderColour: '#BF8F00FF',
129
+ FontColour: '#000000FF',
130
+ FontName: 'Arial',
131
+ FontSize: '16',
132
+ },
133
+ 'Questions category style': {
134
+ BackColour: '#5B9BD5FF',
135
+ TileColour: '#5B9BD5FF',
136
+ BorderColour: '#2E5C8AFF',
137
+ FontColour: '#FFFFFFFF',
138
+ FontName: 'Arial',
139
+ FontSize: '16',
140
+ },
141
+ 'Little words category style': {
142
+ BackColour: '#C55A11FF',
143
+ TileColour: '#C55A11FF',
144
+ BorderColour: '#8B3F0AFF',
145
+ FontColour: '#FFFFFFFF',
146
+ FontName: 'Arial',
147
+ FontSize: '16',
148
+ },
149
+ };
150
+ /**
151
+ * Re-export ensureAlphaChannel from colorUtils for backward compatibility
152
+ * @deprecated Use ensureAlphaChannel from colorUtils instead
153
+ */
154
+ export { ensureAlphaChannel } from './colorUtils';
155
+ /**
156
+ * Create a Grid3 style XML string with default and category styles
157
+ * @param includeCategories - Whether to include category-specific styles (default: true)
158
+ * @returns XML string for Settings0/styles.xml
159
+ */
160
+ export function createDefaultStylesXml(includeCategories = true) {
161
+ const builder = new XMLBuilder({
162
+ ignoreAttributes: false,
163
+ format: true,
164
+ indentBy: ' ',
165
+ });
166
+ const styles = { ...DEFAULT_GRID3_STYLES };
167
+ if (includeCategories) {
168
+ Object.assign(styles, CATEGORY_STYLES);
169
+ }
170
+ const styleArray = Object.entries(styles).map(([key, style]) => ({
171
+ '@_Key': key,
172
+ BackColour: style.BackColour,
173
+ TileColour: style.TileColour,
174
+ BorderColour: style.BorderColour,
175
+ FontColour: style.FontColour,
176
+ FontName: style.FontName,
177
+ FontSize: style.FontSize?.toString(),
178
+ }));
179
+ const stylesData = {
180
+ StyleData: {
181
+ '@_xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
182
+ Styles: {
183
+ Style: styleArray,
184
+ },
185
+ },
186
+ };
187
+ return builder.build(stylesData);
188
+ }
189
+ /**
190
+ * Create a custom category style
191
+ * @param categoryName - Name of the category
192
+ * @param backgroundColor - Background color in hex format
193
+ * @param fontColor - Font color in hex format (default: white)
194
+ * @returns Grid3Style object
195
+ */
196
+ export function createCategoryStyle(categoryName, backgroundColor, fontColor = '#FFFFFFFF') {
197
+ return {
198
+ BackColour: ensureAlphaChannel(backgroundColor),
199
+ TileColour: ensureAlphaChannel(backgroundColor),
200
+ BorderColour: ensureAlphaChannel(darkenColor(backgroundColor, 30)),
201
+ FontColour: ensureAlphaChannel(fontColor),
202
+ FontName: 'Arial',
203
+ FontSize: '16',
204
+ };
205
+ }