@tldraw/tlschema 4.1.0-canary.7b9b8b93443a → 4.1.0-canary.8659480a0467

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 (214) hide show
  1. package/dist-cjs/TLStore.js +3 -10
  2. package/dist-cjs/TLStore.js.map +2 -2
  3. package/dist-cjs/assets/TLBaseAsset.js.map +2 -2
  4. package/dist-cjs/assets/TLBookmarkAsset.js.map +2 -2
  5. package/dist-cjs/assets/TLImageAsset.js.map +2 -2
  6. package/dist-cjs/assets/TLVideoAsset.js.map +2 -2
  7. package/dist-cjs/bindings/TLArrowBinding.js.map +2 -2
  8. package/dist-cjs/bindings/TLBaseBinding.js.map +2 -2
  9. package/dist-cjs/createPresenceStateDerivation.js.map +2 -2
  10. package/dist-cjs/createTLSchema.js.map +2 -2
  11. package/dist-cjs/index.d.ts +4416 -223
  12. package/dist-cjs/index.js +1 -1
  13. package/dist-cjs/index.js.map +2 -2
  14. package/dist-cjs/misc/TLColor.js.map +2 -2
  15. package/dist-cjs/misc/TLCursor.js.map +2 -2
  16. package/dist-cjs/misc/TLHandle.js.map +2 -2
  17. package/dist-cjs/misc/TLOpacity.js.map +2 -2
  18. package/dist-cjs/misc/TLRichText.js.map +2 -2
  19. package/dist-cjs/misc/TLScribble.js.map +2 -2
  20. package/dist-cjs/misc/geometry-types.js.map +2 -2
  21. package/dist-cjs/misc/id-validator.js.map +2 -2
  22. package/dist-cjs/records/TLAsset.js.map +2 -2
  23. package/dist-cjs/records/TLBinding.js.map +2 -2
  24. package/dist-cjs/records/TLCamera.js.map +2 -2
  25. package/dist-cjs/records/TLDocument.js.map +2 -2
  26. package/dist-cjs/records/TLInstance.js.map +2 -2
  27. package/dist-cjs/records/TLPage.js.map +2 -2
  28. package/dist-cjs/records/TLPageState.js.map +2 -2
  29. package/dist-cjs/records/TLPointer.js.map +2 -2
  30. package/dist-cjs/records/TLPresence.js.map +2 -2
  31. package/dist-cjs/records/TLRecord.js.map +1 -1
  32. package/dist-cjs/records/TLShape.js.map +2 -2
  33. package/dist-cjs/recordsWithProps.js.map +2 -2
  34. package/dist-cjs/shapes/ShapeWithCrop.js.map +1 -1
  35. package/dist-cjs/shapes/TLArrowShape.js.map +2 -2
  36. package/dist-cjs/shapes/TLBaseShape.js.map +2 -2
  37. package/dist-cjs/shapes/TLBookmarkShape.js.map +2 -2
  38. package/dist-cjs/shapes/TLDrawShape.js.map +2 -2
  39. package/dist-cjs/shapes/TLEmbedShape.js +0 -10
  40. package/dist-cjs/shapes/TLEmbedShape.js.map +2 -2
  41. package/dist-cjs/shapes/TLFrameShape.js.map +2 -2
  42. package/dist-cjs/shapes/TLGeoShape.js.map +2 -2
  43. package/dist-cjs/shapes/TLGroupShape.js.map +2 -2
  44. package/dist-cjs/shapes/TLHighlightShape.js.map +2 -2
  45. package/dist-cjs/shapes/TLImageShape.js.map +2 -2
  46. package/dist-cjs/shapes/TLLineShape.js.map +2 -2
  47. package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
  48. package/dist-cjs/shapes/TLTextShape.js.map +2 -2
  49. package/dist-cjs/shapes/TLVideoShape.js.map +2 -2
  50. package/dist-cjs/store-migrations.js.map +2 -2
  51. package/dist-cjs/styles/TLColorStyle.js.map +2 -2
  52. package/dist-cjs/styles/TLDashStyle.js.map +2 -2
  53. package/dist-cjs/styles/TLFillStyle.js.map +2 -2
  54. package/dist-cjs/styles/TLFontStyle.js.map +2 -2
  55. package/dist-cjs/styles/TLHorizontalAlignStyle.js.map +2 -2
  56. package/dist-cjs/styles/TLSizeStyle.js.map +2 -2
  57. package/dist-cjs/styles/TLTextAlignStyle.js.map +2 -2
  58. package/dist-cjs/styles/TLVerticalAlignStyle.js.map +2 -2
  59. package/dist-cjs/translations/translations.js +1 -1
  60. package/dist-cjs/translations/translations.js.map +2 -2
  61. package/dist-cjs/util-types.js.map +1 -1
  62. package/dist-esm/TLStore.mjs +3 -10
  63. package/dist-esm/TLStore.mjs.map +2 -2
  64. package/dist-esm/assets/TLBaseAsset.mjs.map +2 -2
  65. package/dist-esm/assets/TLBookmarkAsset.mjs.map +2 -2
  66. package/dist-esm/assets/TLImageAsset.mjs.map +2 -2
  67. package/dist-esm/assets/TLVideoAsset.mjs.map +2 -2
  68. package/dist-esm/bindings/TLArrowBinding.mjs.map +2 -2
  69. package/dist-esm/bindings/TLBaseBinding.mjs.map +2 -2
  70. package/dist-esm/createPresenceStateDerivation.mjs.map +2 -2
  71. package/dist-esm/createTLSchema.mjs.map +2 -2
  72. package/dist-esm/index.d.mts +4416 -223
  73. package/dist-esm/index.mjs +1 -1
  74. package/dist-esm/index.mjs.map +2 -2
  75. package/dist-esm/misc/TLColor.mjs.map +2 -2
  76. package/dist-esm/misc/TLCursor.mjs.map +2 -2
  77. package/dist-esm/misc/TLHandle.mjs.map +2 -2
  78. package/dist-esm/misc/TLOpacity.mjs.map +2 -2
  79. package/dist-esm/misc/TLRichText.mjs.map +2 -2
  80. package/dist-esm/misc/TLScribble.mjs.map +2 -2
  81. package/dist-esm/misc/geometry-types.mjs.map +2 -2
  82. package/dist-esm/misc/id-validator.mjs.map +2 -2
  83. package/dist-esm/records/TLAsset.mjs.map +2 -2
  84. package/dist-esm/records/TLBinding.mjs.map +2 -2
  85. package/dist-esm/records/TLCamera.mjs.map +2 -2
  86. package/dist-esm/records/TLDocument.mjs.map +2 -2
  87. package/dist-esm/records/TLInstance.mjs.map +2 -2
  88. package/dist-esm/records/TLPage.mjs.map +2 -2
  89. package/dist-esm/records/TLPageState.mjs.map +2 -2
  90. package/dist-esm/records/TLPointer.mjs.map +2 -2
  91. package/dist-esm/records/TLPresence.mjs.map +2 -2
  92. package/dist-esm/records/TLShape.mjs.map +2 -2
  93. package/dist-esm/recordsWithProps.mjs.map +2 -2
  94. package/dist-esm/shapes/TLArrowShape.mjs.map +2 -2
  95. package/dist-esm/shapes/TLBaseShape.mjs.map +2 -2
  96. package/dist-esm/shapes/TLBookmarkShape.mjs.map +2 -2
  97. package/dist-esm/shapes/TLDrawShape.mjs.map +2 -2
  98. package/dist-esm/shapes/TLEmbedShape.mjs +0 -10
  99. package/dist-esm/shapes/TLEmbedShape.mjs.map +2 -2
  100. package/dist-esm/shapes/TLFrameShape.mjs.map +2 -2
  101. package/dist-esm/shapes/TLGeoShape.mjs.map +2 -2
  102. package/dist-esm/shapes/TLGroupShape.mjs.map +2 -2
  103. package/dist-esm/shapes/TLHighlightShape.mjs.map +2 -2
  104. package/dist-esm/shapes/TLImageShape.mjs.map +2 -2
  105. package/dist-esm/shapes/TLLineShape.mjs.map +2 -2
  106. package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
  107. package/dist-esm/shapes/TLTextShape.mjs.map +2 -2
  108. package/dist-esm/shapes/TLVideoShape.mjs.map +2 -2
  109. package/dist-esm/store-migrations.mjs.map +2 -2
  110. package/dist-esm/styles/TLColorStyle.mjs.map +2 -2
  111. package/dist-esm/styles/TLDashStyle.mjs.map +2 -2
  112. package/dist-esm/styles/TLFillStyle.mjs.map +2 -2
  113. package/dist-esm/styles/TLFontStyle.mjs.map +2 -2
  114. package/dist-esm/styles/TLHorizontalAlignStyle.mjs.map +2 -2
  115. package/dist-esm/styles/TLSizeStyle.mjs.map +2 -2
  116. package/dist-esm/styles/TLTextAlignStyle.mjs.map +2 -2
  117. package/dist-esm/styles/TLVerticalAlignStyle.mjs.map +2 -2
  118. package/dist-esm/translations/translations.mjs +1 -1
  119. package/dist-esm/translations/translations.mjs.map +2 -2
  120. package/package.json +5 -5
  121. package/src/TLStore.test.ts +644 -0
  122. package/src/TLStore.ts +205 -20
  123. package/src/assets/TLBaseAsset.ts +90 -7
  124. package/src/assets/TLBookmarkAsset.test.ts +96 -0
  125. package/src/assets/TLBookmarkAsset.ts +52 -2
  126. package/src/assets/TLImageAsset.test.ts +213 -0
  127. package/src/assets/TLImageAsset.ts +60 -2
  128. package/src/assets/TLVideoAsset.test.ts +105 -0
  129. package/src/assets/TLVideoAsset.ts +93 -4
  130. package/src/bindings/TLArrowBinding.test.ts +55 -0
  131. package/src/bindings/TLArrowBinding.ts +132 -10
  132. package/src/bindings/TLBaseBinding.ts +140 -3
  133. package/src/createPresenceStateDerivation.test.ts +158 -0
  134. package/src/createPresenceStateDerivation.ts +71 -2
  135. package/src/createTLSchema.test.ts +181 -0
  136. package/src/createTLSchema.ts +164 -7
  137. package/src/index.ts +32 -0
  138. package/src/misc/TLColor.ts +50 -6
  139. package/src/misc/TLCursor.ts +110 -8
  140. package/src/misc/TLHandle.ts +86 -6
  141. package/src/misc/TLOpacity.ts +51 -2
  142. package/src/misc/TLRichText.ts +56 -3
  143. package/src/misc/TLScribble.ts +105 -5
  144. package/src/misc/geometry-types.ts +30 -2
  145. package/src/misc/id-validator.test.ts +50 -0
  146. package/src/misc/id-validator.ts +20 -1
  147. package/src/records/TLAsset.test.ts +234 -0
  148. package/src/records/TLAsset.ts +165 -8
  149. package/src/records/TLBinding.test.ts +22 -0
  150. package/src/records/TLBinding.ts +277 -11
  151. package/src/records/TLCamera.test.ts +19 -0
  152. package/src/records/TLCamera.ts +118 -7
  153. package/src/records/TLDocument.test.ts +35 -0
  154. package/src/records/TLDocument.ts +148 -8
  155. package/src/records/TLInstance.test.ts +201 -0
  156. package/src/records/TLInstance.ts +117 -9
  157. package/src/records/TLPage.test.ts +110 -0
  158. package/src/records/TLPage.ts +106 -8
  159. package/src/records/TLPageState.test.ts +228 -0
  160. package/src/records/TLPageState.ts +88 -7
  161. package/src/records/TLPointer.test.ts +63 -0
  162. package/src/records/TLPointer.ts +105 -7
  163. package/src/records/TLPresence.test.ts +190 -0
  164. package/src/records/TLPresence.ts +99 -5
  165. package/src/records/TLRecord.test.ts +70 -0
  166. package/src/records/TLRecord.ts +43 -1
  167. package/src/records/TLShape.test.ts +232 -0
  168. package/src/records/TLShape.ts +289 -12
  169. package/src/recordsWithProps.test.ts +188 -0
  170. package/src/recordsWithProps.ts +131 -2
  171. package/src/shapes/ShapeWithCrop.test.ts +18 -0
  172. package/src/shapes/ShapeWithCrop.ts +64 -2
  173. package/src/shapes/TLArrowShape.test.ts +505 -0
  174. package/src/shapes/TLArrowShape.ts +188 -10
  175. package/src/shapes/TLBaseShape.test.ts +142 -0
  176. package/src/shapes/TLBaseShape.ts +103 -4
  177. package/src/shapes/TLBookmarkShape.test.ts +122 -0
  178. package/src/shapes/TLBookmarkShape.ts +58 -4
  179. package/src/shapes/TLDrawShape.test.ts +177 -0
  180. package/src/shapes/TLDrawShape.ts +97 -6
  181. package/src/shapes/TLEmbedShape.test.ts +286 -0
  182. package/src/shapes/TLEmbedShape.ts +57 -14
  183. package/src/shapes/TLFrameShape.test.ts +71 -0
  184. package/src/shapes/TLFrameShape.ts +59 -4
  185. package/src/shapes/TLGeoShape.test.ts +247 -0
  186. package/src/shapes/TLGeoShape.ts +103 -7
  187. package/src/shapes/TLGroupShape.test.ts +59 -0
  188. package/src/shapes/TLGroupShape.ts +52 -4
  189. package/src/shapes/TLHighlightShape.test.ts +325 -0
  190. package/src/shapes/TLHighlightShape.ts +79 -4
  191. package/src/shapes/TLImageShape.test.ts +534 -0
  192. package/src/shapes/TLImageShape.ts +105 -5
  193. package/src/shapes/TLLineShape.test.ts +269 -0
  194. package/src/shapes/TLLineShape.ts +128 -8
  195. package/src/shapes/TLNoteShape.test.ts +1568 -0
  196. package/src/shapes/TLNoteShape.ts +97 -4
  197. package/src/shapes/TLTextShape.test.ts +407 -0
  198. package/src/shapes/TLTextShape.ts +94 -4
  199. package/src/shapes/TLVideoShape.test.ts +112 -0
  200. package/src/shapes/TLVideoShape.ts +99 -4
  201. package/src/store-migrations.test.ts +88 -0
  202. package/src/store-migrations.ts +47 -1
  203. package/src/styles/TLColorStyle.test.ts +439 -0
  204. package/src/styles/TLColorStyle.ts +228 -10
  205. package/src/styles/TLDashStyle.ts +54 -2
  206. package/src/styles/TLFillStyle.ts +54 -2
  207. package/src/styles/TLFontStyle.ts +72 -3
  208. package/src/styles/TLHorizontalAlignStyle.ts +55 -2
  209. package/src/styles/TLSizeStyle.ts +54 -2
  210. package/src/styles/TLTextAlignStyle.ts +52 -2
  211. package/src/styles/TLVerticalAlignStyle.ts +52 -2
  212. package/src/translations/translations.test.ts +378 -35
  213. package/src/translations/translations.ts +157 -10
  214. package/src/util-types.ts +51 -1
