@panneau/protocol 5.0.0-alpha.1 → 5.0.0-alpha.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.
Files changed (51) hide show
  1. package/README.md +10 -9
  2. package/dist/conformance/index.d.ts.map +1 -1
  3. package/dist/conformance/index.js +34 -1
  4. package/dist/conformance/index.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +4 -2
  8. package/dist/mock/example.d.ts.map +1 -1
  9. package/dist/mock/example.js +2 -1
  10. package/dist/mock/example.js.map +1 -1
  11. package/dist/mock/index.d.ts.map +1 -1
  12. package/dist/mock/index.js +20 -1
  13. package/dist/mock/index.js.map +1 -1
  14. package/dist/openapi.d.ts +2 -0
  15. package/dist/openapi.d.ts.map +1 -1
  16. package/dist/openapi.js +14 -2
  17. package/dist/openapi.js.map +1 -1
  18. package/dist/runtime/index.d.ts +1 -0
  19. package/dist/runtime/index.d.ts.map +1 -1
  20. package/dist/runtime/index.js +2 -1
  21. package/dist/schemas/action.d.ts +1 -0
  22. package/dist/schemas/action.d.ts.map +1 -1
  23. package/dist/schemas/action.js +1 -0
  24. package/dist/schemas/action.js.map +1 -1
  25. package/dist/schemas/api.d.ts +1 -0
  26. package/dist/schemas/api.d.ts.map +1 -1
  27. package/dist/schemas/api.js +2 -1
  28. package/dist/schemas/api.js.map +1 -1
  29. package/dist/schemas/definition.d.ts +55 -1
  30. package/dist/schemas/definition.d.ts.map +1 -1
  31. package/dist/schemas/definition.js +2 -5
  32. package/dist/schemas/definition.js.map +1 -1
  33. package/dist/schemas/index.d.ts +228 -1
  34. package/dist/schemas/index.d.ts.map +1 -1
  35. package/dist/schemas/index.js +10 -1
  36. package/dist/schemas/index.js.map +1 -1
  37. package/dist/schemas/resource.d.ts +1 -0
  38. package/dist/schemas/resource.d.ts.map +1 -1
  39. package/dist/schemas/theme.d.ts +179 -0
  40. package/dist/schemas/theme.d.ts.map +1 -0
  41. package/dist/schemas/theme.js +66 -0
  42. package/dist/schemas/theme.js.map +1 -0
  43. package/dist/themes.d.ts +11 -0
  44. package/dist/themes.d.ts.map +1 -0
  45. package/dist/themes.js +80 -0
  46. package/dist/themes.js.map +1 -0
  47. package/package.json +2 -1
  48. package/schema/boot.schema.json +258 -12
  49. package/schema/definition.schema.json +258 -12
  50. package/schema/openapi.json +436 -12
  51. package/schema/theme.schema.json +234 -0
