@diagrammo/dgmo 0.92.1 → 0.94.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 (174) hide show
  1. package/dist/advanced.d.ts +103 -38
  2. package/dist/advanced.js +457 -423
  3. package/dist/block.d.ts +2 -2
  4. package/dist/block.js +75 -70
  5. package/dist/{chart-meta-BBqLnv5q.d.ts → chart-meta-BbjsRY7o.d.ts} +2 -2
  6. package/dist/chart-meta.d.ts +3 -3
  7. package/dist/chart-meta.js +25 -19
  8. package/dist/{chart-types-CbXlZFLd.d.ts → chart-types-Cppnp31G.d.ts} +173 -4
  9. package/dist/{charts-d3-QUUDVETP.js → charts-d3-SZV2SFTM.js} +7 -6
  10. package/dist/{chunk-ADNIO3XY.js → chunk-2FDQEQID.js} +5 -5
  11. package/dist/{chunk-QUGC7GWB.js → chunk-2HSHWPTO.js} +15 -15
  12. package/dist/{chunk-L5NW3PVL.js → chunk-2I4UQG7W.js} +1 -1
  13. package/dist/{chunk-2YAFDND3.js → chunk-2MS623GW.js} +4 -6
  14. package/dist/{chunk-73EYNV4O.js → chunk-2XMTZ5JR.js} +4 -6
  15. package/dist/{chunk-ZJAK6C7Y.js → chunk-3PP746YM.js} +6 -1
  16. package/dist/{chunk-MDVJYRJT.js → chunk-3TWBMU7K.js} +22 -22
  17. package/dist/{chunk-FTUMRSGT.js → chunk-3ZP3QC47.js} +8 -288
  18. package/dist/{chunk-J2E7EUER.js → chunk-4EX4OKGZ.js} +86 -23
  19. package/dist/{chunk-Y2V5AEVG.js → chunk-4SP6OUO7.js} +1952 -1824
  20. package/dist/{chunk-HIWHIYLD.js → chunk-4TEPDQHJ.js} +19 -19
  21. package/dist/{chunk-DEFBUZWV.js → chunk-5HAYT43L.js} +70 -54
  22. package/dist/{chunk-6WVX4KNP.js → chunk-5ZUZZDW5.js} +97 -297
  23. package/dist/{chunk-X5BUX2GK.js → chunk-6JCTW74W.js} +7 -5
  24. package/dist/{chunk-Q6W2K33N.js → chunk-6XLMTAEX.js} +1 -1
  25. package/dist/{chunk-ONYO5WJW.js → chunk-7IOZ6JE4.js} +21 -21
  26. package/dist/chunk-7SXV7NUS.js +416 -0
  27. package/dist/{chunk-NPWVOFB3.js → chunk-7WEYXYLC.js} +1 -1
  28. package/dist/{chunk-GE7ICBX6.js → chunk-AM42TLSZ.js} +102 -97
  29. package/dist/{chunk-WLLO3PZ3.js → chunk-AYUSD4Z6.js} +45 -19
  30. package/dist/{chunk-45QUTYPD.js → chunk-B25IWGDH.js} +69 -20
  31. package/dist/{chunk-JKST4RTT.js → chunk-BH2SF4TT.js} +6 -6
  32. package/dist/{chunk-6OIMUSDX.js → chunk-C6G36F5S.js} +9 -9
  33. package/dist/{chunk-DRFGIOZ6.js → chunk-CIHHTS5B.js} +4 -6
  34. package/dist/chunk-CYTFO2LF.js +209 -0
  35. package/dist/{chunk-Q2UFOKPB.js → chunk-DDIOWNHS.js} +22 -22
  36. package/dist/{chunk-Q6ZQX2HX.js → chunk-DLJJOCIT.js} +4 -6
  37. package/dist/{chunk-26BBJUBW.js → chunk-DNM3XZCK.js} +4 -6
  38. package/dist/{chunk-AUS7V54P.js → chunk-ERT7XDQW.js} +1 -1
  39. package/dist/{chunk-7ENDOHAA.js → chunk-FMAVHTYB.js} +919 -927
  40. package/dist/{chunk-URQIWIKX.js → chunk-FWVE373X.js} +4 -4
  41. package/dist/{chunk-VOR32OHN.js → chunk-G3HZ4PGE.js} +13 -15
  42. package/dist/{chunk-RBFJT23E.js → chunk-GWQRTA5W.js} +6 -6
  43. package/dist/chunk-GXCDD6NG.js +24 -0
  44. package/dist/{chunk-3PFMGNOM.js → chunk-HHVIE45A.js} +26 -11
  45. package/dist/{chunk-MXAP37W6.js → chunk-HI6R27YA.js} +16 -7
  46. package/dist/{chunk-QQPNCXAO.js → chunk-I37S3EZE.js} +18 -18
  47. package/dist/{chunk-YITHYQCL.js → chunk-IGJEKO2P.js} +8 -8
  48. package/dist/{chunk-BZX7QCXJ.js → chunk-IHN6WDEY.js} +15 -15
  49. package/dist/{chunk-QT3KDDXK.js → chunk-IN7XI6NO.js} +0 -7
  50. package/dist/{chunk-4QLGGQNO.js → chunk-IZHGT5HD.js} +44 -18
  51. package/dist/{chunk-5SSTVFPX.js → chunk-JT2BG7LM.js} +5 -7
  52. package/dist/{chunk-2BJW7FSF.js → chunk-KBEWVCK3.js} +1 -1
  53. package/dist/{chunk-DUPZ2BBY.js → chunk-KBHT5XEY.js} +143 -6
  54. package/dist/{chunk-V4D2ZQBE.js → chunk-KRPLP5LP.js} +6 -1
  55. package/dist/{chunk-QKY6W4NA.js → chunk-KSZB7TIY.js} +25 -25
  56. package/dist/{chunk-6ZL2XYM7.js → chunk-MLY5ALOV.js} +6 -6
  57. package/dist/{chunk-VSOZZYLK.js → chunk-NERQSSYD.js} +20 -9
  58. package/dist/{chunk-OQW4ETJX.js → chunk-NM5V5EKY.js} +6 -1
  59. package/dist/{chunk-EBSFSOJC.js → chunk-NOQB4KMV.js} +22 -22
  60. package/dist/{chunk-6BNNLVAR.js → chunk-NPDVWFAQ.js} +6 -1
  61. package/dist/{chunk-FSJ3ZA6N.js → chunk-OSSTOSXU.js} +12 -12
  62. package/dist/chunk-P7TRFL4P.js +54 -0
  63. package/dist/{chunk-A4PNWAUW.js → chunk-PGSGJLUR.js} +6 -1
  64. package/dist/{chunk-S7W75MIM.js → chunk-QKPOIJBT.js} +23 -5
  65. package/dist/{chunk-YO6AQU4A.js → chunk-QPQWY5RU.js} +12 -12
  66. package/dist/{chunk-NREU4JFE.js → chunk-RBVFNUAL.js} +6 -8
  67. package/dist/{chunk-5EBYPETE.js → chunk-RESEJSCV.js} +3 -5
  68. package/dist/{chunk-BRSM6Z34.js → chunk-RITTLIDJ.js} +14 -14
  69. package/dist/{chunk-MX4SZLSV.js → chunk-S5Y3OO3V.js} +16 -8
  70. package/dist/{chunk-O5WUZGPV.js → chunk-TASRGDYP.js} +18 -18
  71. package/dist/{chunk-HXULJZA2.js → chunk-TDAGJJPZ.js} +6 -1
  72. package/dist/chunk-UCHZJJIT.js +421 -0
  73. package/dist/{chunk-42UJ23H3.js → chunk-UIEKW4SG.js} +1 -0
  74. package/dist/{chunk-WFA6IULY.js → chunk-URRAWU5D.js} +5 -0
  75. package/dist/{chunk-IGKFOHBG.js → chunk-VBMRZCMQ.js} +13 -13
  76. package/dist/{chunk-JRWUHLRP.js → chunk-VDY2GR6U.js} +51 -8
  77. package/dist/{chunk-EJS3K44P.js → chunk-VGAMBOOC.js} +5 -3
  78. package/dist/{chunk-B5PEKSRH.js → chunk-VSAKEMDD.js} +6 -1
  79. package/dist/chunk-WTTIODDV.js +9 -0
  80. package/dist/{chunk-JLU52ZDT.js → chunk-XJQ6Z3FO.js} +10 -10
  81. package/dist/{chunk-KTGZDMDX.js → chunk-XKCRKD2B.js} +140 -53
  82. package/dist/{chunk-LRP5FXST.js → chunk-YQMIKX54.js} +61 -24
  83. package/dist/{chunk-H5UEVW6Q.js → chunk-ZD3QCNB7.js} +1 -1
  84. package/dist/clock.js +168 -0
  85. package/dist/completion-registry.js +3 -1
  86. package/dist/countdown.js +36 -395
  87. package/dist/{dgmo-router-4UAPPIKN.js → dgmo-router-E5O7RJSW.js} +50 -43
  88. package/dist/{dimensions-SCNVYLRF.js → dimensions-DS6FWLRY.js} +3 -3
  89. package/dist/{d3-BThYBTQk.d.ts → export-context-Ceh3wr0E.d.ts} +2 -8
  90. package/dist/{flowchart-parser-NA75YQ77.js → flowchart-parser-NZXASOZG.js} +8 -3
  91. package/dist/{flowchart-renderer-6MGGX4RC.js → flowchart-renderer-PTCRIANF.js} +17 -19
  92. package/dist/index.d.ts +8 -7
  93. package/dist/index.js +80 -74
  94. package/dist/{layout-MBVBAMPA.js → layout-3TSVAGWH.js} +2 -2
  95. package/dist/layout-ISSBWBH7.js +24 -0
  96. package/dist/layout-IT4ZTV6C.js +24 -0
  97. package/dist/{layout-BNLFQHSB.js → layout-U3AH6M7J.js} +9 -10
  98. package/dist/layout-VC3MXRB4.js +29 -0
  99. package/dist/layout-VDCJOZSH.js +11 -0
  100. package/dist/{layout-search-PMYL3VWS.js → layout-search-BBX2BMEF.js} +11 -12
  101. package/dist/{palettes-IN7ZFRJM.js → palettes-4Y7CL2QL.js} +4 -2
  102. package/dist/{parser-QYISOAGR.js → parser-4RFY7D52.js} +8 -3
  103. package/dist/{parser-3MK56JZC.js → parser-4Y6PODW6.js} +2 -2
  104. package/dist/{parser-GX5YLRIP.js → parser-7QKQ4P4P.js} +8 -3
  105. package/dist/{parser-2NWH5JUS.js → parser-A3AN76RQ.js} +2 -1
  106. package/dist/{parser-LCJ76UXS.js → parser-BT4NI6JY.js} +5 -1
  107. package/dist/{parser-FXDS4JDK.js → parser-F7NDRPMA.js} +2 -2
  108. package/dist/{parser-BES6LV3G.js → parser-GDLKUBTO.js} +5 -1
  109. package/dist/{parser-SEUTXN6U.js → parser-KJPPUN4D.js} +2 -2
  110. package/dist/{parser-SIKL4PLF.js → parser-KMKVFET2.js} +5 -1
  111. package/dist/{parser-5LW5JDYG.js → parser-NL73FSFI.js} +5 -1
  112. package/dist/{parser-VA7ZQQTA.js → parser-NUU3DVW4.js} +5 -1
  113. package/dist/{parser-XZUKNZPB.js → parser-R3LPEQIT.js} +7 -1
  114. package/dist/{parser-X23GRTQJ.js → parser-RCIEKN7Y.js} +5 -1
  115. package/dist/{parser-L6RWDXQN.js → parser-TAYRTCPR.js} +8 -3
  116. package/dist/redraw-AHW7EUUF.js +1698 -0
  117. package/dist/redraw-STZ4WJAI.js +73 -0
  118. package/dist/{renderer-LM4ICK6I.js → renderer-2LYX6NHN.js} +4 -5
  119. package/dist/{renderer-NHTR7IRR.js → renderer-3NLDX7DQ.js} +4 -5
  120. package/dist/{renderer-TO2NVJP3.js → renderer-4SE7R22T.js} +50 -45
  121. package/dist/{renderer-3IHQI4A4.js → renderer-53B523PM.js} +11 -10
  122. package/dist/{renderer-3JY6JAQJ.js → renderer-7OGGV327.js} +5 -6
  123. package/dist/{renderer-2FVUPBGV.js → renderer-AM7P4LN7.js} +1 -1
  124. package/dist/{renderer-5VKPB4LL.js → renderer-BXD5KVSR.js} +5 -5
  125. package/dist/{renderer-OAR5VPH4.js → renderer-DAZWHNLI.js} +2 -2
  126. package/dist/{renderer-WIU5BJUK.js → renderer-DDWDCM2K.js} +2 -2
  127. package/dist/{renderer-3QAFDXEY.js → renderer-FMTLSOCX.js} +16 -12
  128. package/dist/{renderer-JEJT3YET.js → renderer-HX6ICPDX.js} +2 -3
  129. package/dist/{renderer-NDA2FFYB.js → renderer-ISQJ2ELA.js} +5 -5
  130. package/dist/{renderer-XGG2UNXT.js → renderer-IXBOT6DU.js} +3 -4
  131. package/dist/{renderer-S3YCLJKL.js → renderer-J3GPDK73.js} +20 -22
  132. package/dist/{renderer-DVNMCYHZ.js → renderer-J7ZSTJUE.js} +15 -15
  133. package/dist/{renderer-ALWVK3EJ.js → renderer-JJ4QW3SK.js} +6 -6
  134. package/dist/{renderer-RUSFL7WU.js → renderer-JYHA6R2D.js} +8 -7
  135. package/dist/{renderer-5TZVFQ7K.js → renderer-KJ3V5BYP.js} +7 -8
  136. package/dist/{renderer-RSK6QFWN.js → renderer-LNP23NSM.js} +7 -9
  137. package/dist/{renderer-ZHGHTSNG.js → renderer-M5DUMITP.js} +13 -12
  138. package/dist/{renderer-O6DY46AV.js → renderer-MWZC7TMD.js} +7 -7
  139. package/dist/{renderer-DC7C5Q3G.js → renderer-NOYLNVTI.js} +2 -2
  140. package/dist/{renderer-ISSDGK54.js → renderer-O6RP52CQ.js} +3 -3
  141. package/dist/{renderer-ZGY7P4BM.js → renderer-OUDHH5MV.js} +19 -22
  142. package/dist/{renderer-QGIHLZOJ.js → renderer-PHLCYVSN.js} +9 -10
  143. package/dist/{renderer-VPIELEE5.js → renderer-QTPWRRJ7.js} +8 -9
  144. package/dist/{renderer-LQP3AGEJ.js → renderer-RUSQJFFC.js} +3 -4
  145. package/dist/{renderer-MM27BSBO.js → renderer-TINHO2IO.js} +3 -4
  146. package/dist/{renderer-7ZZG5HR3.js → renderer-UTEEJDGB.js} +9 -9
  147. package/dist/{renderer-J5FKF423.js → renderer-W4MUMXJE.js} +7 -4
  148. package/dist/{renderer-XO57LTU4.js → renderer-WPN2SXGT.js} +5 -5
  149. package/dist/{renderer-ZZ6MWVB7.js → renderer-XCLARXCK.js} +4 -4
  150. package/dist/{renderer-J666LZXJ.js → renderer-XOWDERU2.js} +8 -8
  151. package/dist/{state-parser-TIR2ORJY.js → state-parser-KPVW5CRI.js} +8 -3
  152. package/dist/{state-renderer-G6SUXU4J.js → state-renderer-ZVEI265C.js} +18 -21
  153. package/dist/{tag-groups-DsoVpAY-.d.ts → tag-groups-DydewK3D.d.ts} +2 -173
  154. package/dist/{themes-DRNjxX7Q.d.ts → themes-DzIH3Hjv.d.ts} +3 -2
  155. package/docs/ai-integration.md +1 -1
  156. package/docs/language-reference.md +23 -2
  157. package/gallery/fixtures/whiteboard.dgmo +3 -0
  158. package/package.json +2 -6
  159. package/dist/chunk-3Y63RFJL.js +0 -75
  160. package/dist/chunk-5DH3KYFH.js +0 -20
  161. package/dist/chunk-O753JUEZ.js +0 -67
  162. package/dist/chunk-RJNZHFNG.js +0 -51
  163. package/dist/chunk-Z6DXWULM.js +0 -23
  164. package/dist/layout-5USEVQBY.js +0 -25
  165. package/dist/layout-J3AGFZZ7.js +0 -10
  166. package/dist/layout-S3RLVPH4.js +0 -25
  167. package/dist/layout-WRG4APSJ.js +0 -32
  168. package/dist/{chunk-DGUGE67L.js → chunk-CDYV46JE.js} +3 -3
  169. package/dist/{chunk-TKAB3FTK.js → chunk-DRQSB72S.js} +11 -11
  170. package/dist/{chunk-ZKP77MB3.js → chunk-FVTYJUXR.js} +5 -5
  171. package/dist/{chunk-MA42PIGJ.js → chunk-H5NVCOEJ.js} +4 -4
  172. package/dist/{chunk-BEA4D7OS.js → chunk-IXHWS2HI.js} +3 -3
  173. package/dist/{chunk-SOHZDW6N.js → chunk-UXNA2H2V.js} +3 -3
  174. package/dist/{chunk-NO3UX6AP.js → chunk-V2NQV7VL.js} +4 -4
