@shoplix-ai/sdui-schema 1.0.0

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 (110) hide show
  1. package/LICENSE +21 -0
  2. package/dist/action.d.ts +26 -0
  3. package/dist/action.d.ts.map +1 -0
  4. package/dist/action.js +27 -0
  5. package/dist/action.js.map +1 -0
  6. package/dist/assets.d.ts +80 -0
  7. package/dist/assets.d.ts.map +1 -0
  8. package/dist/assets.js +101 -0
  9. package/dist/assets.js.map +1 -0
  10. package/dist/binding.d.ts +144 -0
  11. package/dist/binding.d.ts.map +1 -0
  12. package/dist/binding.js +80 -0
  13. package/dist/binding.js.map +1 -0
  14. package/dist/block-definition.d.ts +1639 -0
  15. package/dist/block-definition.d.ts.map +1 -0
  16. package/dist/block-definition.js +527 -0
  17. package/dist/block-definition.js.map +1 -0
  18. package/dist/block-type-id.d.ts +15 -0
  19. package/dist/block-type-id.d.ts.map +1 -0
  20. package/dist/block-type-id.js +43 -0
  21. package/dist/block-type-id.js.map +1 -0
  22. package/dist/block-type.d.ts +21 -0
  23. package/dist/block-type.d.ts.map +1 -0
  24. package/dist/block-type.js +24 -0
  25. package/dist/block-type.js.map +1 -0
  26. package/dist/blocks.d.ts +922 -0
  27. package/dist/blocks.d.ts.map +1 -0
  28. package/dist/blocks.js +353 -0
  29. package/dist/blocks.js.map +1 -0
  30. package/dist/definition-validator.d.ts +47 -0
  31. package/dist/definition-validator.d.ts.map +1 -0
  32. package/dist/definition-validator.js +340 -0
  33. package/dist/definition-validator.js.map +1 -0
  34. package/dist/display.d.ts +139 -0
  35. package/dist/display.d.ts.map +1 -0
  36. package/dist/display.js +118 -0
  37. package/dist/display.js.map +1 -0
  38. package/dist/envelope.d.ts +2721 -0
  39. package/dist/envelope.d.ts.map +1 -0
  40. package/dist/envelope.js +116 -0
  41. package/dist/envelope.js.map +1 -0
  42. package/dist/icons.d.ts +10 -0
  43. package/dist/icons.d.ts.map +1 -0
  44. package/dist/icons.js +49 -0
  45. package/dist/icons.js.map +1 -0
  46. package/dist/index.d.ts +38 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +20 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/locale.d.ts +11 -0
  51. package/dist/locale.d.ts.map +1 -0
  52. package/dist/locale.js +15 -0
  53. package/dist/locale.js.map +1 -0
  54. package/dist/manifest.d.ts +28 -0
  55. package/dist/manifest.d.ts.map +1 -0
  56. package/dist/manifest.js +242 -0
  57. package/dist/manifest.js.map +1 -0
  58. package/dist/parse.d.ts +33 -0
  59. package/dist/parse.d.ts.map +1 -0
  60. package/dist/parse.js +61 -0
  61. package/dist/parse.js.map +1 -0
  62. package/dist/path.d.ts +3 -0
  63. package/dist/path.d.ts.map +1 -0
  64. package/dist/path.js +14 -0
  65. package/dist/path.js.map +1 -0
  66. package/dist/primitives.d.ts +1206 -0
  67. package/dist/primitives.d.ts.map +1 -0
  68. package/dist/primitives.js +631 -0
  69. package/dist/primitives.js.map +1 -0
  70. package/dist/props.d.ts +9 -0
  71. package/dist/props.d.ts.map +1 -0
  72. package/dist/props.js +12 -0
  73. package/dist/props.js.map +1 -0
  74. package/dist/screen.d.ts +57 -0
  75. package/dist/screen.d.ts.map +1 -0
  76. package/dist/screen.js +76 -0
  77. package/dist/screen.js.map +1 -0
  78. package/dist/starters/electronics.d.ts +3 -0
  79. package/dist/starters/electronics.d.ts.map +1 -0
  80. package/dist/starters/electronics.js +235 -0
  81. package/dist/starters/electronics.js.map +1 -0
  82. package/dist/starters/fashion.d.ts +3 -0
  83. package/dist/starters/fashion.d.ts.map +1 -0
  84. package/dist/starters/fashion.js +232 -0
  85. package/dist/starters/fashion.js.map +1 -0
  86. package/dist/starters/index.d.ts +5 -0
  87. package/dist/starters/index.d.ts.map +1 -0
  88. package/dist/starters/index.js +10 -0
  89. package/dist/starters/index.js.map +1 -0
  90. package/dist/starters/minimal.d.ts +3 -0
  91. package/dist/starters/minimal.d.ts.map +1 -0
  92. package/dist/starters/minimal.js +232 -0
  93. package/dist/starters/minimal.js.map +1 -0
  94. package/dist/starters/starter-seed.d.ts +17 -0
  95. package/dist/starters/starter-seed.d.ts.map +1 -0
  96. package/dist/starters/starter-seed.js +2 -0
  97. package/dist/starters/starter-seed.js.map +1 -0
  98. package/dist/theme.d.ts +54 -0
  99. package/dist/theme.d.ts.map +1 -0
  100. package/dist/theme.js +68 -0
  101. package/dist/theme.js.map +1 -0
  102. package/dist/tokens.d.ts +115 -0
  103. package/dist/tokens.d.ts.map +1 -0
  104. package/dist/tokens.js +349 -0
  105. package/dist/tokens.js.map +1 -0
  106. package/dist/version.d.ts +11 -0
  107. package/dist/version.d.ts.map +1 -0
  108. package/dist/version.js +10 -0
  109. package/dist/version.js.map +1 -0
  110. package/package.json +50 -0