package/dist/themes.js ADDED
@@ -0,0 +1,80 @@
1
+ //#region src/themes.ts
2
+ function mergeRecords(first, second) {
3
+ return first === void 0 && second === void 0 ? void 0 : {
4
+ ...first,
5
+ ...second
6
+ };
7
+ }
8
+ function mergeComponents(first, second) {
9
+ const components = mergeRecords(first, second);
10
+ if (components === void 0) return;
11
+ return Object.fromEntries(Object.keys(components).map((component) => {
12
+ const before = first?.[component];
13
+ const after = second?.[component];
14
+ const variants = mergeRecords(before?.variants, after?.variants);
15
+ return [component, {
16
+ ...before,
17
+ ...after,
18
+ ...variants !== void 0 && { variants: Object.fromEntries(Object.keys(variants).map((name) => [name, {
19
+ ...before?.variants?.[name],
20
+ ...after?.variants?.[name]
21
+ }])) }
22
+ }];
23
+ }));
24
+ }
25
+ var DENSITIES = [
26
+ "compact",
27
+ "comfortable",
28
+ "touch"
29
+ ];
30
+ function mergeDensities(first, second) {
31
+ if (first === void 0 && second === void 0) return;
32
+ const densities = {
33
+ ...first,
34
+ ...second
35
+ };
36
+ DENSITIES.forEach((density) => {
37
+ if (first?.[density] !== void 0 && second?.[density] !== void 0) densities[density] = {
38
+ ...first[density],
39
+ ...second[density]
40
+ };
41
+ });
42
+ return densities;
43
+ }
44
+ function mergeFonts(first, second) {
45
+ if (first === void 0 && second === void 0) return;
46
+ const fonts = [...first ?? [], ...second ?? []];
47
+ return fonts.filter((font, index) => fonts.findIndex((other) => JSON.stringify(other) === JSON.stringify(font)) === index);
48
+ }
49
+ /**
50
+ * Merges themes, in order: each one overrides the tokens, palette colors, tones and variants of
51
+ * those before it. A token a theme sets in `tokens` but not in `dark` applies to both schemes, so it
52
+ * also replaces the dark value of earlier themes. Variants merge token by token; tones are replaced
53
+ * whole; densities merge token by token; fonts add up. The label is the last one set. `defineTheme()` of `@panneau/ui` merges the same way.
54
+ */
55
+ function mergeThemes(...themes) {
56
+ return themes.reduce((merged, theme) => {
57
+ const tokens = theme.tokens ?? {};
58
+ const dark = mergeRecords(merged.dark !== void 0 ? Object.fromEntries(Object.entries(merged.dark).filter(([name]) => !Object.hasOwn(tokens, name))) : void 0, theme.dark);
59
+ const result = {
60
+ ...merged,
61
+ ...theme,
62
+ label: theme.label ?? merged.label,
63
+ tokens: {
64
+ ...merged.tokens,
65
+ ...tokens
66
+ },
67
+ dark: dark !== void 0 && Object.keys(dark).length > 0 ? dark : void 0,
68
+ palette: mergeRecords(merged.palette, theme.palette),
69
+ tones: mergeRecords(merged.tones, theme.tones),
70
+ components: mergeComponents(merged.components, theme.components),
71
+ densities: mergeDensities(merged.densities, theme.densities),
72
+ fonts: mergeFonts(merged.fonts, theme.fonts)
73
+ };
74
+ return Object.fromEntries(Object.entries(result).filter(([, value]) => value !== void 0));
75
+ }, { tokens: {} });
76
+ }
77
+ //#endregion
78
+ export { mergeThemes };
79
+
80
+ //# sourceMappingURL=themes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"themes.js","names":[],"sources":["../src/themes.ts"],"sourcesContent":["import type { Theme } from './schemas/theme';\n\n/** A theme to merge: `tokens` can be left out, as in the theme of a definition. */\nexport type PartialTheme = Partial<Theme>;\n\nfunction mergeRecords<T>(\n first: Record<string, T> | undefined,\n second: Record<string, T> | undefined,\n): Record<string, T> | undefined {\n return first === undefined && second === undefined ? undefined : { ...first, ...second };\n}\n\nfunction mergeComponents(\n first: Theme['components'],\n second: Theme['components'],\n): Theme['components'] {\n const components = mergeRecords(first, second);\n if (components === undefined) {\n return undefined;\n }\n return Object.fromEntries(\n Object.keys(components).map((component) => {\n const before = first?.[component];\n const after = second?.[component];\n const variants = mergeRecords(before?.variants, after?.variants);\n return [\n component,\n {\n ...before,\n ...after,\n ...(variants !== undefined && {\n variants: Object.fromEntries(\n Object.keys(variants).map((name) => [\n name,\n { ...before?.variants?.[name], ...after?.variants?.[name] },\n ]),\n ),\n }),\n },\n ];\n }),\n );\n}\n\nconst DENSITIES = ['compact', 'comfortable', 'touch'] as const;\n\nfunction mergeDensities(first: Theme['densities'], second: Theme['densities']): Theme['densities'] {\n if (first === undefined && second === undefined) {\n return undefined;\n }\n const densities = { ...first, ...second };\n DENSITIES.forEach((density) => {\n if (first?.[density] !== undefined && second?.[density] !== undefined) {\n densities[density] = { ...first[density], ...second[density] };\n }\n });\n return densities;\n}\n\nfunction mergeFonts(first: Theme['fonts'], second: Theme['fonts']): Theme['fonts'] {\n if (first === undefined && second === undefined) {\n return undefined;\n }\n const fonts = [...(first ?? []), ...(second ?? [])];\n return fonts.filter(\n (font, index) =>\n fonts.findIndex((other) => JSON.stringify(other) === JSON.stringify(font)) === index,\n );\n}\n\n/**\n * Merges themes, in order: each one overrides the tokens, palette colors, tones and variants of\n * those before it. A token a theme sets in `tokens` but not in `dark` applies to both schemes, so it\n * also replaces the dark value of earlier themes. Variants merge token by token; tones are replaced\n * whole; densities merge token by token; fonts add up. The label is the last one set. `defineTheme()` of `@panneau/ui` merges the same way.\n */\nexport function mergeThemes(...themes: readonly PartialTheme[]): Theme {\n return themes.reduce<Theme>(\n (merged, theme) => {\n const tokens = theme.tokens ?? {};\n const dark = mergeRecords(\n merged.dark !== undefined\n ? Object.fromEntries(\n Object.entries(merged.dark).filter(\n ([name]) => !Object.hasOwn(tokens, name),\n ),\n )\n : undefined,\n theme.dark,\n );\n const result: Theme = {\n ...merged,\n ...theme,\n label: theme.label ?? merged.label,\n tokens: { ...merged.tokens, ...tokens },\n dark: dark !== undefined && Object.keys(dark).length > 0 ? dark : undefined,\n palette: mergeRecords(merged.palette, theme.palette),\n tones: mergeRecords(merged.tones, theme.tones),\n components: mergeComponents(merged.components, theme.components),\n densities: mergeDensities(merged.densities, theme.densities),\n fonts: mergeFonts(merged.fonts, theme.fonts),\n };\n return Object.fromEntries(\n Object.entries(result).filter(([, value]) => value !== undefined),\n ) as Theme;\n },\n { tokens: {} },\n );\n}\n"],"mappings":";AAKA,SAAS,aACL,OACA,QAC6B;CAC7B,OAAO,UAAU,KAAA,KAAa,WAAW,KAAA,IAAY,KAAA,IAAY;EAAE,GAAG;EAAO,GAAG;CAAO;AAC3F;AAEA,SAAS,gBACL,OACA,QACmB;CACnB,MAAM,aAAa,aAAa,OAAO,MAAM;CAC7C,IAAI,eAAe,KAAA,GACf;CAEJ,OAAO,OAAO,YACV,OAAO,KAAK,UAAU,CAAC,CAAC,KAAK,cAAc;EACvC,MAAM,SAAS,QAAQ;EACvB,MAAM,QAAQ,SAAS;EACvB,MAAM,WAAW,aAAa,QAAQ,UAAU,OAAO,QAAQ;EAC/D,OAAO,CACH,WACA;GACI,GAAG;GACH,GAAG;GACH,GAAI,aAAa,KAAA,KAAa,EAC1B,UAAU,OAAO,YACb,OAAO,KAAK,QAAQ,CAAC,CAAC,KAAK,SAAS,CAChC,MACA;IAAE,GAAG,QAAQ,WAAW;IAAO,GAAG,OAAO,WAAW;GAAM,CAC9D,CAAC,CACL,EACJ;EACJ,CACJ;CACJ,CAAC,CACL;AACJ;AAEA,IAAM,YAAY;CAAC;CAAW;CAAe;AAAO;AAEpD,SAAS,eAAe,OAA2B,QAAgD;CAC/F,IAAI,UAAU,KAAA,KAAa,WAAW,KAAA,GAClC;CAEJ,MAAM,YAAY;EAAE,GAAG;EAAO,GAAG;CAAO;CACxC,UAAU,SAAS,YAAY;EAC3B,IAAI,QAAQ,aAAa,KAAA,KAAa,SAAS,aAAa,KAAA,GACxD,UAAU,WAAW;GAAE,GAAG,MAAM;GAAU,GAAG,OAAO;EAAS;CAErE,CAAC;CACD,OAAO;AACX;AAEA,SAAS,WAAW,OAAuB,QAAwC;CAC/E,IAAI,UAAU,KAAA,KAAa,WAAW,KAAA,GAClC;CAEJ,MAAM,QAAQ,CAAC,GAAI,SAAS,CAAC,GAAI,GAAI,UAAU,CAAC,CAAE;CAClD,OAAO,MAAM,QACR,MAAM,UACH,MAAM,WAAW,UAAU,KAAK,UAAU,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC,MAAM,KACvF;AACJ;;;;;;;AAQA,SAAgB,YAAY,GAAG,QAAwC;CACnE,OAAO,OAAO,QACT,QAAQ,UAAU;EACf,MAAM,SAAS,MAAM,UAAU,CAAC;EAChC,MAAM,OAAO,aACT,OAAO,SAAS,KAAA,IACV,OAAO,YACH,OAAO,QAAQ,OAAO,IAAI,CAAC,CAAC,QACvB,CAAC,UAAU,CAAC,OAAO,OAAO,QAAQ,IAAI,CAC3C,CACJ,IACA,KAAA,GACN,MAAM,IACV;EACA,MAAM,SAAgB;GAClB,GAAG;GACH,GAAG;GACH,OAAO,MAAM,SAAS,OAAO;GAC7B,QAAQ;IAAE,GAAG,OAAO;IAAQ,GAAG;GAAO;GACtC,MAAM,SAAS,KAAA,KAAa,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,IAAI,OAAO,KAAA;GAClE,SAAS,aAAa,OAAO,SAAS,MAAM,OAAO;GACnD,OAAO,aAAa,OAAO,OAAO,MAAM,KAAK;GAC7C,YAAY,gBAAgB,OAAO,YAAY,MAAM,UAAU;GAC/D,WAAW,eAAe,OAAO,WAAW,MAAM,SAAS;GAC3D,OAAO,WAAW,OAAO,OAAO,MAAM,KAAK;EAC/C;EACA,OAAO,OAAO,YACV,OAAO,QAAQ,MAAM,CAAC,CAAC,QAAQ,GAAG,WAAW,UAAU,KAAA,CAAS,CACpE;CACJ,GACA,EAAE,QAAQ,CAAC,EAAE,CACjB;AACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panneau/protocol",
3
- "version": "5.0.0-alpha.1",
3
+ "version": "5.0.0-alpha.3",
4
4
  "description": "The Panneau protocol: definition schema, HTTP API spec and conformance kit",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,6 +34,7 @@
