Skip to content

Commit a14f12f

Browse files
committed
Enhance Grid 3 symbol library and color utilities support
Fixed import error in src/processors/index.ts - isSymbolLibraryReference and parseImageSymbolReference are exported from resolver.ts, not symbols.ts 3. Fixed self-reference bug in src/processors/gridsetProcessor.ts - removed ...button?.parameters that referenced the variable being created 4. Added missing constructor parameters to AACButton class in src/core/treeStructure.ts for symbolLibrary and symbolPath 5. Fixed resolver logic in src/processors/gridset/resolver.ts - restructured the check to ensure [grid3x] built-in resources use the builtinHandler before treating them as symbol library references
1 parent da1b836 commit a14f12f

6 files changed

Lines changed: 110 additions & 40 deletions

File tree

src/core/baseProcessor.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ export interface ProcessorOptions {
1616

1717
// Preserve original behavior for backwards compatibility
1818
preserveAllButtons?: boolean;
19+
20+
// Grid 3 symbol library directory (for resolving [widgit]/ style references)
21+
// If not specified, will attempt to auto-detect from Grid 3 installation
22+
grid3SymbolDir?: string;
23+
24+
// Grid 3 installation path (for auto-detecting symbol directory)
25+
// If not specified, will use default platform-specific path
26+
grid3Path?: string;
27+
28+
// Locale for symbol libraries (e.g., 'en-GB', 'en-US')
29+
// Defaults to 'en-GB' if not specified
30+
grid3Locale?: string;
1931
}
2032

2133
// Types for aac-tools-platform compatibility

