@tldraw/tlschema 4.6.0-next.20de11b7e238 → 4.6.0-next.241e87d4700a

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 (79) hide show
  1. package/dist-cjs/assets/TLBaseAsset.js +4 -3
  2. package/dist-cjs/assets/TLBaseAsset.js.map +2 -2
  3. package/dist-cjs/assets/TLBookmarkAsset.js +9 -7
  4. package/dist-cjs/assets/TLBookmarkAsset.js.map +2 -2
  5. package/dist-cjs/assets/TLImageAsset.js +12 -10
  6. package/dist-cjs/assets/TLImageAsset.js.map +2 -2
  7. package/dist-cjs/assets/TLVideoAsset.js +11 -9
  8. package/dist-cjs/assets/TLVideoAsset.js.map +2 -2
  9. package/dist-cjs/createTLSchema.js +10 -4
  10. package/dist-cjs/createTLSchema.js.map +2 -2
  11. package/dist-cjs/index.d.ts +601 -343
  12. package/dist-cjs/index.js +17 -7
  13. package/dist-cjs/index.js.map +2 -2
  14. package/dist-cjs/records/TLAsset.js +29 -14
  15. package/dist-cjs/records/TLAsset.js.map +2 -2
  16. package/dist-cjs/shapes/TLFrameShape.js +3 -1
  17. package/dist-cjs/shapes/TLFrameShape.js.map +2 -2
  18. package/dist-cjs/shapes/TLNoteShape.js +12 -2
  19. package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
  20. package/dist-cjs/styles/StyleProp.js +38 -1
  21. package/dist-cjs/styles/StyleProp.js.map +2 -2
  22. package/dist-cjs/styles/TLColorStyle.js +36 -487
  23. package/dist-cjs/styles/TLColorStyle.js.map +2 -2
  24. package/dist-cjs/styles/TLDashStyle.js +1 -1
  25. package/dist-cjs/styles/TLDashStyle.js.map +2 -2
  26. package/dist-cjs/styles/TLFontFace.js +17 -0
  27. package/dist-cjs/styles/TLFontFace.js.map +7 -0
  28. package/dist-cjs/styles/TLFontStyle.js +36 -1
  29. package/dist-cjs/styles/TLFontStyle.js.map +2 -2
  30. package/dist-cjs/styles/TLTheme.js +17 -0
  31. package/dist-cjs/styles/TLTheme.js.map +7 -0
  32. package/dist-esm/assets/TLBaseAsset.mjs +4 -3
  33. package/dist-esm/assets/TLBaseAsset.mjs.map +2 -2
  34. package/dist-esm/assets/TLBookmarkAsset.mjs +9 -7
  35. package/dist-esm/assets/TLBookmarkAsset.mjs.map +2 -2
  36. package/dist-esm/assets/TLImageAsset.mjs +12 -10
  37. package/dist-esm/assets/TLImageAsset.mjs.map +2 -2
  38. package/dist-esm/assets/TLVideoAsset.mjs +11 -9
  39. package/dist-esm/assets/TLVideoAsset.mjs.map +2 -2
  40. package/dist-esm/createTLSchema.mjs +17 -8
  41. package/dist-esm/createTLSchema.mjs.map +2 -2
  42. package/dist-esm/index.d.mts +601 -343
  43. package/dist-esm/index.mjs +28 -14
  44. package/dist-esm/index.mjs.map +2 -2
  45. package/dist-esm/records/TLAsset.mjs +29 -14
  46. package/dist-esm/records/TLAsset.mjs.map +2 -2
  47. package/dist-esm/shapes/TLFrameShape.mjs +3 -1
  48. package/dist-esm/shapes/TLFrameShape.mjs.map +2 -2
  49. package/dist-esm/shapes/TLNoteShape.mjs +12 -2
  50. package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
  51. package/dist-esm/styles/StyleProp.mjs +38 -1
  52. package/dist-esm/styles/StyleProp.mjs.map +2 -2
  53. package/dist-esm/styles/TLColorStyle.mjs +36 -487
  54. package/dist-esm/styles/TLColorStyle.mjs.map +2 -2
  55. package/dist-esm/styles/TLDashStyle.mjs +1 -1
  56. package/dist-esm/styles/TLDashStyle.mjs.map +2 -2
  57. package/dist-esm/styles/TLFontFace.mjs +1 -0
  58. package/dist-esm/styles/TLFontFace.mjs.map +7 -0
  59. package/dist-esm/styles/TLFontStyle.mjs +36 -1
  60. package/dist-esm/styles/TLFontStyle.mjs.map +2 -2
  61. package/dist-esm/styles/TLTheme.mjs +1 -0
  62. package/dist-esm/styles/TLTheme.mjs.map +7 -0
  63. package/package.json +5 -5
  64. package/src/assets/TLBaseAsset.ts +25 -28
  65. package/src/assets/TLBookmarkAsset.ts +13 -33
  66. package/src/assets/TLImageAsset.ts +16 -42
  67. package/src/assets/TLVideoAsset.ts +15 -40
  68. package/src/createTLSchema.ts +54 -15
  69. package/src/index.ts +31 -11
  70. package/src/migrations.test.ts +22 -0
  71. package/src/records/TLAsset.ts +139 -74
  72. package/src/shapes/TLFrameShape.ts +3 -1
  73. package/src/shapes/TLNoteShape.ts +19 -5
  74. package/src/styles/StyleProp.ts +42 -5
  75. package/src/styles/TLColorStyle.ts +55 -698
  76. package/src/styles/TLDashStyle.ts +1 -1
  77. package/src/styles/TLFontFace.ts +65 -0
  78. package/src/styles/TLFontStyle.ts +53 -4
  79. package/src/styles/TLTheme.ts +240 -0