34
34
  "./definition.schema.json": "./schema/definition.schema.json",
35
35
  "./openapi.json": "./schema/openapi.json",
36
36
  "./boot.schema.json": "./schema/boot.schema.json",
37
+ "./theme.schema.json": "./schema/theme.schema.json",
37
38
  "./package.json": "./package.json"
38
39
  },
39
40
  "files": [
@@ -141,18 +141,7 @@
141
141
  "$ref": "#/$defs/Uploads"
142
142
  },
143
143
  "theme": {
144
- "type": "object",
145
- "properties": {
146
- "colorScheme": {
147
- "type": "string",
148
- "enum": [
149
- "light",
150
- "dark",
151
- "auto"
152
- ]
153
- }
154
- },
155
- "additionalProperties": {}
144
+ "$ref": "#/$defs/DefinitionTheme"
156
145
  },
157
146
  "user": {
158
147
  "anyOf": [
@@ -897,6 +886,9 @@
897
886
  "queued": {
898
887
  "type": "boolean"
899
888
  },
889
+ "dryRun": {
890
+ "type": "boolean"
891
+ },
900
892
  "url": {
901
893
  "type": "string"
902
894
  },
@@ -1196,6 +1188,260 @@
1196
1188
  ],
1197
1189
  "additionalProperties": {}
1198
1190
  },