@@ -0,0 +1,439 @@
1
+ import { describe, expect, it, test } from 'vitest'
2
+ import {
3
+ defaultColorNames,
4
+ DefaultColorStyle,
5
+ DefaultColorThemePalette,
6
+ DefaultLabelColorStyle,
7
+ getColorValue,
8
+ getDefaultColorTheme,
9
+ isDefaultThemeColor,
10
+ TLDefaultColorStyle,
11
+ TLDefaultColorThemeColor,
12
+ } from './TLColorStyle'
13
+
14
+ describe('TLColorStyle', () => {
15
+ describe('defaultColorNames', () => {
16
+ it('should contain expected default colors', () => {
17
+ expect(defaultColorNames).toEqual([
18
+ 'black',
19
+ 'grey',
20
+ 'light-violet',
21
+ 'violet',
22
+ 'blue',
23
+ 'light-blue',
24
+ 'yellow',
25
+ 'orange',
26
+ 'green',
27
+ 'light-green',
28
+ 'light-red',
29
+ 'red',
30
+ 'white',
31
+ ])
32
+ })
33
+ })
34
+
35
+ describe('DefaultColorThemePalette', () => {
36
+ it('should contain all default colors for both themes', () => {
37
+ const lightTheme = DefaultColorThemePalette.lightMode
38
+ const darkTheme = DefaultColorThemePalette.darkMode
39
+
40
+ defaultColorNames.forEach((colorName) => {
41
+ expect(lightTheme).toHaveProperty(colorName)
42
+ expect(darkTheme).toHaveProperty(colorName)
43
+ })
44
+ })
45
+ })
46
+
47
+ describe('getDefaultColorTheme', () => {
48
+ it('should return light theme when isDarkMode is false', () => {
49
+ const result = getDefaultColorTheme({ isDarkMode: false })
50
+ expect(result).toBe(DefaultColorThemePalette.lightMode)
51
+ })
52
+
53
+ it('should return dark theme when isDarkMode is true', () => {
54
+ const result = getDefaultColorTheme({ isDarkMode: true })
55
+ expect(result).toBe(DefaultColorThemePalette.darkMode)
56
+ })
57
+ })
58
+
59
+ describe('DefaultColorStyle', () => {
60
+ it('should validate all default color names', () => {
61
+ defaultColorNames.forEach((color) => {
62
+ expect(() => DefaultColorStyle.validate(color)).not.toThrow()
63
+ expect(DefaultColorStyle.validate(color)).toBe(color)
64
+ })
65
+ })
66
+
67
+ it('should reject invalid color names', () => {
68
+ const invalidColors = ['invalid', 'pink', 'purple', 'cyan', '']
69
+
70
+ invalidColors.forEach((color) => {
71
+ expect(() => DefaultColorStyle.validate(color)).toThrow()
72
+ })
73
+ })
74
+ })
75
+
76
+ describe('DefaultLabelColorStyle', () => {
77
+ it('should be a StyleProp with correct configuration', () => {
78
+ expect(DefaultLabelColorStyle.id).toBe('tldraw:labelColor')
79
+ expect(DefaultLabelColorStyle.defaultValue).toBe('black')
80
+ })
81
+
82
+ it('should validate all default color names', () => {
83
+ defaultColorNames.forEach((color) => {
84
+ expect(() => DefaultLabelColorStyle.validate(color)).not.toThrow()
85
+ expect(DefaultLabelColorStyle.validate(color)).toBe(color)
86
+ })
87
+ })
88
+
89
+ it('should reject invalid color names', () => {
90
+ const invalidColors = ['invalid', 'pink', 'purple', 'cyan', '']
91
+
92
+ invalidColors.forEach((color) => {
93
+ expect(() => DefaultLabelColorStyle.validate(color)).toThrow()
94
+ })
95
+ })
96
+
97
+ it('should have values property with all default colors', () => {
98
+ expect(DefaultLabelColorStyle.values).toEqual(defaultColorNames)
99
+ })
100
+
101
+ it('should be separate from DefaultColorStyle', () => {
102
+ expect(DefaultColorStyle.id).not.toBe(DefaultLabelColorStyle.id)
103
+ expect(DefaultColorStyle).not.toBe(DefaultLabelColorStyle)
104
+ })
105
+
106
+ it('should allow different default values from DefaultColorStyle', () => {
107
+ const originalColorDefault = DefaultColorStyle.defaultValue
108
+ const originalLabelDefault = DefaultLabelColorStyle.defaultValue
109
+
110
+ DefaultColorStyle.setDefaultValue('red')
111
+ DefaultLabelColorStyle.setDefaultValue('blue')
112
+
113
+ expect(DefaultColorStyle.defaultValue).toBe('red')
114
+ expect(DefaultLabelColorStyle.defaultValue).toBe('blue')
115
+ expect(DefaultColorStyle.defaultValue).not.toBe(DefaultLabelColorStyle.defaultValue)
116
+
117
+ // Restore originals
118
+ DefaultColorStyle.setDefaultValue(originalColorDefault)
119
+ DefaultLabelColorStyle.setDefaultValue(originalLabelDefault)
120
+ })
121
+ })
122
+
123
+ describe('isDefaultThemeColor', () => {
124
+ it('should return true for all default color names', () => {
125
+ defaultColorNames.forEach((color) => {
126
+ expect(isDefaultThemeColor(color)).toBe(true)
127
+ })
128
+ })
129
+
130
+ it('should return false for invalid color names', () => {
131
+ const invalidColors = ['invalid', 'pink', 'purple', 'cyan', '', 'custom-color']
132
+
133
+ invalidColors.forEach((color) => {
134
+ expect(isDefaultThemeColor(color as TLDefaultColorStyle)).toBe(false)
135
+ })
136
+ })
137
+
138
+ it('should return false for hex colors', () => {
139
+ const hexColors = ['#ff0000', '#00ff00', '#0000ff', '#ffffff', '#000000']
140
+
141
+ hexColors.forEach((color) => {
142
+ expect(isDefaultThemeColor(color as TLDefaultColorStyle)).toBe(false)
143
+ })
144
+ })
145
+
146
+ it('should return false for CSS color names not in defaults', () => {
147
+ // Use CSS color names that are NOT in the default color list
148
+ const cssColors = ['aqua', 'fuchsia', 'lime', 'navy', 'silver']
149
+
150
+ cssColors.forEach((color) => {
151
+ expect(isDefaultThemeColor(color as TLDefaultColorStyle)).toBe(false)
152
+ })
153
+ })
154
+
155
+ it('should handle edge cases', () => {
156
+ expect(isDefaultThemeColor(null as any)).toBe(false)
157
+ expect(isDefaultThemeColor(undefined as any)).toBe(false)
158
+ expect(isDefaultThemeColor(123 as any)).toBe(false)
159
+ expect(isDefaultThemeColor({} as any)).toBe(false)
160
+ })
161
+
162
+ it('should be case sensitive', () => {
163
+ expect(isDefaultThemeColor('Black' as TLDefaultColorStyle)).toBe(false)
164
+ expect(isDefaultThemeColor('RED' as TLDefaultColorStyle)).toBe(false)
165
+ expect(isDefaultThemeColor('Blue' as TLDefaultColorStyle)).toBe(false)
166
+ })
167
+
168
+ it('should work as a type guard', () => {
169
+ const color: TLDefaultColorStyle = 'red'
170
+
171
+ if (isDefaultThemeColor(color)) {
172
+ // TypeScript should narrow the type here
173
+ expect(defaultColorNames.includes(color)).toBe(true)
174
+ }
175
+ })
176
+ })
177
+
178
+ describe('getColorValue', () => {
179
+ const lightTheme = DefaultColorThemePalette.lightMode
180
+ const darkTheme = DefaultColorThemePalette.darkMode
181
+
182
+ it('should return correct color values for default colors', () => {
183
+ expect(getColorValue(lightTheme, 'red', 'solid')).toBe('#e03131')
184
+ expect(getColorValue(lightTheme, 'blue', 'fill')).toBe('#4465e9')
185
+ expect(getColorValue(lightTheme, 'black', 'solid')).toBe('#1d1d1d')
186
+ })
187
+
188
+ it('should work with different variants', () => {
189
+ const variants: (keyof TLDefaultColorThemeColor)[] = [
190
+ 'solid',
191
+ 'semi',
192
+ 'pattern',
193
+ 'fill',
194
+ 'frameHeadingStroke',
195
+ 'frameHeadingFill',
196
+ 'frameStroke',
197
+ 'frameFill',
198
+ 'frameText',
199
+ 'noteFill',
200
+ 'noteText',
201
+ 'highlightSrgb',
202
+ 'highlightP3',
203
+ ]
204
+
205
+ variants.forEach((variant) => {
206
+ const result = getColorValue(lightTheme, 'red', variant)
207
+ expect(typeof result).toBe('string')
208
+ expect(result.length).toBeGreaterThan(0)
209
+ expect(result).toBe(lightTheme.red[variant])
210
+ })
211
+ })
212
+
213
+ it('should return different values for light and dark themes', () => {
214
+ // Use colors/variants that actually differ between themes
215
+ expect(getColorValue(lightTheme, 'black', 'solid')).not.toBe(
216
+ getColorValue(darkTheme, 'black', 'solid')
217
+ )
218
+ expect(getColorValue(lightTheme, 'white', 'solid')).not.toBe(
219
+ getColorValue(darkTheme, 'white', 'solid')
220
+ )
221
+ })
222
+
223
+ it('should pass through non-default colors unchanged', () => {
224
+ const customColors = ['#ff0000', '#00ff00', '#0000ff', 'custom-color', 'rgb(255, 0, 0)']
225
+
226
+ customColors.forEach((color) => {
227
+ expect(getColorValue(lightTheme, color as TLDefaultColorStyle, 'solid')).toBe(color)
228
+ expect(getColorValue(darkTheme, color as TLDefaultColorStyle, 'fill')).toBe(color)
229
+ })
230
+ })
231
+
232
+ it('should work with all default colors', () => {
233
+ defaultColorNames.forEach((colorName) => {
234
+ const lightResult = getColorValue(lightTheme, colorName, 'solid')
235
+ const darkResult = getColorValue(darkTheme, colorName, 'solid')
236
+
237
+ expect(typeof lightResult).toBe('string')
238
+ expect(typeof darkResult).toBe('string')
239
+ expect(lightResult).toBe(lightTheme[colorName].solid)
240
+ expect(darkResult).toBe(darkTheme[colorName].solid)
241
+ })
242
+ })
243
+
244
+ it('should handle edge cases gracefully', () => {
245
+ // Test with empty string
246
+ expect(getColorValue(lightTheme, '' as TLDefaultColorStyle, 'solid')).toBe('')
247
+
248
+ // Test with null/undefined (they should pass through)
249
+ expect(getColorValue(lightTheme, null as any, 'solid')).toBe(null)
250
+ expect(getColorValue(lightTheme, undefined as any, 'solid')).toBe(undefined)
251
+ })
252
+
253
+ it('should work consistently across all variants for a color', () => {
254
+ const color = 'blue'
255
+ const variants: (keyof TLDefaultColorThemeColor)[] = [
256
+ 'solid',
257
+ 'semi',
258
+ 'pattern',
259
+ 'fill',
260
+ 'frameHeadingStroke',
261
+ 'frameHeadingFill',
262
+ 'frameStroke',
263
+ 'frameFill',
264
+ 'frameText',
265
+ 'noteFill',
266
+ 'noteText',
267
+ 'highlightSrgb',
268
+ 'highlightP3',
269
+ ]
270
+
271
+ variants.forEach((variant) => {
272
+ const lightResult = getColorValue(lightTheme, color, variant)
273
+ const darkResult = getColorValue(darkTheme, color, variant)
274
+
275
+ expect(lightResult).toBe(lightTheme[color][variant])
276
+ expect(darkResult).toBe(darkTheme[color][variant])
277
+ })
278
+ })
279
+
280
+ it('should maintain consistency with isDefaultThemeColor', () => {
281
+ const testColors = [...defaultColorNames, '#ff0000', 'custom', 'invalid']
282
+
283
+ testColors.forEach((color) => {
284
+ const isDefault = isDefaultThemeColor(color as TLDefaultColorStyle)
285
+ const result = getColorValue(lightTheme, color as TLDefaultColorStyle, 'solid')
286
+
287
+ if (isDefault) {
288
+ // Should return the theme color value
289
+ expect(result).toBe(
290
+ (lightTheme[color as keyof typeof lightTheme] as TLDefaultColorThemeColor).solid
291
+ )
292
+ } else {
293
+ // Should pass through unchanged
294
+ expect(result).toBe(color)
295
+ }
296
+ })
297
+ })
298
+ })
299
+
300
+ describe('type safety and integration', () => {
301
+ it('should have proper TypeScript types', () => {
302
+ // Test that TLDefaultColorStyle is properly typed
303
+ const validColor: TLDefaultColorStyle = 'red'
304
+ expect(DefaultColorStyle.validate(validColor)).toBe('red')
305
+ })
306
+
307
+ it('should work with both color style props', () => {
308
+ const colorValue: TLDefaultColorStyle = 'blue'
309
+ const labelColorValue: TLDefaultColorStyle = 'white'
310
+
311
+ expect(DefaultColorStyle.validate(colorValue)).toBe('blue')
312
+ expect(DefaultLabelColorStyle.validate(labelColorValue)).toBe('white')
313
+ })
314
+
315
+ it('should integrate properly with theme system', () => {
316
+ const theme = getDefaultColorTheme({ isDarkMode: false })
317
+ const color: TLDefaultColorStyle = 'red'
318
+
319
+ if (isDefaultThemeColor(color)) {
320
+ const colorValue = getColorValue(theme, color, 'solid')
321
+ expect(typeof colorValue).toBe('string')
322
+ expect(colorValue).toBe(theme.red.solid)
323
+ }
324
+ })
325
+
326
+ it('should maintain consistent behavior across all exports', () => {
327
+ // Test that all parts work together correctly
328
+ const theme = getDefaultColorTheme({ isDarkMode: false })
329
+
330
+ defaultColorNames.forEach((colorName) => {
331
+ // Should validate in both style props
332
+ expect(DefaultColorStyle.validate(colorName)).toBe(colorName)
333
+ expect(DefaultLabelColorStyle.validate(colorName)).toBe(colorName)
334
+
335
+ // Should be recognized as default theme color
336
+ expect(isDefaultThemeColor(colorName)).toBe(true)
337
+
338
+ // Should resolve to theme color value
339
+ const colorValue = getColorValue(theme, colorName, 'solid')
340
+ expect(colorValue).toBe(theme[colorName].solid)
341
+ })
342
+ })
343
+ })
344
+
345
+ describe('error handling and edge cases', () => {
346
+ it('should handle malformed theme objects gracefully', () => {
347
+ // Create a partial theme for testing edge cases
348
+ const partialTheme = {
349
+ ...DefaultColorThemePalette.lightMode,
350
+ red: {
351
+ ...DefaultColorThemePalette.lightMode.red,
352
+ solid: undefined,
353
+ } as any,
354
+ }
355
+
356
+ // getColorValue should still work but return undefined for this case
357
+ expect(getColorValue(partialTheme, 'red', 'solid')).toBe(undefined)
358
+ })
359
+
360
+ it('should handle very large color names', () => {
361
+ const longColorName = 'a'.repeat(1000)
362
+ expect(isDefaultThemeColor(longColorName as TLDefaultColorStyle)).toBe(false)
363
+ expect(
364
+ getColorValue(
365
+ DefaultColorThemePalette.lightMode,
366
+ longColorName as TLDefaultColorStyle,
367
+ 'solid'
368
+ )
369
+ ).toBe(longColorName)
370
+ })
371
+
372
+ it('should handle special characters in color values', () => {
373
+ const specialColors = ['color-with-dashes', 'color_with_underscores', 'color.with.dots']
374
+
375
+ specialColors.forEach((color) => {
376
+ expect(isDefaultThemeColor(color as TLDefaultColorStyle)).toBe(false)
377
+ expect(
378
+ getColorValue(DefaultColorThemePalette.lightMode, color as TLDefaultColorStyle, 'solid')
379
+ ).toBe(color)
380
+ })
381
+ })
382
+
383
+ test('should maintain immutability of exported objects', () => {
384
+ const originalLightTheme = DefaultColorThemePalette.lightMode
385
+ const originalDarkTheme = DefaultColorThemePalette.darkMode
386
+ const originalColorNames = defaultColorNames
387
+
388
+ // These should be the same references
389
+ expect(getDefaultColorTheme({ isDarkMode: false })).toBe(originalLightTheme)
390
+ expect(getDefaultColorTheme({ isDarkMode: true })).toBe(originalDarkTheme)
391
+
392
+ // Arrays should maintain their values
393
+ expect(defaultColorNames).toEqual(originalColorNames)
394
+ expect(DefaultColorStyle.values).toEqual(originalColorNames)
395
+ })
396
+ })
397
+
398
+ describe('performance considerations', () => {
399
+ it('should validate colors efficiently', () => {
400
+ const start = performance.now()
401
+
402
+ for (let i = 0; i < 1000; i++) {
403
+ defaultColorNames.forEach((color) => {
404
+ DefaultColorStyle.validate(color)
405
+ isDefaultThemeColor(color)
406
+ })
407
+ }
408
+
409
+ const end = performance.now()
410
+ expect(end - start).toBeLessThan(100) // Should be fast
411
+ })
412
+
413
+ it('should resolve color values efficiently', () => {
414
+ const theme = DefaultColorThemePalette.lightMode
415
+ const start = performance.now()
416
+
417
+ for (let i = 0; i < 1000; i++) {
418
+ defaultColorNames.forEach((color) => {
419
+ getColorValue(theme, color, 'solid')
420
+ getColorValue(theme, color, 'fill')
421
+ })
422
+ }
423
+
424
+ const end = performance.now()
425
+ expect(end - start).toBeLessThan(50) // Should be very fast
426
+ })
427
+
428
+ it('should handle theme switching efficiently', () => {
429
+ const start = performance.now()
430
+
431
+ for (let i = 0; i < 1000; i++) {
432
+ getDefaultColorTheme({ isDarkMode: i % 2 === 0 })
433
+ }
434
+
435
+ const end = performance.now()
436
+ expect(end - start).toBeLessThan(10) // Should be extremely fast (just returns references)
437
+ })
438
+ })
439
+ })