@@ -1,26 +1,23 @@
1
- import { Expand } from '@tldraw/utils'
2
- import { T } from '@tldraw/validate'
3
1
  import { StyleProp } from './StyleProp'
2
+ import { TLDefaultColor, TLThemeDefaultColors, TLThemes } from './TLTheme'
4
3
 
5
4
  /**
6
- * Array of default color names available in tldraw's color palette.
7
- * These colors form the basis for the default color style system and are available
8
- * in both light and dark theme variants.
9
- *
10
- * @example
11
- * ```ts
12
- * import { defaultColorNames } from '@tldraw/tlschema'
13
- *
14
- * // Create a color picker with all default colors
15
- * const colorOptions = defaultColorNames.map(color => ({
16
- * name: color,
17
- * value: color
18
- * }))
19
- * ```
5
+ * The names of all available shape colors, derived from {@link TLThemeDefaultColors}.
6
+ * Extend {@link TLThemeDefaultColors} to add custom color names.
20
7
  *
21
8
  * @public
22
9
  */
23
- export const defaultColorNames = [
10
+ export type TLDefaultColorStyle = {
11
+ [K in keyof TLThemeDefaultColors]: TLThemeDefaultColors[K] extends TLDefaultColor ? K : never
12
+ }[keyof TLThemeDefaultColors] &
13
+ string
14
+
15
+ /**
16
+ * Used only for initial values of the color style; the source of truth has moved to TLTheme.
17
+ *
18
+ * @internal
19
+ */
20
+ const defaultColorNames: TLDefaultColorStyle[] = [
24
21
  'black',
25
22
  'grey',
26
23
  'light-violet',
@@ -37,579 +34,6 @@ export const defaultColorNames = [
37
34
  ] as const
38
35
 
39
36
  /**
40
- * Defines the color variants available for each color in the default theme.
41
- * Each color has multiple variants for different use cases like fills, strokes,
42
- * patterns, and UI elements like frames and notes.
43
- *
44
- * @example
45
- * ```ts
46
- * import { TLDefaultColorThemeColor } from '@tldraw/tlschema'
47
- *
48
- * const blueColor: TLDefaultColorThemeColor = {
49
- * solid: '#4465e9',
50
- * semi: '#dce1f8',
51
- * pattern: '#6681ee',
52
- * fill: '#4465e9',
53
- * // ... other variants
54
- * }
55
- * ```
56
- *
57
- * @public
58
- */
59
- export interface TLDefaultColorThemeColor {
60
- solid: string
61
- semi: string
62
- pattern: string
63
- fill: string // usually same as solid
64
- linedFill: string // usually slightly lighter than fill
65
- frameHeadingStroke: string
66
- frameHeadingFill: string
67
- frameStroke: string
68
- frameFill: string
69
- frameText: string
70
- noteFill: string
71
- noteText: string
72
- highlightSrgb: string
73
- highlightP3: string
74
- }
75
-
76
- /**
77
- * Complete color theme definition containing all colors and their variants
78
- * for either light or dark mode. Includes base theme properties and all
79
- * default colors with their respective color variants.
80
- *
81
- * @example
82
- * ```ts
83
- * import { TLDefaultColorTheme } from '@tldraw/tlschema'
84
- *
85
- * const customTheme: TLDefaultColorTheme = {
86
- * id: 'light',
87
- * text: '#000000',
88
- * background: '#ffffff',
89
- * solid: '#fcfffe',
90
- * black: { solid: '#000000', semi: '#cccccc', ... },
91
- * // ... other colors
92
- * }
93
- * ```
94
- *
95
- * @public
96
- */
97
- export type TLDefaultColorTheme = Expand<
98
- {
99
- id: 'light' | 'dark'
100
- text: string
101
- background: string
102
- solid: string
103
- } & Record<(typeof defaultColorNames)[number], TLDefaultColorThemeColor>
104
- >
105
-
106
- /**
107
- * Complete color palette containing both light and dark theme definitions.
108
- * This object provides the full color system used by tldraw's default themes,
109
- * including all color variants and theme-specific adjustments.
110
- *
111
- * @example
112
- * ```ts
113
- * import { DefaultColorThemePalette } from '@tldraw/tlschema'
114
- *
115
- * // Get the dark theme colors
116
- * const darkTheme = DefaultColorThemePalette.darkMode
117
- * const redColor = darkTheme.red.solid // '#e03131'
118
- *
119
- * // Access light theme colors
120
- * const lightTheme = DefaultColorThemePalette.lightMode
121
- * const blueColor = lightTheme.blue.fill // '#4465e9'
122
- * ```
123
- *
124
- * @public
125
- */
126
- export const DefaultColorThemePalette: {
127
- lightMode: TLDefaultColorTheme
128
- darkMode: TLDefaultColorTheme
129
- } = {
130
- lightMode: {
131
- id: 'light',
132
- text: '#000000',
133
- background: '#f9fafb',
134
- solid: '#fcfffe',
135
- black: {
136
- solid: '#1d1d1d',
137
- fill: '#1d1d1d',
138
- linedFill: '#363636',
139
- frameHeadingStroke: '#717171',
140
- frameHeadingFill: '#ffffff',
141
- frameStroke: '#717171',
142
- frameFill: '#ffffff',
143
- frameText: '#000000',
144
- noteFill: '#FCE19C',
145
- noteText: '#000000',
146
- semi: '#e8e8e8',
147
- pattern: '#494949',
148
- highlightSrgb: '#fddd00',
149
- highlightP3: 'color(display-p3 0.972 0.8205 0.05)',
150
- },
151
- blue: {
152
- solid: '#4465e9',
153
- fill: '#4465e9',
154
- linedFill: '#6580ec',
155
- frameHeadingStroke: '#6681ec',
156
- frameHeadingFill: '#f9fafe',
157
- frameStroke: '#6681ec',
158
- frameFill: '#f9fafe',
159
- frameText: '#000000',
160
- noteFill: '#8AA3FF',
161
- noteText: '#000000',
162
- semi: '#dce1f8',
163
- pattern: '#6681ee',
164
- highlightSrgb: '#10acff',
165
- highlightP3: 'color(display-p3 0.308 0.6632 0.9996)',
166
- },
167
- green: {
168
- solid: '#099268',
169
- fill: '#099268',
170
- linedFill: '#0bad7c',
171
- frameHeadingStroke: '#37a684',
172
- frameHeadingFill: '#f8fcfa',
173
- frameStroke: '#37a684',
174
- frameFill: '#f8fcfa',
175
- frameText: '#000000',
176
- noteFill: '#6FC896',
177
- noteText: '#000000',
178
- semi: '#d3e9e3',
179
- pattern: '#39a785',
180
- highlightSrgb: '#00ffc8',
181
- highlightP3: 'color(display-p3 0.2536 0.984 0.7981)',
182
- },
183
- grey: {
184
- solid: '#9fa8b2',
185
- fill: '#9fa8b2',
186
- linedFill: '#bbc1c9',
187
- frameHeadingStroke: '#aaaaab',
188
- frameHeadingFill: '#fbfcfc',
189
- frameStroke: '#aaaaab',
190
- frameFill: '#fcfcfd',
191
- frameText: '#000000',
192
- noteFill: '#C0CAD3',
193
- noteText: '#000000',
194
- semi: '#eceef0',
195
- pattern: '#bcc3c9',
196
- highlightSrgb: '#cbe7f1',
197
- highlightP3: 'color(display-p3 0.8163 0.9023 0.9416)',
198
- },
199
- 'light-blue': {
200
- solid: '#4ba1f1',
201
- fill: '#4ba1f1',
202
- linedFill: '#7abaf5',
203
- frameHeadingStroke: '#6cb2f3',
204
- frameHeadingFill: '#f8fbfe',
205
- frameStroke: '#6cb2f3',
206
- frameFill: '#fafcff',
207
- frameText: '#000000',
208
- noteFill: '#9BC4FD',
209
- noteText: '#000000',
210
- semi: '#ddedfa',
211
- pattern: '#6fbbf8',
212
- highlightSrgb: '#00f4ff',
213
- highlightP3: 'color(display-p3 0.1512 0.9414 0.9996)',
214
- },
215
- 'light-green': {
216
- solid: '#4cb05e',
217
- fill: '#4cb05e',
218
- linedFill: '#7ec88c',
219
- frameHeadingStroke: '#6dbe7c',
220
- frameHeadingFill: '#f8fcf9',
221
- frameStroke: '#6dbe7c',
222
- frameFill: '#fafdfa',
223
- frameText: '#000000',
224
- noteFill: '#98D08A',
225
- noteText: '#000000',
226
- semi: '#dbf0e0',
227
- pattern: '#65cb78',
228
- highlightSrgb: '#65f641',
229
- highlightP3: 'color(display-p3 0.563 0.9495 0.3857)',
230
- },
231
- 'light-red': {
232
- solid: '#f87777',
233
- fill: '#f87777',
234
- linedFill: '#f99a9a',
235
- frameHeadingStroke: '#f89090',
236
- frameHeadingFill: '#fffafa',
237
- frameStroke: '#f89090',
238
- frameFill: '#fffbfb',
239
- frameText: '#000000',
240
- noteFill: '#F7A5A1',
241
- noteText: '#000000',
242
- semi: '#f4dadb',
243
- pattern: '#fe9e9e',
244
- highlightSrgb: '#ff7fa3',
245
- highlightP3: 'color(display-p3 0.9988 0.5301 0.6397)',
246
- },
247
- 'light-violet': {
248
- solid: '#e085f4',
249
- fill: '#e085f4',
250
- linedFill: '#e9abf7',
251
- frameHeadingStroke: '#e59bf5',
252
- frameHeadingFill: '#fefaff',
253
- frameStroke: '#e59bf5',
254
- frameFill: '#fefbff',
255
- frameText: '#000000',
256
- noteFill: '#DFB0F9',
257
- noteText: '#000000',
258
- semi: '#f5eafa',
259
- pattern: '#e9acf8',
260
- highlightSrgb: '#ff88ff',
261
- highlightP3: 'color(display-p3 0.9676 0.5652 0.9999)',
262
- },
263
- orange: {
264
- solid: '#e16919',
265
- fill: '#e16919',
266
- linedFill: '#ea8643',
267
- frameHeadingStroke: '#e68544',
268
- frameHeadingFill: '#fef9f6',
269
- frameStroke: '#e68544',
270
- frameFill: '#fef9f6',
271
- frameText: '#000000',
272
- noteFill: '#FAA475',
273
- noteText: '#000000',
274
- semi: '#f8e2d4',
275
- pattern: '#f78438',
276
- highlightSrgb: '#ffa500',
277
- highlightP3: 'color(display-p3 0.9988 0.6905 0.266)',
278
- },
279
- red: {
280
- solid: '#e03131',
281
- fill: '#e03131',
282
- linedFill: '#e75f5f',
283
- frameHeadingStroke: '#e55757',
284
- frameHeadingFill: '#fef7f7',
285
- frameStroke: '#e55757',
286
- frameFill: '#fef9f9',
287
- frameText: '#000000',
288
- noteFill: '#FC8282',
289
- noteText: '#000000',
290
- semi: '#f4dadb',
291
- pattern: '#e55959',
292
- highlightSrgb: '#ff636e',
293
- highlightP3: 'color(display-p3 0.9992 0.4376 0.45)',
294
- },
295
- violet: {
296
- solid: '#ae3ec9',
297
- fill: '#ae3ec9',
298
- linedFill: '#be68d4',
299
- frameHeadingStroke: '#bc62d3',
300
- frameHeadingFill: '#fcf7fd',
301
- frameStroke: '#bc62d3',
302
- frameFill: '#fdf9fd',
303
- frameText: '#000000',
304
- noteFill: '#DB91FD',
305
- noteText: '#000000',
306
- semi: '#ecdcf2',
307
- pattern: '#bd63d3',
308
- highlightSrgb: '#c77cff',
309
- highlightP3: 'color(display-p3 0.7469 0.5089 0.9995)',
310
- },
311
- yellow: {
312
- solid: '#f1ac4b',
313
- fill: '#f1ac4b',
314
- linedFill: '#f5c27a',
315
- frameHeadingStroke: '#f3bb6c',
316
- frameHeadingFill: '#fefcf8',
317
- frameStroke: '#f3bb6c',
318
- frameFill: '#fffdfa',
319
- frameText: '#000000',
320
- noteFill: '#FED49A',
321
- noteText: '#000000',
322
- semi: '#f9f0e6',
323
- pattern: '#fecb92',
324
- highlightSrgb: '#fddd00',
325
- highlightP3: 'color(display-p3 0.972 0.8705 0.05)',
326
- },
327
- white: {
328
- solid: '#FFFFFF',
329
- fill: '#FFFFFF',
330
- linedFill: '#ffffff',
331
- semi: '#f5f5f5',
332
- pattern: '#f9f9f9',
333
- frameHeadingStroke: '#7d7d7d',
334
- frameHeadingFill: '#ffffff',
335
- frameStroke: '#7d7d7d',
336
- frameFill: '#ffffff',
337
- frameText: '#000000',
338
- noteFill: '#FFFFFF',
339
- noteText: '#000000',
340
- highlightSrgb: '#ffffff',
341
- highlightP3: 'color(display-p3 1 1 1)',
342
- },
343
- },
344
- darkMode: {
345
- id: 'dark',
346
- text: 'hsl(210, 17%, 98%)',
347
- background: 'hsl(240, 5%, 6.5%)',
348
- solid: '#010403',
349
-
350
- black: {
351
- solid: '#f2f2f2',
352
- fill: '#f2f2f2',
353
- linedFill: '#ffffff',
354
- frameHeadingStroke: '#5c5c5c',
355
- frameHeadingFill: '#252525',
356
- frameStroke: '#5c5c5c',
357
- frameFill: '#0c0c0c',
358
- frameText: '#f2f2f2',
359
- noteFill: '#2c2c2c',
360
- noteText: '#f2f2f2',
361
- semi: '#2c3036',
362
- pattern: '#989898',
363
- highlightSrgb: '#d2b700',
364
- highlightP3: 'color(display-p3 0.8078 0.6225 0.0312)',
365
- },
366
- blue: {
367
- solid: '#4f72fc', // 3c60f0
368
- fill: '#4f72fc',
369
- linedFill: '#3c5cdd',
370
- frameHeadingStroke: '#384994',
371
- frameHeadingFill: '#1C2036',
372
- frameStroke: '#384994',
373
- frameFill: '#11141f',
374
- frameText: '#f2f2f2',
375
- noteFill: '#2A3F98',
376
- noteText: '#f2f2f2',
377
- semi: '#262d40',
378
- pattern: '#3a4b9e',
379
- highlightSrgb: '#0079d2',
380
- highlightP3: 'color(display-p3 0.0032 0.4655 0.7991)',
381
- },
382
- green: {
383
- solid: '#099268',
384
- fill: '#099268',
385
- linedFill: '#087856',
386
- frameHeadingStroke: '#10513C',
387
- frameHeadingFill: '#14241f',
388
- frameStroke: '#10513C',
389
- frameFill: '#0E1614',
390
- frameText: '#f2f2f2',
391
- noteFill: '#014429',
392
- noteText: '#f2f2f2',
393
- semi: '#253231',
394
- pattern: '#366a53',
395
- highlightSrgb: '#009774',
396
- highlightP3: 'color(display-p3 0.0085 0.582 0.4604)',
397
- },
398
- grey: {
399
- solid: '#9398b0',
400
- fill: '#9398b0',
401
- linedFill: '#8388a5',
402
- frameHeadingStroke: '#42474D',
403
- frameHeadingFill: '#23262A',
404
- frameStroke: '#42474D',
405
- frameFill: '#151719',
406
- frameText: '#f2f2f2',
407
- noteFill: '#56595F',
408
- noteText: '#f2f2f2',
409
- semi: '#33373c',
410
- pattern: '#7c8187',
411
- highlightSrgb: '#9cb4cb',
412
- highlightP3: 'color(display-p3 0.6299 0.7012 0.7856)',
413
- },
414
- 'light-blue': {
415
- solid: '#4dabf7',
416
- fill: '#4dabf7',
417
- linedFill: '#2793ec',
418
- frameHeadingStroke: '#075797',
419
- frameHeadingFill: '#142839',
420
- frameStroke: '#075797',
421
- frameFill: '#0B1823',
422
- frameText: '#f2f2f2',
423
- noteFill: '#1F5495',
424
- noteText: '#f2f2f2',
425
- semi: '#2a3642',
426
- pattern: '#4d7aa9',
427
- highlightSrgb: '#00bdc8',
428
- highlightP3: 'color(display-p3 0.0023 0.7259 0.7735)',
429
- },
430
- 'light-green': {
431
- solid: '#40c057',
432
- fill: '#40c057',
433
- linedFill: '#37a44b',
434
- frameHeadingStroke: '#1C5427',
435
- frameHeadingFill: '#18251A',
436
- frameStroke: '#1C5427',
437
- frameFill: '#0F1911',
438
- frameText: '#f2f2f2',
439
- noteFill: '#21581D',
440
- noteText: '#f2f2f2',
441
- semi: '#2a3830',
442
- pattern: '#4e874e',
443
- highlightSrgb: '#00a000',
444
- highlightP3: 'color(display-p3 0.2711 0.6172 0.0195)',
445
- },
446
- 'light-red': {
447
- solid: '#ff8787',
448
- fill: '#ff8787',
449
- linedFill: '#ff6666',
450
- frameHeadingStroke: '#6f3232', // Darker and desaturated variant of solid
451
- frameHeadingFill: '#341818', // Deep, muted dark red
452
- frameStroke: '#6f3232', // Matches headingStroke
453
- frameFill: '#181212', // Darker, muted background shade
454
- frameText: '#f2f2f2', // Consistent bright text color
455
- noteFill: '#7a3333', // Medium-dark, muted variant of solid
456
- noteText: '#f2f2f2',
457
- semi: '#3c2b2b', // Subdued, darker neutral-red tone
458
- pattern: '#a56767', // Existing pattern shade retained
459
- highlightSrgb: '#db005b',
460
- highlightP3: 'color(display-p3 0.7849 0.0585 0.3589)',
461
- },
462
- 'light-violet': {
463
- solid: '#e599f7',
464
- fill: '#e599f7',
465
- linedFill: '#dc71f4',
466
- frameHeadingStroke: '#6c367a',
467
- frameHeadingFill: '#2D2230',
468
- frameStroke: '#6c367a',
469
- frameFill: '#1C151E',
470
- frameText: '#f2f2f2',
471
- noteFill: '#762F8E',
472
- noteText: '#f2f2f2',
473
- semi: '#383442',
474
- pattern: '#9770a9',
475
- highlightSrgb: '#c400c7',
476
- highlightP3: 'color(display-p3 0.7024 0.0403 0.753)',
477
- },
478
- orange: {
479
- solid: '#f76707',
480
- fill: '#f76707',
481
- linedFill: '#f54900',
482
- frameHeadingStroke: '#773a0e', // Darker, muted version of solid
483
- frameHeadingFill: '#2f1d13', // Deep, warm, muted background
484
- frameStroke: '#773a0e', // Matches headingStroke
485
- frameFill: '#1c1512', // Darker, richer muted background
486
- frameText: '#f2f2f2', // Bright text for contrast
487
- noteFill: '#7c3905', // Muted dark variant for note fill
488
- noteText: '#f2f2f2',
489
- semi: '#3b2e27', // Muted neutral-orange tone
490
- pattern: '#9f552d', // Retained existing shade
491
- highlightSrgb: '#d07a00',
492
- highlightP3: 'color(display-p3 0.7699 0.4937 0.0085)',
493
- },
494
- red: {
495
- solid: '#e03131',
496
- fill: '#e03131',
497
- linedFill: '#c31d1d',
498
- frameHeadingStroke: '#701e1e', // Darker, muted variation of solid
499
- frameHeadingFill: '#301616', // Deep, muted reddish backdrop
500
- frameStroke: '#701e1e', // Matches headingStroke
501
- frameFill: '#1b1313', // Rich, dark muted background
502
- frameText: '#f2f2f2', // Bright text for readability
503
- noteFill: '#7e201f', // Muted dark variant for note fill
504
- noteText: '#f2f2f2',
505
- semi: '#382726', // Dark neutral-red tone
506
- pattern: '#8f3734', // Existing pattern color retained
507
- highlightSrgb: '#de002c',
508
- highlightP3: 'color(display-p3 0.7978 0.0509 0.2035)',
509
- },
510
- violet: {
511
- solid: '#ae3ec9',
512
- fill: '#ae3ec9',
513
- linedFill: '#8f2fa7',
514
- frameHeadingStroke: '#6d1583', // Darker, muted variation of solid
515
- frameHeadingFill: '#27152e', // Deep, rich muted violet backdrop
516
- frameStroke: '#6d1583', // Matches headingStroke
517
- frameFill: '#1b0f21', // Darker muted violet background
518
- frameText: '#f2f2f2', // Consistent bright text color
519
- noteFill: '#5f1c70', // Muted dark variant for note fill
520
- noteText: '#f2f2f2',
521
- semi: '#342938', // Dark neutral-violet tone
522
- pattern: '#763a8b', // Retained existing pattern color
523
- highlightSrgb: '#9e00ee',
524
- highlightP3: 'color(display-p3 0.5651 0.0079 0.8986)',
525
- },
526
- yellow: {
527
- solid: '#ffc034',
528
- fill: '#ffc034',
529
- linedFill: '#ffae00',
530
- frameHeadingStroke: '#684e12', // Darker, muted variant of solid
531
- frameHeadingFill: '#2a2113', // Rich, muted dark-yellow background
532
- frameStroke: '#684e12', // Matches headingStroke
533
- frameFill: '#1e1911', // Darker muted shade for background fill
534
- frameText: '#f2f2f2', // Bright text color for readability
535
- noteFill: '#8a5e1c', // Muted, dark complementary variant
536
- noteText: '#f2f2f2',
537
- semi: '#3b352b', // Dark muted neutral-yellow tone
538
- pattern: '#fecb92', // Existing shade retained
539
- highlightSrgb: '#d2b700',
540
- highlightP3: 'color(display-p3 0.8078 0.7225 0.0312)',
541
- },
542
- white: {
543
- solid: '#f3f3f3',
544
- fill: '#f3f3f3',
545
- linedFill: '#f3f3f3',
546
- semi: '#f5f5f5',
547
- pattern: '#f9f9f9',
548
- frameHeadingStroke: '#ffffff',
549
- frameHeadingFill: '#ffffff',
550
- frameStroke: '#ffffff',
551
- frameFill: '#ffffff',
552
- frameText: '#000000',
553
- noteFill: '#eaeaea',
554
- noteText: '#1d1d1d',
555
- highlightSrgb: '#ffffff',
556
- highlightP3: 'color(display-p3 1 1 1)',
557
- },
558
- },
559
- }
560
-
561
- /**
562
- * Returns the appropriate default color theme based on the dark mode preference.
563
- *
564
- * @param opts - Configuration options
565
- * - isDarkMode - Whether to return the dark theme (true) or light theme (false)
566
- * @returns The corresponding TLDefaultColorTheme (light or dark)
567
- *
568
- * @example
569
- * ```ts
570
- * import { getDefaultColorTheme } from '@tldraw/tlschema'
571
- *
572
- * // Get light theme
573
- * const lightTheme = getDefaultColorTheme({ isDarkMode: false })
574
- *
575
- * // Get dark theme
576
- * const darkTheme = getDefaultColorTheme({ isDarkMode: true })
577
- *
578
- * // Use with editor
579
- * const theme = getDefaultColorTheme({ isDarkMode: window.matchMedia('(prefers-color-scheme: dark)').matches })
580
- * ```
581
- *
582
- * @public
583
- */
584
- export function getDefaultColorTheme(opts: { isDarkMode: boolean }): TLDefaultColorTheme {
585
- return opts.isDarkMode ? DefaultColorThemePalette.darkMode : DefaultColorThemePalette.lightMode
586
- }
587
-
588
- /**
589
- * Default color style property used by tldraw shapes for their primary color.
590
- * This style prop allows shapes to use any of the default color names and
591
- * automatically saves the last used value for new shapes.
592
- *
593
- * @example
594
- * ```ts
595
- * import { DefaultColorStyle } from '@tldraw/tlschema'
596
- *
597
- * // Use in shape props definition
598
- * interface MyShapeProps {
599
- * color: typeof DefaultColorStyle
600
- * // other props...
601
- * }
602
- *
603
- * // Set color on a shape
604
- * const shape = {
605
- * // ... other properties
606
- * props: {
607
- * color: 'red' as const,
608
- * // ... other props
609
- * }
610
- * }
611
- * ```
612
- *
613
37
  * @public
614
38
  */
615
39
  export const DefaultColorStyle = StyleProp.defineEnum('tldraw:color', {
@@ -618,31 +42,6 @@ export const DefaultColorStyle = StyleProp.defineEnum('tldraw:color', {
618
42
  })
619
43
 
620
44
  /**
621
- * Default label color style property used for text labels on shapes.
622
- * This is separate from the main color style to allow different colors
623
- * for shape fills/strokes versus their text labels.
624
- *
625
- * @example
626
- * ```ts
627
- * import { DefaultLabelColorStyle } from '@tldraw/tlschema'
628
- *
629
- * // Use in shape props definition
630
- * interface MyShapeProps {
631
- * labelColor: typeof DefaultLabelColorStyle
632
- * // other props...
633
- * }
634
- *
635
- * // Create a shape with different fill and label colors
636
- * const shape = {
637
- * // ... other properties
638
- * props: {
639
- * color: 'blue' as const,
640
- * labelColor: 'white' as const,
641
- * // ... other props
642
- * }
643
- * }
644
- * ```
645
- *
646
45
  * @public
647
46
  */
648
47
  export const DefaultLabelColorStyle = StyleProp.defineEnum('tldraw:labelColor', {
@@ -651,94 +50,52 @@ export const DefaultLabelColorStyle = StyleProp.defineEnum('tldraw:labelColor',
651
50
  })
652
51
 
653
52
  /**
654
- * Type representing a default color style value.
655
- * This is a union type of all available default color names.
656
- *
657
- * @example
658
- * ```ts
659
- * import { TLDefaultColorStyle } from '@tldraw/tlschema'
660
- *
661
- * // Valid color values
662
- * const redColor: TLDefaultColorStyle = 'red'
663
- * const blueColor: TLDefaultColorStyle = 'blue'
664
- *
665
- * // Type guard usage
666
- * function isValidColor(color: string): color is TLDefaultColorStyle {
667
- * return ['black', 'red', 'blue'].includes(color as TLDefaultColorStyle)
668
- * }
669
- * ```
670
- *
671
- * @public
672
- */
673
- export type TLDefaultColorStyle = T.TypeOf<typeof DefaultColorStyle>
674
-
675
- const defaultColorNamesSet = new Set(defaultColorNames)
676
-
677
- /**
678
- * Type guard to check if a color value is one of the default theme colors.
679
- * Useful for determining if a color can be looked up in the theme palette.
680
- *
681
- * @param color - The color value to check
682
- * @returns True if the color is a default theme color, false otherwise
683
- *
684
- * @example
685
- * ```ts
686
- * import { isDefaultThemeColor, TLDefaultColorStyle } from '@tldraw/tlschema'
687
- *
688
- * const color: TLDefaultColorStyle = 'red'
53
+ * Scan theme definitions and sync color registrations to match.
54
+ * A color entry is any key in `TLThemeColors` whose value is an object
55
+ * (i.e. a {@link TLDefaultColor}), as opposed to utility strings like
56
+ * `background` or `text`.
689
57
  *
690
- * if (isDefaultThemeColor(color)) {
691
- * // color is guaranteed to be a default theme color
692
- * console.log(`${color} is a default theme color`)
693
- * } else {
694
- * // color might be a custom hex value or other format
695
- * console.log(`${color} is a custom color`)
696
- * }
697
- * ```
58
+ * Colors present in themes but not yet registered will be added.
59
+ * Colors currently registered but absent from all themes will be removed.
698
60
  *
699
61
  * @public
700
62
  */
701
- export function isDefaultThemeColor(
702
- color: TLDefaultColorStyle
703
- ): color is (typeof defaultColorNames)[number] {
704
- return defaultColorNamesSet.has(color as (typeof defaultColorNames)[number])
705
- }
63
+ export function registerColorsFromThemes(definitions: TLThemes): void {
64
+ const colorNames = new Set<TLDefaultColorStyle>()
65
+ for (const def of Object.values(definitions)) {
66
+ for (const colorPalette of [def.colors.light, def.colors.dark]) {
67
+ for (const [key, value] of Object.entries(colorPalette)) {
68
+ if (typeof value === 'object' && value !== null) {
69
+ colorNames.add(key as TLDefaultColorStyle)
70
+ }
71
+ }
72
+ }
73
+ }
74
+ if (colorNames.size > 0) {
75
+ DefaultColorStyle.addValues(...colorNames)
76
+ DefaultLabelColorStyle.addValues(...colorNames)
77
+ }
706
78
 
707
- /**
708
- * Resolves a color style value to its actual CSS color string for a given theme and variant.
709
- * If the color is not a default theme color, returns the color value as-is.
710
- *
711
- * @param theme - The color theme to use for resolution
712
- * @param color - The color style value to resolve
713
- * @param variant - Which variant of the color to return (solid, fill, pattern, etc.)
714
- * @returns The CSS color string for the specified color and variant
715
- *
716
- * @example
717
- * ```ts
718
- * import { getColorValue, getDefaultColorTheme } from '@tldraw/tlschema'
719
- *
720
- * const theme = getDefaultColorTheme({ isDarkMode: false })
721
- *
722
- * // Get the solid variant of red
723
- * const redSolid = getColorValue(theme, 'red', 'solid') // '#e03131'
724
- *
725
- * // Get the fill variant of blue
726
- * const blueFill = getColorValue(theme, 'blue', 'fill') // '#4465e9'
727
- *
728
- * // Custom color passes through unchanged
729
- * const customColor = getColorValue(theme, '#ff0000', 'solid') // '#ff0000'
730
- * ```
731
- *
732
- * @public
733
- */
734
- export function getColorValue(
735
- theme: TLDefaultColorTheme,
736
- color: TLDefaultColorStyle,
737
- variant: keyof TLDefaultColorThemeColor
738
- ): string {
739
- if (!isDefaultThemeColor(color)) {
740
- return color
79
+ const toRemove = DefaultColorStyle.values.filter((v) => !colorNames.has(v as TLDefaultColorStyle))
80
+ if (toRemove.length > 0) {
81
+ DefaultColorStyle.removeValues(...toRemove)
82
+ DefaultLabelColorStyle.removeValues(...toRemove)
741
83
  }
742
84
 
743
- return theme[color][variant]
85
+ if (process.env.NODE_ENV !== 'production') {
86
+ for (const def of Object.values(definitions)) {
87
+ for (const color of colorNames) {
88
+ if (!(color in def.colors.light)) {
89
+ console.warn(
90
+ `Theme '${def.id}' light palette is missing color '${color}'. Shapes using this color won't render correctly.`
91
+ )
92
+ }
93
+ if (!(color in def.colors.dark)) {
94
+ console.warn(
95
+ `Theme '${def.id}' dark palette is missing color '${color}'. Shapes using this color won't render correctly.`
96
+ )
97
+ }
98
+ }
99
+ }
100
+ }
744
101
  }