1191
+ "DefinitionTheme": {
1192
+ "type": "object",
1193
+ "properties": {
1194
+ "label": {
1195
+ "type": "string"
1196
+ },
1197
+ "tokens": {
1198
+ "$ref": "#/$defs/ThemeTokens"
1199
+ },
1200
+ "dark": {
1201
+ "$ref": "#/$defs/ThemeTokens"
1202
+ },
1203
+ "palette": {
1204
+ "type": "object",
1205
+ "propertyNames": {
1206
+ "type": "string",
1207
+ "pattern": "^[a-z0-9-]+$"
1208
+ },
1209
+ "additionalProperties": {
1210
+ "type": "string",
1211
+ "pattern": "^[^{};<]*$"
1212
+ }
1213
+ },
1214
+ "tones": {
1215
+ "type": "object",
1216
+ "propertyNames": {
1217
+ "type": "string",
1218
+ "pattern": "^[a-z0-9-]+$"
1219
+ },
1220
+ "additionalProperties": {
1221
+ "$ref": "#/$defs/ToneInput"
1222
+ }
1223
+ },
1224
+ "components": {
1225
+ "type": "object",
1226
+ "propertyNames": {
1227
+ "type": "string",
1228
+ "pattern": "^[a-z0-9-]+$"
1229
+ },
1230
+ "additionalProperties": {
1231
+ "type": "object",
1232
+ "properties": {
1233
+ "variants": {
1234
+ "type": "object",
1235
+ "propertyNames": {
1236
+ "type": "string",
1237
+ "pattern": "^[a-z0-9-]+$"
1238
+ },
1239
+ "additionalProperties": {
1240
+ "$ref": "#/$defs/ThemeTokens"
1241
+ }
1242
+ }
1243
+ },
1244
+ "additionalProperties": {}
1245
+ }
1246
+ },
1247
+ "densities": {
1248
+ "type": "object",
1249
+ "properties": {
1250
+ "compact": {
1251
+ "$ref": "#/$defs/ThemeTokens"
1252
+ },
1253
+ "comfortable": {
1254
+ "$ref": "#/$defs/ThemeTokens"
1255
+ },
1256
+ "touch": {
1257
+ "$ref": "#/$defs/ThemeTokens"
1258
+ }
1259
+ },
1260
+ "additionalProperties": {}
1261
+ },
1262
+ "fonts": {
1263
+ "type": "array",
1264
+ "items": {
1265
+ "$ref": "#/$defs/ThemeFont"
1266
+ }
1267
+ },
1268
+ "colorScheme": {
1269
+ "type": "string",
1270
+ "enum": [
1271
+ "light",
1272
+ "dark",
1273
+ "auto"
1274
+ ]
1275
+ },
1276
+ "density": {
1277
+ "type": "string",
1278
+ "enum": [
1279
+ "compact",
1280
+ "comfortable",
1281
+ "touch",
1282
+ "auto"
1283
+ ]
1284
+ },
1285
+ "extends": {
1286
+ "anyOf": [
1287
+ {
1288
+ "type": "string"
1289
+ },
1290
+ {
1291
+ "type": "array",
1292
+ "items": {
1293
+ "type": "string"
1294
+ }
1295
+ }
1296
+ ]
1297
+ }
1298
+ },
1299
+ "additionalProperties": {}
1300
+ },
1301
+ "ThemeTokens": {
1302
+ "type": "object",
1303
+ "propertyNames": {
1304
+ "type": "string",
1305
+ "pattern": "^[a-zA-Z0-9_-]+$"
1306
+ },
1307
+ "additionalProperties": {
1308
+ "type": "string",
1309
+ "pattern": "^[^{};<]*$"
1310
+ }
1311
+ },
1312
+ "ToneInput": {
1313
+ "anyOf": [
1314
+ {
1315
+ "type": "string"
1316
+ },
1317
+ {
1318
+ "type": "object",
1319
+ "properties": {
1320
+ "text": {
1321
+ "type": "string"
1322
+ },
1323
+ "subtle": {
1324
+ "type": "string"
1325
+ },
1326
+ "border": {
1327
+ "type": "string"
1328
+ },
1329
+ "outline": {
1330
+ "type": "string"
1331
+ },
1332
+ "solid": {
1333
+ "type": "string"
1334
+ },
1335
+ "solidHover": {
1336
+ "type": "string"
1337
+ },
1338
+ "solidText": {
1339
+ "type": "string"
1340
+ },
1341
+ "dark": {
1342
+ "type": "object",
1343
+ "properties": {
1344
+ "text": {
1345
+ "type": "string"
1346
+ },
1347
+ "subtle": {
1348
+ "type": "string"
1349
+ },
1350
+ "border": {
1351
+ "type": "string"
1352
+ },
1353
+ "outline": {
1354
+ "type": "string"
1355
+ },
1356
+ "solid": {
1357
+ "type": "string"
1358
+ },
1359
+ "solidHover": {
1360
+ "type": "string"
1361
+ },
1362
+ "solidText": {
1363
+ "type": "string"
1364
+ }
1365
+ },
1366
+ "additionalProperties": {}
1367
+ }
1368
+ },
1369
+ "required": [
1370
+ "text",
1371
+ "subtle",
1372
+ "border",
1373
+ "outline",
1374
+ "solid",
1375
+ "solidHover",
1376
+ "solidText"
1377
+ ],
1378
+ "additionalProperties": {}
1379
+ }
1380
+ ]
1381
+ },
1382
+ "ThemeFont": {
1383
+ "anyOf": [
1384
+ {
1385
+ "$ref": "#/$defs/ThemeFontFace"
1386
+ },
1387
+ {
1388
+ "$ref": "#/$defs/ThemeFontStylesheet"
1389
+ }
1390
+ ]
1391
+ },
1392
+ "ThemeFontFace": {
1393
+ "type": "object",
1394
+ "properties": {
1395
+ "family": {
1396
+ "type": "string",
1397
+ "pattern": "^[^{}<;\"\\\\]+$"
1398
+ },
1399
+ "src": {
1400
+ "type": "string",
1401
+ "pattern": "^[^{}<]+$"
1402
+ },
1403
+ "weight": {
1404
+ "type": "string",
1405
+ "pattern": "^[^{}<;]*$"
1406
+ },
1407
+ "style": {
1408
+ "type": "string",
1409
+ "pattern": "^[^{}<;]*$"
1410
+ },
1411
+ "display": {
1412
+ "type": "string",
1413
+ "enum": [
1414
+ "auto",
1415
+ "block",
1416
+ "swap",
1417
+ "fallback",
1418
+ "optional"
1419
+ ]
1420
+ },
1421
+ "unicodeRange": {
1422
+ "type": "string",
1423
+ "pattern": "^[^{}<;]*$"
1424
+ }
1425
+ },
1426
+ "required": [
1427
+ "family",
1428
+ "src"
1429
+ ],
1430
+ "additionalProperties": {}
1431
+ },
1432
+ "ThemeFontStylesheet": {
1433
+ "type": "object",
1434
+ "properties": {
1435
+ "stylesheet": {
1436
+ "type": "string",
1437
+ "minLength": 1
1438
+ }
1439
+ },
1440
+ "required": [
1441
+ "stylesheet"
1442
+ ],
1443
+ "additionalProperties": {}
1444
+ },
1199
1445
  "User": {
1200
1446
  "type": "object",
1201
1447
  "properties": {