src/core/treeStructure.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ export class AACButton implements IAACButton {
156156
contentSubType,
157157
image,
158158
resolvedImageEntry,
159+
symbolLibrary,
160+
symbolPath,
159161
x,
160162
y,
161163
columnSpan,
@@ -184,6 +186,8 @@ export class AACButton implements IAACButton {
184186
contentSubType?: string;
185187
image?: string;
186188
resolvedImageEntry?: string;
189+
symbolLibrary?: string;
190+
symbolPath?: string;
187191
x?: number;
188192
y?: number;
189193
columnSpan?: number;
@@ -211,6 +215,8 @@ export class AACButton implements IAACButton {
211215
this.contentSubType = contentSubType;
212216
this.image = image;
213217
this.resolvedImageEntry = resolvedImageEntry;
218+
this.symbolLibrary = symbolLibrary;
219+
this.symbolPath = symbolPath;
214220
this.x = x;
215221
this.y = y;
216222
this.columnSpan = columnSpan;

src/processors/gridset/colorUtils.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,42 @@ export function darkenColor(hex: string, amount: number): string {
289289
return `#${channelToHex(newR)}${channelToHex(newG)}${channelToHex(newB)}${alpha.toUpperCase()}`;
290290
}
291291

292+
/**
293+
* Lighten a hex color by a specified amount
294+
* @param hex - Hex color string
295+
* @param amount - Amount to lighten (0-255)
296+
* @returns Lightened hex color
297+
*/
298+
export function lightenColor(hex: string, amount: number): string {
299+
const normalized = ensureAlphaChannel(hex).substring(1); // strip #
300+
const rgb = normalized.substring(0, 6);
301+
const alpha = normalized.substring(6) || 'FF';
302+
const r = parseInt(rgb.substring(0, 2), 16);
303+
const g = parseInt(rgb.substring(2, 4), 16);
304+
const b = parseInt(rgb.substring(4, 6), 16);
305+
const clamp = (val: number): number => Math.max(0, Math.min(255, val));
306+
const newR = clamp(r + amount);
307+
const newG = clamp(g + amount);
308+
const newB = clamp(b + amount);
309+
return `#${channelToHex(newR)}${channelToHex(newG)}${channelToHex(newB)}${alpha.toUpperCase()}`;
310+
}
311+
312+
/**
313+
* Convert hex color to RGBA object
314+
* @param hex - Hex color string (#RRGGBB or #RRGGBBAA)
315+
* @returns RGBA object with r, g, b, a properties (0-1 for alpha)
316+
*/
317+
export function hexToRgba(hex: string): { r: number; g: number; b: number; a: number } {
318+
const normalized = ensureAlphaChannel(hex).substring(1); // strip #
319+
const rgb = normalized.substring(0, 6);
320+
const alphaHex = normalized.substring(6) || 'FF';
321+
const r = parseInt(rgb.substring(0, 2), 16);
322+
const g = parseInt(rgb.substring(2, 4), 16);
323+
const b = parseInt(rgb.substring(4, 6), 16);
324+
const a = parseInt(alphaHex, 16) / 255;
325+
return { r, g, b, a };
326+
}
327+
292328
/**
293329
* Normalize any color format to Grid3's 8-digit hex format
294330
* @param input - Color string in any supported format

src/processors/gridset/resolver.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isSymbolReference, parseSymbolReference, type SymbolReference } from './symbols';
1+
import { isSymbolReference, parseSymbolReference } from './symbols';
22

33
function normalizeZipPathLocal(p: string): string {
44
const unified = p.replace(/\\/g, '/');
@@ -57,16 +57,22 @@ export function resolveGrid3CellImage(
5757
const entries = new Set(listZipEntries(zip, zipEntries));
5858
const has = (p: string): boolean => entries.has(normalizeZipPathLocal(p));
5959

60-
// Check for symbol library reference like [widgit]/food/apple.png
61-
if (imageName && isSymbolReference(imageName)) {
62-
// Symbol library references are NOT stored as files in the gridset
63-
// They are resolved from the external Grid 3 installation
64-
// Return null to indicate this is an external symbol reference
65-
return null;
66-
}
67-
6860
// Built-in resource like [grid3x]... (old format, not symbol library)
61+
// Check this BEFORE general symbol references to avoid misclassification
6962
if (imageName && imageName.startsWith('[')) {
63+
// Check if it's a symbol library reference like [widgit]/food/apple.png
64+
// Symbol library references have a path after the library name
65+
if (isSymbolReference(imageName)) {
66+
const parsed = parseSymbolReference(imageName);
67+
// If it's grid3x, it's a built-in resource, not a symbol library
68+
if (parsed.library !== 'grid3x') {
69+
// Symbol library references are NOT stored as files in the gridset
70+
// They are resolved from the external Grid 3 installation
71+
// Return null to indicate this is an external symbol reference
72+
return null;
73+
}
74+
}
75+
// For grid3x and other built-in resources, use the builtinHandler
7076
if (args.builtinHandler) {
7177
const mapped = args.builtinHandler(imageName);
7278
if (mapped) return mapped;
@@ -135,7 +141,7 @@ export function isSymbolLibraryReference(imageName?: string): boolean {
135141
* @param imageName - Image reference from Grid 3
136142
* @returns Parsed reference or null if not a symbol reference
137143
*/
138-
export function parseImageSymbolReference(imageName: string): SymbolReference | null {
144+
export function parseImageSymbolReference(imageName: string) {
139145
if (!isSymbolLibraryReference(imageName)) {
140146
return null;
141147
}

src/processors/gridsetProcessor.ts

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,27 @@ import zlib from 'zlib';
2424
import { GridsetValidator } from '../validation/gridsetValidator';
2525
import { ValidationResult } from '../validation/validationTypes';
2626
// New imports for enhanced Grid 3 support
27-
import { detectPluginCellType, Grid3CellType } from './gridset/pluginTypes';
28-
import { detectCommand } from './gridset/commands';
29-
import { parseSymbolReference, type SymbolReference } from './gridset/symbols';
30-
import { isSymbolLibraryReference } from './gridset/resolver';
27+
import { CellBackgroundShape } from './gridset/styleHelpers';
28+
import { detectPluginCellType, Grid3PluginMetadata, Grid3CellType } from './gridset/pluginTypes';
29+
import {
30+
detectCommand,
31+
getCommandDefinition,
32+
Grid3CommandCategory,
33+
GRID3_COMMANDS,
34+
getAllCommandIds,
35+
getAllPluginIds,
36+
} from './gridset/commands';
37+
import {
38+
isSymbolReference,
39+
parseSymbolReference,
40+
resolveSymbolReference,
41+
getSymbolLibraryDisplayName,
42+
type SymbolReference,
43+
} from './gridset/symbols';
44+
import {
45+
isSymbolLibraryReference,
46+
parseImageSymbolReference,
47+
} from './gridset/resolver';
3148

3249
class GridsetProcessor extends BaseProcessor {
3350
constructor(options?: ProcessorOptions) {
@@ -282,10 +299,9 @@ class GridsetProcessor extends BaseProcessor {
282299
fontColor: grid3Style.FontColour,
283300
fontFamily: grid3Style.FontName,
284301
fontSize: grid3Style.FontSize ? parseInt(String(grid3Style.FontSize)) : undefined,
285-
backgroundShape:
286-
grid3Style.BackgroundShape !== undefined
287-
? parseInt(String(grid3Style.BackgroundShape))
288-
: undefined,
302+
backgroundShape: grid3Style.BackgroundShape !== undefined
303+
? parseInt(String(grid3Style.BackgroundShape))
304+
: undefined,
289305
};
290306
}
291307

@@ -583,7 +599,7 @@ class GridsetProcessor extends BaseProcessor {
583599

584600
if (commands) {
585601
const commandArr = Array.isArray(commands) ? commands : [commands];
586-
detectedCommands = commandArr.map((cmd) => detectCommand(cmd));
602+
detectedCommands = commandArr.map(cmd => detectCommand(cmd));
587603

588604
for (const command of commandArr) {
589605
const commandId = command['@_ID'] || command.ID || command.id;
@@ -993,18 +1009,14 @@ class GridsetProcessor extends BaseProcessor {
9931009
y: cellY,
9941010
columnSpan: colSpan,
9951011
rowSpan: rowSpan,
996-
contentType:
997-
pluginMetadata.cellType === Grid3CellType.Regular
998-
? 'Normal'
999-
: pluginMetadata.cellType === Grid3CellType.Workspace
1000-
? 'Workspace'
1001-
: pluginMetadata.cellType === Grid3CellType.LiveCell
1002-
? 'LiveCell'
1003-
: 'AutoContent',
1004-
contentSubType:
1005-
pluginMetadata.subType ||
1006-
pluginMetadata.liveCellType ||
1007-
pluginMetadata.autoContentType,
1012+
contentType: pluginMetadata.cellType === Grid3CellType.Regular
1013+
? 'Normal'
1014+
: pluginMetadata.cellType === Grid3CellType.Workspace
1015+
? 'Workspace'
1016+
: pluginMetadata.cellType === Grid3CellType.LiveCell
1017+
? 'LiveCell'
1018+
: 'AutoContent',
1019+
contentSubType: pluginMetadata.subType || pluginMetadata.liveCellType || pluginMetadata.autoContentType,
10081020
symbolLibrary: symbolLibraryRef?.library || undefined,
10091021
symbolPath: symbolLibraryRef?.path || undefined,
10101022
style: {
@@ -1019,7 +1031,7 @@ class GridsetProcessor extends BaseProcessor {
10191031
});
10201032

10211033
// Add button to page
1022-
page.addButton(button as AACButton);
1034+
page.addButton(button);
10231035

10241036
// Place button in grid layout (handle colspan/rowspan)
10251037
for (let r = cellY; r < cellY + rowSpan && r < maxRows; r++) {

src/processors/index.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export {
4848
readGrid3HistoryForUser as readGridsetHistoryForUser,
4949
readAllGrid3History as readAllGridsetHistory,
5050
} from './gridset/helpers';
51+
export { resolveGrid3CellImage } from './gridset/resolver';
5152

5253
// Gridset (Grid 3) wordlist helpers
5354
export {
@@ -140,16 +141,13 @@ export {
140141
symbolReferenceToFilename,
141142
SYMBOL_LIBRARIES,
142143
} from './gridset/symbols';
143-
144-
// Gridset image resolution helpers
145-
export {
146-
resolveGrid3CellImage,
147-
isSymbolLibraryReference,
148-
parseImageSymbolReference,
149-
} from './gridset/resolver';
144+
export { isSymbolLibraryReference, parseImageSymbolReference } from './gridset/resolver';
150145

151146
// Backward compatibility
152-
export { getSymbolsDir, getSymbolSearchDir } from './gridset/symbols';
147+
export {
148+
getSymbolsDir,
149+
getSymbolSearchDir,
150+
} from './gridset/symbols';
153151

154152
// Gridset (Grid 3) symbol extraction for conversion
155153
export {

0 commit comments

Comments
 (0)