@upsoftware_tech/svarium 1.0.7 → 1.0.9

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.
@@ -0,0 +1,798 @@
1
+ type AppearanceLike = {
2
+ class?: unknown;
3
+ style?: unknown;
4
+ fontWeight?: unknown;
5
+ fontSize?: unknown;
6
+ textColor?: unknown;
7
+ fontColor?: unknown;
8
+ textDecoration?: unknown;
9
+ bgColor?: unknown;
10
+ borderWidth?: unknown;
11
+ borderRadius?: unknown;
12
+ borderColor?: unknown;
13
+ borderStyle?: unknown;
14
+ outlineWidth?: unknown;
15
+ outlineColor?: unknown;
16
+ outlineStyle?: unknown;
17
+ outlineOffset?: unknown;
18
+ [key: string]: unknown;
19
+ };
20
+
21
+ const fontWeightToClass: Record<string, string> = {
22
+ '100': 'font-thin',
23
+ '200': 'font-extralight',
24
+ '300': 'font-light',
25
+ '400': 'font-normal',
26
+ '500': 'font-medium',
27
+ '600': 'font-semibold',
28
+ '700': 'font-bold',
29
+ '800': 'font-extrabold',
30
+ '900': 'font-black',
31
+ thin: 'font-thin',
32
+ extralight: 'font-extralight',
33
+ 'extra-light': 'font-extralight',
34
+ light: 'font-light',
35
+ normal: 'font-normal',
36
+ regular: 'font-normal',
37
+ medium: 'font-medium',
38
+ semibold: 'font-semibold',
39
+ 'semi-bold': 'font-semibold',
40
+ bold: 'font-bold',
41
+ extrabold: 'font-extrabold',
42
+ 'extra-bold': 'font-extrabold',
43
+ black: 'font-black',
44
+ };
45
+
46
+ const fontSizeToClass: Record<string, string> = {
47
+ xs: 'text-xs',
48
+ sm: 'text-sm',
49
+ base: 'text-base',
50
+ lg: 'text-lg',
51
+ xl: 'text-xl',
52
+ '2xl': 'text-2xl',
53
+ '3xl': 'text-3xl',
54
+ '4xl': 'text-4xl',
55
+ '5xl': 'text-5xl',
56
+ '6xl': 'text-6xl',
57
+ '7xl': 'text-7xl',
58
+ '8xl': 'text-8xl',
59
+ '9xl': 'text-9xl',
60
+ };
61
+
62
+ const fontColorToClass: Record<string, string> = {
63
+ slate: 'text-slate-500',
64
+ gray: 'text-gray-500',
65
+ zinc: 'text-zinc-500',
66
+ neutral: 'text-neutral-500',
67
+ stone: 'text-stone-500',
68
+ red: 'text-red-500',
69
+ orange: 'text-orange-500',
70
+ amber: 'text-amber-500',
71
+ yellow: 'text-yellow-500',
72
+ lime: 'text-lime-500',
73
+ green: 'text-green-500',
74
+ emerald: 'text-emerald-500',
75
+ teal: 'text-teal-500',
76
+ cyan: 'text-cyan-500',
77
+ sky: 'text-sky-500',
78
+ blue: 'text-blue-500',
79
+ indigo: 'text-indigo-500',
80
+ violet: 'text-violet-500',
81
+ purple: 'text-purple-500',
82
+ fuchsia: 'text-fuchsia-500',
83
+ pink: 'text-pink-500',
84
+ rose: 'text-rose-500',
85
+ primary: 'text-primary',
86
+ white: 'text-white',
87
+ black: 'text-black',
88
+ };
89
+
90
+ const backgroundColorToClass: Record<string, string> = {
91
+ slate: 'bg-slate-500',
92
+ gray: 'bg-gray-500',
93
+ zinc: 'bg-zinc-500',
94
+ neutral: 'bg-neutral-500',
95
+ stone: 'bg-stone-500',
96
+ red: 'bg-red-500',
97
+ 'red-200': 'bg-red-200',
98
+ orange: 'bg-orange-500',
99
+ amber: 'bg-amber-500',
100
+ yellow: 'bg-yellow-500',
101
+ lime: 'bg-lime-500',
102
+ green: 'bg-green-500',
103
+ emerald: 'bg-emerald-500',
104
+ teal: 'bg-teal-500',
105
+ cyan: 'bg-cyan-500',
106
+ sky: 'bg-sky-500',
107
+ blue: 'bg-blue-500',
108
+ indigo: 'bg-indigo-500',
109
+ violet: 'bg-violet-500',
110
+ purple: 'bg-purple-500',
111
+ fuchsia: 'bg-fuchsia-500',
112
+ pink: 'bg-pink-500',
113
+ rose: 'bg-rose-500',
114
+ white: 'bg-white',
115
+ black: 'bg-black',
116
+ };
117
+
118
+ const borderColorToClass: Record<string, string> = {
119
+ slate: 'border-slate-500',
120
+ gray: 'border-gray-500',
121
+ zinc: 'border-zinc-500',
122
+ neutral: 'border-neutral-500',
123
+ stone: 'border-stone-500',
124
+ red: 'border-red-500',
125
+ orange: 'border-orange-500',
126
+ amber: 'border-amber-500',
127
+ yellow: 'border-yellow-500',
128
+ lime: 'border-lime-500',
129
+ green: 'border-green-500',
130
+ emerald: 'border-emerald-500',
131
+ teal: 'border-teal-500',
132
+ cyan: 'border-cyan-500',
133
+ sky: 'border-sky-500',
134
+ blue: 'border-blue-500',
135
+ indigo: 'border-indigo-500',
136
+ violet: 'border-violet-500',
137
+ purple: 'border-purple-500',
138
+ fuchsia: 'border-fuchsia-500',
139
+ pink: 'border-pink-500',
140
+ rose: 'border-rose-500',
141
+ white: 'border-white',
142
+ black: 'border-black',
143
+ };
144
+
145
+ const outlineColorToClass: Record<string, string> = {
146
+ slate: 'outline-slate-500',
147
+ gray: 'outline-gray-500',
148
+ zinc: 'outline-zinc-500',
149
+ neutral: 'outline-neutral-500',
150
+ stone: 'outline-stone-500',
151
+ red: 'outline-red-500',
152
+ orange: 'outline-orange-500',
153
+ amber: 'outline-amber-500',
154
+ yellow: 'outline-yellow-500',
155
+ lime: 'outline-lime-500',
156
+ green: 'outline-green-500',
157
+ emerald: 'outline-emerald-500',
158
+ teal: 'outline-teal-500',
159
+ cyan: 'outline-cyan-500',
160
+ sky: 'outline-sky-500',
161
+ blue: 'outline-blue-500',
162
+ indigo: 'outline-indigo-500',
163
+ violet: 'outline-violet-500',
164
+ purple: 'outline-purple-500',
165
+ fuchsia: 'outline-fuchsia-500',
166
+ pink: 'outline-pink-500',
167
+ rose: 'outline-rose-500',
168
+ white: 'outline-white',
169
+ black: 'outline-black',
170
+ };
171
+
172
+ function getColorParts(value: unknown): { light?: unknown; dark?: unknown } {
173
+ if (Array.isArray(value)) {
174
+ return {
175
+ light: value[0],
176
+ dark: value[1],
177
+ };
178
+ }
179
+
180
+ if (value && typeof value === 'object') {
181
+ const record = value as Record<string, unknown>;
182
+ if ('light' in record || 'dark' in record) {
183
+ return {
184
+ light: record.light,
185
+ dark: record.dark,
186
+ };
187
+ }
188
+ }
189
+
190
+ if (value !== undefined) {
191
+ return { light: value };
192
+ }
193
+
194
+ return {};
195
+ }
196
+
197
+ function appendTextColor(
198
+ value: unknown,
199
+ classTokens: string[],
200
+ style: Record<string, string>,
201
+ dark = false,
202
+ ): void {
203
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
204
+ if (raw === '') {
205
+ return;
206
+ }
207
+
208
+ const normalized = raw.toLowerCase();
209
+ let token = '';
210
+
211
+ if (normalized.startsWith('text-')) {
212
+ token = normalized;
213
+ } else if (fontColorToClass[normalized]) {
214
+ token = fontColorToClass[normalized];
215
+ } else if (/^[a-z]+-(50|[1-9]00)$/.test(normalized)) {
216
+ token = `text-${normalized}`;
217
+ }
218
+
219
+ if (token !== '') {
220
+ classTokens.push(dark ? `dark:${token}` : token);
221
+ return;
222
+ }
223
+
224
+ if (dark) {
225
+ return;
226
+ }
227
+
228
+ if (/^(#|rgb\(|rgba\(|hsl\(|hsla\(|var\()/.test(raw)) {
229
+ style.color = raw;
230
+ return;
231
+ }
232
+
233
+ style.color = raw;
234
+ }
235
+
236
+ function appendTextDecoration(
237
+ value: unknown,
238
+ classTokens: string[],
239
+ style: Record<string, string>,
240
+ ): void {
241
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
242
+ if (raw === '') {
243
+ return;
244
+ }
245
+
246
+ const normalized = raw.toLowerCase();
247
+ const tokens = normalized.split(/\s+/).map((token) => token.trim()).filter(Boolean);
248
+ const utilityTokens = new Set([
249
+ 'underline',
250
+ 'overline',
251
+ 'line-through',
252
+ 'no-underline',
253
+ 'decoration-solid',
254
+ 'decoration-double',
255
+ 'decoration-dotted',
256
+ 'decoration-dashed',
257
+ 'decoration-wavy',
258
+ 'decoration-auto',
259
+ 'decoration-from-font',
260
+ ]);
261
+
262
+ if (tokens.length > 0) {
263
+ const allUtilities = tokens.every((token) => utilityTokens.has(token) || token.startsWith('decoration-'));
264
+
265
+ if (allUtilities) {
266
+ classTokens.push(...tokens);
267
+ return;
268
+ }
269
+ }
270
+
271
+ style.textDecoration = raw;
272
+ }
273
+
274
+ function appendBackgroundColor(
275
+ value: unknown,
276
+ classTokens: string[],
277
+ style: Record<string, string>,
278
+ dark = false,
279
+ ): void {
280
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
281
+ if (raw === '') {
282
+ return;
283
+ }
284
+
285
+ const normalized = raw.toLowerCase();
286
+ let token = '';
287
+
288
+ if (normalized.startsWith('bg-')) {
289
+ token = normalized;
290
+ } else if (backgroundColorToClass[normalized]) {
291
+ token = backgroundColorToClass[normalized];
292
+ } else if (/^[a-z]+-(50|[1-9]00)$/.test(normalized)) {
293
+ token = `bg-${normalized}`;
294
+ }
295
+
296
+ if (token !== '') {
297
+ classTokens.push(dark ? `dark:${token}` : token);
298
+ return;
299
+ }
300
+
301
+ if (dark) {
302
+ return;
303
+ }
304
+
305
+ if (/^(#|rgb\(|rgba\(|hsl\(|hsla\(|var\()/.test(raw)) {
306
+ style.backgroundColor = raw;
307
+ return;
308
+ }
309
+
310
+ style.backgroundColor = raw;
311
+ }
312
+
313
+ function appendBorderWidth(
314
+ value: unknown,
315
+ classTokens: string[],
316
+ style: Record<string, string>,
317
+ ): void {
318
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
319
+ if (raw === '') {
320
+ return;
321
+ }
322
+
323
+ const normalized = raw.toLowerCase();
324
+ const normalizedNumber = normalized.endsWith('.')
325
+ ? normalized.slice(0, -1)
326
+ : normalized;
327
+
328
+ if (normalized === 'border' || normalized.startsWith('border-')) {
329
+ classTokens.push(normalized);
330
+ return;
331
+ }
332
+
333
+ if (/^(x|y|t|r|b|l)-.+$/.test(normalized)) {
334
+ classTokens.push(`border-${normalized}`);
335
+ return;
336
+ }
337
+
338
+ if (/^\d+$/.test(normalizedNumber)) {
339
+ if (normalizedNumber === '0') {
340
+ classTokens.push('border-0');
341
+ return;
342
+ }
343
+
344
+ if (normalizedNumber === '1') {
345
+ classTokens.push('border');
346
+ return;
347
+ }
348
+
349
+ classTokens.push(`border-${normalizedNumber}`);
350
+ return;
351
+ }
352
+
353
+ if (/^\d+(\.\d+)?(px|rem|em|%)$/.test(normalized)) {
354
+ style.borderWidth = normalized;
355
+ return;
356
+ }
357
+
358
+ if (/^\d+(\.\d+)?$/.test(normalizedNumber)) {
359
+ style.borderWidth = `${normalizedNumber}px`;
360
+ return;
361
+ }
362
+
363
+ style.borderWidth = raw;
364
+ }
365
+
366
+ function appendBorderRadius(
367
+ value: unknown,
368
+ classTokens: string[],
369
+ style: Record<string, string>,
370
+ ): void {
371
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
372
+ if (raw === '') {
373
+ return;
374
+ }
375
+
376
+ const normalized = raw.toLowerCase();
377
+
378
+ if (normalized.startsWith('rounded')) {
379
+ classTokens.push(normalized);
380
+ return;
381
+ }
382
+
383
+ if (normalized === 'base' || normalized === 'default') {
384
+ classTokens.push('rounded');
385
+ return;
386
+ }
387
+
388
+ if (/^[a-z]{1,2}-.+$/.test(normalized)) {
389
+ classTokens.push(`rounded-${normalized}`);
390
+ return;
391
+ }
392
+
393
+ if (/^(none|sm|md|lg|xl|2xl|3xl|full)$/.test(normalized)) {
394
+ classTokens.push(`rounded-${normalized}`);
395
+ return;
396
+ }
397
+
398
+ if (/^\d+(\.\d+)?(px|rem|em|%)$/.test(normalized)) {
399
+ style.borderRadius = normalized;
400
+ return;
401
+ }
402
+
403
+ if (/^\d+(\.\d+)?$/.test(normalized)) {
404
+ style.borderRadius = `${normalized}px`;
405
+ return;
406
+ }
407
+
408
+ style.borderRadius = raw;
409
+ }
410
+
411
+ function appendBorderColor(
412
+ value: unknown,
413
+ classTokens: string[],
414
+ style: Record<string, string>,
415
+ dark = false,
416
+ ): void {
417
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
418
+ if (raw === '') {
419
+ return;
420
+ }
421
+
422
+ const normalized = raw.toLowerCase();
423
+ let token = '';
424
+
425
+ if (normalized.startsWith('border-')) {
426
+ token = normalized;
427
+ } else if (borderColorToClass[normalized]) {
428
+ token = borderColorToClass[normalized];
429
+ } else if (/^[a-z]+-(50|[1-9]00)$/.test(normalized)) {
430
+ token = `border-${normalized}`;
431
+ }
432
+
433
+ if (token !== '') {
434
+ classTokens.push(dark ? `dark:${token}` : token);
435
+ return;
436
+ }
437
+
438
+ if (dark) {
439
+ return;
440
+ }
441
+
442
+ if (/^(#|rgb\(|rgba\(|hsl\(|hsla\(|var\()/.test(raw)) {
443
+ style.borderColor = raw;
444
+ return;
445
+ }
446
+
447
+ style.borderColor = raw;
448
+ }
449
+
450
+ function appendBorderStyle(
451
+ value: unknown,
452
+ classTokens: string[],
453
+ style: Record<string, string>,
454
+ ): void {
455
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
456
+ if (raw === '') {
457
+ return;
458
+ }
459
+
460
+ const normalized = raw.toLowerCase();
461
+
462
+ if (normalized.startsWith('border-')) {
463
+ classTokens.push(normalized);
464
+ return;
465
+ }
466
+
467
+ const styleMap: Record<string, string> = {
468
+ solid: 'border-solid',
469
+ dashed: 'border-dashed',
470
+ dotted: 'border-dotted',
471
+ double: 'border-double',
472
+ none: 'border-none',
473
+ hidden: 'border-hidden',
474
+ };
475
+
476
+ if (styleMap[normalized]) {
477
+ classTokens.push(styleMap[normalized]);
478
+ return;
479
+ }
480
+
481
+ style.borderStyle = raw;
482
+ }
483
+
484
+ function appendOutlineWidth(
485
+ value: unknown,
486
+ classTokens: string[],
487
+ style: Record<string, string>,
488
+ ): void {
489
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
490
+ if (raw === '') {
491
+ return;
492
+ }
493
+
494
+ const normalized = raw.toLowerCase();
495
+
496
+ if (normalized === 'outline' || normalized.startsWith('outline-')) {
497
+ classTokens.push(normalized);
498
+ return;
499
+ }
500
+
501
+ if (/^\d+$/.test(normalized)) {
502
+ if (normalized === '1') {
503
+ classTokens.push('outline');
504
+ return;
505
+ }
506
+
507
+ classTokens.push(`outline-${normalized}`);
508
+ return;
509
+ }
510
+
511
+ if (/^\d+(\.\d+)?(px|rem|em|%)$/.test(normalized)) {
512
+ style.outlineWidth = normalized;
513
+ return;
514
+ }
515
+
516
+ if (/^\d+(\.\d+)?$/.test(normalized)) {
517
+ style.outlineWidth = `${normalized}px`;
518
+ return;
519
+ }
520
+
521
+ style.outlineWidth = raw;
522
+ }
523
+
524
+ function appendOutlineColor(
525
+ value: unknown,
526
+ classTokens: string[],
527
+ style: Record<string, string>,
528
+ dark = false,
529
+ ): void {
530
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
531
+ if (raw === '') {
532
+ return;
533
+ }
534
+
535
+ const normalized = raw.toLowerCase();
536
+ let token = '';
537
+
538
+ if (normalized.startsWith('outline-')) {
539
+ token = normalized;
540
+ } else if (outlineColorToClass[normalized]) {
541
+ token = outlineColorToClass[normalized];
542
+ } else if (/^[a-z]+-(50|[1-9]00)$/.test(normalized)) {
543
+ token = `outline-${normalized}`;
544
+ }
545
+
546
+ if (token !== '') {
547
+ classTokens.push(dark ? `dark:${token}` : token);
548
+ return;
549
+ }
550
+
551
+ if (dark) {
552
+ return;
553
+ }
554
+
555
+ if (/^(#|rgb\(|rgba\(|hsl\(|hsla\(|var\()/.test(raw)) {
556
+ style.outlineColor = raw;
557
+ return;
558
+ }
559
+
560
+ style.outlineColor = raw;
561
+ }
562
+
563
+ function appendOutlineStyle(
564
+ value: unknown,
565
+ classTokens: string[],
566
+ style: Record<string, string>,
567
+ ): void {
568
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
569
+ if (raw === '') {
570
+ return;
571
+ }
572
+
573
+ const normalized = raw.toLowerCase();
574
+
575
+ if (normalized.startsWith('outline-')) {
576
+ classTokens.push(normalized);
577
+ return;
578
+ }
579
+
580
+ const styleMap: Record<string, string> = {
581
+ solid: 'outline-solid',
582
+ dashed: 'outline-dashed',
583
+ dotted: 'outline-dotted',
584
+ double: 'outline-double',
585
+ none: 'outline-none',
586
+ hidden: 'outline-hidden',
587
+ };
588
+
589
+ if (styleMap[normalized]) {
590
+ classTokens.push(styleMap[normalized]);
591
+ return;
592
+ }
593
+
594
+ style.outlineStyle = raw;
595
+ }
596
+
597
+ function appendOutlineOffset(
598
+ value: unknown,
599
+ classTokens: string[],
600
+ style: Record<string, string>,
601
+ ): void {
602
+ const raw = value !== undefined && value !== null ? String(value).trim() : '';
603
+ if (raw === '') {
604
+ return;
605
+ }
606
+
607
+ const normalized = raw.toLowerCase();
608
+
609
+ if (normalized.startsWith('outline-offset-')) {
610
+ classTokens.push(normalized);
611
+ return;
612
+ }
613
+
614
+ if (/^\d+$/.test(normalized)) {
615
+ classTokens.push(`outline-offset-${normalized}`);
616
+ return;
617
+ }
618
+
619
+ if (/^\d+(\.\d+)?(px|rem|em|%)$/.test(normalized)) {
620
+ style.outlineOffset = normalized;
621
+ return;
622
+ }
623
+
624
+ if (/^\d+(\.\d+)?$/.test(normalized)) {
625
+ style.outlineOffset = `${normalized}px`;
626
+ return;
627
+ }
628
+
629
+ style.outlineOffset = raw;
630
+ }
631
+
632
+ function normalizeClassTokens(input: unknown): string[] {
633
+ if (typeof input === 'string') {
634
+ return input.split(/\s+/).map((token) => token.trim()).filter(Boolean);
635
+ }
636
+
637
+ if (Array.isArray(input)) {
638
+ return input.flatMap((entry) => normalizeClassTokens(entry));
639
+ }
640
+
641
+ if (input && typeof input === 'object') {
642
+ return Object.entries(input as Record<string, unknown>)
643
+ .filter(([, enabled]) => Boolean(enabled))
644
+ .map(([token]) => token);
645
+ }
646
+
647
+ return [];
648
+ }
649
+
650
+ function uniqueTokens(tokens: string[]): string[] {
651
+ return Array.from(new Set(tokens.filter(Boolean)));
652
+ }
653
+
654
+ function mergeStyle(base: unknown, extra: Record<string, string>): unknown {
655
+ if (Object.keys(extra).length === 0) {
656
+ return base;
657
+ }
658
+
659
+ if (base === undefined || base === null || base === '') {
660
+ return extra;
661
+ }
662
+
663
+ if (Array.isArray(base)) {
664
+ return [...base, extra];
665
+ }
666
+
667
+ if (typeof base === 'object') {
668
+ return { ...(base as Record<string, unknown>), ...extra };
669
+ }
670
+
671
+ return [base, extra];
672
+ }
673
+
674
+ function normalizeAppearance(appearance: AppearanceLike): {
675
+ classTokens: string[];
676
+ style: Record<string, string>;
677
+ appearance: AppearanceLike;
678
+ } {
679
+ const classTokens = normalizeClassTokens(appearance.class);
680
+ const style: Record<string, string> = {};
681
+
682
+ const weight = appearance.fontWeight !== undefined
683
+ ? String(appearance.fontWeight).trim().toLowerCase()
684
+ : '';
685
+
686
+ if (weight !== '' && fontWeightToClass[weight]) {
687
+ classTokens.push(fontWeightToClass[weight]);
688
+ }
689
+
690
+ const fontSize = appearance.fontSize !== undefined
691
+ ? String(appearance.fontSize).trim().toLowerCase()
692
+ : '';
693
+
694
+ if (fontSize !== '') {
695
+ if (fontSizeToClass[fontSize]) {
696
+ classTokens.push(fontSizeToClass[fontSize]);
697
+ } else if (fontSize.startsWith('text-')) {
698
+ classTokens.push(fontSize);
699
+ } else if (/^\d+(\.\d+)?$/.test(fontSize)) {
700
+ style.fontSize = `${fontSize}px`;
701
+ } else if (/^\d+(\.\d+)?(px|rem|em|%)$/.test(fontSize)) {
702
+ style.fontSize = fontSize;
703
+ }
704
+ }
705
+
706
+ const textColorValue = appearance.textColor !== undefined
707
+ ? appearance.textColor
708
+ : appearance.fontColor;
709
+ const { light: lightTextColor, dark: darkTextColor } = getColorParts(textColorValue);
710
+ appendTextColor(lightTextColor, classTokens, style);
711
+ appendTextColor(darkTextColor, classTokens, style, true);
712
+ appendTextDecoration(appearance.textDecoration, classTokens, style);
713
+
714
+ const { light: lightBgColor, dark: darkBgColor } = getColorParts(appearance.bgColor);
715
+ appendBackgroundColor(lightBgColor, classTokens, style);
716
+ appendBackgroundColor(darkBgColor, classTokens, style, true);
717
+
718
+ appendBorderWidth(appearance.borderWidth, classTokens, style);
719
+ appendBorderRadius(appearance.borderRadius, classTokens, style);
720
+
721
+ const { light: lightBorderColor, dark: darkBorderColor } = getColorParts(appearance.borderColor);
722
+ appendBorderColor(lightBorderColor, classTokens, style);
723
+ appendBorderColor(darkBorderColor, classTokens, style, true);
724
+
725
+ appendBorderStyle(appearance.borderStyle, classTokens, style);
726
+
727
+ appendOutlineWidth(appearance.outlineWidth, classTokens, style);
728
+
729
+ const { light: lightOutlineColor, dark: darkOutlineColor } = getColorParts(appearance.outlineColor);
730
+ appendOutlineColor(lightOutlineColor, classTokens, style);
731
+ appendOutlineColor(darkOutlineColor, classTokens, style, true);
732
+
733
+ appendOutlineStyle(appearance.outlineStyle, classTokens, style);
734
+ appendOutlineOffset(appearance.outlineOffset, classTokens, style);
735
+
736
+ const nextAppearance: AppearanceLike = {
737
+ ...appearance,
738
+ };
739
+
740
+ delete nextAppearance.fontWeight;
741
+ delete nextAppearance.fontSize;
742
+ delete nextAppearance.textColor;
743
+ delete nextAppearance.fontColor;
744
+ delete nextAppearance.textDecoration;
745
+ delete nextAppearance.bgColor;
746
+ delete nextAppearance.borderWidth;
747
+ delete nextAppearance.borderRadius;
748
+ delete nextAppearance.borderColor;
749
+ delete nextAppearance.borderStyle;
750
+ delete nextAppearance.outlineWidth;
751
+ delete nextAppearance.outlineColor;
752
+ delete nextAppearance.outlineStyle;
753
+ delete nextAppearance.outlineOffset;
754
+
755
+ if (classTokens.length > 0) {
756
+ nextAppearance.class = uniqueTokens(classTokens).join(' ');
757
+ }
758
+
759
+ if (Object.keys(style).length > 0) {
760
+ nextAppearance.style = mergeStyle(appearance.style, style);
761
+ }
762
+
763
+ return {
764
+ classTokens: uniqueTokens(classTokens),
765
+ style,
766
+ appearance: nextAppearance,
767
+ };
768
+ }
769
+
770
+ export function normalizeNodeProps(nodeProps: Record<string, any>): Record<string, any> {
771
+ const resolved = { ...nodeProps };
772
+ const appearance = resolved.appearance;
773
+
774
+ if (appearance && typeof appearance === 'object' && !Array.isArray(appearance)) {
775
+ const normalized = normalizeAppearance(appearance as AppearanceLike);
776
+ const combinedClass = uniqueTokens([
777
+ ...normalizeClassTokens(resolved.class),
778
+ ...normalized.classTokens,
779
+ ]);
780
+
781
+ if (combinedClass.length > 0) {
782
+ resolved.class = combinedClass.join(' ');
783
+ }
784
+
785
+ const appearanceStyle = (normalized.appearance as AppearanceLike).style;
786
+ if (appearanceStyle !== undefined && appearanceStyle !== null && appearanceStyle !== '') {
787
+ resolved.style = mergeStyle(
788
+ resolved.style,
789
+ appearanceStyle as Record<string, string>,
790
+ );
791
+ }
792
+
793
+ resolved.style = mergeStyle(resolved.style, normalized.style);
794
+ resolved.appearance = normalized.appearance;
795
+ }
796
+
797
+ return resolved;
798
+ }