@@ -8,987 +8,987 @@ import {
8
8
  shapeFill
9
9
  } from "./chunk-6GXLAKUH.js";
10
10
 
11
- // src/palettes/registry.ts
12
- var PALETTE_REGISTRY = /* @__PURE__ */ new Map();
13
- var DEFAULT_PALETTE_ID = "slate";
14
- function isValidHex(value) {
15
- return /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value);
16
- }
17
- var COLOR_KEYS = [
18
- "red",
19
- "orange",
20
- "yellow",
21
- "green",
22
- "blue",
23
- "purple",
24
- "teal",
25
- "cyan",
26
- "gray",
27
- "black",
28
- "white"
29
- ];
30
- var SEMANTIC_KEYS = [
31
- "bg",
32
- "surface",
33
- "overlay",
34
- "border",
35
- "text",
36
- "textMuted",
37
- "textOnFillLight",
38
- "textOnFillDark",
39
- "primary",
40
- "secondary",
41
- "accent",
42
- "destructive"
43
- ];
44
- function validatePaletteColors(colors, mode, paletteId) {
45
- for (const key of SEMANTIC_KEYS) {
46
- const value = colors[key];
47
- if (typeof value !== "string" || !isValidHex(value)) {
48
- throw new Error(
49
- `Palette "${paletteId}" ${mode}.${key}: invalid hex "${value}"`
50
- );
11
+ // src/palettes/atlas.ts
12
+ var atlasPalette = {
13
+ id: "atlas",
14
+ name: "Atlas",
15
+ light: {
16
+ bg: "#f3ead3",
17
+ // warm manila / parchment
18
+ surface: "#ece0c0",
19
+ // deeper paper (cards, panels)
20
+ overlay: "#e8dab8",
21
+ // popovers, dropdowns
22
+ border: "#bcaa86",
23
+ // muted sepia rule line
24
+ text: "#463a26",
25
+ // aged sepia-brown ink
26
+ textMuted: "#7a6a4f",
27
+ // faded annotation ink
28
+ textOnFillLight: "#f7f1de",
29
+ // parchment (light text on dark fills)
30
+ textOnFillDark: "#3a2e1c",
31
+ // deep ink (dark text on light fills)
32
+ primary: "#5b7a99",
33
+ // pull-down map ocean (steel-blue)
34
+ secondary: "#7e9a6f",
35
+ // lowland sage / celadon
36
+ accent: "#b07f7c",
37
+ // dusty rose
38
+ destructive: "#b25a45",
39
+ // brick / terracotta
40
+ colors: {
41
+ red: "#bf6a52",
42
+ // terracotta brick
43
+ orange: "#cf9a5c",
44
+ // map tan / ochre
45
+ yellow: "#cdb35e",
46
+ // straw / muted lemon
47
+ green: "#7e9a6f",
48
+ // sage / celadon lowland
49
+ blue: "#5b7a99",
50
+ // steel-blue ocean
51
+ purple: "#9a7fa6",
52
+ // dusty lilac / mauve
53
+ teal: "#6fa094",
54
+ // muted seafoam
55
+ cyan: "#79a7b5",
56
+ // shallow-water blue
57
+ gray: "#8a7d68",
58
+ // warm taupe
59
+ black: "#463a26",
60
+ // ink
61
+ white: "#ece0c0"
62
+ // paper
51
63
  }
52
- }
53
- for (const key of COLOR_KEYS) {
54
- const value = colors.colors[key];
55
- if (typeof value !== "string" || !isValidHex(value)) {
56
- throw new Error(
57
- `Palette "${paletteId}" ${mode}.colors.${key}: invalid hex "${value}"`
58
- );
64
+ },
65
+ dark: {
66
+ bg: "#1e2a33",
67
+ // deep map ocean (night globe)
68
+ surface: "#27353f",
69
+ // raised ocean
70
+ overlay: "#2e3d48",
71
+ // popovers, dropdowns
72
+ border: "#3d4f5c",
73
+ // depth-contour line
74
+ text: "#e8dcc0",
75
+ // parchment ink, inverted
76
+ textMuted: "#a89a7d",
77
+ // faded label
78
+ textOnFillLight: "#f7f1de",
79
+ // parchment
80
+ textOnFillDark: "#1a242c",
81
+ // deep ocean ink
82
+ primary: "#7ba0bf",
83
+ // brighter ocean
84
+ secondary: "#9bb588",
85
+ // sage, lifted
86
+ accent: "#cf9a96",
87
+ // dusty rose, lifted
88
+ destructive: "#c9745c",
89
+ // brick, lifted
90
+ colors: {
91
+ red: "#cf7a60",
92
+ // terracotta
93
+ orange: "#d9a96a",
94
+ // tan / ochre
95
+ yellow: "#d8c074",
96
+ // straw
97
+ green: "#9bb588",
98
+ // sage lowland
99
+ blue: "#7ba0bf",
100
+ // ocean
101
+ purple: "#b59ac0",
102
+ // lilac / mauve
103
+ teal: "#85b3a6",
104
+ // seafoam
105
+ cyan: "#92bccb",
106
+ // shallow-water blue
107
+ gray: "#9a8d76",
108
+ // warm taupe
109
+ black: "#27353f",
110
+ // raised ocean
111
+ white: "#e8dcc0"
112
+ // parchment
59
113
  }
60
114
  }
61
- }
62
- function registerPalette(palette) {
63
- validatePaletteColors(palette.light, "light", palette.id);
64
- validatePaletteColors(palette.dark, "dark", palette.id);
65
- PALETTE_REGISTRY.set(palette.id, palette);
66
- }
67
- function getPalette(id) {
68
- return PALETTE_REGISTRY.get(id) ?? PALETTE_REGISTRY.get(DEFAULT_PALETTE_ID);
69
- }
70
- function resolvePaletteOrFallback(id, warn) {
71
- const found = PALETTE_REGISTRY.get(id);
72
- if (found) return found;
73
- warn?.(
74
- `Palette "${id}" is not registered \u2014 falling back to "${DEFAULT_PALETTE_ID}".`
75
- );
76
- return PALETTE_REGISTRY.get(DEFAULT_PALETTE_ID);
77
- }
78
- function getAvailablePalettes() {
79
- return Array.from(PALETTE_REGISTRY.values()).sort(
80
- (a, b) => a.name.localeCompare(b.name)
81
- );
82
- }
115
+ };
83
116
 
84
- // src/palettes/theme-file.ts
85
- var CONTRAST_FLOOR = 4.5;
86
- var SOLID_FLOOR_LC = 45;
87
- var FILL_ACCENT_KEYS = [
88
- "primary",
89
- "secondary",
90
- "accent",
91
- "destructive"
92
- ];
93
- var CONTRAST_EXEMPT = /* @__PURE__ */ new Set([
94
- "black",
95
- "white"
96
- ]);
97
- function isRecord(value) {
98
- return typeof value === "object" && value !== null && !Array.isArray(value);
99
- }
100
- function collectShapeErrors(value, mode, errors) {
101
- if (!isRecord(value)) {
102
- errors.push(
103
- `${mode}: expected an object of colors, got ${describe(value)}`
104
- );
105
- return false;
106
- }
107
- const before = errors.length;
108
- const fields = /* @__PURE__ */ new Set([...SEMANTIC_KEYS, "colors"]);
109
- for (const key of Object.keys(value)) {
110
- if (!fields.has(key)) {
111
- errors.push(`${mode}.${key}: not a palette field`);
112
- }
113
- }
114
- for (const key of SEMANTIC_KEYS) {
115
- const hex = value[key];
116
- if (typeof hex !== "string" || !isValidHex(hex)) {
117
- errors.push(`${mode}.${key}: invalid hex ${describe(hex)}`);
118
- }
119
- }
120
- const named = value["colors"];
121
- if (!isRecord(named)) {
122
- errors.push(
123
- `${mode}.colors: expected an object of named colors, got ${describe(named)}`
124
- );
125
- } else {
126
- const names = new Set(COLOR_KEYS);
127
- for (const key of Object.keys(named)) {
128
- if (!names.has(key)) {
129
- errors.push(
130
- `${mode}.colors.${key}: not a palette color \u2014 a theme sets the existing color names and cannot add one`
131
- );
132
- }
133
- }
134
- for (const key of COLOR_KEYS) {
135
- const hex = named[key];
136
- if (typeof hex !== "string" || !isValidHex(hex)) {
137
- errors.push(`${mode}.colors.${key}: invalid hex ${describe(hex)}`);
138
- }
139
- }
140
- }
141
- return errors.length === before;
142
- }
143
- function describe(value) {
144
- if (value === void 0) return "nothing";
145
- if (typeof value === "string") return `"${value}"`;
146
- if (value === null) return "null";
147
- return typeof value;
148
- }
149
- function intents(colors) {
150
- const out = [];
151
- for (const key of COLOR_KEYS) {
152
- if (CONTRAST_EXEMPT.has(key)) continue;
153
- out.push([`colors.${key}`, colors.colors[key]]);
154
- }
155
- for (const key of FILL_ACCENT_KEYS) out.push([key, colors[key]]);
156
- return out;
157
- }
158
- function drawnToken(colors, bg) {
159
- const drawn = contrastText(bg, colors.textOnFillLight, colors.textOnFillDark);
160
- return drawn === colors.textOnFillDark ? "textOnFillDark" : "textOnFillLight";
161
- }
162
- function worstTintedFill(colors, isDark) {
163
- let worst;
164
- for (const [fill, intent] of intents(colors)) {
165
- const fillHex = shapeFill(colors, intent, isDark);
166
- const token = drawnToken(colors, fillHex);
167
- const ratio = contrastRatio(colors[token], fillHex);
168
- if (!worst || ratio < worst.ratio) {
169
- worst = { ratio, token, fill, fillHex };
117
+ // src/palettes/blueprint.ts
118
+ var blueprintPalette = {
119
+ id: "blueprint",
120
+ name: "Blueprint",
121
+ light: {
122
+ bg: "#f4f8fb",
123
+ // pale drafting white (faint cyan)
124
+ surface: "#e6eef4",
125
+ // drafting panel
126
+ overlay: "#dde9f1",
127
+ // popovers, dropdowns
128
+ border: "#aac3d6",
129
+ // pale blue grid line
130
+ text: "#123a5e",
131
+ // blueprint navy ink
132
+ textMuted: "#4f7390",
133
+ // faint draft note
134
+ textOnFillLight: "#f4f8fb",
135
+ // drafting white
136
+ textOnFillDark: "#0c2f4d",
137
+ // deep blueprint navy
138
+ primary: "#1f5e8c",
139
+ // blueprint blue
140
+ secondary: "#5b7d96",
141
+ // steel
142
+ accent: "#b08a3e",
143
+ // draftsman's ochre highlight
144
+ destructive: "#c0504d",
145
+ // correction red
146
+ colors: {
147
+ red: "#c25a4e",
148
+ // correction red
149
+ orange: "#c2823e",
150
+ // ochre
151
+ yellow: "#c2a843",
152
+ // pencil gold
153
+ green: "#4f8a6b",
154
+ // drafting green
155
+ blue: "#1f5e8c",
156
+ // blueprint blue
157
+ purple: "#6f5e96",
158
+ // indigo pencil
159
+ teal: "#3a8a8a",
160
+ // teal
161
+ cyan: "#3f8fb5",
162
+ // cyan
163
+ gray: "#7e8e98",
164
+ // graphite
165
+ black: "#123a5e",
166
+ // navy ink
167
+ white: "#e6eef4"
168
+ // panel
170
169
  }
171
- }
172
- return worst;
173
- }
174
- function worstSolidFill(colors) {
175
- let worst;
176
- for (const [fill, intent] of intents(colors)) {
177
- const token = drawnToken(colors, intent);
178
- const lc = Math.abs(apcaContrast(colors[token], intent));
179
- if (!worst || lc < worst.lc) {
180
- worst = { lc, token, fill, fillHex: intent };
170
+ },
171
+ dark: {
172
+ bg: "#103a5e",
173
+ // deep blueprint blue (cyanotype ground)
174
+ surface: "#16466e",
175
+ // raised sheet
176
+ overlay: "#1c5180",
177
+ // popovers, dropdowns
178
+ border: "#3a6f96",
179
+ // grid line
180
+ text: "#eaf2f8",
181
+ // chalk white
182
+ textMuted: "#9fc0d6",
183
+ // faint chalk note
184
+ textOnFillLight: "#eaf2f8",
185
+ // chalk white
186
+ textOnFillDark: "#0c2f4d",
187
+ // deep blueprint navy
188
+ primary: "#7fb8d8",
189
+ // chalk cyan
190
+ secondary: "#9fb8c8",
191
+ // pale steel
192
+ accent: "#d8c27a",
193
+ // chalk amber
194
+ destructive: "#e08a7a",
195
+ // chalk correction red
196
+ colors: {
197
+ red: "#e0907e",
198
+ // chalk red
199
+ orange: "#e0ab78",
200
+ // chalk amber
201
+ yellow: "#e3d089",
202
+ // chalk gold
203
+ green: "#93c79e",
204
+ // chalk green
205
+ blue: "#8ec3e0",
206
+ // chalk cyan-blue
207
+ purple: "#b6a6d8",
208
+ // chalk indigo
209
+ teal: "#84c7c2",
210
+ // chalk teal
211
+ cyan: "#9fd6e0",
212
+ // chalk cyan
213
+ gray: "#aebecb",
214
+ // chalk graphite
215
+ black: "#16466e",
216
+ // raised sheet
217
+ white: "#eaf2f8"
218
+ // chalk white
181
219
  }
182
220
  }
183
- return worst;
184
- }
185
- function collectContrastErrors(colors, where, isDark, errors) {
186
- const tinted = worstTintedFill(colors, isDark);
187
- if (tinted.ratio < CONTRAST_FLOOR) {
188
- errors.push(
189
- `${where}: ${tinted.token} ${colors[tinted.token]} on the ${tinted.fill} fill ${tinted.fillHex} reaches only ${tinted.ratio.toFixed(2)}:1 \u2014 text on a fill needs ${CONTRAST_FLOOR.toFixed(1)}:1`
190
- );
191
- }
192
- }
193
- function collectSolidErrors(colors, where, errors) {
194
- const solid = worstSolidFill(colors);
195
- if (solid.lc >= SOLID_FLOOR_LC) return;
196
- errors.push(
197
- `${where}: ${solid.token} ${colors[solid.token]} on the solid ${solid.fill} ${solid.fillHex} reaches only Lc ${solid.lc.toFixed(1)} \u2014 text on a solid fill needs Lc ${SOLID_FLOOR_LC}`
198
- );
199
- }
200
- function validateThemeFile(input) {
201
- const errors = [];
202
- if (!isRecord(input)) {
203
- return {
204
- ok: false,
205
- errors: [`expected a theme object, got ${describe(input)}`]
206
- };
207
- }
208
- const id = input["id"];
209
- if (typeof id !== "string" || id.trim() === "") {
210
- errors.push(`id: expected a non-empty string, got ${describe(id)}`);
211
- } else if (BUILT_IN_PALETTE_IDS.has(id)) {
212
- errors.push(
213
- `id: "${id}" is a built-in palette \u2014 a theme file needs an id of its own`
214
- );
215
- }
216
- const name = input["name"];
217
- if (typeof name !== "string" || name.trim() === "") {
218
- errors.push(`name: expected a non-empty string, got ${describe(name)}`);
219
- }
220
- const declared = input["mode"];
221
- let mode = null;
222
- if (declared !== void 0) {
223
- if (declared === "light" || declared === "dark") {
224
- mode = declared;
225
- } else {
226
- errors.push(
227
- `mode: expected "light" or "dark", got ${describe(declared)}`
228
- );
221
+ };
222
+
223
+ // src/palettes/catppuccin.ts
224
+ var catppuccinPalette = {
225
+ id: "catppuccin",
226
+ name: "Catppuccin",
227
+ light: {
228
+ bg: "#eff1f5",
229
+ // Latte Base
230
+ surface: "#e6e9ef",
231
+ // Latte Mantle
232
+ overlay: "#ccd0da",
233
+ // Latte Surface0
234
+ border: "#dce0e8",
235
+ // Latte Crust
236
+ text: "#4c4f69",
237
+ // Latte Text
238
+ textMuted: "#5c5f77",
239
+ // Latte Subtext1
240
+ textOnFillLight: "#eff1f5",
241
+ // Latte Base
242
+ textOnFillDark: "#11111b",
243
+ // Mocha Crust (Latte Text #4c4f69 fails 3:1 on saturated mid-luminance intents — orange/green/teal/cyan)
244
+ primary: "#1e66f5",
245
+ // Latte Blue
246
+ secondary: "#7287fd",
247
+ // Latte Lavender
248
+ accent: "#8839ef",
249
+ // Latte Mauve
250
+ destructive: "#d20f39",
251
+ // Latte Red
252
+ colors: {
253
+ red: "#d20f39",
254
+ orange: "#fe640b",
255
+ yellow: "#df8e1d",
256
+ green: "#40a02b",
257
+ blue: "#1e66f5",
258
+ purple: "#8839ef",
259
+ teal: "#179299",
260
+ cyan: "#209fb5",
261
+ gray: "#9ca0b0",
262
+ // Latte Overlay0
263
+ black: "#4c4f69",
264
+ white: "#e6e9ef"
229
265
  }
230
- }
231
- if (mode) {
232
- const other = mode === "light" ? "dark" : "light";
233
- if (input[other] !== void 0) {
234
- errors.push(
235
- `${other}: a theme declaring mode "${mode}" must not also define ${other} \u2014 drop the mode to define both`
236
- );
266
+ },
267
+ dark: {
268
+ bg: "#1e1e2e",
269
+ // Mocha Base
270
+ surface: "#313244",
271
+ // Mocha Surface0
272
+ overlay: "#45475a",
273
+ // Mocha Surface1
274
+ border: "#6c7086",
275
+ // Mocha Overlay0
276
+ text: "#cdd6f4",
277
+ // Mocha Text
278
+ textMuted: "#bac2de",
279
+ // Mocha Subtext1
280
+ textOnFillLight: "#f5e0dc",
281
+ // Mocha Rosewater (highest-luminance accent)
282
+ textOnFillDark: "#11111b",
283
+ // Mocha Crust (low luminance)
284
+ primary: "#89b4fa",
285
+ // Mocha Blue
286
+ secondary: "#b4befe",
287
+ // Mocha Lavender
288
+ accent: "#cba6f7",
289
+ // Mocha Mauve
290
+ destructive: "#f38ba8",
291
+ // Mocha Red
292
+ colors: {
293
+ red: "#f38ba8",
294
+ orange: "#fab387",
295
+ yellow: "#f9e2af",
296
+ green: "#a6e3a1",
297
+ blue: "#89b4fa",
298
+ purple: "#cba6f7",
299
+ teal: "#94e2d5",
300
+ cyan: "#74c7ec",
301
+ gray: "#6c7086",
302
+ // Mocha Overlay0
303
+ black: "#313244",
304
+ white: "#cdd6f4"
237
305
  }
238
306
  }
239
- const wanted = mode ? [mode] : ["light", "dark"];
240
- const modes = {};
241
- for (const key of wanted) {
242
- const value = input[key];
243
- if (value === void 0) {
244
- errors.push(
245
- mode ? `${key}: a theme declaring mode "${mode}" has to define ${key}` : `${key}: a theme without a mode has to define both light and dark`
246
- );
247
- continue;
307
+ };
308
+
309
+ // src/palettes/nord.ts
310
+ var nordPalette = {
311
+ id: "nord",
312
+ name: "Nord",
313
+ light: {
314
+ bg: "#eceff4",
315
+ // nord6
316
+ surface: "#e5e9f0",
317
+ // nord5
318
+ overlay: "#d8dee9",
319
+ // nord4 (muted/secondary backgrounds)
320
+ border: "#d8dee9",
321
+ // nord4
322
+ text: "#2e3440",
323
+ // nord0
324
+ textMuted: "#4c566a",
325
+ // nord3
326
+ textOnFillLight: "#eceff4",
327
+ // nord6
328
+ textOnFillDark: "#2e3440",
329
+ // nord0
330
+ primary: "#5e81ac",
331
+ // nord10
332
+ secondary: "#81a1c1",
333
+ // nord9
334
+ accent: "#81a1c1",
335
+ // nord9
336
+ destructive: "#bf616a",
337
+ // nord11
338
+ colors: {
339
+ red: "#bf616a",
340
+ // nord11
341
+ orange: "#d08770",
342
+ // nord12
343
+ yellow: "#ebcb8b",
344
+ // nord13
345
+ green: "#a3be8c",
346
+ // nord14
347
+ blue: "#5e81ac",
348
+ // nord10
349
+ purple: "#b48ead",
350
+ // nord15
351
+ teal: "#8fbcbb",
352
+ // nord7
353
+ cyan: "#88c0d0",
354
+ // nord8
355
+ gray: "#4c566a",
356
+ // nord3
357
+ black: "#2e3440",
358
+ white: "#e5e9f0"
248
359
  }
249
- if (collectShapeErrors(value, key, errors)) modes[key] = value;
250
- }
251
- if (errors.length === 0) {
252
- const light2 = modes.light ?? modes.dark;
253
- const dark2 = modes.dark ?? modes.light;
254
- const declaredMode = mode;
255
- const label = (render) => declaredMode !== null && render !== declaredMode ? `${render} (a theme declaring mode "${declaredMode}" is used in ${render} mode too)` : render;
256
- collectContrastErrors(light2, label("light"), false, errors);
257
- collectContrastErrors(dark2, label("dark"), true, errors);
258
- if (declaredMode !== null) {
259
- collectSolidErrors(light2, declaredMode, errors);
260
- } else {
261
- collectSolidErrors(light2, "light", errors);
262
- collectSolidErrors(dark2, "dark", errors);
360
+ },
361
+ dark: {
362
+ bg: "#2e3440",
363
+ // nord0
364
+ surface: "#3b4252",
365
+ // nord1
366
+ overlay: "#434c5e",
367
+ // nord2
368
+ border: "#4c566a",
369
+ // nord3
370
+ text: "#eceff4",
371
+ // nord6
372
+ textMuted: "#d8dee9",
373
+ // nord4
374
+ textOnFillLight: "#eceff4",
375
+ // nord6
376
+ textOnFillDark: "#2e3440",
377
+ // nord0
378
+ primary: "#88c0d0",
379
+ // nord8 (different from light's nord10)
380
+ secondary: "#81a1c1",
381
+ // nord9
382
+ accent: "#81a1c1",
383
+ // nord9
384
+ destructive: "#bf616a",
385
+ // nord11
386
+ colors: {
387
+ red: "#bf616a",
388
+ // nord11
389
+ orange: "#d08770",
390
+ // nord12
391
+ yellow: "#ebcb8b",
392
+ // nord13
393
+ green: "#a3be8c",
394
+ // nord14
395
+ blue: "#5e81ac",
396
+ // nord10
397
+ purple: "#b48ead",
398
+ // nord15
399
+ teal: "#8fbcbb",
400
+ // nord7
401
+ cyan: "#88c0d0",
402
+ // nord8
403
+ gray: "#4c566a",
404
+ // nord3
405
+ black: "#3b4252",
406
+ white: "#eceff4"
263
407
  }
264
408
  }
265
- if (errors.length > 0) return { ok: false, errors };
266
- const light = modes.light ?? modes.dark;
267
- const dark = modes.dark ?? modes.light;
268
- return {
269
- ok: true,
270
- palette: { id, name, light, dark },
271
- mode
272
- };
273
- }
409
+ };
274
410
 
275
- // src/palettes/atlas.ts
276
- var atlasPalette = {
277
- id: "atlas",
278
- name: "Atlas",
411
+ // src/palettes/slate.ts
412
+ var slatePalette = {
413
+ id: "slate",
414
+ name: "Slate",
279
415
  light: {
280
- bg: "#f3ead3",
281
- // warm manila / parchment
282
- surface: "#ece0c0",
283
- // deeper paper (cards, panels)
284
- overlay: "#e8dab8",
416
+ bg: "#ffffff",
417
+ // clean slide white
418
+ surface: "#f3f5f8",
419
+ // light cool-gray panel
420
+ overlay: "#eaeef3",
285
421
  // popovers, dropdowns
286
- border: "#bcaa86",
287
- // muted sepia rule line
288
- text: "#463a26",
289
- // aged sepia-brown ink
290
- textMuted: "#7a6a4f",
291
- // faded annotation ink
292
- textOnFillLight: "#f7f1de",
293
- // parchment (light text on dark fills)
294
- textOnFillDark: "#3a2e1c",
295
- // deep ink (dark text on light fills)
296
- primary: "#5b7a99",
297
- // pull-down map ocean (steel-blue)
298
- secondary: "#7e9a6f",
299
- // lowland sage / celadon
300
- accent: "#b07f7c",
301
- // dusty rose
302
- destructive: "#b25a45",
303
- // brick / terracotta
422
+ border: "#d4dae1",
423
+ // hairline rule
424
+ text: "#1f2933",
425
+ // near-black slate (softer than pure black)
426
+ textMuted: "#5b6672",
427
+ // secondary label
428
+ textOnFillLight: "#ffffff",
429
+ // light text on dark fills
430
+ textOnFillDark: "#1f2933",
431
+ // dark text on light fills
432
+ primary: "#3b6ea5",
433
+ // confident corporate blue
434
+ secondary: "#5b6672",
435
+ // slate gray
436
+ accent: "#3a9188",
437
+ // muted teal accent
438
+ destructive: "#c0504d",
439
+ // brick red
304
440
  colors: {
305
- red: "#bf6a52",
306
- // terracotta brick
307
- orange: "#cf9a5c",
308
- // map tan / ochre
309
- yellow: "#cdb35e",
310
- // straw / muted lemon
311
- green: "#7e9a6f",
312
- // sage / celadon lowland
313
- blue: "#5b7a99",
314
- // steel-blue ocean
315
- purple: "#9a7fa6",
316
- // dusty lilac / mauve
317
- teal: "#6fa094",
318
- // muted seafoam
319
- cyan: "#79a7b5",
320
- // shallow-water blue
321
- gray: "#8a7d68",
322
- // warm taupe
323
- black: "#463a26",
324
- // ink
325
- white: "#ece0c0"
326
- // paper
441
+ red: "#c0504d",
442
+ // brick
443
+ orange: "#cc7a33",
444
+ // muted amber
445
+ yellow: "#c9a227",
446
+ // gold (not neon)
447
+ green: "#5b9357",
448
+ // forest / sage
449
+ blue: "#3b6ea5",
450
+ // corporate blue
451
+ purple: "#7d5ba6",
452
+ // muted violet
453
+ teal: "#3a9188",
454
+ // teal
455
+ cyan: "#4f96c4",
456
+ // steel cyan
457
+ gray: "#7e8a97",
458
+ // cool gray
459
+ black: "#1f2933",
460
+ // slate ink
461
+ white: "#f3f5f8"
462
+ // panel
327
463
  }
328
464
  },
329
465
  dark: {
330
- bg: "#1e2a33",
331
- // deep map ocean (night globe)
332
- surface: "#27353f",
333
- // raised ocean
334
- overlay: "#2e3d48",
466
+ bg: "#161b22",
467
+ // deep slate (keynote dark)
468
+ surface: "#202833",
469
+ // raised panel
470
+ overlay: "#29323e",
335
471
  // popovers, dropdowns
336
- border: "#3d4f5c",
337
- // depth-contour line
338
- text: "#e8dcc0",
339
- // parchment ink, inverted
340
- textMuted: "#a89a7d",
341
- // faded label
342
- textOnFillLight: "#f7f1de",
343
- // parchment
344
- textOnFillDark: "#1a242c",
345
- // deep ocean ink
346
- primary: "#7ba0bf",
347
- // brighter ocean
348
- secondary: "#9bb588",
349
- // sage, lifted
350
- accent: "#cf9a96",
351
- // dusty rose, lifted
352
- destructive: "#c9745c",
353
- // brick, lifted
354
- colors: {
355
- red: "#cf7a60",
356
- // terracotta
357
- orange: "#d9a96a",
358
- // tan / ochre
359
- yellow: "#d8c074",
360
- // straw
361
- green: "#9bb588",
362
- // sage lowland
363
- blue: "#7ba0bf",
364
- // ocean
365
- purple: "#b59ac0",
366
- // lilac / mauve
367
- teal: "#85b3a6",
368
- // seafoam
369
- cyan: "#92bccb",
370
- // shallow-water blue
371
- gray: "#9a8d76",
372
- // warm taupe
373
- black: "#27353f",
374
- // raised ocean
375
- white: "#e8dcc0"
376
- // parchment
472
+ border: "#38424f",
473
+ // divider
474
+ text: "#e6eaef",
475
+ // off-white
476
+ textMuted: "#9aa5b1",
477
+ // secondary label
478
+ textOnFillLight: "#ffffff",
479
+ // light text on dark fills
480
+ textOnFillDark: "#161b22",
481
+ // dark text on light fills
482
+ primary: "#5b9bd5",
483
+ // lifted corporate blue
484
+ secondary: "#8593a3",
485
+ // slate gray, lifted
486
+ accent: "#45b3a3",
487
+ // teal, lifted
488
+ destructive: "#e07b6e",
489
+ // brick, lifted
490
+ colors: {
491
+ red: "#e07b6e",
492
+ // brick
493
+ orange: "#e0975a",
494
+ // amber
495
+ yellow: "#d9bd5a",
496
+ // gold
497
+ green: "#74b56e",
498
+ // forest / sage
499
+ blue: "#5b9bd5",
500
+ // corporate blue
501
+ purple: "#a585c9",
502
+ // violet
503
+ teal: "#45b3a3",
504
+ // teal
505
+ cyan: "#62b0d9",
506
+ // steel cyan
507
+ gray: "#95a1ae",
508
+ // cool gray
509
+ black: "#202833",
510
+ // raised panel
511
+ white: "#e6eaef"
512
+ // off-white
377
513
  }
378
514
  }
379
515
  };
380
- registerPalette(atlasPalette);
381
516
 
382
- // src/palettes/blueprint.ts
383
- var blueprintPalette = {
384
- id: "blueprint",
385
- name: "Blueprint",
517
+ // src/palettes/tidewater.ts
518
+ var tidewaterPalette = {
519
+ id: "tidewater",
520
+ name: "Tidewater",
386
521
  light: {
387
- bg: "#f4f8fb",
388
- // pale drafting white (faint cyan)
389
- surface: "#e6eef4",
390
- // drafting panel
391
- overlay: "#dde9f1",
522
+ bg: "#eceff0",
523
+ // weathered sea-mist paper
524
+ surface: "#e0e4e3",
525
+ // worn deck panel
526
+ overlay: "#dadfdf",
392
527
  // popovers, dropdowns
393
- border: "#aac3d6",
394
- // pale blue grid line
395
- text: "#123a5e",
396
- // blueprint navy ink
397
- textMuted: "#4f7390",
398
- // faint draft note
399
- textOnFillLight: "#f4f8fb",
400
- // drafting white
401
- textOnFillDark: "#0c2f4d",
402
- // deep blueprint navy
403
- primary: "#1f5e8c",
404
- // blueprint blue
405
- secondary: "#5b7d96",
406
- // steel
407
- accent: "#b08a3e",
408
- // draftsman's ochre highlight
409
- destructive: "#c0504d",
410
- // correction red
528
+ border: "#a9b2b3",
529
+ // muted slate rule
530
+ text: "#18313f",
531
+ // ship's-log navy ink
532
+ textMuted: "#51636b",
533
+ // faded log entry
534
+ textOnFillLight: "#f3f5f3",
535
+ // weathered white
536
+ textOnFillDark: "#162c38",
537
+ // deep navy
538
+ primary: "#1f4e6b",
539
+ // deep-sea navy
540
+ secondary: "#b08a4f",
541
+ // rope / manila tan
542
+ accent: "#c69a3e",
543
+ // brass
544
+ destructive: "#c1433a",
545
+ // signal-flag red
411
546
  colors: {
412
- red: "#c25a4e",
413
- // correction red
414
- orange: "#c2823e",
415
- // ochre
416
- yellow: "#c2a843",
417
- // pencil gold
547
+ red: "#c1433a",
548
+ // signal-flag red
549
+ orange: "#cc7a38",
550
+ // weathered amber
551
+ yellow: "#d6bf5a",
552
+ // brass gold
418
553
  green: "#4f8a6b",
419
- // drafting green
420
- blue: "#1f5e8c",
421
- // blueprint blue
422
- purple: "#6f5e96",
423
- // indigo pencil
424
- teal: "#3a8a8a",
425
- // teal
426
- cyan: "#3f8fb5",
427
- // cyan
428
- gray: "#7e8e98",
429
- // graphite
430
- black: "#123a5e",
554
+ // sea-glass green
555
+ blue: "#1f4e6b",
556
+ // deep-sea navy
557
+ purple: "#6a5a8c",
558
+ // twilight harbor
559
+ teal: "#3d8c8c",
560
+ // sea-glass teal
561
+ cyan: "#4f9bb5",
562
+ // shallow water
563
+ gray: "#8a8d86",
564
+ // driftwood gray
565
+ black: "#18313f",
431
566
  // navy ink
432
- white: "#e6eef4"
433
- // panel
567
+ white: "#e0e4e3"
568
+ // deck panel
434
569
  }
435
570
  },
436
571
  dark: {
437
- bg: "#103a5e",
438
- // deep blueprint blue (cyanotype ground)
439
- surface: "#16466e",
440
- // raised sheet
441
- overlay: "#1c5180",
572
+ bg: "#0f2230",
573
+ // night-harbor deep sea
574
+ surface: "#16303f",
575
+ // raised hull
576
+ overlay: "#1d3a4a",
442
577
  // popovers, dropdowns
443
- border: "#3a6f96",
444
- // grid line
445
- text: "#eaf2f8",
446
- // chalk white
447
- textMuted: "#9fc0d6",
448
- // faint chalk note
449
- textOnFillLight: "#eaf2f8",
450
- // chalk white
451
- textOnFillDark: "#0c2f4d",
452
- // deep blueprint navy
453
- primary: "#7fb8d8",
454
- // chalk cyan
455
- secondary: "#9fb8c8",
456
- // pale steel
457
- accent: "#d8c27a",
458
- // chalk amber
459
- destructive: "#e08a7a",
460
- // chalk correction red
578
+ border: "#2c4856",
579
+ // rigging line
580
+ text: "#e6ebe8",
581
+ // weathered white
582
+ textMuted: "#9aaab0",
583
+ // faded label
584
+ textOnFillLight: "#f3f5f3",
585
+ // weathered white
586
+ textOnFillDark: "#0f2230",
587
+ // deep sea
588
+ primary: "#4f9bc4",
589
+ // lifted sea blue
590
+ secondary: "#c9a46a",
591
+ // rope tan, lifted
592
+ accent: "#d9b25a",
593
+ // brass, lifted
594
+ destructive: "#e06a5e",
595
+ // signal red, lifted
461
596
  colors: {
462
- red: "#e0907e",
463
- // chalk red
464
- orange: "#e0ab78",
465
- // chalk amber
466
- yellow: "#e3d089",
467
- // chalk gold
468
- green: "#93c79e",
469
- // chalk green
470
- blue: "#8ec3e0",
471
- // chalk cyan-blue
472
- purple: "#b6a6d8",
473
- // chalk indigo
474
- teal: "#84c7c2",
475
- // chalk teal
476
- cyan: "#9fd6e0",
477
- // chalk cyan
478
- gray: "#aebecb",
479
- // chalk graphite
480
- black: "#16466e",
481
- // raised sheet
482
- white: "#eaf2f8"
483
- // chalk white
597
+ red: "#e06a5e",
598
+ // signal-flag red
599
+ orange: "#df9a52",
600
+ // amber
601
+ yellow: "#e0c662",
602
+ // brass gold
603
+ green: "#6fb58c",
604
+ // sea-glass green
605
+ blue: "#4f9bc4",
606
+ // sea blue
607
+ purple: "#9486bf",
608
+ // twilight harbor
609
+ teal: "#5cb0ac",
610
+ // sea-glass teal
611
+ cyan: "#62b4cf",
612
+ // shallow water
613
+ gray: "#9aa39c",
614
+ // driftwood gray
615
+ black: "#16303f",
616
+ // raised hull
617
+ white: "#e6ebe8"
618
+ // weathered white
484
619
  }
485
620
  }
486
621
  };
487
- registerPalette(blueprintPalette);
488
622
 
489
- // src/palettes/catppuccin.ts
490
- var catppuccinPalette = {
491
- id: "catppuccin",
492
- name: "Catppuccin",
623
+ // src/palettes/tokyo-night.ts
624
+ var tokyoNightPalette = {
625
+ id: "tokyo-night",
626
+ name: "Tokyo Night",
493
627
  light: {
494
- bg: "#eff1f5",
495
- // Latte Base
496
- surface: "#e6e9ef",
497
- // Latte Mantle
498
- overlay: "#ccd0da",
499
- // Latte Surface0
500
- border: "#dce0e8",
501
- // Latte Crust
502
- text: "#4c4f69",
503
- // Latte Text
504
- textMuted: "#5c5f77",
505
- // Latte Subtext1
506
- textOnFillLight: "#eff1f5",
507
- // Latte Base
508
- textOnFillDark: "#11111b",
509
- // Mocha Crust (Latte Text #4c4f69 fails 3:1 on saturated mid-luminance intents — orange/green/teal/cyan)
510
- primary: "#1e66f5",
511
- // Latte Blue
512
- secondary: "#7287fd",
513
- // Latte Lavender
514
- accent: "#8839ef",
515
- // Latte Mauve
516
- destructive: "#d20f39",
517
- // Latte Red
628
+ bg: "#e1e2e7",
629
+ // Day bg
630
+ surface: "#d0d5e3",
631
+ // Day bg_float
632
+ overlay: "#c4c8da",
633
+ // Day bg_highlight
634
+ border: "#a8aecb",
635
+ // Day fg_gutter
636
+ text: "#3760bf",
637
+ // Day fg
638
+ textMuted: "#6172b0",
639
+ // Day fg_dark
640
+ textOnFillLight: "#e1e2e7",
641
+ // Day bg
642
+ textOnFillDark: "#1a1b26",
643
+ // Night bg (deep dark)
644
+ primary: "#2e7de9",
645
+ // Day blue
646
+ secondary: "#007197",
647
+ // Day cyan
648
+ accent: "#9854f1",
649
+ // Day magenta
650
+ destructive: "#f52a65",
651
+ // Day red
518
652
  colors: {
519
- red: "#d20f39",
520
- orange: "#fe640b",
521
- yellow: "#df8e1d",
522
- green: "#40a02b",
523
- blue: "#1e66f5",
524
- purple: "#8839ef",
525
- teal: "#179299",
526
- cyan: "#209fb5",
527
- gray: "#9ca0b0",
528
- // Latte Overlay0
529
- black: "#4c4f69",
530
- white: "#e6e9ef"
653
+ red: "#f52a65",
654
+ orange: "#b15c00",
655
+ yellow: "#8c6c3e",
656
+ green: "#587539",
657
+ blue: "#2e7de9",
658
+ purple: "#7847bd",
659
+ teal: "#118c74",
660
+ cyan: "#007197",
661
+ gray: "#8990b3",
662
+ // Day dark3
663
+ black: "#1a1b26",
664
+ white: "#d0d5e3"
531
665
  }
532
666
  },
533
667
  dark: {
534
- bg: "#1e1e2e",
535
- // Mocha Base
536
- surface: "#313244",
537
- // Mocha Surface0
538
- overlay: "#45475a",
539
- // Mocha Surface1
540
- border: "#6c7086",
541
- // Mocha Overlay0
542
- text: "#cdd6f4",
543
- // Mocha Text
544
- textMuted: "#bac2de",
545
- // Mocha Subtext1
546
- textOnFillLight: "#f5e0dc",
547
- // Mocha Rosewater (highest-luminance accent)
548
- textOnFillDark: "#11111b",
549
- // Mocha Crust (low luminance)
550
- primary: "#89b4fa",
551
- // Mocha Blue
552
- secondary: "#b4befe",
553
- // Mocha Lavender
554
- accent: "#cba6f7",
555
- // Mocha Mauve
556
- destructive: "#f38ba8",
557
- // Mocha Red
668
+ bg: "#1a1b26",
669
+ // Night bg
670
+ surface: "#292e42",
671
+ // Night bg_highlight
672
+ overlay: "#414868",
673
+ // Night terminal_black
674
+ border: "#3b4261",
675
+ // Night fg_gutter
676
+ text: "#c0caf5",
677
+ // Night fg
678
+ textMuted: "#a9b1d6",
679
+ // Night fg_dark
680
+ textOnFillLight: "#c0caf5",
681
+ // Night fg
682
+ textOnFillDark: "#1a1b26",
683
+ // Night bg
684
+ primary: "#7aa2f7",
685
+ // Night blue
686
+ secondary: "#7dcfff",
687
+ // Night cyan
688
+ accent: "#bb9af7",
689
+ // Night magenta
690
+ destructive: "#f7768e",
691
+ // Night red
558
692
  colors: {
559
- red: "#f38ba8",
560
- orange: "#fab387",
561
- yellow: "#f9e2af",
562
- green: "#a6e3a1",
563
- blue: "#89b4fa",
564
- purple: "#cba6f7",
565
- teal: "#94e2d5",
566
- cyan: "#74c7ec",
567
- gray: "#6c7086",
568
- // Mocha Overlay0
569
- black: "#313244",
570
- white: "#cdd6f4"
693
+ red: "#f7768e",
694
+ orange: "#ff9e64",
695
+ yellow: "#e0af68",
696
+ green: "#9ece6a",
697
+ blue: "#7aa2f7",
698
+ purple: "#bb9af7",
699
+ teal: "#1abc9c",
700
+ cyan: "#7dcfff",
701
+ gray: "#565f89",
702
+ // Night comment
703
+ black: "#292e42",
704
+ white: "#c0caf5"
571
705
  }
572
706
  }
573
707
  };
574
- registerPalette(catppuccinPalette);
575
708
 
576
- // src/palettes/nord.ts
577
- var nordPalette = {
578
- id: "nord",
579
- name: "Nord",
580
- light: {
581
- bg: "#eceff4",
582
- // nord6
583
- surface: "#e5e9f0",
584
- // nord5
585
- overlay: "#d8dee9",
586
- // nord4 (muted/secondary backgrounds)
587
- border: "#d8dee9",
588
- // nord4
589
- text: "#2e3440",
590
- // nord0
591
- textMuted: "#4c566a",
592
- // nord3
593
- textOnFillLight: "#eceff4",
594
- // nord6
595
- textOnFillDark: "#2e3440",
596
- // nord0
597
- primary: "#5e81ac",
598
- // nord10
599
- secondary: "#81a1c1",
600
- // nord9
601
- accent: "#81a1c1",
602
- // nord9
603
- destructive: "#bf616a",
604
- // nord11
605
- colors: {
606
- red: "#bf616a",
607
- // nord11
608
- orange: "#d08770",
609
- // nord12
610
- yellow: "#ebcb8b",
611
- // nord13
612
- green: "#a3be8c",
613
- // nord14
614
- blue: "#5e81ac",
615
- // nord10
616
- purple: "#b48ead",
617
- // nord15
618
- teal: "#8fbcbb",
619
- // nord7
620
- cyan: "#88c0d0",
621
- // nord8
622
- gray: "#4c566a",
623
- // nord3
624
- black: "#2e3440",
625
- white: "#e5e9f0"
709
+ // src/palettes/registry.ts
710
+ var PALETTE_REGISTRY = /* @__PURE__ */ new Map();
711
+ var DEFAULT_PALETTE_ID = "slate";
712
+ function isValidHex(value) {
713
+ return /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value);
714
+ }
715
+ var COLOR_KEYS = [
716
+ "red",
717
+ "orange",
718
+ "yellow",
719
+ "green",
720
+ "blue",
721
+ "purple",
722
+ "teal",
723
+ "cyan",
724
+ "gray",
725
+ "black",
726
+ "white"
727
+ ];
728
+ var SEMANTIC_KEYS = [
729
+ "bg",
730
+ "surface",
731
+ "overlay",
732
+ "border",
733
+ "text",
734
+ "textMuted",
735
+ "textOnFillLight",
736
+ "textOnFillDark",
737
+ "primary",
738
+ "secondary",
739
+ "accent",
740
+ "destructive"
741
+ ];
742
+ function validatePaletteColors(colors, mode, paletteId) {
743
+ for (const key of SEMANTIC_KEYS) {
744
+ const value = colors[key];
745
+ if (typeof value !== "string" || !isValidHex(value)) {
746
+ throw new Error(
747
+ `Palette "${paletteId}" ${mode}.${key}: invalid hex "${value}"`
748
+ );
749
+ }
750
+ }
751
+ for (const key of COLOR_KEYS) {
752
+ const value = colors.colors[key];
753
+ if (typeof value !== "string" || !isValidHex(value)) {
754
+ throw new Error(
755
+ `Palette "${paletteId}" ${mode}.colors.${key}: invalid hex "${value}"`
756
+ );
757
+ }
758
+ }
759
+ }
760
+ function registerPalette(palette) {
761
+ validatePaletteColors(palette.light, "light", palette.id);
762
+ validatePaletteColors(palette.dark, "dark", palette.id);
763
+ PALETTE_REGISTRY.set(palette.id, palette);
764
+ }
765
+ function getPalette(id) {
766
+ return PALETTE_REGISTRY.get(id) ?? PALETTE_REGISTRY.get(DEFAULT_PALETTE_ID);
767
+ }
768
+ function resolvePaletteOrFallback(id, warn) {
769
+ const found = PALETTE_REGISTRY.get(id);
770
+ if (found) return found;
771
+ warn?.(
772
+ `Palette "${id}" is not registered \u2014 falling back to "${DEFAULT_PALETTE_ID}".`
773
+ );
774
+ return PALETTE_REGISTRY.get(DEFAULT_PALETTE_ID);
775
+ }
776
+ function getAvailablePalettes() {
777
+ return Array.from(PALETTE_REGISTRY.values()).sort(
778
+ (a, b) => a.name.localeCompare(b.name)
779
+ );
780
+ }
781
+ for (const palette of [
782
+ atlasPalette,
783
+ blueprintPalette,
784
+ catppuccinPalette,
785
+ nordPalette,
786
+ slatePalette,
787
+ tidewaterPalette,
788
+ tokyoNightPalette
789
+ ]) {
790
+ registerPalette(palette);
791
+ }
792
+
793
+ // src/palettes/theme-file.ts
794
+ var CONTRAST_FLOOR = 4.5;
795
+ var SOLID_FLOOR_LC = 45;
796
+ var FILL_ACCENT_KEYS = [
797
+ "primary",
798
+ "secondary",
799
+ "accent",
800
+ "destructive"
801
+ ];
802
+ var CONTRAST_EXEMPT = /* @__PURE__ */ new Set([
803
+ "black",
804
+ "white"
805
+ ]);
806
+ function isRecord(value) {
807
+ return typeof value === "object" && value !== null && !Array.isArray(value);
808
+ }
809
+ function collectShapeErrors(value, mode, errors) {
810
+ if (!isRecord(value)) {
811
+ errors.push(
812
+ `${mode}: expected an object of colors, got ${describe(value)}`
813
+ );
814
+ return false;
815
+ }
816
+ const before = errors.length;
817
+ const fields = /* @__PURE__ */ new Set([...SEMANTIC_KEYS, "colors"]);
818
+ for (const key of Object.keys(value)) {
819
+ if (!fields.has(key)) {
820
+ errors.push(`${mode}.${key}: not a palette field`);
626
821
  }
627
- },
628
- dark: {
629
- bg: "#2e3440",
630
- // nord0
631
- surface: "#3b4252",
632
- // nord1
633
- overlay: "#434c5e",
634
- // nord2
635
- border: "#4c566a",
636
- // nord3
637
- text: "#eceff4",
638
- // nord6
639
- textMuted: "#d8dee9",
640
- // nord4
641
- textOnFillLight: "#eceff4",
642
- // nord6
643
- textOnFillDark: "#2e3440",
644
- // nord0
645
- primary: "#88c0d0",
646
- // nord8 (different from light's nord10)
647
- secondary: "#81a1c1",
648
- // nord9
649
- accent: "#81a1c1",
650
- // nord9
651
- destructive: "#bf616a",
652
- // nord11
653
- colors: {
654
- red: "#bf616a",
655
- // nord11
656
- orange: "#d08770",
657
- // nord12
658
- yellow: "#ebcb8b",
659
- // nord13
660
- green: "#a3be8c",
661
- // nord14
662
- blue: "#5e81ac",
663
- // nord10
664
- purple: "#b48ead",
665
- // nord15
666
- teal: "#8fbcbb",
667
- // nord7
668
- cyan: "#88c0d0",
669
- // nord8
670
- gray: "#4c566a",
671
- // nord3
672
- black: "#3b4252",
673
- white: "#eceff4"
822
+ }
823
+ for (const key of SEMANTIC_KEYS) {
824
+ const hex = value[key];
825
+ if (typeof hex !== "string" || !isValidHex(hex)) {
826
+ errors.push(`${mode}.${key}: invalid hex ${describe(hex)}`);
674
827
  }
675
828
  }
676
- };
677
- registerPalette(nordPalette);
678
-
679
- // src/palettes/slate.ts
680
- var slatePalette = {
681
- id: "slate",
682
- name: "Slate",
683
- light: {
684
- bg: "#ffffff",
685
- // clean slide white
686
- surface: "#f3f5f8",
687
- // light cool-gray panel
688
- overlay: "#eaeef3",
689
- // popovers, dropdowns
690
- border: "#d4dae1",
691
- // hairline rule
692
- text: "#1f2933",
693
- // near-black slate (softer than pure black)
694
- textMuted: "#5b6672",
695
- // secondary label
696
- textOnFillLight: "#ffffff",
697
- // light text on dark fills
698
- textOnFillDark: "#1f2933",
699
- // dark text on light fills
700
- primary: "#3b6ea5",
701
- // confident corporate blue
702
- secondary: "#5b6672",
703
- // slate gray
704
- accent: "#3a9188",
705
- // muted teal accent
706
- destructive: "#c0504d",
707
- // brick red
708
- colors: {
709
- red: "#c0504d",
710
- // brick
711
- orange: "#cc7a33",
712
- // muted amber
713
- yellow: "#c9a227",
714
- // gold (not neon)
715
- green: "#5b9357",
716
- // forest / sage
717
- blue: "#3b6ea5",
718
- // corporate blue
719
- purple: "#7d5ba6",
720
- // muted violet
721
- teal: "#3a9188",
722
- // teal
723
- cyan: "#4f96c4",
724
- // steel cyan
725
- gray: "#7e8a97",
726
- // cool gray
727
- black: "#1f2933",
728
- // slate ink
729
- white: "#f3f5f8"
730
- // panel
829
+ const named = value["colors"];
830
+ if (!isRecord(named)) {
831
+ errors.push(
832
+ `${mode}.colors: expected an object of named colors, got ${describe(named)}`
833
+ );
834
+ } else {
835
+ const names = new Set(COLOR_KEYS);
836
+ for (const key of Object.keys(named)) {
837
+ if (!names.has(key)) {
838
+ errors.push(
839
+ `${mode}.colors.${key}: not a palette color \u2014 a theme sets the existing color names and cannot add one`
840
+ );
841
+ }
731
842
  }
732
- },
733
- dark: {
734
- bg: "#161b22",
735
- // deep slate (keynote dark)
736
- surface: "#202833",
737
- // raised panel
738
- overlay: "#29323e",
739
- // popovers, dropdowns
740
- border: "#38424f",
741
- // divider
742
- text: "#e6eaef",
743
- // off-white
744
- textMuted: "#9aa5b1",
745
- // secondary label
746
- textOnFillLight: "#ffffff",
747
- // light text on dark fills
748
- textOnFillDark: "#161b22",
749
- // dark text on light fills
750
- primary: "#5b9bd5",
751
- // lifted corporate blue
752
- secondary: "#8593a3",
753
- // slate gray, lifted
754
- accent: "#45b3a3",
755
- // teal, lifted
756
- destructive: "#e07b6e",
757
- // brick, lifted
758
- colors: {
759
- red: "#e07b6e",
760
- // brick
761
- orange: "#e0975a",
762
- // amber
763
- yellow: "#d9bd5a",
764
- // gold
765
- green: "#74b56e",
766
- // forest / sage
767
- blue: "#5b9bd5",
768
- // corporate blue
769
- purple: "#a585c9",
770
- // violet
771
- teal: "#45b3a3",
772
- // teal
773
- cyan: "#62b0d9",
774
- // steel cyan
775
- gray: "#95a1ae",
776
- // cool gray
777
- black: "#202833",
778
- // raised panel
779
- white: "#e6eaef"
780
- // off-white
843
+ for (const key of COLOR_KEYS) {
844
+ const hex = named[key];
845
+ if (typeof hex !== "string" || !isValidHex(hex)) {
846
+ errors.push(`${mode}.colors.${key}: invalid hex ${describe(hex)}`);
847
+ }
848
+ }
849
+ }
850
+ return errors.length === before;
851
+ }
852
+ function describe(value) {
853
+ if (value === void 0) return "nothing";
854
+ if (typeof value === "string") return `"${value}"`;
855
+ if (value === null) return "null";
856
+ return typeof value;
857
+ }
858
+ function intents(colors) {
859
+ const out = [];
860
+ for (const key of COLOR_KEYS) {
861
+ if (CONTRAST_EXEMPT.has(key)) continue;
862
+ out.push([`colors.${key}`, colors.colors[key]]);
863
+ }
864
+ for (const key of FILL_ACCENT_KEYS) out.push([key, colors[key]]);
865
+ return out;
866
+ }
867
+ function drawnToken(colors, bg) {
868
+ const drawn = contrastText(bg, colors.textOnFillLight, colors.textOnFillDark);
869
+ return drawn === colors.textOnFillDark ? "textOnFillDark" : "textOnFillLight";
870
+ }
871
+ function worstTintedFill(colors, isDark) {
872
+ let worst;
873
+ for (const [fill, intent] of intents(colors)) {
874
+ const fillHex = shapeFill(colors, intent, isDark);
875
+ const token = drawnToken(colors, fillHex);
876
+ const ratio = contrastRatio(colors[token], fillHex);
877
+ if (!worst || ratio < worst.ratio) {
878
+ worst = { ratio, token, fill, fillHex };
879
+ }
880
+ }
881
+ return worst;
882
+ }
883
+ function worstSolidFill(colors) {
884
+ let worst;
885
+ for (const [fill, intent] of intents(colors)) {
886
+ const token = drawnToken(colors, intent);
887
+ const lc = Math.abs(apcaContrast(colors[token], intent));
888
+ if (!worst || lc < worst.lc) {
889
+ worst = { lc, token, fill, fillHex: intent };
781
890
  }
782
891
  }
783
- };
784
- registerPalette(slatePalette);
785
-
786
- // src/palettes/tidewater.ts
787
- var tidewaterPalette = {
788
- id: "tidewater",
789
- name: "Tidewater",
790
- light: {
791
- bg: "#eceff0",
792
- // weathered sea-mist paper
793
- surface: "#e0e4e3",
794
- // worn deck panel
795
- overlay: "#dadfdf",
796
- // popovers, dropdowns
797
- border: "#a9b2b3",
798
- // muted slate rule
799
- text: "#18313f",
800
- // ship's-log navy ink
801
- textMuted: "#51636b",
802
- // faded log entry
803
- textOnFillLight: "#f3f5f3",
804
- // weathered white
805
- textOnFillDark: "#162c38",
806
- // deep navy
807
- primary: "#1f4e6b",
808
- // deep-sea navy
809
- secondary: "#b08a4f",
810
- // rope / manila tan
811
- accent: "#c69a3e",
812
- // brass
813
- destructive: "#c1433a",
814
- // signal-flag red
815
- colors: {
816
- red: "#c1433a",
817
- // signal-flag red
818
- orange: "#cc7a38",
819
- // weathered amber
820
- yellow: "#d6bf5a",
821
- // brass gold
822
- green: "#4f8a6b",
823
- // sea-glass green
824
- blue: "#1f4e6b",
825
- // deep-sea navy
826
- purple: "#6a5a8c",
827
- // twilight harbor
828
- teal: "#3d8c8c",
829
- // sea-glass teal
830
- cyan: "#4f9bb5",
831
- // shallow water
832
- gray: "#8a8d86",
833
- // driftwood gray
834
- black: "#18313f",
835
- // navy ink
836
- white: "#e0e4e3"
837
- // deck panel
892
+ return worst;
893
+ }
894
+ function collectContrastErrors(colors, where, isDark, errors) {
895
+ const tinted = worstTintedFill(colors, isDark);
896
+ if (tinted.ratio < CONTRAST_FLOOR) {
897
+ errors.push(
898
+ `${where}: ${tinted.token} ${colors[tinted.token]} on the ${tinted.fill} fill ${tinted.fillHex} reaches only ${tinted.ratio.toFixed(2)}:1 \u2014 text on a fill needs ${CONTRAST_FLOOR.toFixed(1)}:1`
899
+ );
900
+ }
901
+ }
902
+ function collectSolidErrors(colors, where, errors) {
903
+ const solid = worstSolidFill(colors);
904
+ if (solid.lc >= SOLID_FLOOR_LC) return;
905
+ errors.push(
906
+ `${where}: ${solid.token} ${colors[solid.token]} on the solid ${solid.fill} ${solid.fillHex} reaches only Lc ${solid.lc.toFixed(1)} \u2014 text on a solid fill needs Lc ${SOLID_FLOOR_LC}`
907
+ );
908
+ }
909
+ function validateThemeFile(input) {
910
+ const errors = [];
911
+ if (!isRecord(input)) {
912
+ return {
913
+ ok: false,
914
+ errors: [`expected a theme object, got ${describe(input)}`]
915
+ };
916
+ }
917
+ const id = input["id"];
918
+ if (typeof id !== "string" || id.trim() === "") {
919
+ errors.push(`id: expected a non-empty string, got ${describe(id)}`);
920
+ } else if (BUILT_IN_PALETTE_IDS.has(id)) {
921
+ errors.push(
922
+ `id: "${id}" is a built-in palette \u2014 a theme file needs an id of its own`
923
+ );
924
+ }
925
+ const name = input["name"];
926
+ if (typeof name !== "string" || name.trim() === "") {
927
+ errors.push(`name: expected a non-empty string, got ${describe(name)}`);
928
+ }
929
+ const declared = input["mode"];
930
+ let mode = null;
931
+ if (declared !== void 0) {
932
+ if (declared === "light" || declared === "dark") {
933
+ mode = declared;
934
+ } else {
935
+ errors.push(
936
+ `mode: expected "light" or "dark", got ${describe(declared)}`
937
+ );
838
938
  }
839
- },
840
- dark: {
841
- bg: "#0f2230",
842
- // night-harbor deep sea
843
- surface: "#16303f",
844
- // raised hull
845
- overlay: "#1d3a4a",
846
- // popovers, dropdowns
847
- border: "#2c4856",
848
- // rigging line
849
- text: "#e6ebe8",
850
- // weathered white
851
- textMuted: "#9aaab0",
852
- // faded label
853
- textOnFillLight: "#f3f5f3",
854
- // weathered white
855
- textOnFillDark: "#0f2230",
856
- // deep sea
857
- primary: "#4f9bc4",
858
- // lifted sea blue
859
- secondary: "#c9a46a",
860
- // rope tan, lifted
861
- accent: "#d9b25a",
862
- // brass, lifted
863
- destructive: "#e06a5e",
864
- // signal red, lifted
865
- colors: {
866
- red: "#e06a5e",
867
- // signal-flag red
868
- orange: "#df9a52",
869
- // amber
870
- yellow: "#e0c662",
871
- // brass gold
872
- green: "#6fb58c",
873
- // sea-glass green
874
- blue: "#4f9bc4",
875
- // sea blue
876
- purple: "#9486bf",
877
- // twilight harbor
878
- teal: "#5cb0ac",
879
- // sea-glass teal
880
- cyan: "#62b4cf",
881
- // shallow water
882
- gray: "#9aa39c",
883
- // driftwood gray
884
- black: "#16303f",
885
- // raised hull
886
- white: "#e6ebe8"
887
- // weathered white
939
+ }
940
+ if (mode) {
941
+ const other = mode === "light" ? "dark" : "light";
942
+ if (input[other] !== void 0) {
943
+ errors.push(
944
+ `${other}: a theme declaring mode "${mode}" must not also define ${other} \u2014 drop the mode to define both`
945
+ );
888
946
  }
889
947
  }
890
- };
891
- registerPalette(tidewaterPalette);
892
-
893
- // src/palettes/tokyo-night.ts
894
- var tokyoNightPalette = {
895
- id: "tokyo-night",
896
- name: "Tokyo Night",
897
- light: {
898
- bg: "#e1e2e7",
899
- // Day bg
900
- surface: "#d0d5e3",
901
- // Day bg_float
902
- overlay: "#c4c8da",
903
- // Day bg_highlight
904
- border: "#a8aecb",
905
- // Day fg_gutter
906
- text: "#3760bf",
907
- // Day fg
908
- textMuted: "#6172b0",
909
- // Day fg_dark
910
- textOnFillLight: "#e1e2e7",
911
- // Day bg
912
- textOnFillDark: "#1a1b26",
913
- // Night bg (deep dark)
914
- primary: "#2e7de9",
915
- // Day blue
916
- secondary: "#007197",
917
- // Day cyan
918
- accent: "#9854f1",
919
- // Day magenta
920
- destructive: "#f52a65",
921
- // Day red
922
- colors: {
923
- red: "#f52a65",
924
- orange: "#b15c00",
925
- yellow: "#8c6c3e",
926
- green: "#587539",
927
- blue: "#2e7de9",
928
- purple: "#7847bd",
929
- teal: "#118c74",
930
- cyan: "#007197",
931
- gray: "#8990b3",
932
- // Day dark3
933
- black: "#1a1b26",
934
- white: "#d0d5e3"
948
+ const wanted = mode ? [mode] : ["light", "dark"];
949
+ const modes = {};
950
+ for (const key of wanted) {
951
+ const value = input[key];
952
+ if (value === void 0) {
953
+ errors.push(
954
+ mode ? `${key}: a theme declaring mode "${mode}" has to define ${key}` : `${key}: a theme without a mode has to define both light and dark`
955
+ );
956
+ continue;
935
957
  }
936
- },
937
- dark: {
938
- bg: "#1a1b26",
939
- // Night bg
940
- surface: "#292e42",
941
- // Night bg_highlight
942
- overlay: "#414868",
943
- // Night terminal_black
944
- border: "#3b4261",
945
- // Night fg_gutter
946
- text: "#c0caf5",
947
- // Night fg
948
- textMuted: "#a9b1d6",
949
- // Night fg_dark
950
- textOnFillLight: "#c0caf5",
951
- // Night fg
952
- textOnFillDark: "#1a1b26",
953
- // Night bg
954
- primary: "#7aa2f7",
955
- // Night blue
956
- secondary: "#7dcfff",
957
- // Night cyan
958
- accent: "#bb9af7",
959
- // Night magenta
960
- destructive: "#f7768e",
961
- // Night red
962
- colors: {
963
- red: "#f7768e",
964
- orange: "#ff9e64",
965
- yellow: "#e0af68",
966
- green: "#9ece6a",
967
- blue: "#7aa2f7",
968
- purple: "#bb9af7",
969
- teal: "#1abc9c",
970
- cyan: "#7dcfff",
971
- gray: "#565f89",
972
- // Night comment
973
- black: "#292e42",
974
- white: "#c0caf5"
958
+ if (collectShapeErrors(value, key, errors)) modes[key] = value;
959
+ }
960
+ if (errors.length === 0) {
961
+ const light2 = modes.light ?? modes.dark;
962
+ const dark2 = modes.dark ?? modes.light;
963
+ const declaredMode = mode;
964
+ const label = (render) => declaredMode !== null && render !== declaredMode ? `${render} (a theme declaring mode "${declaredMode}" is used in ${render} mode too)` : render;
965
+ collectContrastErrors(light2, label("light"), false, errors);
966
+ collectContrastErrors(dark2, label("dark"), true, errors);
967
+ if (declaredMode !== null) {
968
+ collectSolidErrors(light2, declaredMode, errors);
969
+ } else {
970
+ collectSolidErrors(light2, "light", errors);
971
+ collectSolidErrors(dark2, "dark", errors);
975
972
  }
976
973
  }
977
- };
978
- registerPalette(tokyoNightPalette);
979
-
980
- // src/palettes/index.ts
981
- var palettes = {
982
- atlas: atlasPalette,
983
- blueprint: blueprintPalette,
984
- slate: slatePalette,
985
- tidewater: tidewaterPalette,
986
- nord: nordPalette,
987
- catppuccin: catppuccinPalette,
988
- tokyoNight: tokyoNightPalette
989
- };
974
+ if (errors.length > 0) return { ok: false, errors };
975
+ const light = modes.light ?? modes.dark;
976
+ const dark = modes.dark ?? modes.light;
977
+ return {
978
+ ok: true,
979
+ palette: { id, name, light, dark },
980
+ mode
981
+ };
982
+ }
990
983
 
991
984
  export {
985
+ atlasPalette,
986
+ blueprintPalette,
987
+ catppuccinPalette,
988
+ nordPalette,
989
+ slatePalette,
990
+ tidewaterPalette,
991
+ tokyoNightPalette,
992
992
  DEFAULT_PALETTE_ID,
993
993
  isValidHex,
994
994
  COLOR_KEYS,
@@ -997,13 +997,5 @@ export {
997
997
  getPalette,
998
998
  resolvePaletteOrFallback,
999
999
  getAvailablePalettes,
1000
- validateThemeFile,
1001
- atlasPalette,
1002
- blueprintPalette,
1003
- catppuccinPalette,
1004
- nordPalette,
1005
- slatePalette,
1006
- tidewaterPalette,
1007
- tokyoNightPalette,
1008
- palettes
1000
+ validateThemeFile
1009
1001
  };