package/dist/theme.js ADDED
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod';
2
+ import { SCHEMA_VERSION } from './version.js';
3
+ import { localizedTextSchema } from './locale.js';
4
+ import { themeTokensSchema } from './tokens.js';
5
+ import { screenDocumentSchema } from './screen.js';
6
+ /** How many tabs a tab bar holds; the same number the api and the editor enforce. */
7
+ export const NAVIGATION_TAB_LIMITS = { min: 1, max: 5 };
8
+ const navigationTabSchema = z.object({
9
+ screenId: z.uuid(),
10
+ label: localizedTextSchema,
11
+ icon: z.string().min(1).max(64),
12
+ });
13
+ export const navigationSchema = z.object({
14
+ tabs: z.array(navigationTabSchema).min(NAVIGATION_TAB_LIMITS.min).max(NAVIGATION_TAB_LIMITS.max),
15
+ });
16
+ export const themeDocumentSchema = z
17
+ .object({
18
+ schemaVersion: z.literal(SCHEMA_VERSION),
19
+ name: z.string().min(1).max(120),
20
+ tokens: themeTokensSchema,
21
+ navigation: navigationSchema,
22
+ screens: z.array(screenDocumentSchema).min(1),
23
+ })
24
+ .superRefine((theme, ctx) => {
25
+ const screenIds = new Set();
26
+ const systemKinds = new Set();
27
+ const slugs = new Set();
28
+ theme.screens.forEach((screen, index) => {
29
+ if (screenIds.has(screen.id)) {
30
+ ctx.addIssue({
31
+ code: 'custom',
32
+ message: `duplicate screen id "${screen.id}"`,
33
+ path: ['screens', index, 'id'],
34
+ });
35
+ }
36
+ screenIds.add(screen.id);
37
+ if (screen.kind !== 'custom') {
38
+ if (systemKinds.has(screen.kind)) {
39
+ ctx.addIssue({
40
+ code: 'custom',
41
+ message: `a theme holds one "${screen.kind}" screen`,
42
+ path: ['screens', index, 'kind'],
43
+ });
44
+ }
45
+ systemKinds.add(screen.kind);
46
+ }
47
+ if (screen.slug !== undefined) {
48
+ if (slugs.has(screen.slug)) {
49
+ ctx.addIssue({
50
+ code: 'custom',
51
+ message: `duplicate screen slug "${screen.slug}"`,
52
+ path: ['screens', index, 'slug'],
53
+ });
54
+ }
55
+ slugs.add(screen.slug);
56
+ }
57
+ });
58
+ theme.navigation.tabs.forEach((tab, index) => {
59
+ if (!screenIds.has(tab.screenId)) {
60
+ ctx.addIssue({
61
+ code: 'custom',
62
+ message: 'tab targets a screen that is not in the theme',
63
+ path: ['navigation', 'tabs', index, 'screenId'],
64
+ });
65
+ }
66
+ });
67
+ });
68
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ import { z } from 'zod';
2
+ export declare const TOKEN_TYPES: readonly ["color", "dimension", "fontFamily", "fontWeight", "number"];
3
+ export type TokenType = (typeof TOKEN_TYPES)[number];
4
+ export interface DimensionValue {
5
+ value: number;
6
+ unit: 'px';
7
+ }
8
+ export type TokenValue = string | number | DimensionValue;
9
+ /** DTCG leaf shape: `$value` plus `$type`, aliases as `{group.path}` strings. */
10
+ export interface TokenLeaf {
11
+ $type: TokenType;
12
+ $value: TokenValue;
13
+ }
14
+ export type TokenGroup = {
15
+ [name: string]: TokenLeaf | TokenGroup;
16
+ };
17
+ /** Three tiers: raw palette, semantic roles, per-component overrides. */
18
+ export interface ThemeTokens {
19
+ palette: TokenGroup;
20
+ semantic: TokenGroup;
21
+ component: TokenGroup;
22
+ }
23
+ export declare const themeTokensSchema: z.ZodObject<{
24
+ palette: z.ZodType<TokenGroup, unknown, z.core.$ZodTypeInternals<TokenGroup, unknown>>;
25
+ semantic: z.ZodType<TokenGroup, unknown, z.core.$ZodTypeInternals<TokenGroup, unknown>>;
26
+ component: z.ZodType<TokenGroup, unknown, z.core.$ZodTypeInternals<TokenGroup, unknown>>;
27
+ }, z.core.$strip>;
28
+ /**
29
+ * The semantic roles a merchant edits and every renderer reads. Each role
30
+ * names the palette leaf it reads by default and writes through, so one edit
31
+ * of "accent" moves every token aliased to it rather than one control.
32
+ */
33
+ export interface SemanticTokenSpec {
34
+ readonly type: TokenType;
35
+ readonly palettePath: string;
36
+ }
37
+ export declare const SEMANTIC_TOKENS: {
38
+ readonly brand: {
39
+ readonly type: "color";
40
+ readonly palettePath: "palette.brand.primary";
41
+ };
42
+ readonly accent: {
43
+ readonly type: "color";
44
+ readonly palettePath: "palette.brand.accent";
45
+ };
46
+ readonly action: {
47
+ readonly type: "color";
48
+ readonly palettePath: "palette.brand.accent";
49
+ };
50
+ readonly surface: {
51
+ readonly type: "color";
52
+ readonly palettePath: "palette.neutral.background";
53
+ };
54
+ readonly elevated: {
55
+ readonly type: "color";
56
+ readonly palettePath: "palette.neutral.surface";
57
+ };
58
+ readonly text: {
59
+ readonly type: "color";
60
+ readonly palettePath: "palette.neutral.text";
61
+ };
62
+ readonly muted: {
63
+ readonly type: "color";
64
+ readonly palettePath: "palette.neutral.muted";
65
+ };
66
+ readonly heading: {
67
+ readonly type: "fontFamily";
68
+ readonly palettePath: "palette.typeface.heading";
69
+ };
70
+ readonly body: {
71
+ readonly type: "fontFamily";
72
+ readonly palettePath: "palette.typeface.body";
73
+ };
74
+ readonly radius: {
75
+ readonly type: "dimension";
76
+ readonly palettePath: "palette.radius.md";
77
+ };
78
+ readonly spacing: {
79
+ readonly type: "dimension";
80
+ readonly palettePath: "palette.spacing.md";
81
+ };
82
+ };
83
+ export type SemanticTokenKey = keyof typeof SEMANTIC_TOKENS;
84
+ /** The semantic tier flattened into values a renderer can use without a resolver. */
85
+ export interface ThemeStyle {
86
+ colors: Record<'brand' | 'accent' | 'action' | 'surface' | 'elevated' | 'text' | 'muted', string>;
87
+ fonts: Record<'heading' | 'body', string>;
88
+ radius: number;
89
+ spacing: number;
90
+ }
91
+ export declare const DEFAULT_THEME_STYLE: ThemeStyle;
92
+ /**
93
+ * Where an alias chain ends. Two roles that answer the same path are the same
94
+ * value: that is what makes "action follows accent" a fact rather than a
95
+ * label, and what a write has to move so the change cascades.
96
+ */
97
+ export declare function terminalTokenPath(tokens: unknown, path: string): string | null;
98
+ /** The whole semantic tier resolved once, for a renderer that only wants values. */
99
+ export declare function resolveThemeStyle(tokens: unknown): ThemeStyle;
100
+ /**
101
+ * Sets one role, writing wherever its alias chain ends so every token pointed
102
+ * at the same leaf moves with it. A role a theme does not carry yet is created
103
+ * on its declared palette leaf, with the semantic alias added over it -- an old
104
+ * theme gains the role by being edited, never by a migration.
105
+ */
106
+ export declare function writeSemanticToken(tokens: ThemeTokens, key: SemanticTokenKey, value: TokenValue): ThemeTokens;
107
+ /**
108
+ * Points one role at another's value again. The pair the editor offers is
109
+ * action to accent: a merchant who set a one-off button colour gets back the
110
+ * cascade rather than having to retype the accent's hex.
111
+ */
112
+ export declare function linkSemanticToken(tokens: ThemeTokens, key: SemanticTokenKey, to: SemanticTokenKey): ThemeTokens;
113
+ /** Whether two roles resolve to the same leaf, i.e. one follows the other. */
114
+ export declare function semanticTokensLinked(tokens: unknown, key: SemanticTokenKey, to: SemanticTokenKey): boolean;
115
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,WAAW,uEAAwE,CAAC;AACjG,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,cAAc,CAAC;AAE1D,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;CACxC,CAAC;AAEF,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,EAAE,UAAU,CAAC;CACvB;AAsGD,eAAO,MAAM,iBAAiB;;;;iBA0C1B,CAAC;AAEL;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY0B,CAAC;AAEvD,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,eAAe,CAAC;AAE5D,qFAAqF;AACrF,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;IAClG,KAAK,EAAE,MAAM,CAAC,SAAS,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,mBAAmB,EAAE,UAajC,CAAC;AAuBF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc9E;AAgED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,UAAU,CAqB7D;AA4BD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,UAAU,GAChB,WAAW,CAWb;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,gBAAgB,EACrB,EAAE,EAAE,gBAAgB,GACnB,WAAW,CAoBb;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,EACf,GAAG,EAAE,gBAAgB,EACrB,EAAE,EAAE,gBAAgB,GACnB,OAAO,CAIT"}
package/dist/tokens.js ADDED
@@ -0,0 +1,349 @@
1
+ import { z } from 'zod';
2
+ export const TOKEN_TYPES = ['color', 'dimension', 'fontFamily', 'fontWeight', 'number'];
3
+ const ALIAS_PATTERN = /^\{[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)*\}$/;
4
+ const HEX_COLOR_PATTERN = /^#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
5
+ function isAliasValue(value) {
6
+ return typeof value === 'string' && ALIAS_PATTERN.test(value);
7
+ }
8
+ const tokenNameSchema = z
9
+ .string()
10
+ .regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/, 'token and group names are alphanumeric with "-" or "_"');
11
+ const dimensionValueSchema = z.object({
12
+ value: z.number().finite(),
13
+ unit: z.literal('px'),
14
+ });
15
+ const tokenLeafSchema = z
16
+ .object({
17
+ $type: z.enum(TOKEN_TYPES),
18
+ $value: z.union([z.string(), z.number(), dimensionValueSchema]),
19
+ })
20
+ .superRefine((leaf, ctx) => {
21
+ if (isAliasValue(leaf.$value))
22
+ return;
23
+ const bad = (message) => ctx.addIssue({ code: 'custom', message, path: ['$value'] });
24
+ switch (leaf.$type) {
25
+ case 'color':
26
+ if (typeof leaf.$value !== 'string' || !HEX_COLOR_PATTERN.test(leaf.$value)) {
27
+ bad('expected "#rrggbb", "#rrggbbaa" or an alias');
28
+ }
29
+ break;
30
+ case 'dimension':
31
+ if (typeof leaf.$value !== 'object') {
32
+ bad('expected { value, unit: "px" } or an alias');
33
+ }
34
+ break;
35
+ case 'fontFamily':
36
+ if (typeof leaf.$value !== 'string' || leaf.$value.length === 0) {
37
+ bad('expected a font family name or an alias');
38
+ }
39
+ break;
40
+ case 'fontWeight':
41
+ if (typeof leaf.$value !== 'number' ||
42
+ !Number.isInteger(leaf.$value) ||
43
+ leaf.$value < 100 ||
44
+ leaf.$value > 900) {
45
+ bad('expected an integer weight between 100 and 900 or an alias');
46
+ }
47
+ break;
48
+ case 'number':
49
+ if (typeof leaf.$value !== 'number') {
50
+ bad('expected a number or an alias');
51
+ }
52
+ break;
53
+ }
54
+ });
55
+ const tokenNodeSchema = z
56
+ .unknown()
57
+ .transform((value, ctx) => {
58
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
59
+ ctx.addIssue({ code: 'custom', message: 'expected a token or a group of tokens' });
60
+ return z.NEVER;
61
+ }
62
+ const schema = '$value' in value || '$type' in value ? tokenLeafSchema : tokenGroupSchema;
63
+ const parsed = schema.safeParse(value);
64
+ if (!parsed.success) {
65
+ for (const issue of parsed.error.issues) {
66
+ ctx.addIssue({ code: 'custom', message: issue.message, path: [...issue.path] });
67
+ }
68
+ return z.NEVER;
69
+ }
70
+ return parsed.data;
71
+ });
72
+ const tokenGroupSchema = z.lazy(() => z.record(tokenNameSchema, tokenNodeSchema));
73
+ function isLeaf(node) {
74
+ return '$value' in node;
75
+ }
76
+ function flattenLeaves(group, path, out) {
77
+ for (const [name, node] of Object.entries(group)) {
78
+ const nodePath = [...path, name];
79
+ if (isLeaf(node)) {
80
+ out.set(nodePath.join('.'), { leaf: node, path: nodePath });
81
+ }
82
+ else {
83
+ flattenLeaves(node, nodePath, out);
84
+ }
85
+ }
86
+ }
87
+ export const themeTokensSchema = z
88
+ .object({
89
+ palette: tokenGroupSchema,
90
+ semantic: tokenGroupSchema,
91
+ component: tokenGroupSchema,
92
+ })
93
+ .superRefine((tokens, ctx) => {
94
+ const leaves = new Map();
95
+ flattenLeaves(tokens.palette, ['palette'], leaves);
96
+ flattenLeaves(tokens.semantic, ['semantic'], leaves);
97
+ flattenLeaves(tokens.component, ['component'], leaves);
98
+ for (const [key, { leaf, path }] of leaves) {
99
+ if (!isAliasValue(leaf.$value))
100
+ continue;
101
+ const issue = (message) => ctx.addIssue({ code: 'custom', message, path: [...path, '$value'] });
102
+ const seen = new Set([key]);
103
+ let current = leaf;
104
+ let terminal;
105
+ while (true) {
106
+ if (!isAliasValue(current.$value)) {
107
+ terminal = current;
108
+ break;
109
+ }
110
+ const ref = current.$value.slice(1, -1);
111
+ const next = leaves.get(ref);
112
+ if (next === undefined) {
113
+ issue(`alias "{${ref}}" does not resolve to a token`);
114
+ break;
115
+ }
116
+ if (seen.has(ref)) {
117
+ issue(`alias cycle through "{${ref}}"`);
118
+ break;
119
+ }
120
+ seen.add(ref);
121
+ current = next.leaf;
122
+ }
123
+ if (terminal !== undefined && terminal.$type !== leaf.$type) {
124
+ issue(`alias resolves to a "${terminal.$type}" token but this token is "${leaf.$type}"`);
125
+ }
126
+ }
127
+ });
128
+ export const SEMANTIC_TOKENS = {
129
+ brand: { type: 'color', palettePath: 'palette.brand.primary' },
130
+ accent: { type: 'color', palettePath: 'palette.brand.accent' },
131
+ action: { type: 'color', palettePath: 'palette.brand.accent' },
132
+ surface: { type: 'color', palettePath: 'palette.neutral.background' },
133
+ elevated: { type: 'color', palettePath: 'palette.neutral.surface' },
134
+ text: { type: 'color', palettePath: 'palette.neutral.text' },
135
+ muted: { type: 'color', palettePath: 'palette.neutral.muted' },
136
+ heading: { type: 'fontFamily', palettePath: 'palette.typeface.heading' },
137
+ body: { type: 'fontFamily', palettePath: 'palette.typeface.body' },
138
+ radius: { type: 'dimension', palettePath: 'palette.radius.md' },
139
+ spacing: { type: 'dimension', palettePath: 'palette.spacing.md' },
140
+ };
141
+ export const DEFAULT_THEME_STYLE = {
142
+ colors: {
143
+ brand: '#111827',
144
+ accent: '#2563EB',
145
+ action: '#2563EB',
146
+ surface: '#FFFFFF',
147
+ elevated: '#F9FAFB',
148
+ text: '#111827',
149
+ muted: '#6B7280',
150
+ },
151
+ fonts: { heading: 'Inter', body: 'Inter' },
152
+ radius: 8,
153
+ spacing: 16,
154
+ };
155
+ function nodeAt(tokens, path) {
156
+ let node = tokens;
157
+ for (const key of path.split('.')) {
158
+ if (typeof node !== 'object' || node === null)
159
+ return undefined;
160
+ node = node[key];
161
+ }
162
+ if (typeof node !== 'object' || node === null || Array.isArray(node))
163
+ return undefined;
164
+ return node;
165
+ }
166
+ function leafAt(tokens, path) {
167
+ const node = nodeAt(tokens, path);
168
+ return node !== undefined && '$value' in node ? node : undefined;
169
+ }
170
+ function aliasTarget(value) {
171
+ if (typeof value !== 'string')
172
+ return null;
173
+ const match = ALIAS_PATTERN.exec(value);
174
+ return match ? value.slice(1, -1) : null;
175
+ }
176
+ /**
177
+ * Where an alias chain ends. Two roles that answer the same path are the same
178
+ * value: that is what makes "action follows accent" a fact rather than a
179
+ * label, and what a write has to move so the change cascades.
180
+ */
181
+ export function terminalTokenPath(tokens, path) {
182
+ const seen = new Set();
183
+ let current = path;
184
+ while (!seen.has(current)) {
185
+ seen.add(current);
186
+ const leaf = leafAt(tokens, current);
187
+ if (leaf === undefined)
188
+ return null;
189
+ const next = aliasTarget(leaf.$value);
190
+ if (next === null)
191
+ return current;
192
+ current = next;
193
+ }
194
+ // A cycle. The contract refuses one, so this only answers a tree that has
195
+ // not been through the parser yet.
196
+ return null;
197
+ }
198
+ function terminalLeaf(tokens, path) {
199
+ const terminal = terminalTokenPath(tokens, path);
200
+ return terminal === null ? undefined : leafAt(tokens, terminal);
201
+ }
202
+ /**
203
+ * Where a role's value actually lives: its own chain, or -- for a theme
204
+ * written before the role existed -- the palette leaf it is declared against.
205
+ */
206
+ function effectiveTerminal(tokens, key) {
207
+ return (terminalTokenPath(tokens, `semantic.${key}`) ??
208
+ terminalTokenPath(tokens, SEMANTIC_TOKENS[key].palettePath));
209
+ }
210
+ /**
211
+ * The role's value, read through its alias chain. A theme written before a
212
+ * role existed still answers: the palette leaf the role is declared against
213
+ * stands in, and the platform default behind that. Nothing is ever missing.
214
+ */
215
+ function readRole(tokens, key) {
216
+ const spec = SEMANTIC_TOKENS[key];
217
+ const own = terminalLeaf(tokens, `semantic.${key}`);
218
+ if (own?.$type === spec.type)
219
+ return own.$value;
220
+ const fallback = terminalLeaf(tokens, spec.palettePath);
221
+ return fallback?.$type === spec.type ? fallback.$value : undefined;
222
+ }
223
+ /** The platform default for one role, in the role's own type. */
224
+ function defaultRoleValue(key) {
225
+ const d = DEFAULT_THEME_STYLE;
226
+ switch (key) {
227
+ case 'heading':
228
+ return d.fonts.heading;
229
+ case 'body':
230
+ return d.fonts.body;
231
+ case 'radius':
232
+ return { value: d.radius, unit: 'px' };
233
+ case 'spacing':
234
+ return { value: d.spacing, unit: 'px' };
235
+ default:
236
+ return d.colors[key];
237
+ }
238
+ }
239
+ /** One role's value as it stands now, whichever tier it resolves through. */
240
+ function roleValue(tokens, key) {
241
+ return readRole(tokens, key) ?? defaultRoleValue(key);
242
+ }
243
+ function pixels(value, fallback) {
244
+ if (typeof value === 'object' && value !== null && typeof value.value === 'number') {
245
+ return value.value;
246
+ }
247
+ return fallback;
248
+ }
249
+ function text(value, fallback) {
250
+ return typeof value === 'string' && value.length > 0 ? value : fallback;
251
+ }
252
+ /** The whole semantic tier resolved once, for a renderer that only wants values. */
253
+ export function resolveThemeStyle(tokens) {
254
+ const d = DEFAULT_THEME_STYLE;
255
+ const color = (key) => text(readRole(tokens, key), d.colors[key]);
256
+ return {
257
+ colors: {
258
+ brand: color('brand'),
259
+ accent: color('accent'),
260
+ action: color('action'),
261
+ surface: color('surface'),
262
+ elevated: color('elevated'),
263
+ text: color('text'),
264
+ muted: color('muted'),
265
+ },
266
+ fonts: {
267
+ heading: text(readRole(tokens, 'heading'), d.fonts.heading),
268
+ body: text(readRole(tokens, 'body'), d.fonts.body),
269
+ },
270
+ radius: pixels(readRole(tokens, 'radius'), d.radius),
271
+ spacing: pixels(readRole(tokens, 'spacing'), d.spacing),
272
+ };
273
+ }
274
+ /** Token trees are plain JSON, so a round trip is a deep copy and nothing else. */
275
+ function clone(tokens) {
276
+ return JSON.parse(JSON.stringify(tokens));
277
+ }
278
+ const TOKEN_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
279
+ /**
280
+ * Writes one leaf at a dotted path, creating the groups on the way. Every
281
+ * segment is checked against the contract's own name rule first: the path can
282
+ * come from an alias inside a document, and walking an inherited key like
283
+ * `__proto__` would write somewhere no token lives.
284
+ */
285
+ function putLeaf(tokens, path, leaf) {
286
+ const segments = path.split('.');
287
+ if (segments.length === 0 || !segments.every((name) => TOKEN_NAME_PATTERN.test(name)))
288
+ return;
289
+ const last = segments.pop();
290
+ let node = tokens;
291
+ for (const segment of segments) {
292
+ const next = node[segment];
293
+ if (next === undefined || '$value' in next)
294
+ node[segment] = {};
295
+ node = node[segment];
296
+ }
297
+ node[last] = leaf;
298
+ }
299
+ /**
300
+ * Sets one role, writing wherever its alias chain ends so every token pointed
301
+ * at the same leaf moves with it. A role a theme does not carry yet is created
302
+ * on its declared palette leaf, with the semantic alias added over it -- an old
303
+ * theme gains the role by being edited, never by a migration.
304
+ */
305
+ export function writeSemanticToken(tokens, key, value) {
306
+ const spec = SEMANTIC_TOKENS[key];
307
+ const next = clone(tokens);
308
+ const terminal = terminalTokenPath(next, `semantic.${key}`);
309
+ if (terminal !== null) {
310
+ putLeaf(next, terminal, { $type: spec.type, $value: value });
311
+ return next;
312
+ }
313
+ putLeaf(next, spec.palettePath, { $type: spec.type, $value: value });
314
+ putLeaf(next, `semantic.${key}`, { $type: spec.type, $value: `{${spec.palettePath}}` });
315
+ return next;
316
+ }
317
+ /**
318
+ * Points one role at another's value again. The pair the editor offers is
319
+ * action to accent: a merchant who set a one-off button colour gets back the
320
+ * cascade rather than having to retype the accent's hex.
321
+ */
322
+ export function linkSemanticToken(tokens, key, to) {
323
+ const spec = SEMANTIC_TOKENS[key];
324
+ const target = SEMANTIC_TOKENS[to];
325
+ // An alias whose target is another type is refused by the contract, so a
326
+ // link across two types is not a link, it is a broken document.
327
+ if (spec.type !== target.type)
328
+ return tokens;
329
+ const current = roleValue(tokens, to);
330
+ let next = clone(tokens);
331
+ if (terminalTokenPath(next, `semantic.${to}`) === null) {
332
+ next = writeSemanticToken(next, to, current);
333
+ }
334
+ putLeaf(next, `semantic.${key}`, { $type: spec.type, $value: `{semantic.${to}}` });
335
+ // Keep the declared palette leaf in the picture: a role that only ever
336
+ // existed as an alias would leave `target.palettePath` unwritten and the
337
+ // next reader falling through to the platform default.
338
+ if (leafAt(next, target.palettePath) === undefined) {
339
+ putLeaf(next, target.palettePath, { $type: target.type, $value: current });
340
+ }
341
+ return next;
342
+ }
343
+ /** Whether two roles resolve to the same leaf, i.e. one follows the other. */
344
+ export function semanticTokensLinked(tokens, key, to) {
345
+ const a = effectiveTerminal(tokens, key);
346
+ const b = effectiveTerminal(tokens, to);
347
+ return a !== null && a === b;
348
+ }
349
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Bumped on every breaking change to the published schema set. Consumers
4
+ * (api validation, dashboard editor, mobile renderer) read it from here.
5
+ */
6
+ export declare const SCHEMA_VERSION: 1;
7
+ export declare const schemaVersionSchema: z.ZodObject<{
8
+ schemaVersion: z.ZodLiteral<1>;
9
+ }, z.core.$strip>;
10
+ export type SchemaVersion = z.infer<typeof schemaVersionSchema>;
11
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAG,CAAU,CAAC;AAEzC,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Bumped on every breaking change to the published schema set. Consumers
4
+ * (api validation, dashboard editor, mobile renderer) read it from here.
5
+ */
6
+ export const SCHEMA_VERSION = 1;
7
+ export const schemaVersionSchema = z.object({
8
+ schemaVersion: z.literal(SCHEMA_VERSION),
9
+ });
10
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;CACzC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@shoplix-ai/sdui-schema",
3
+ "version": "1.0.0",
4
+ "description": "Zod source of truth for the Shoplix SDUI contract: documents, Bindings, tokens, block manifest, envelopes and display shapes. Consumers import parse helpers and inferred types; zod stays inside.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Rastova/shoplix.git",
9
+ "directory": "packages/sdui-schema"
10
+ },
11
+ "type": "module",
12
+ "engines": {
13
+ "node": ">=22.13"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "./starters": {
21
+ "types": "./dist/starters/index.d.ts",
22
+ "default": "./dist/starters/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "!dist/fixtures.*"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "zod": "^4.4.3"
34
+ },
35
+ "devDependencies": {
36
+ "@eslint/js": "^9.39.1",
37
+ "eslint": "^9.39.1",
38
+ "eslint-config-prettier": "^10.1.1",
39
+ "globals": "^16.5.0",
40
+ "typescript": "5.9.2",
41
+ "typescript-eslint": "^8.50.0",
42
+ "vitest": "^4.0.18"
43
+ },
44
+ "scripts": {
45
+ "build": "tsc -p tsconfig.build.json",
46
+ "typecheck": "tsc -p tsconfig.json --noEmit",
47
+ "test": "vitest run",
48
+ "lint": "eslint src/ tests/"
49
+ }
50
+ }