@rafters/shared 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/LICENSE +21 -0
- package/README.md +121 -0
- package/package.json +43 -0
- package/src/component-intelligence.ts +477 -0
- package/src/fill-signature.ts +217 -0
- package/src/import-pending.ts +210 -0
- package/src/index.ts +5 -0
- package/src/types.ts +651 -0
- package/src/version.ts +7 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rafters/shared - W3C DTCG Types
|
|
3
|
+
* Core type definitions for Rafters design system following W3C Design Token Community Group spec
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Signal to clear an override and revert to computed value.
|
|
10
|
+
* Use with registry.set(tokenName, COMPUTED) to let the system decide.
|
|
11
|
+
*/
|
|
12
|
+
declare const computedBrand: unique symbol;
|
|
13
|
+
export const COMPUTED: typeof computedBrand = Symbol.for(
|
|
14
|
+
'rafters.computed',
|
|
15
|
+
) as typeof computedBrand;
|
|
16
|
+
export type ComputedSymbol = typeof COMPUTED;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* OKLCH Color Space
|
|
20
|
+
* Perceptually uniform color space based on human vision
|
|
21
|
+
* https://www.w3.org/TR/css-color-4/#ok-lab
|
|
22
|
+
*/
|
|
23
|
+
export const OKLCHSchema = z.object({
|
|
24
|
+
/** Lightness: 0 (black) to 1 (white) */
|
|
25
|
+
l: z.number().min(0).max(1),
|
|
26
|
+
/** Chroma: 0 (gray) to ~0.4 (vivid) - no theoretical max */
|
|
27
|
+
c: z.number().min(0),
|
|
28
|
+
/** Hue: 0-360 degrees (red=0, yellow=90, green=150, cyan=180, blue=270, magenta=330) */
|
|
29
|
+
h: z.number().min(0).max(360),
|
|
30
|
+
/** Alpha transparency: 0 (transparent) to 1 (opaque) */
|
|
31
|
+
alpha: z.number().min(0).max(1).optional().default(1),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export type OKLCH = z.infer<typeof OKLCHSchema>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* W3C DTCG Token Base
|
|
38
|
+
* All design tokens follow this structure
|
|
39
|
+
* https://design-tokens.github.io/community-group/format/
|
|
40
|
+
*/
|
|
41
|
+
export const DTCGTokenBaseSchema = z.object({
|
|
42
|
+
/** Required: The token's value */
|
|
43
|
+
$value: z.unknown(),
|
|
44
|
+
/** Token type - helps tools understand how to use the value */
|
|
45
|
+
$type: z
|
|
46
|
+
.enum([
|
|
47
|
+
'color',
|
|
48
|
+
'dimension',
|
|
49
|
+
'fontFamily',
|
|
50
|
+
'fontWeight',
|
|
51
|
+
'duration',
|
|
52
|
+
'cubicBezier',
|
|
53
|
+
'number',
|
|
54
|
+
'strokeStyle',
|
|
55
|
+
'border',
|
|
56
|
+
'transition',
|
|
57
|
+
'shadow',
|
|
58
|
+
'gradient',
|
|
59
|
+
'typography',
|
|
60
|
+
])
|
|
61
|
+
.optional(),
|
|
62
|
+
/** Human-readable description */
|
|
63
|
+
$description: z.string().optional(),
|
|
64
|
+
/** Deprecation marker - boolean or string explaining why */
|
|
65
|
+
$deprecated: z.union([z.boolean(), z.string()]).optional(),
|
|
66
|
+
/** Vendor-specific metadata */
|
|
67
|
+
$extensions: z.record(z.string(), z.unknown()).optional(),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export type DTCGTokenBase = z.infer<typeof DTCGTokenBaseSchema>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* W3C DTCG Color Value (OKLCH format)
|
|
74
|
+
*/
|
|
75
|
+
export const DTCGColorValueSchema = z.object({
|
|
76
|
+
colorSpace: z.literal('oklch'),
|
|
77
|
+
channels: z.tuple([
|
|
78
|
+
z.number().min(0).max(1), // Lightness
|
|
79
|
+
z.number().min(0), // Chroma
|
|
80
|
+
z.number().min(0).max(360), // Hue
|
|
81
|
+
]),
|
|
82
|
+
alpha: z.number().min(0).max(1).optional().default(1),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export type DTCGColorValue = z.infer<typeof DTCGColorValueSchema>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* W3C DTCG Color Token
|
|
89
|
+
*/
|
|
90
|
+
export const DTCGColorTokenSchema = DTCGTokenBaseSchema.extend({
|
|
91
|
+
$value: z.union([
|
|
92
|
+
DTCGColorValueSchema, // Explicit OKLCH
|
|
93
|
+
z.string().regex(/^\{[^{}]+\}$/), // Reference: {color.primary.500}
|
|
94
|
+
]),
|
|
95
|
+
$type: z.literal('color'),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
export type DTCGColorToken = z.infer<typeof DTCGColorTokenSchema>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* W3C DTCG Group
|
|
102
|
+
* Groups organize tokens hierarchically
|
|
103
|
+
*/
|
|
104
|
+
export type DTCGGroup = {
|
|
105
|
+
$type?: string | undefined;
|
|
106
|
+
$description?: string | undefined;
|
|
107
|
+
$deprecated?: boolean | string | undefined;
|
|
108
|
+
$extensions?: Record<string, unknown> | undefined;
|
|
109
|
+
[key: string]: DTCGTokenBase | DTCGGroup | string | boolean | unknown;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const DTCGGroupSchema: z.ZodType<DTCGGroup> = z
|
|
113
|
+
.object({
|
|
114
|
+
$type: z.string().optional(),
|
|
115
|
+
$description: z.string().optional(),
|
|
116
|
+
$deprecated: z.union([z.boolean(), z.string()]).optional(),
|
|
117
|
+
$extensions: z.record(z.string(), z.unknown()).optional(),
|
|
118
|
+
})
|
|
119
|
+
.catchall(z.lazy(() => z.union([DTCGTokenBaseSchema, DTCGGroupSchema])));
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Complete DTCG Design Token File
|
|
123
|
+
*/
|
|
124
|
+
export const DTCGFileSchema = z.record(z.string(), z.union([DTCGTokenBaseSchema, DTCGGroupSchema]));
|
|
125
|
+
|
|
126
|
+
export type DTCGFile = z.infer<typeof DTCGFileSchema>;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Helper: Convert OKLCH to DTCG Color Value
|
|
130
|
+
*/
|
|
131
|
+
export function oklchToDTCG(oklch: OKLCH): DTCGColorValue {
|
|
132
|
+
return {
|
|
133
|
+
colorSpace: 'oklch',
|
|
134
|
+
channels: [oklch.l, oklch.c, oklch.h],
|
|
135
|
+
alpha: oklch.alpha ?? 1,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Helper: Convert DTCG Color Value to OKLCH
|
|
141
|
+
*/
|
|
142
|
+
export function dtcgToOKLCH(dtcg: DTCGColorValue): OKLCH {
|
|
143
|
+
return {
|
|
144
|
+
l: dtcg.channels[0],
|
|
145
|
+
c: dtcg.channels[1],
|
|
146
|
+
h: dtcg.channels[2],
|
|
147
|
+
alpha: dtcg.alpha ?? 1,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Rafters Intelligence Types
|
|
153
|
+
* Extended schemas for AI-readable design intelligence
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
// Color Vision Types for accessibility
|
|
157
|
+
export const ColorVisionTypeSchema = z.enum([
|
|
158
|
+
'normal',
|
|
159
|
+
'deuteranopia', // Red-green (most common)
|
|
160
|
+
'protanopia', // Red-green
|
|
161
|
+
'tritanopia', // Blue-yellow (rare)
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
export type ColorVisionType = z.infer<typeof ColorVisionTypeSchema>;
|
|
165
|
+
|
|
166
|
+
// Accessibility Contrast Levels
|
|
167
|
+
export const ContrastLevelSchema = z.enum(['AA', 'AAA']);
|
|
168
|
+
|
|
169
|
+
export type ContrastLevel = z.infer<typeof ContrastLevelSchema>;
|
|
170
|
+
|
|
171
|
+
// Component Intelligence for AI consumption
|
|
172
|
+
export const ComponentIntelligenceSchema = z.object({
|
|
173
|
+
cognitiveLoad: z.number().min(1).max(5), // 1=simple, 5=complex
|
|
174
|
+
attentionHierarchy: z.string(), // How this component fits in attention economy
|
|
175
|
+
safetyConstraints: z.string().optional(), // Safety patterns required (e.g., confirmation)
|
|
176
|
+
accessibilityRules: z.string(), // WCAG compliance requirements
|
|
177
|
+
usageContext: z.string(), // When/where to use this component
|
|
178
|
+
decisionConstraints: z.string().optional(), // AI decision-making constraints
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
export type ComponentIntelligence = z.infer<typeof ComponentIntelligenceSchema>;
|
|
182
|
+
|
|
183
|
+
// CVA (class-variance-authority) intelligence schemas
|
|
184
|
+
export const ClassMappingSchema = z.object({
|
|
185
|
+
propName: z.string(),
|
|
186
|
+
values: z.record(z.string(), z.array(z.string())),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
export const CVAIntelligenceSchema = z
|
|
190
|
+
.object({
|
|
191
|
+
baseClasses: z.array(z.string()),
|
|
192
|
+
propMappings: z.array(ClassMappingSchema),
|
|
193
|
+
allClasses: z.array(z.string()),
|
|
194
|
+
css: z.string().optional(), // Generated critical CSS for preview component
|
|
195
|
+
})
|
|
196
|
+
.optional();
|
|
197
|
+
|
|
198
|
+
export type ClassMapping = z.infer<typeof ClassMappingSchema>;
|
|
199
|
+
export type CVAIntelligence = z.infer<typeof CVAIntelligenceSchema>;
|
|
200
|
+
|
|
201
|
+
// CVA structure for preview rendering (without optional css field)
|
|
202
|
+
export const PreviewCVASchema = z.object({
|
|
203
|
+
baseClasses: z.array(z.string()),
|
|
204
|
+
propMappings: z.array(ClassMappingSchema),
|
|
205
|
+
allClasses: z.array(z.string()),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
export type PreviewCVA = z.infer<typeof PreviewCVASchema>;
|
|
209
|
+
|
|
210
|
+
// Rafters intelligence schemas for CLI compatibility
|
|
211
|
+
export const IntelligenceSchema = z.object({
|
|
212
|
+
cognitiveLoad: z.number().min(0).max(10),
|
|
213
|
+
attentionEconomics: z.string(),
|
|
214
|
+
accessibility: z.string(),
|
|
215
|
+
trustBuilding: z.string(),
|
|
216
|
+
semanticMeaning: z.string(),
|
|
217
|
+
cva: CVAIntelligenceSchema,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
export const UsagePatternsSchema = z.object({
|
|
221
|
+
dos: z.array(z.string()),
|
|
222
|
+
nevers: z.array(z.string()),
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
export const DesignGuideSchema = z.object({
|
|
226
|
+
name: z.string(),
|
|
227
|
+
url: z.string(),
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
export const ExampleSchema = z.object({
|
|
231
|
+
title: z.string().optional(),
|
|
232
|
+
code: z.string(),
|
|
233
|
+
description: z.string().optional(),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
export type UsagePatterns = z.infer<typeof UsagePatternsSchema>;
|
|
237
|
+
export type DesignGuide = z.infer<typeof DesignGuideSchema>;
|
|
238
|
+
export type Example = z.infer<typeof ExampleSchema>;
|
|
239
|
+
export type Intelligence = z.infer<typeof IntelligenceSchema>;
|
|
240
|
+
|
|
241
|
+
// Color Intelligence Schema (from API with uncertainty quantification)
|
|
242
|
+
// Note: Color naming is now deterministic via generateColorName() in @rafters/color-utils
|
|
243
|
+
export const ColorIntelligenceSchema = z.object({
|
|
244
|
+
// Designer-facing evocative handle ("Aged Terracotta", "Solar Citrine") from
|
|
245
|
+
// the intelligence generator. Language, not identity: the deterministic
|
|
246
|
+
// `name` on ColorValue is the stable, parseable address; `label` is the
|
|
247
|
+
// voice. Optional because pre-label intelligence persists in Vectorize and
|
|
248
|
+
// token files. Backported from platform's generateColorIntelligence, which
|
|
249
|
+
// requires it on generation.
|
|
250
|
+
label: z.string().optional(),
|
|
251
|
+
reasoning: z.string(),
|
|
252
|
+
emotionalImpact: z.string(),
|
|
253
|
+
culturalContext: z.string(),
|
|
254
|
+
accessibilityNotes: z.string(),
|
|
255
|
+
usageGuidance: z.string(),
|
|
256
|
+
balancingGuidance: z.string().optional(), // Based on perceptual weight
|
|
257
|
+
metadata: z
|
|
258
|
+
.object({
|
|
259
|
+
predictionId: z.string(),
|
|
260
|
+
confidence: z.number().min(0).max(1),
|
|
261
|
+
uncertaintyBounds: z.object({
|
|
262
|
+
lower: z.number().min(0).max(1),
|
|
263
|
+
upper: z.number().min(0).max(1),
|
|
264
|
+
confidenceInterval: z.number().min(0).max(1),
|
|
265
|
+
}),
|
|
266
|
+
qualityScore: z.number().min(0).max(1),
|
|
267
|
+
method: z.enum(['bootstrap', 'quantile', 'ensemble', 'bayesian', 'conformal']),
|
|
268
|
+
})
|
|
269
|
+
.optional(),
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
export type ColorIntelligence = z.infer<typeof ColorIntelligenceSchema>;
|
|
273
|
+
|
|
274
|
+
// Color Harmonies Schema (calculated by color-utils)
|
|
275
|
+
export const ColorHarmoniesSchema = z.object({
|
|
276
|
+
complementary: OKLCHSchema,
|
|
277
|
+
triadic: z.array(OKLCHSchema),
|
|
278
|
+
analogous: z.array(OKLCHSchema),
|
|
279
|
+
tetradic: z.array(OKLCHSchema),
|
|
280
|
+
splitComplementary: z.array(OKLCHSchema),
|
|
281
|
+
monochromatic: z.array(OKLCHSchema),
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
export type ColorHarmonies = z.infer<typeof ColorHarmoniesSchema>;
|
|
285
|
+
|
|
286
|
+
// Color Accessibility Schema (calculated by color-utils)
|
|
287
|
+
export const ColorAccessibilitySchema = z.object({
|
|
288
|
+
// Pre-computed contrast matrices (indices into scale array)
|
|
289
|
+
wcagAA: z
|
|
290
|
+
.object({
|
|
291
|
+
normal: z.array(z.array(z.number())), // [[0, 5], [0, 6], ...] - pairs that meet AA
|
|
292
|
+
large: z.array(z.array(z.number())), // [[0, 4], [0, 5], ...] - more pairs for large text
|
|
293
|
+
})
|
|
294
|
+
.optional(),
|
|
295
|
+
wcagAAA: z
|
|
296
|
+
.object({
|
|
297
|
+
normal: z.array(z.array(z.number())), // [[0, 7], [0, 8], ...] - fewer pairs meet AAA
|
|
298
|
+
large: z.array(z.array(z.number())), // [[0, 6], [0, 7], ...]
|
|
299
|
+
})
|
|
300
|
+
.optional(),
|
|
301
|
+
|
|
302
|
+
// Basic compatibility data for the base color
|
|
303
|
+
onWhite: z.object({
|
|
304
|
+
wcagAA: z.boolean(),
|
|
305
|
+
wcagAAA: z.boolean(),
|
|
306
|
+
contrastRatio: z.number(),
|
|
307
|
+
// Pre-computed indices for scale lookups
|
|
308
|
+
aa: z.array(z.number()).optional(), // [5, 6, 7, 8, 9] - shades that pass AA on white
|
|
309
|
+
aaa: z.array(z.number()).optional(), // [7, 8, 9] - shades that pass AAA on white
|
|
310
|
+
}),
|
|
311
|
+
onBlack: z.object({
|
|
312
|
+
wcagAA: z.boolean(),
|
|
313
|
+
wcagAAA: z.boolean(),
|
|
314
|
+
contrastRatio: z.number(),
|
|
315
|
+
// Pre-computed indices for scale lookups
|
|
316
|
+
aa: z.array(z.number()).optional(), // [0, 1, 2, 3, 4] - shades that pass AA on black
|
|
317
|
+
aaa: z.array(z.number()).optional(), // [0, 1, 2] - shades that pass AAA on black
|
|
318
|
+
}),
|
|
319
|
+
|
|
320
|
+
// APCA (Advanced Perceptual Contrast Algorithm) scores - Future WCAG 3.0
|
|
321
|
+
apca: z
|
|
322
|
+
.object({
|
|
323
|
+
onWhite: z.number(), // APCA contrast score on white background
|
|
324
|
+
onBlack: z.number(), // APCA contrast score on black background
|
|
325
|
+
minFontSize: z.number(), // Minimum font size in px from fontLookupAPCA
|
|
326
|
+
})
|
|
327
|
+
.optional(),
|
|
328
|
+
|
|
329
|
+
// Color Vision Deficiency simulations
|
|
330
|
+
cvd: z
|
|
331
|
+
.object({
|
|
332
|
+
deuteranopia: OKLCHSchema, // Red-green (most common) simulated appearance
|
|
333
|
+
protanopia: OKLCHSchema, // Red-green simulated appearance
|
|
334
|
+
tritanopia: OKLCHSchema, // Blue-yellow (rare) simulated appearance
|
|
335
|
+
})
|
|
336
|
+
.optional(),
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
export type ColorAccessibility = z.infer<typeof ColorAccessibilitySchema>;
|
|
340
|
+
|
|
341
|
+
// Color Analysis Schema (calculated by color-utils)
|
|
342
|
+
export const ColorAnalysisSchema = z.object({
|
|
343
|
+
temperature: z.enum(['warm', 'cool', 'neutral']),
|
|
344
|
+
isLight: z.boolean(),
|
|
345
|
+
name: z.string(),
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
export type ColorAnalysis = z.infer<typeof ColorAnalysisSchema>;
|
|
349
|
+
|
|
350
|
+
// Atmospheric Weight Schema (atmospheric perspective color theory)
|
|
351
|
+
export const AtmosphericWeightSchema = z.object({
|
|
352
|
+
distanceWeight: z.number().min(0).max(1), // 0 = background, 1 = foreground
|
|
353
|
+
temperature: z.enum(['warm', 'neutral', 'cool']),
|
|
354
|
+
atmosphericRole: z.enum(['background', 'midground', 'foreground']),
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
export type AtmosphericWeight = z.infer<typeof AtmosphericWeightSchema>;
|
|
358
|
+
|
|
359
|
+
// Perceptual Weight Schema (visual balance in UI layouts)
|
|
360
|
+
export const PerceptualWeightSchema = z.object({
|
|
361
|
+
weight: z.number().min(0).max(1), // 0-1, higher = more visual weight
|
|
362
|
+
density: z.enum(['light', 'medium', 'heavy']),
|
|
363
|
+
balancingRecommendation: z.string(),
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
export type PerceptualWeight = z.infer<typeof PerceptualWeightSchema>;
|
|
367
|
+
|
|
368
|
+
// Status roles for semantic color suggestions. 'destructive' is canonical
|
|
369
|
+
// (matches colorWheel and the exporter's token vocabulary). Persisted files
|
|
370
|
+
// and the API may still carry the legacy 'danger' key; the schema lifts it.
|
|
371
|
+
export const SEMANTIC_STATUS_ROLES = ['destructive', 'success', 'warning', 'info'] as const;
|
|
372
|
+
export type SemanticStatusRole = (typeof SEMANTIC_STATUS_ROLES)[number];
|
|
373
|
+
|
|
374
|
+
// Semantic Color Suggestions Schema.
|
|
375
|
+
// 'danger' is a deprecated mirror of 'destructive', kept while apps/api (which
|
|
376
|
+
// asserts .danger) migrates to platform. Inputs with only the legacy key parse
|
|
377
|
+
// cleanly; outputs carry both until the mirror is removed.
|
|
378
|
+
export const SemanticColorSuggestionsSchema = z.preprocess(
|
|
379
|
+
(raw) => {
|
|
380
|
+
if (raw && typeof raw === 'object' && !('destructive' in raw) && 'danger' in raw) {
|
|
381
|
+
return { ...raw, destructive: (raw as { danger: unknown }).danger };
|
|
382
|
+
}
|
|
383
|
+
return raw;
|
|
384
|
+
},
|
|
385
|
+
z.object({
|
|
386
|
+
destructive: z.array(OKLCHSchema),
|
|
387
|
+
success: z.array(OKLCHSchema),
|
|
388
|
+
warning: z.array(OKLCHSchema),
|
|
389
|
+
info: z.array(OKLCHSchema),
|
|
390
|
+
/** @deprecated mirror of `destructive`; dies when apps/api leaves the repo */
|
|
391
|
+
danger: z.array(OKLCHSchema).optional(),
|
|
392
|
+
}),
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
export type SemanticColorSuggestions = z.infer<typeof SemanticColorSuggestionsSchema>;
|
|
396
|
+
|
|
397
|
+
// Color Value Schema for complex color structures
|
|
398
|
+
export const ColorValueSchema = z.object({
|
|
399
|
+
name: z.string(), // the fancy name from color-utils, IE ocean-blue
|
|
400
|
+
scale: z.array(OKLCHSchema), // OKLCH values array [50, 100, 200...900] positions - index maps to standard scale
|
|
401
|
+
token: z.string().optional(), // the semantic assignment IE, primary
|
|
402
|
+
value: z.string().optional(), // the string of the position in the scale IE 400
|
|
403
|
+
use: z.string().optional(), // any reasons the human notes for the color choice and assignment
|
|
404
|
+
states: z.record(z.string(), z.string()).optional(), // { hover: "blue-900", focus: "blue-700", ... }
|
|
405
|
+
|
|
406
|
+
// Complete intelligence data (from /api/color-intel)
|
|
407
|
+
intelligence: ColorIntelligenceSchema.optional(),
|
|
408
|
+
harmonies: ColorHarmoniesSchema.optional(),
|
|
409
|
+
accessibility: ColorAccessibilitySchema.optional(),
|
|
410
|
+
analysis: ColorAnalysisSchema.optional(),
|
|
411
|
+
|
|
412
|
+
// Advanced color theory intelligence (calculated by color-utils)
|
|
413
|
+
atmosphericWeight: AtmosphericWeightSchema.optional(),
|
|
414
|
+
perceptualWeight: PerceptualWeightSchema.optional(),
|
|
415
|
+
semanticSuggestions: SemanticColorSuggestionsSchema.optional(),
|
|
416
|
+
|
|
417
|
+
// Unique token ID for quick color lookups (e.g., "color-0.500-0.120-240.0")
|
|
418
|
+
tokenId: z.string().optional(),
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
export type ColorValue = z.infer<typeof ColorValueSchema>;
|
|
422
|
+
|
|
423
|
+
// Color Reference Schema for semantic tokens that reference color families
|
|
424
|
+
export const ColorReferenceSchema = z.object({
|
|
425
|
+
family: z.string(), // "flipped-out-gray", "ocean-blue", etc.
|
|
426
|
+
position: z.string(), // "50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
export type ColorReference = z.infer<typeof ColorReferenceSchema>;
|
|
430
|
+
|
|
431
|
+
// Progression system labels stamped on tokens to record which math system
|
|
432
|
+
// produced them. Used only by TokenSchema below; the math-utils package
|
|
433
|
+
// carries the actual ratio definitions in DEFAULT_RATIOS. This array will be
|
|
434
|
+
// reshaped when the design-tokens package is refactored.
|
|
435
|
+
export const PROGRESSION_SYSTEMS = [
|
|
436
|
+
'linear',
|
|
437
|
+
'golden',
|
|
438
|
+
'major-third',
|
|
439
|
+
'minor-third',
|
|
440
|
+
'perfect-fourth',
|
|
441
|
+
'perfect-fifth',
|
|
442
|
+
'augmented-fourth',
|
|
443
|
+
'major-second',
|
|
444
|
+
'minor-second',
|
|
445
|
+
'custom',
|
|
446
|
+
] as const;
|
|
447
|
+
|
|
448
|
+
// Binding: typed reference to the plugin + input that produces a token's value.
|
|
449
|
+
// When present on a Token, the registry resolves the value via the named plugin
|
|
450
|
+
// instead of treating the token as a leaf. The plugin name is opaque to the
|
|
451
|
+
// schema; the registry resolves it against its plugin map.
|
|
452
|
+
export const BindingSchema = z.object({
|
|
453
|
+
plugin: z.string(),
|
|
454
|
+
input: z.unknown(),
|
|
455
|
+
});
|
|
456
|
+
export type Binding = z.infer<typeof BindingSchema>;
|
|
457
|
+
|
|
458
|
+
// Override provenance: WHO put the value there, as a machine-readable kind
|
|
459
|
+
// rather than a free-text convention on the reason string.
|
|
460
|
+
// baseline -- the generated system value, restated as an explicit override
|
|
461
|
+
// preset -- written by applying a Studio value-set
|
|
462
|
+
// designer -- a human decision; preset application must not clobber it
|
|
463
|
+
// Extension point: 'measured' / 'tuned' can join the enum later.
|
|
464
|
+
export const OVERRIDE_KINDS = ['baseline', 'preset', 'designer'] as const;
|
|
465
|
+
export const OverrideKindSchema = z.enum(OVERRIDE_KINDS);
|
|
466
|
+
export type OverrideKind = z.infer<typeof OverrideKindSchema>;
|
|
467
|
+
|
|
468
|
+
// Comprehensive Design Token Schema - Single Source of Truth
|
|
469
|
+
export const TokenSchema = z.object({
|
|
470
|
+
// Core token data
|
|
471
|
+
name: z.string(),
|
|
472
|
+
value: z.union([z.string(), ColorValueSchema, ColorReferenceSchema]), // String, ColorValue for families, or ColorReference for semantic
|
|
473
|
+
category: z.string(),
|
|
474
|
+
namespace: z.string(),
|
|
475
|
+
binding: BindingSchema.optional(), // Plugin binding for cascade-driven values
|
|
476
|
+
|
|
477
|
+
// Typography-specific properties
|
|
478
|
+
lineHeight: z.string().optional(),
|
|
479
|
+
|
|
480
|
+
// AI Intelligence (comprehensive)
|
|
481
|
+
semanticMeaning: z.string().optional(),
|
|
482
|
+
usageContext: z.array(z.string()).optional(),
|
|
483
|
+
trustLevel: z.enum(['low', 'medium', 'high', 'critical']).optional(),
|
|
484
|
+
cognitiveLoad: z.number().min(1).max(10).optional(),
|
|
485
|
+
accessibilityLevel: z.enum(['AA', 'AAA']).optional(),
|
|
486
|
+
consequence: z.enum(['reversible', 'significant', 'permanent', 'destructive']).optional(),
|
|
487
|
+
|
|
488
|
+
// Designer intent - captures WHY values deviate from computed defaults
|
|
489
|
+
// Git blame shows WHAT changed and WHEN; these fields explain the reasoning
|
|
490
|
+
appliesWhen: z.array(z.string()).optional(), // ["data-heavy interfaces", "dashboard contexts"]
|
|
491
|
+
usagePatterns: z
|
|
492
|
+
.object({
|
|
493
|
+
do: z.array(z.string()), // ["Use for primary actions", "Pair with muted backgrounds"]
|
|
494
|
+
never: z.array(z.string()), // ["Multiple primary buttons competing", "On busy backgrounds"]
|
|
495
|
+
})
|
|
496
|
+
.optional(),
|
|
497
|
+
|
|
498
|
+
// Human override tracking - enables undo and agent intelligence.
|
|
499
|
+
// Required on every token. Null = generated baseline (no designer override).
|
|
500
|
+
// Populated = designer has explicitly changed this value with documented intent.
|
|
501
|
+
// Null IS the signal that no override exists -- do not auto-fill with synthetic strings.
|
|
502
|
+
userOverride: z
|
|
503
|
+
.object({
|
|
504
|
+
// Value before override (for undo)
|
|
505
|
+
previousValue: z.union([z.string(), ColorValueSchema, ColorReferenceSchema]),
|
|
506
|
+
// Why was this overridden
|
|
507
|
+
reason: z.string(),
|
|
508
|
+
// Additional context (e.g. "Q1 marketing campaign", "accessibility audit")
|
|
509
|
+
context: z.string().optional(),
|
|
510
|
+
// Who attributed the value. The reason string is for humans; kind is what
|
|
511
|
+
// machines branch on (preset application skips kind === 'designer').
|
|
512
|
+
// Optional and never defaulted: absent means the provenance is unknown,
|
|
513
|
+
// which is the honest state of every override written before this field
|
|
514
|
+
// existed.
|
|
515
|
+
kind: OverrideKindSchema.optional(),
|
|
516
|
+
})
|
|
517
|
+
.nullable(),
|
|
518
|
+
|
|
519
|
+
// Computed value from generation rule (before any override)
|
|
520
|
+
// Stored so agents can see what the system WOULD produce vs what human chose
|
|
521
|
+
computedValue: z.union([z.string(), ColorValueSchema, ColorReferenceSchema]).optional(),
|
|
522
|
+
|
|
523
|
+
// Dependency tracking for automatic regeneration
|
|
524
|
+
dependsOn: z.array(z.string()).optional(), // Parent token(s) - empty = root token
|
|
525
|
+
generationRule: z.string().optional(), // How generated: "calc({base}*2)", "state:hover", etc
|
|
526
|
+
progressionSystem: z.enum(PROGRESSION_SYSTEMS).optional(), // Mathematical system used
|
|
527
|
+
scalePosition: z.number().optional(), // Position in color/spacing scale
|
|
528
|
+
mathRelationship: z.string().optional(), // Mathematical expression for calc() rules
|
|
529
|
+
|
|
530
|
+
// Responsive behavior (containerQueryAware is default true for modern tokens)
|
|
531
|
+
containerQueryAware: z.boolean().optional().default(true),
|
|
532
|
+
pointerTypeAware: z.boolean().optional(), // Adapts to fine/coarse pointer
|
|
533
|
+
reducedMotionAware: z.boolean().optional(), // Respects prefers-reduced-motion
|
|
534
|
+
viewportAware: z.boolean().optional(), // Should generate responsive variants
|
|
535
|
+
|
|
536
|
+
// Localization (MVP+1: RTL/LTR support, basic locale spacing)
|
|
537
|
+
textDirection: z.enum(['ltr', 'rtl', 'auto']).optional(),
|
|
538
|
+
localeAware: z.boolean().optional(), // Token varies by locale
|
|
539
|
+
|
|
540
|
+
// Component associations
|
|
541
|
+
applicableComponents: z.array(z.string()).optional(), // ["button", "input", "card"]
|
|
542
|
+
requiredForComponents: z.array(z.string()).optional(), // Critical dependencies
|
|
543
|
+
|
|
544
|
+
// Interaction patterns
|
|
545
|
+
interactionType: z.enum(['hover', 'focus', 'active', 'disabled', 'loading']).optional(),
|
|
546
|
+
animationSafe: z.boolean().optional(), // Safe for vestibular disorders
|
|
547
|
+
highContrastMode: z.string().optional(), // Value for high contrast mode
|
|
548
|
+
|
|
549
|
+
// Motion tokens (derived from spacing progression for cohesive feel)
|
|
550
|
+
motionIntent: z.enum(['enter', 'exit', 'emphasis', 'transition']).optional(),
|
|
551
|
+
easingCurve: z.tuple([z.number(), z.number(), z.number(), z.number()]).optional(), // cubicBezier [x1, y1, x2, y2]
|
|
552
|
+
easingName: z
|
|
553
|
+
.enum(['standard', 'enter', 'exit', 'linear', 'spring-smooth', 'spring-snappy'])
|
|
554
|
+
.optional(),
|
|
555
|
+
delayMs: z.number().optional(), // Delay before animation starts
|
|
556
|
+
|
|
557
|
+
// Keyframe tokens (CSS @keyframes content / animation step definitions)
|
|
558
|
+
keyframeName: z.string().optional(), // Name of the keyframe (e.g., "fade-in")
|
|
559
|
+
|
|
560
|
+
// Animation tokens (combine keyframe + duration + easing)
|
|
561
|
+
animationName: z.string().optional(), // Name of the animation (e.g., "fade-in")
|
|
562
|
+
animationDuration: z.string().optional(), // Duration (e.g., "150ms", "1s")
|
|
563
|
+
animationEasing: z.string().optional(), // Easing function CSS value
|
|
564
|
+
animationIterations: z.string().optional(), // Iteration count (e.g., "1", "infinite")
|
|
565
|
+
|
|
566
|
+
// Focus tokens (WCAG 2.2 compliance, derive from ring unless overridden)
|
|
567
|
+
focusRingWidth: z.string().optional(), // e.g., "2px", "3px"
|
|
568
|
+
focusRingColor: z.string().optional(), // Reference to ring token or override
|
|
569
|
+
focusRingOffset: z.string().optional(), // e.g., "2px"
|
|
570
|
+
focusRingStyle: z.enum(['solid', 'dashed', 'double']).optional(),
|
|
571
|
+
|
|
572
|
+
// Elevation (pairs depth with shadow, can be independent)
|
|
573
|
+
elevationLevel: z
|
|
574
|
+
.enum(['surface', 'raised', 'overlay', 'sticky', 'modal', 'popover', 'tooltip'])
|
|
575
|
+
.optional(),
|
|
576
|
+
shadowToken: z.string().optional(), // Reference to paired shadow token
|
|
577
|
+
|
|
578
|
+
// Export behavior
|
|
579
|
+
generateUtilityClass: z.boolean().optional(), // Should create @utility class
|
|
580
|
+
tailwindOverride: z.boolean().optional(), // Overrides default TW value
|
|
581
|
+
customPropertyOnly: z.boolean().optional(), // CSS var only, no utility
|
|
582
|
+
|
|
583
|
+
// Validation hints (for human Studio validation)
|
|
584
|
+
contrastRatio: z.number().optional(), // Pre-calculated contrast
|
|
585
|
+
touchTargetSize: z.number().optional(), // Pre-calculated size in px
|
|
586
|
+
motionDuration: z.number().optional(), // Duration in ms
|
|
587
|
+
|
|
588
|
+
// Design system relationships
|
|
589
|
+
pairedWith: z.array(z.string()).optional(), // Other tokens used together
|
|
590
|
+
conflictsWith: z.array(z.string()).optional(), // Tokens that shouldn't be used together
|
|
591
|
+
|
|
592
|
+
// Meta information
|
|
593
|
+
description: z.string().optional(),
|
|
594
|
+
deprecated: z.boolean().optional(),
|
|
595
|
+
version: z.string().optional(),
|
|
596
|
+
lastModified: z.string().optional(),
|
|
597
|
+
generatedAt: z.string().optional(), // ISO timestamp when token was generated
|
|
598
|
+
requiresConfirmation: z.boolean().optional(), // UI pattern requirement for destructive actions
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
export type Token = z.infer<typeof TokenSchema>;
|
|
602
|
+
|
|
603
|
+
// Extract TokenUsagePatterns type for convenience
|
|
604
|
+
export type TokenUsagePatterns = NonNullable<Token['usagePatterns']>;
|
|
605
|
+
|
|
606
|
+
// Legacy alias for backward compatibility
|
|
607
|
+
export const SemanticTokenSchema = TokenSchema;
|
|
608
|
+
export type SemanticToken = Token;
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Typography Element Override Schema
|
|
612
|
+
* Stores per-element typography overrides with why-gate provenance.
|
|
613
|
+
* When a designer overrides a specific element's typography (e.g. H3 uses
|
|
614
|
+
* title-medium but needs font-thin font-sans), this captures the override.
|
|
615
|
+
*/
|
|
616
|
+
export const TypographyElementOverrideSchema = z.object({
|
|
617
|
+
/** CSS element selector, e.g. 'h3' */
|
|
618
|
+
element: z.string().min(1),
|
|
619
|
+
/** Base role this element uses, e.g. 'title-medium' */
|
|
620
|
+
role: z.string().min(1),
|
|
621
|
+
/** Only the properties that differ from the role */
|
|
622
|
+
overrides: z.object({
|
|
623
|
+
fontFamily: z.string().optional(),
|
|
624
|
+
fontWeight: z.string().optional(),
|
|
625
|
+
fontSize: z.string().optional(),
|
|
626
|
+
lineHeight: z.string().optional(),
|
|
627
|
+
letterSpacing: z.string().optional(),
|
|
628
|
+
}),
|
|
629
|
+
/** Why-gate: reason for the override (required, non-empty) */
|
|
630
|
+
why: z.string().min(1, 'Why-gate required: provide a reason for this override'),
|
|
631
|
+
/** Who made the override */
|
|
632
|
+
who: z.string().min(1),
|
|
633
|
+
/** When the override was made (ISO timestamp) */
|
|
634
|
+
when: z.string(),
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
export type TypographyElementOverride = z.infer<typeof TypographyElementOverrideSchema>;
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Namespace File Schema
|
|
641
|
+
* File format for .rafters/tokens/{namespace}.rafters.json files
|
|
642
|
+
*/
|
|
643
|
+
export const NamespaceFileSchema = z.object({
|
|
644
|
+
$schema: z.string(),
|
|
645
|
+
namespace: z.string(),
|
|
646
|
+
version: z.string(),
|
|
647
|
+
generatedAt: z.string(),
|
|
648
|
+
tokens: z.array(TokenSchema),
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
export type NamespaceFile = z.infer<typeof NamespaceFileSchema>;
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lockstep suite version: @rafters/shared, @rafters/color-utils,
|
|
3
|
+
* @rafters/math-utils, and the rafters CLI all ship at this number.
|
|
4
|
+
* Written by packages/cli/scripts/sync-version.ts from the CLI's own
|
|
5
|
+
* package.json version at build time -- do not edit by hand.
|
|
6
|
+
*/
|
|
7
|
+
export const RAFTERS_VERSION = '0.2.3';
|