@bookklik/senangstart-css 0.2.9 → 0.2.12

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 (69) hide show
  1. package/.agent/skills/add-utility/SKILL.md +65 -0
  2. package/.agent/workflows/add-utility.md +2 -0
  3. package/.agent/workflows/build.md +2 -0
  4. package/.agent/workflows/dev.md +2 -0
  5. package/AGENTS.md +30 -0
  6. package/dist/senangstart-css.js +607 -180
  7. package/dist/senangstart-css.min.js +234 -195
  8. package/dist/senangstart-tw.js +274 -8
  9. package/dist/senangstart-tw.min.js +1 -1
  10. package/docs/SYNTAX-REFERENCE.md +1731 -1590
  11. package/docs/guide/preflight.md +20 -1
  12. package/docs/ms/guide/preflight.md +19 -0
  13. package/docs/ms/reference/breakpoints.md +14 -0
  14. package/docs/ms/reference/visual/border-radius.md +50 -10
  15. package/docs/ms/reference/visual/contain.md +57 -0
  16. package/docs/ms/reference/visual/content-visibility.md +53 -0
  17. package/docs/ms/reference/visual/placeholder-color.md +92 -0
  18. package/docs/ms/reference/visual/ring-color.md +2 -2
  19. package/docs/ms/reference/visual/ring-offset.md +3 -3
  20. package/docs/ms/reference/visual/ring.md +5 -5
  21. package/docs/ms/reference/visual/writing-mode.md +53 -0
  22. package/docs/ms/reference/visual.md +6 -0
  23. package/docs/public/assets/senangstart-css.min.js +234 -195
  24. package/docs/public/llms.txt +45 -12
  25. package/docs/reference/breakpoints.md +14 -0
  26. package/docs/reference/visual/border-radius.md +50 -10
  27. package/docs/reference/visual/contain.md +57 -0
  28. package/docs/reference/visual/content-visibility.md +53 -0
  29. package/docs/reference/visual/placeholder-color.md +92 -0
  30. package/docs/reference/visual/ring-color.md +2 -2
  31. package/docs/reference/visual/ring-offset.md +3 -3
  32. package/docs/reference/visual/ring.md +5 -5
  33. package/docs/reference/visual/writing-mode.md +53 -0
  34. package/docs/reference/visual.md +7 -0
  35. package/docs/syntax-reference.json +2185 -2009
  36. package/package.json +1 -1
  37. package/scripts/convert-tailwind.js +300 -26
  38. package/scripts/generate-docs.js +403 -403
  39. package/src/cdn/senangstart-engine.js +5 -5
  40. package/src/cdn/tw-conversion-engine.js +305 -8
  41. package/src/cli/commands/build.js +51 -13
  42. package/src/cli/commands/dev.js +157 -93
  43. package/src/compiler/generators/css.js +467 -208
  44. package/src/compiler/generators/preflight.js +26 -13
  45. package/src/compiler/generators/typescript.js +3 -1
  46. package/src/compiler/index.js +27 -3
  47. package/src/compiler/parser.js +13 -6
  48. package/src/compiler/tokenizer.js +25 -23
  49. package/src/config/defaults.js +3 -0
  50. package/src/core/tokenizer-core.js +46 -19
  51. package/src/definitions/index.js +4 -1
  52. package/src/definitions/visual-borders.js +10 -10
  53. package/src/definitions/visual-performance.js +126 -0
  54. package/src/definitions/visual.js +25 -9
  55. package/src/utils/common.js +456 -27
  56. package/src/utils/node-io.js +82 -0
  57. package/tests/integration/dev-recovery.test.js +231 -0
  58. package/tests/unit/cli/memory-limits.test.js +169 -0
  59. package/tests/unit/compiler/css-generation-error-handling.test.js +204 -0
  60. package/tests/unit/compiler/generators/css-errors.test.js +102 -0
  61. package/tests/unit/compiler/generators/css.test.js +102 -5
  62. package/tests/unit/convert-tailwind.test.js +518 -431
  63. package/tests/unit/utils/common.test.js +376 -26
  64. package/tests/unit/utils/file-timeout.test.js +154 -0
  65. package/tests/unit/utils/theme-validation.test.js +181 -0
  66. package/tests/unit/compiler/generators/css.coverage.test.js +0 -833
  67. package/tests/unit/convert-tailwind.cli.test.js +0 -95
  68. package/tests/unit/security.test.js +0 -206
  69. /package/tests/unit/{convert-tailwind.coverage.test.js → convert-tailwind-edgecases.test.js} +0 -0
@@ -39,11 +39,61 @@
39
39
  if (typeof value !== "string") {
40
40
  return "";
41
41
  }
42
- const dangerousChars = /[;]/g;
43
- if (dangerousChars.test(value)) {
44
- return value.replace(dangerousChars, "_");
42
+ if (value.length > 1e3) {
43
+ return "";
44
+ }
45
+ let sanitized = value;
46
+ sanitized = sanitized.replace(/[\\`$]/g, "");
47
+ const dangerousUrlProtocols = [
48
+ "javascript:",
49
+ "vbscript:",
50
+ "data:",
51
+ "about:",
52
+ "file:",
53
+ "ftp:",
54
+ "mailto:"
55
+ ].join("|");
56
+ const urlRegex = /url\s*\((?:[^()]|\((?:[^()]|\([^()]*\))*\))*\)/gi;
57
+ sanitized = sanitized.replace(urlRegex, (match) => {
58
+ if (dangerousUrlProtocols.split("|").some((protocol) => match.toLowerCase().includes(protocol))) {
59
+ return "url(about:blank)";
60
+ }
61
+ return match;
62
+ });
63
+ const scriptVectors = [
64
+ /expression\s*\(/gi,
65
+ // IE expression()
66
+ /\beval\s*\(/gi,
67
+ // eval()
68
+ /\balert\s*\(/gi,
69
+ // alert()
70
+ /\bdocument\./gi,
71
+ // document access
72
+ /\bwindow\./gi,
73
+ // window access
74
+ /on\w+\s*=/gi,
75
+ // event handlers (onclick=, etc.)
76
+ /<script[^>]*>/gi,
77
+ // <script> tags
78
+ /<\/script>/gi
79
+ // <\/script> tags
80
+ ];
81
+ for (const pattern of scriptVectors) {
82
+ sanitized = sanitized.replace(pattern, "");
83
+ }
84
+ const atRules = /@(?:import|charset|namespace|supports|keyframes|font-face|media|page)/gi;
85
+ sanitized = sanitized.replace(atRules, "");
86
+ sanitized = sanitized.replace(/[;]/g, "_");
87
+ const openBrackets = (sanitized.match(/\[/g) || []).length;
88
+ const closeBrackets = (sanitized.match(/\]/g) || []).length;
89
+ if (Math.abs(openBrackets - closeBrackets) > 3 || Math.max(openBrackets, closeBrackets) > 10) {
90
+ return "";
91
+ }
92
+ sanitized = sanitized.replace(/@/g, "");
93
+ if (sanitized.length > 500) {
94
+ sanitized = sanitized.substring(0, 500);
45
95
  }
46
- return value;
96
+ return sanitized;
47
97
  }
48
98
 
49
99
  // src/core/tokenizer-core.js
@@ -221,10 +271,13 @@ hr {
221
271
  }
222
272
 
223
273
  /*
224
- * Add the correct text decoration in Chrome, Edge, and Safari
274
+ * Set default placeholder color to a semi-transparent gray
275
+ * Uses theme variable for customization with fallback
225
276
  */
226
- abbr:where([title]) {
227
- text-decoration: underline dotted;
277
+ input::placeholder,
278
+ textarea::placeholder {
279
+ opacity: 1; /* 1 */
280
+ color: var(--placeholder-color, #9ca3af); /* 2 */
228
281
  }
229
282
 
230
283
  /*
@@ -367,10 +420,17 @@ input:where([type='submit']) {
367
420
  }
368
421
 
369
422
  /*
370
- * Add the correct vertical alignment in Chrome and Firefox
423
+ * Add the correct text decoration in Chrome, Edge, and Safari
371
424
  */
372
- progress {
373
- vertical-align: baseline;
425
+ abbr:where([title]) {
426
+ text-decoration: underline dotted;
427
+ }
428
+
429
+ /*
430
+ * Make sure links don't get underlined in headings
431
+ */
432
+ h1, h2, h3, h4, h5, h6 {
433
+ text-decoration: none;
374
434
  }
375
435
 
376
436
  /*
@@ -442,14 +502,17 @@ legend {
442
502
  }
443
503
 
444
504
  /*
445
- * Remove default list styles
505
+ * 1. Use a more sensible default box-sizing strategy
446
506
  */
447
- ol,
448
- ul,
449
- menu {
450
- list-style: none;
451
- margin: 0;
452
- padding: 0;
507
+ *,
508
+ ::before,
509
+ ::after {
510
+ box-sizing: border-box;
511
+ /* Support safe-area-inset for modern devices with notches */
512
+ padding-top: env(safe-area-inset-top);
513
+ padding-right: env(safe-area-inset-right);
514
+ padding-bottom: env(safe-area-inset-bottom);
515
+ padding-left: env(safe-area-inset-left);
453
516
  }
454
517
 
455
518
  /*
@@ -3151,11 +3214,12 @@ video {
3151
3214
  var borderRadius = {
3152
3215
  name: "border-radius",
3153
3216
  property: "visual",
3154
- syntax: 'visual="rounded:[value]"',
3155
- description: "Set border radius",
3156
- descriptionMs: "Tetapkan jejari sempadan",
3217
+ syntax: 'visual="rounded:[value]" | visual="rounded-{t|b|l|r|tl|tr|bl|br}:[value]"',
3218
+ description: "Set border radius for all corners or specific corners",
3219
+ descriptionMs: "Tetapkan jejari sempadan untuk semua bucu atau bucu tertentu",
3157
3220
  category: "visual",
3158
3221
  usesScale: "radius",
3222
+ supportsArbitrary: true,
3159
3223
  values: [
3160
3224
  { value: "none", css: "border-radius: var(--r-none);", description: "No rounding", descriptionMs: "Tiada pembulatan" },
3161
3225
  { value: "small", css: "border-radius: var(--r-small);", description: "Small radius", descriptionMs: "Jejari kecil" },
@@ -3164,8 +3228,10 @@ video {
3164
3228
  { value: "round", css: "border-radius: var(--r-round);", description: "Fully round", descriptionMs: "Sepenuhnya bulat" }
3165
3229
  ],
3166
3230
  examples: [
3167
- { code: '<div visual="rounded:medium">Rounded corners</div>', description: "Medium radius" },
3168
- { code: '<div visual="rounded:round">Pill shape</div>', description: "Pill" }
3231
+ { code: '<div visual="rounded:medium">Rounded corners</div>', description: "All corners rounded" },
3232
+ { code: '<div visual="rounded:round">Pill shape</div>', description: "Fully round" },
3233
+ { code: '<div visual="rounded-t:medium">Top rounded</div>', description: "Top corners only" },
3234
+ { code: '<div visual="rounded-tl:big rounded-br:big">Opposite corners</div>', description: "Specific corners" }
3169
3235
  ],
3170
3236
  footnotes: [
3171
3237
  {
@@ -3183,12 +3249,25 @@ video {
3183
3249
  description: "Round element corners from subtle to pill-shaped",
3184
3250
  descriptionMs: "Bulatkan sudut elemen dari halus hingga berbentuk pil",
3185
3251
  html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
3186
- <div space="p:small" visual="bg:primary text:white rounded:none">none</div>
3187
- <div space="p:small" visual="bg:primary text:white rounded:small">small</div>
3188
- <div space="p:small" visual="bg:primary text:white rounded:medium">medium</div>
3189
- <div space="p:small" visual="bg:primary text:white rounded:round">round</div>
3252
+ <div space="p:small" visual="bg:primary text:white rounded:none">none</div>
3253
+ <div space="p:small" visual="bg:primary text:white rounded:small">small</div>
3254
+ <div space="p:small" visual="bg:primary text:white rounded:medium">medium</div>
3255
+ <div space="p:small" visual="bg:primary text:white rounded:round">round</div>
3190
3256
  </div>`,
3191
3257
  highlightValue: "rounded:medium"
3258
+ },
3259
+ {
3260
+ title: "Directional Border Radius",
3261
+ titleMs: "Jejari Sempadan Arah",
3262
+ description: "Round specific corners for unique shapes",
3263
+ descriptionMs: "Bulatkan bucu tertentu untuk bentuk unik",
3264
+ html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
3265
+ <div space="p:small" visual="bg:primary text:white rounded-t:medium">top</div>
3266
+ <div space="p:small" visual="bg:primary text:white rounded-b:medium">bottom</div>
3267
+ <div space="p:small" visual="bg:primary text:white rounded-l:medium">left</div>
3268
+ <div space="p:small" visual="bg:primary text:white rounded-r:medium">right</div>
3269
+ </div>`,
3270
+ highlightValue: "rounded-t:medium"
3192
3271
  }
3193
3272
  ]
3194
3273
  };
@@ -6458,11 +6537,11 @@ video {
6458
6537
  supportsArbitrary: true,
6459
6538
  values: [
6460
6539
  { value: "none", css: "box-shadow: 0 0 0 0 transparent;", description: "No ring", descriptionMs: "Tiada cincin" },
6461
- { value: "thin", css: "box-shadow: 0 0 0 1px var(--ring-color);", description: "Thin ring (1px)", descriptionMs: "Cincin nipis (1px)" },
6462
- { value: "regular", css: "box-shadow: 0 0 0 2px var(--ring-color);", description: "Regular ring (2px)", descriptionMs: "Cincin biasa (2px)" },
6463
- { value: "small", css: "box-shadow: 0 0 0 4px var(--ring-color);", description: "Small ring (4px)", descriptionMs: "Cincin kecil (4px)" },
6464
- { value: "medium", css: "box-shadow: 0 0 0 6px var(--ring-color);", description: "Medium ring (6px)", descriptionMs: "Cincin sederhana (6px)" },
6465
- { value: "big", css: "box-shadow: 0 0 0 8px var(--ring-color);", description: "Big ring (8px)", descriptionMs: "Cincin besar (8px)" }
6540
+ { value: "thin", css: "box-shadow: var(--ring-inset) 0 0 0 1px var(--ss-ring-color);", description: "Thin ring (1px)", descriptionMs: "Cincin nipis (1px)" },
6541
+ { value: "regular", css: "box-shadow: var(--ring-inset) 0 0 0 2px var(--ss-ring-color);", description: "Regular ring (2px)", descriptionMs: "Cincin biasa (2px)" },
6542
+ { value: "small", css: "box-shadow: var(--ring-inset) 0 0 0 4px var(--ss-ring-color);", description: "Small ring (4px)", descriptionMs: "Cincin kecil (4px)" },
6543
+ { value: "medium", css: "box-shadow: var(--ring-inset) 0 0 0 6px var(--ss-ring-color);", description: "Medium ring (6px)", descriptionMs: "Cincin sederhana (6px)" },
6544
+ { value: "big", css: "box-shadow: var(--ring-inset) 0 0 0 8px var(--ss-ring-color);", description: "Big ring (8px)", descriptionMs: "Cincin besar (8px)" }
6466
6545
  ],
6467
6546
  examples: [
6468
6547
  { code: '<button visual="focus-visible:ring:small ring-color:primary">Focus me</button>', description: "Focus ring on keyboard focus" },
@@ -6492,8 +6571,8 @@ video {
6492
6571
  usesScale: "colors",
6493
6572
  supportsArbitrary: true,
6494
6573
  values: [
6495
- { value: "primary", css: "--ring-color: var(--c-primary);", description: "Primary ring color", descriptionMs: "Warna cincin utama" },
6496
- { value: "blue-500", css: "--ring-color: var(--c-blue-500);", description: "Blue ring color", descriptionMs: "Warna cincin biru" }
6574
+ { value: "primary", css: "--ss-ring-color: var(--c-primary);", description: "Primary ring color", descriptionMs: "Warna cincin utama" },
6575
+ { value: "blue-500", css: "--ss-ring-color: var(--c-blue-500);", description: "Blue ring color", descriptionMs: "Warna cincin biru" }
6497
6576
  ],
6498
6577
  examples: [
6499
6578
  { code: '<button visual="ring:small ring-color:primary">Colored ring</button>', description: "Ring with custom color" }
@@ -6508,9 +6587,9 @@ video {
6508
6587
  category: "visual",
6509
6588
  supportsArbitrary: true,
6510
6589
  values: [
6511
- { value: "0", css: "--ring-offset: 0px;", description: "No offset", descriptionMs: "Tiada ruang" },
6512
- { value: "2", css: "--ring-offset: 2px;", description: "2px offset", descriptionMs: "Ruang 2px" },
6513
- { value: "4", css: "--ring-offset: 4px;", description: "4px offset", descriptionMs: "Ruang 4px" }
6590
+ { value: "0", css: "--ss-ring-offset-width: 0px;", description: "No offset", descriptionMs: "Tiada ruang" },
6591
+ { value: "2", css: "--ss-ring-offset-width: 2px;", description: "2px offset", descriptionMs: "Ruang 2px" },
6592
+ { value: "4", css: "--ss-ring-offset-width: 4px;", description: "4px offset", descriptionMs: "Ruang 4px" }
6514
6593
  ],
6515
6594
  examples: [
6516
6595
  { code: '<button visual="ring:small ring-offset:2 ring-color:primary">With offset</button>', description: "Ring with offset" }
@@ -6828,6 +6907,112 @@ video {
6828
6907
  };
6829
6908
  var visual_svg_default = svgDefinitions;
6830
6909
 
6910
+ // src/definitions/visual-performance.js
6911
+ var contentVisibility = {
6912
+ name: "content-visibility",
6913
+ property: "visual",
6914
+ syntax: 'visual="content-visibility:[value]"',
6915
+ description: "Optimize rendering by skipping off-screen content",
6916
+ descriptionMs: "Optimumkan rendering dengan melangkau kandungan luar skrin",
6917
+ category: "visual",
6918
+ values: [
6919
+ { value: "visible", css: "content-visibility: visible;", description: "Render all content", descriptionMs: "Render semua kandungan" },
6920
+ { value: "auto", css: "content-visibility: auto;", description: "Skip when off-screen", descriptionMs: "Langkau bila luar skrin" },
6921
+ { value: "hidden", css: "content-visibility: hidden;", description: "Never render off-screen", descriptionMs: "Jangan render luar skrin" }
6922
+ ],
6923
+ examples: [
6924
+ { code: '<section visual="content-visibility:auto">Large list</section>', description: "Auto-optimize large content" },
6925
+ { code: '<div visual="content-visibility:hidden">Hidden until needed</div>', description: "Hide until revealed" }
6926
+ ],
6927
+ preview: [
6928
+ {
6929
+ title: "Content Visibility",
6930
+ titleMs: "Ketampakan Kandungan",
6931
+ description: "Performance optimization for off-screen content",
6932
+ descriptionMs: "Pengoptimuman prestasi untuk kandungan luar skrin",
6933
+ html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
6934
+ <div space="p:small" visual="bg:primary text:white rounded:small">visible</div>
6935
+ <div space="p:small" visual="bg:primary text:white rounded:small">auto</div>
6936
+ <div space="p:small" visual="bg:primary text:white rounded:small">hidden</div>
6937
+ </div>`,
6938
+ highlightValue: "content-visibility:auto"
6939
+ }
6940
+ ]
6941
+ };
6942
+ var contain = {
6943
+ name: "contain",
6944
+ property: "visual",
6945
+ syntax: 'visual="contain:[value]"',
6946
+ description: "Isolate element rendering for performance",
6947
+ descriptionMs: "Pencil rendering elemen untuk prestasi",
6948
+ category: "visual",
6949
+ values: [
6950
+ { value: "none", css: "contain: none;", description: "No containment", descriptionMs: "Tiada pengandungan" },
6951
+ { value: "strict", css: "contain: strict;", description: "Full containment", descriptionMs: "Pengandungan penuh" },
6952
+ { value: "content", css: "contain: content;", description: "Content containment", descriptionMs: "Pengandungan kandungan" },
6953
+ { value: "size", css: "contain: size;", description: "Size containment", descriptionMs: "Pengandungan saiz" },
6954
+ { value: "layout", css: "contain: layout;", description: "Layout containment", descriptionMs: "Pengandungan susun atur" },
6955
+ { value: "style", css: "contain: style;", description: "Style containment", descriptionMs: "Pengandungan gaya" },
6956
+ { value: "paint", css: "contain: paint;", description: "Paint containment", descriptionMs: "Pengandungan lukis" }
6957
+ ],
6958
+ examples: [
6959
+ { code: '<div visual="contain:strict">Isolated rendering</div>', description: "Full containment" },
6960
+ { code: '<div visual="contain:content">Content isolation</div>', description: "Content only" }
6961
+ ],
6962
+ preview: [
6963
+ {
6964
+ title: "Contain",
6965
+ titleMs: "Mengandung",
6966
+ description: "Isolate element from rest of page for performance",
6967
+ descriptionMs: "Pencil elemen dari halaman lain untuk prestasi",
6968
+ html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
6969
+ <div space="p:small" visual="bg:primary text:white rounded:small">none</div>
6970
+ <div space="p:small" visual="bg:primary text:white rounded:small">content</div>
6971
+ <div space="p:small" visual="bg:primary text:white rounded:small">strict</div>
6972
+ </div>`,
6973
+ highlightValue: "contain:strict"
6974
+ }
6975
+ ]
6976
+ };
6977
+ var writingMode = {
6978
+ name: "writing-mode",
6979
+ property: "visual",
6980
+ syntax: 'visual="writing-mode:[value]"',
6981
+ description: "Set writing direction for RTL/vertical text",
6982
+ descriptionMs: "Tetapkan arah penulisan untuk teks RTL/menegak",
6983
+ category: "visual",
6984
+ values: [
6985
+ { value: "horizontal-tb", css: "writing-mode: horizontal-tb;", description: "Left to right", descriptionMs: "Kiri ke kanan" },
6986
+ { value: "vertical-rl", css: "writing-mode: vertical-rl;", description: "Top to bottom RTL", descriptionMs: "Atas ke bawah RTL" },
6987
+ { value: "vertical-lr", css: "writing-mode: vertical-lr;", description: "Top to bottom LTR", descriptionMs: "Atas ke bawah LTR" },
6988
+ { value: "sideways-rl", css: "writing-mode: sideways-rl;", description: "Sideways RTL", descriptionMs: "Menyerong RTL" },
6989
+ { value: "sideways-lr", css: "writing-mode: sideways-lr;", description: "Sideways LTR", descriptionMs: "Menyerong LTR" }
6990
+ ],
6991
+ examples: [
6992
+ { code: '<div visual="writing-mode:vertical-rl">Vertical text</div>', description: "Vertical text RTL" },
6993
+ { code: '<div visual="writing-mode:horizontal-tb">Horizontal text</div>', description: "Horizontal text LTR" }
6994
+ ],
6995
+ preview: [
6996
+ {
6997
+ title: "Writing Mode",
6998
+ titleMs: "Mod Penulisan",
6999
+ description: "Control text direction and orientation",
7000
+ descriptionMs: "Kawal arah dan orientasi teks",
7001
+ html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
7002
+ <div space="p:small" visual="bg:primary text:white rounded:small">horizontal-tb</div>
7003
+ <div space="p:small" visual="bg:primary text:white rounded:small">vertical-rl</div>
7004
+ </div>`,
7005
+ highlightValue: "writing-mode:vertical-rl"
7006
+ }
7007
+ ]
7008
+ };
7009
+ var performanceDefinitions = {
7010
+ contentVisibility,
7011
+ contain,
7012
+ writingMode
7013
+ };
7014
+ var visual_performance_default = performanceDefinitions;
7015
+
6831
7016
  // src/definitions/index.js
6832
7017
  var allVisualDefinitions = {
6833
7018
  ...visual_default,
@@ -6840,7 +7025,8 @@ video {
6840
7025
  ...visual_transforms_default,
6841
7026
  ...visual_borders_default,
6842
7027
  ...visual_divide_default,
6843
- ...visual_svg_default
7028
+ ...visual_svg_default,
7029
+ ...visual_performance_default
6844
7030
  };
6845
7031
  function buildAllMaps() {
6846
7032
  return {
@@ -6898,6 +7084,16 @@ video {
6898
7084
  css += ` --c-${key}: ${value};
6899
7085
  `;
6900
7086
  }
7087
+ if (theme.placeholder) {
7088
+ css += ` --placeholder-color: ${theme.placeholder};
7089
+ `;
7090
+ } else {
7091
+ css += " --placeholder-color: #9ca3af;\n";
7092
+ }
7093
+ css += " --gradient-from: transparent;\n";
7094
+ css += " --gradient-via: transparent;\n";
7095
+ css += " --gradient-to: transparent;\n";
7096
+ css += " --gradient-stops: var(--gradient-from), var(--gradient-via), var(--gradient-to);\n";
6901
7097
  for (const [key, value] of Object.entries(theme.zIndex)) {
6902
7098
  css += ` --z-${key}: ${value};
6903
7099
  `;
@@ -7025,6 +7221,10 @@ video {
7025
7221
  css += ` --tw-font-${key}: ${value};
7026
7222
  `;
7027
7223
  }
7224
+ css += " --ss-divide-x-reverse: 0;\n";
7225
+ css += " --ss-divide-y-reverse: 0;\n";
7226
+ css += " --ring-inset: ;\n";
7227
+ css += " --ss-ring-color: var(--c-primary);\n";
7028
7228
  css += "}\n\n";
7029
7229
  return css;
7030
7230
  }
@@ -7130,6 +7330,31 @@ video {
7130
7330
  const cssValue = isArbitrary ? value.replace(/_/g, " ") : value;
7131
7331
  return `object-position: ${cssValue};`;
7132
7332
  }
7333
+ if (property === "content-visibility") {
7334
+ return `content-visibility: ${value};`;
7335
+ }
7336
+ if (property === "contain") {
7337
+ const containMap = {
7338
+ "none": "none",
7339
+ "strict": "strict",
7340
+ "content": "content",
7341
+ "size": "size",
7342
+ "layout": "layout",
7343
+ "style": "style",
7344
+ "paint": "paint"
7345
+ };
7346
+ const cssValue = isArbitrary ? value : containMap[value] || value;
7347
+ return `contain: ${cssValue};`;
7348
+ }
7349
+ if (property === "writing") {
7350
+ const writingMap = {
7351
+ "horizontal-tb": "horizontal-tb",
7352
+ "vertical-rl": "vertical-rl",
7353
+ "vertical-lr": "vertical-lr"
7354
+ };
7355
+ const cssValue = isArbitrary ? value.replace(/_/g, " ") : writingMap[value] || value;
7356
+ return `writing-mode: ${cssValue};`;
7357
+ }
7133
7358
  const positioningPercentages = {
7134
7359
  "full": "100%",
7135
7360
  "half": "50%",
@@ -7149,7 +7374,7 @@ video {
7149
7374
  };
7150
7375
  const resolvePositioningValue = (val, arb) => {
7151
7376
  if (arb) return val;
7152
- if (val === "0") return "0";
7377
+ if (!val || val === "0") return "0";
7153
7378
  if (val.startsWith("-")) {
7154
7379
  const positiveVal = val.substring(1);
7155
7380
  if (positioningPercentages[positiveVal]) {
@@ -7349,8 +7574,8 @@ video {
7349
7574
  if (isArbitrary) {
7350
7575
  cssValue = value;
7351
7576
  } else {
7352
- const isNegative = value.startsWith("-");
7353
- const cleanValue = isNegative ? value.substring(1) : value;
7577
+ const isNegative = value && value.startsWith("-");
7578
+ const cleanValue = isNegative ? value.substring(1) : value || "";
7354
7579
  let baseValue;
7355
7580
  if (cleanValue.startsWith("tw-")) {
7356
7581
  const twValue = cleanValue.slice(3);
@@ -7417,7 +7642,7 @@ video {
7417
7642
  },
7418
7643
  // Background Image
7419
7644
  "bg-image": () => {
7420
- if (value === "none") return "background-image: none;";
7645
+ if (!value || value === "none") return "background-image: none;";
7421
7646
  if (value.startsWith("gradient-to-")) {
7422
7647
  const directionMap = {
7423
7648
  "t": "to top",
@@ -7659,32 +7884,32 @@ video {
7659
7884
  // Border width
7660
7885
  "border-w": () => {
7661
7886
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7662
- return `border-width: ${cssValue}; border-style: solid;`;
7887
+ return `border-width: ${cssValue};`;
7663
7888
  },
7664
7889
  // Border width - directional
7665
7890
  "border-t-w": () => {
7666
7891
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7667
- return `border-top-width: ${cssValue}; border-top-style: solid;`;
7892
+ return `border-top-width: ${cssValue};`;
7668
7893
  },
7669
7894
  "border-b-w": () => {
7670
7895
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7671
- return `border-bottom-width: ${cssValue}; border-bottom-style: solid;`;
7896
+ return `border-bottom-width: ${cssValue};`;
7672
7897
  },
7673
7898
  "border-l-w": () => {
7674
7899
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7675
- return `border-left-width: ${cssValue}; border-left-style: solid;`;
7900
+ return `border-left-width: ${cssValue};`;
7676
7901
  },
7677
7902
  "border-r-w": () => {
7678
7903
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7679
- return `border-right-width: ${cssValue}; border-right-style: solid;`;
7904
+ return `border-right-width: ${cssValue};`;
7680
7905
  },
7681
7906
  "border-x-w": () => {
7682
7907
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7683
- return `border-left-width: ${cssValue}; border-right-width: ${cssValue}; border-left-style: solid; border-right-style: solid;`;
7908
+ return `border-left-width: ${cssValue}; border-right-width: ${cssValue};`;
7684
7909
  },
7685
7910
  "border-y-w": () => {
7686
7911
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7687
- return `border-top-width: ${cssValue}; border-bottom-width: ${cssValue}; border-top-style: solid; border-bottom-style: solid;`;
7912
+ return `border-top-width: ${cssValue}; border-bottom-width: ${cssValue};`;
7688
7913
  },
7689
7914
  // Border style
7690
7915
  "border-style": () => {
@@ -7694,6 +7919,39 @@ video {
7694
7919
  "rounded": () => {
7695
7920
  return `border-radius: var(--r-${value});`;
7696
7921
  },
7922
+ // Directional border radius
7923
+ "rounded-t": () => {
7924
+ const cssValue = isArbitrary ? value : `var(--r-${value})`;
7925
+ return `border-top-left-radius: ${cssValue}; border-top-right-radius: ${cssValue};`;
7926
+ },
7927
+ "rounded-b": () => {
7928
+ const cssValue = isArbitrary ? value : `var(--r-${value})`;
7929
+ return `border-bottom-left-radius: ${cssValue}; border-bottom-right-radius: ${cssValue};`;
7930
+ },
7931
+ "rounded-l": () => {
7932
+ const cssValue = isArbitrary ? value : `var(--r-${value})`;
7933
+ return `border-top-left-radius: ${cssValue}; border-bottom-left-radius: ${cssValue};`;
7934
+ },
7935
+ "rounded-r": () => {
7936
+ const cssValue = isArbitrary ? value : `var(--r-${value})`;
7937
+ return `border-top-right-radius: ${cssValue}; border-bottom-right-radius: ${cssValue};`;
7938
+ },
7939
+ "rounded-tl": () => {
7940
+ const cssValue = isArbitrary ? value : `var(--r-${value})`;
7941
+ return `border-top-left-radius: ${cssValue};`;
7942
+ },
7943
+ "rounded-tr": () => {
7944
+ const cssValue = isArbitrary ? value : `var(--r-${value})`;
7945
+ return `border-top-right-radius: ${cssValue};`;
7946
+ },
7947
+ "rounded-bl": () => {
7948
+ const cssValue = isArbitrary ? value : `var(--r-${value})`;
7949
+ return `border-bottom-left-radius: ${cssValue};`;
7950
+ },
7951
+ "rounded-br": () => {
7952
+ const cssValue = isArbitrary ? value : `var(--r-${value})`;
7953
+ return `border-bottom-right-radius: ${cssValue};`;
7954
+ },
7697
7955
  // =====================
7698
7956
  // DIVIDE UTILITIES
7699
7957
  // =====================
@@ -7720,16 +7978,16 @@ video {
7720
7978
  // Divide width - all sides
7721
7979
  "divide-w": () => {
7722
7980
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7723
- return `border-width: ${cssValue}; border-style: solid;`;
7981
+ return `border-top-width: calc(${cssValue} * (1 - var(--ss-divide-y-reverse))); border-bottom-width: calc(${cssValue} * var(--ss-divide-y-reverse)); border-left-width: calc(${cssValue} * (1 - var(--ss-divide-x-reverse))); border-right-width: calc(${cssValue} * var(--ss-divide-x-reverse));`;
7724
7982
  },
7725
7983
  // Divide width - directional
7726
7984
  "divide-x-w": () => {
7727
7985
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7728
- return `border-left-width: ${cssValue}; border-right-width: ${cssValue}; border-left-style: solid; border-right-style: solid;`;
7986
+ return `border-right-width: calc(${cssValue} * var(--ss-divide-x-reverse)); border-left-width: calc(${cssValue} * (1 - var(--ss-divide-x-reverse)));`;
7729
7987
  },
7730
7988
  "divide-y-w": () => {
7731
7989
  const cssValue = isArbitrary ? value : `var(--s-${value})`;
7732
- return `border-top-width: ${cssValue}; border-bottom-width: ${cssValue}; border-top-style: solid; border-bottom-style: solid;`;
7990
+ return `border-bottom-width: calc(${cssValue} * var(--ss-divide-y-reverse)); border-top-width: calc(${cssValue} * (1 - var(--ss-divide-y-reverse)));`;
7733
7991
  },
7734
7992
  // Divide style
7735
7993
  "divide-style": () => {
@@ -7742,6 +8000,9 @@ video {
7742
8000
  },
7743
8001
  // Outline Color
7744
8002
  "outline": () => {
8003
+ if (value === "none") {
8004
+ return "outline: none;";
8005
+ }
7745
8006
  const cssValue = resolveColorValue(value, isArbitrary);
7746
8007
  return `outline-color: ${cssValue};`;
7747
8008
  },
@@ -7787,7 +8048,11 @@ video {
7787
8048
  "big": "8px"
7788
8049
  };
7789
8050
  const width2 = isArbitrary ? value : ringPresets[value] || (parseInt(value) ? `${value}px` : `var(--s-${value})`);
7790
- return `--ss-ring-width: ${width2}; box-shadow: var(--ss-ring-inset) 0 0 0 calc(var(--ss-ring-width) + var(--ss-ring-offset-width, 0px)) var(--ss-ring-color, currentColor);`;
8051
+ return `--ss-ring-width: ${width2}; box-shadow: var(--ring-inset) 0 0 0 calc(var(--ss-ring-width) + var(--ss-ring-offset-width, 0px)) var(--ss-ring-color);`;
8052
+ },
8053
+ // Ring Inset
8054
+ "ring-inset": () => {
8055
+ return "--ring-inset: inset;";
7791
8056
  },
7792
8057
  // Box shadow
7793
8058
  "shadow": () => {
@@ -8569,69 +8834,122 @@ video {
8569
8834
  const generator = rules[property];
8570
8835
  return generator ? generator() : "";
8571
8836
  }
8572
- function generateRule(token, config, skipDarkWrapper = false, interactIds = /* @__PURE__ */ new Set()) {
8573
- const { raw, attrType, breakpoint, state } = token;
8574
- let cssDeclaration = "";
8575
- switch (attrType) {
8576
- case "layout":
8577
- cssDeclaration = generateLayoutRule(token, config);
8578
- break;
8579
- case "space":
8580
- cssDeclaration = generateSpaceRule(token, config);
8581
- break;
8582
- case "visual":
8583
- cssDeclaration = generateVisualRule(token, config);
8584
- break;
8585
- }
8586
- if (!cssDeclaration) return "";
8587
- const isDivide = raw.startsWith("divide");
8588
- let selector = "";
8589
- if (isDivide) {
8590
- selector = `[${attrType}~="${raw}"] > :not([hidden]) ~ :not([hidden])`;
8591
- } else {
8592
- selector = `[${attrType}~="${raw}"]`;
8837
+ function isValidCSSRule(declaration) {
8838
+ if (!declaration || typeof declaration !== "string") {
8839
+ return false;
8593
8840
  }
8594
- if (state && state !== "dark") {
8841
+ declaration = declaration.trim();
8842
+ if (!declaration) return false;
8843
+ if (!declaration.endsWith(";")) return false;
8844
+ const parts = declaration.substring(0, declaration.length - 1).split(":");
8845
+ if (parts.length < 2) return false;
8846
+ const property = parts[0].trim();
8847
+ const value = parts.slice(1).join(":").trim();
8848
+ if (!property || !value) return false;
8849
+ return true;
8850
+ }
8851
+ function generateRule(token, config, skipDarkWrapper = false, interactIds = /* @__PURE__ */ new Set()) {
8852
+ try {
8853
+ if (!token || typeof token !== "object") {
8854
+ console.warn("[SenangStart] Invalid token object:", token);
8855
+ return "";
8856
+ }
8857
+ const { raw, attrType, breakpoint, state } = token;
8858
+ if (!attrType || typeof attrType !== "string") {
8859
+ console.warn("[SenangStart] Invalid token attrType:", attrType);
8860
+ return "";
8861
+ }
8862
+ if (!raw || typeof raw !== "string") {
8863
+ console.warn("[SenangStart] Invalid token raw:", raw);
8864
+ return "";
8865
+ }
8866
+ let cssDeclaration = "";
8867
+ switch (attrType) {
8868
+ case "layout":
8869
+ try {
8870
+ cssDeclaration = generateLayoutRule(token, config);
8871
+ } catch (e) {
8872
+ console.warn(`[SenangStart] Error generating layout rule for "${raw}": ${e.message}`);
8873
+ return "";
8874
+ }
8875
+ break;
8876
+ case "space":
8877
+ try {
8878
+ cssDeclaration = generateSpaceRule(token, config);
8879
+ } catch (e) {
8880
+ console.warn(`[SenangStart] Error generating space rule for "${raw}": ${e.message}`);
8881
+ return "";
8882
+ }
8883
+ break;
8884
+ case "visual":
8885
+ try {
8886
+ cssDeclaration = generateVisualRule(token, config);
8887
+ } catch (e) {
8888
+ console.warn(`[SenangStart] Error generating visual rule for "${raw}": ${e.message}`);
8889
+ return "";
8890
+ }
8891
+ break;
8892
+ default:
8893
+ console.warn(`[SenangStart] Unknown attrType: ${attrType}`);
8894
+ return "";
8895
+ }
8896
+ if (!cssDeclaration) return "";
8897
+ if (!isValidCSSRule(cssDeclaration)) {
8898
+ console.warn(`[SenangStart] Invalid CSS rule generated for "${raw}": ${cssDeclaration}`);
8899
+ return "";
8900
+ }
8901
+ const isDivide = raw && raw.startsWith("divide");
8902
+ let selector = "";
8595
8903
  if (isDivide) {
8596
- selector = `[${attrType}~="${raw}"] > :not([hidden]) ~ :not([hidden]):${state}`;
8904
+ selector = `[${attrType}~="${raw}"] > :not([hidden]) ~ :not([hidden])`;
8597
8905
  } else {
8598
- const getStateSelector = (s) => {
8599
- const map = {
8600
- "expanded": '[aria-expanded="true"]',
8601
- "selected": '[aria-selected="true"]',
8602
- "disabled": ":disabled"
8906
+ selector = `[${attrType}~="${raw}"]`;
8907
+ }
8908
+ if (state && state !== "dark") {
8909
+ if (isDivide) {
8910
+ selector = `[${attrType}~="${raw}"] > :not([hidden]) ~ :not([hidden]):${state}`;
8911
+ } else {
8912
+ const getStateSelector = (s) => {
8913
+ const map = {
8914
+ "expanded": '[aria-expanded="true"]',
8915
+ "selected": '[aria-selected="true"]',
8916
+ "disabled": ":disabled"
8917
+ };
8918
+ return map[s] || `:${s}`;
8603
8919
  };
8604
- return map[s] || `:${s}`;
8605
- };
8606
- const selectors = [];
8607
- selectors.push(`${selector}${getStateSelector(state)}`);
8608
- const groupTriggers = {
8609
- "hover": "hoverable",
8610
- "focus": "focusable",
8611
- "focus-visible": "focusable",
8612
- "active": "pressable",
8613
- "expanded": "expandable",
8614
- "selected": "selectable"
8615
- };
8616
- if (groupTriggers[state]) {
8617
- const parentAttr = groupTriggers[state];
8618
- let triggerState = state;
8619
- if (state === "focus" || state === "focus-visible") triggerState = "focus-within";
8620
- const triggerSelector = getStateSelector(triggerState);
8621
- const groupSelector = `[layout~="${parentAttr}"]:not([layout~="disabled"])${triggerSelector} ${selector}`;
8622
- selectors.push(groupSelector);
8623
- if (interactIds && interactIds.size > 0) {
8624
- for (const id of interactIds) {
8625
- const peerSelector = `[interact~="${id}"]:not([layout~="disabled"])${triggerSelector} ~ [listens~="${id}"]${selector}`;
8626
- selectors.push(peerSelector);
8920
+ const selectors = [];
8921
+ selectors.push(`${selector}${getStateSelector(state)}`);
8922
+ const groupTriggers = {
8923
+ "hover": "hoverable",
8924
+ "focus": "focusable",
8925
+ "focus-visible": "focusable",
8926
+ "active": "pressable",
8927
+ "expanded": "expandable",
8928
+ "selected": "selectable"
8929
+ };
8930
+ if (groupTriggers[state]) {
8931
+ const parentAttr = groupTriggers[state];
8932
+ let triggerState = state;
8933
+ if (state === "focus" || state === "focus-visible") triggerState = "focus-within";
8934
+ const triggerSelector = getStateSelector(triggerState);
8935
+ const groupSelector = `[layout~="${parentAttr}"]:not([layout~="disabled"])${triggerSelector} ${selector}`;
8936
+ selectors.push(groupSelector);
8937
+ if (interactIds && interactIds.size > 0) {
8938
+ for (const id of interactIds) {
8939
+ const peerSelector = `[interact~="${id}"]:not([layout~="disabled"])${triggerSelector} ~ [listens~="${id}"]${selector}`;
8940
+ selectors.push(peerSelector);
8941
+ }
8627
8942
  }
8628
8943
  }
8944
+ selector = selectors.join(",\n");
8629
8945
  }
8630
- selector = selectors.join(",\n");
8631
8946
  }
8632
- }
8633
- return `${selector} { ${cssDeclaration} }
8947
+ return `${selector} { ${cssDeclaration} }
8634
8948
  `;
8949
+ } catch (e) {
8950
+ console.warn(`[SenangStart] Error in generateRule: ${e.message}`);
8951
+ return "";
8952
+ }
8635
8953
  }
8636
8954
  function getDarkModeSelector(config) {
8637
8955
  const darkMode = config.darkMode || "media";
@@ -8643,13 +8961,33 @@ video {
8643
8961
  }
8644
8962
  return null;
8645
8963
  }
8646
- function generateCSS(tokens, config) {
8647
- let css = "";
8648
- css += generateCSSVariables(config);
8649
- if (config.preflight !== false) {
8650
- css += generatePreflight(config);
8651
- }
8652
- css += `/* SenangStart CSS - Animation Keyframes */
8964
+ function generateCSSWithErrors(tokens, config) {
8965
+ const errors = [];
8966
+ try {
8967
+ let css = "";
8968
+ if (!config || typeof config !== "object") {
8969
+ errors.push({ type: "config", message: "Invalid config provided" });
8970
+ return { css: "", errors };
8971
+ }
8972
+ if (!Array.isArray(tokens)) {
8973
+ errors.push({ type: "tokens", message: "Invalid tokens provided" });
8974
+ return { css: "", errors };
8975
+ }
8976
+ try {
8977
+ css += generateCSSVariables(config);
8978
+ } catch (e) {
8979
+ errors.push({ type: "variables", message: e.message });
8980
+ console.warn(`[SenangStart] Error generating CSS variables: ${e.message}`);
8981
+ }
8982
+ if (config.preflight !== false) {
8983
+ try {
8984
+ css += generatePreflight(config);
8985
+ } catch (e) {
8986
+ errors.push({ type: "preflight", message: e.message });
8987
+ console.warn(`[SenangStart] Error generating preflight: ${e.message}`);
8988
+ }
8989
+ }
8990
+ css += `/* SenangStart CSS - Animation Keyframes */
8653
8991
  @keyframes spin {
8654
8992
  to { transform: rotate(360deg); }
8655
8993
  }
@@ -8666,93 +9004,178 @@ video {
8666
9004
 
8667
9005
  /* SenangStart CSS - Utility Classes */
8668
9006
  `;
8669
- const baseTokens = [];
8670
- const darkTokens = [];
8671
- const breakpointTokens = {};
8672
- const { screens } = config.theme;
8673
- for (const bp of Object.keys(screens)) {
8674
- breakpointTokens[bp] = [];
8675
- }
8676
- for (const token of tokens) {
8677
- if (token.state === "dark") {
8678
- darkTokens.push(token);
8679
- } else if (token.breakpoint) {
8680
- if (!breakpointTokens[token.breakpoint]) {
8681
- breakpointTokens[token.breakpoint] = [];
9007
+ const baseTokens = [];
9008
+ const darkTokens = [];
9009
+ const breakpointTokens = {};
9010
+ const { screens } = config.theme || {};
9011
+ if (screens && typeof screens === "object") {
9012
+ for (const bp of Object.keys(screens)) {
9013
+ breakpointTokens[bp] = [];
8682
9014
  }
8683
- breakpointTokens[token.breakpoint].push(token);
8684
- } else {
8685
- baseTokens.push(token);
8686
9015
  }
8687
- }
8688
- const interactIds = /* @__PURE__ */ new Set();
8689
- for (const token of tokens) {
8690
- if (token.attrType === "interact") {
8691
- interactIds.add(token.raw);
9016
+ for (const token of tokens) {
9017
+ try {
9018
+ if (token && typeof token === "object") {
9019
+ if (token.state === "dark") {
9020
+ darkTokens.push(token);
9021
+ } else if (token.breakpoint) {
9022
+ if (!breakpointTokens[token.breakpoint]) {
9023
+ breakpointTokens[token.breakpoint] = [];
9024
+ }
9025
+ breakpointTokens[token.breakpoint].push(token);
9026
+ } else {
9027
+ baseTokens.push(token);
9028
+ }
9029
+ } else {
9030
+ errors.push({ type: "token_format", token, message: "Token is not an object" });
9031
+ }
9032
+ } catch (e) {
9033
+ errors.push({ type: "token_processing", token: token?.raw, message: e.message });
9034
+ console.warn(`[SenangStart] Error processing token: ${e.message}`);
9035
+ }
8692
9036
  }
8693
- }
8694
- const displayProps = ["flex", "grid", "inline-flex", "inline-grid", "block", "inline", "hidden", "contents"];
8695
- const baseDisplayTokens = /* @__PURE__ */ new Map();
8696
- for (const token of baseTokens) {
8697
- if (token.attrType && displayProps.includes(token.property)) {
8698
- if (!baseDisplayTokens.has(token.attrType)) {
8699
- baseDisplayTokens.set(token.attrType, /* @__PURE__ */ new Set());
9037
+ const interactIds = /* @__PURE__ */ new Set();
9038
+ for (const token of tokens) {
9039
+ try {
9040
+ if (token && token.attrType === "interact" && token.raw) {
9041
+ interactIds.add(token.raw);
9042
+ }
9043
+ } catch (e) {
9044
+ errors.push({ type: "interact_collection", token: token?.raw, message: e.message });
9045
+ console.warn(`[SenangStart] Error collecting interact IDs: ${e.message}`);
8700
9046
  }
8701
- baseDisplayTokens.get(token.attrType).add(token.raw);
8702
9047
  }
8703
- }
8704
- for (const token of baseTokens) {
8705
- css += generateRule(token, config, false, interactIds);
8706
- }
8707
- for (const [bp, bpTokens] of Object.entries(breakpointTokens)) {
8708
- if (bpTokens.length > 0) {
8709
- css += `
8710
- @media (min-width: ${screens[bp]}) {
9048
+ const displayProps = ["flex", "grid", "inline-flex", "inline-grid", "block", "inline", "hidden", "contents"];
9049
+ const baseDisplayTokens = /* @__PURE__ */ new Map();
9050
+ for (const token of baseTokens) {
9051
+ try {
9052
+ if (token.attrType && displayProps.includes(token.property)) {
9053
+ if (!baseDisplayTokens.has(token.attrType)) {
9054
+ baseDisplayTokens.set(token.attrType, /* @__PURE__ */ new Set());
9055
+ }
9056
+ baseDisplayTokens.get(token.attrType).add(token.raw);
9057
+ }
9058
+ } catch (e) {
9059
+ errors.push({ type: "display_track", token: token?.raw, message: e.message });
9060
+ console.warn(`[SenangStart] Error tracking display properties: ${e.message}`);
9061
+ }
9062
+ }
9063
+ for (const token of baseTokens) {
9064
+ try {
9065
+ const rule = generateRule(token, config, false, interactIds);
9066
+ if (rule) {
9067
+ css += rule;
9068
+ } else {
9069
+ errors.push({ type: "rule_generation", token: token.raw, message: "No rule generated" });
9070
+ }
9071
+ } catch (e) {
9072
+ errors.push({ type: "rule_generation", token: token.raw, message: e.message });
9073
+ console.warn(`[SenangStart] Error generating base rule: ${e.message}`);
9074
+ }
9075
+ }
9076
+ for (const [bp, bpTokens] of Object.entries(breakpointTokens)) {
9077
+ try {
9078
+ if (bpTokens.length > 0) {
9079
+ const screenWidth = screens && screens[bp] ? screens[bp] : bp;
9080
+ css += `
9081
+ @media (min-width: ${screenWidth}) {
8711
9082
  `;
8712
- const processedResetSelectors = /* @__PURE__ */ new Set();
8713
- for (const bpToken of bpTokens) {
8714
- if (bpToken.attrType && displayProps.includes(bpToken.property)) {
8715
- if (baseDisplayTokens.has(bpToken.attrType)) {
8716
- const baseDisplays = baseDisplayTokens.get(bpToken.attrType);
8717
- if (baseDisplays.size > 0 && !baseDisplays.has(bpToken.raw) && !processedResetSelectors.has(bpToken.raw)) {
8718
- const selector = `[${bpToken.attrType}~="${bpToken.raw}"]`;
8719
- css += ` ${selector} { display: revert-layer; }
9083
+ const processedResetSelectors = /* @__PURE__ */ new Set();
9084
+ for (const bpToken of bpTokens) {
9085
+ try {
9086
+ if (bpToken.attrType && displayProps.includes(bpToken.property)) {
9087
+ if (baseDisplayTokens.has(bpToken.attrType)) {
9088
+ const baseDisplays = baseDisplayTokens.get(bpToken.attrType);
9089
+ if (baseDisplays.size > 0 && !baseDisplays.has(bpToken.raw) && !processedResetSelectors.has(bpToken.raw)) {
9090
+ const selector = `[${bpToken.attrType}~="${bpToken.raw}"]`;
9091
+ css += ` ${selector} { display: revert-layer; }
8720
9092
  `;
8721
- processedResetSelectors.add(bpToken.raw);
9093
+ processedResetSelectors.add(bpToken.raw);
9094
+ }
9095
+ }
9096
+ }
9097
+ } catch (e) {
9098
+ errors.push({ type: "display_reset", token: bpToken.raw, message: e.message });
9099
+ console.warn(`[SenangStart] Error generating display reset: ${e.message}`);
8722
9100
  }
8723
9101
  }
9102
+ for (const token of bpTokens) {
9103
+ try {
9104
+ const rule = generateRule(token, config, false, interactIds);
9105
+ if (rule) {
9106
+ css += " " + rule;
9107
+ } else {
9108
+ errors.push({ type: "responsive_rule", token: token.raw, message: "No rule generated" });
9109
+ }
9110
+ } catch (e) {
9111
+ errors.push({ type: "responsive_rule", token: token.raw, message: e.message });
9112
+ console.warn(`[SenangStart] Error generating responsive rule: ${e.message}`);
9113
+ }
9114
+ }
9115
+ css += "}\n";
8724
9116
  }
9117
+ } catch (e) {
9118
+ errors.push({ type: "breakpoint_generation", message: `Error generating breakpoint ${bp}: ${e.message}` });
9119
+ console.warn(`[SenangStart] Error generating breakpoint ${bp}: ${e.message}`);
8725
9120
  }
8726
- for (const token of bpTokens) {
8727
- css += " " + generateRule(token, config, false, interactIds);
8728
- }
8729
- css += "}\n";
8730
9121
  }
8731
- }
8732
- if (darkTokens.length > 0) {
8733
- const darkMode = config.darkMode || "media";
8734
- const darkSelector = getDarkModeSelector(config);
8735
- if (darkMode === "media") {
8736
- css += `
9122
+ if (darkTokens.length > 0) {
9123
+ try {
9124
+ const darkMode = config.darkMode || "media";
9125
+ const darkSelector = getDarkModeSelector(config);
9126
+ if (darkMode === "media") {
9127
+ css += `
8737
9128
  /* Dark Mode (prefers-color-scheme) */
8738
9129
  `;
8739
- css += `@media (prefers-color-scheme: dark) {
9130
+ css += `@media (prefers-color-scheme: dark) {
8740
9131
  `;
8741
- for (const token of darkTokens) {
8742
- css += " " + generateRule(token, config, true, interactIds);
8743
- }
8744
- css += "}\n";
8745
- } else {
8746
- css += `
9132
+ for (const token of darkTokens) {
9133
+ try {
9134
+ const rule = generateRule(token, config, true, interactIds);
9135
+ if (rule) {
9136
+ css += " " + rule;
9137
+ } else {
9138
+ errors.push({ type: "dark_rule", token: token.raw, message: "No rule generated" });
9139
+ }
9140
+ } catch (e) {
9141
+ errors.push({ type: "dark_rule", token: token.raw, message: e.message });
9142
+ console.warn(`[SenangStart] Error generating dark rule (media): ${e.message}`);
9143
+ }
9144
+ }
9145
+ css += "}\n";
9146
+ } else {
9147
+ css += `
8747
9148
  /* Dark Mode (${darkSelector}) */
8748
9149
  `;
8749
- for (const token of darkTokens) {
8750
- const baseRule = generateRule(token, config, true, interactIds);
8751
- const wrappedRule = baseRule.replace(/^(\[[^\]]+\])/, `${darkSelector} $1`);
8752
- css += wrappedRule;
9150
+ for (const token of darkTokens) {
9151
+ try {
9152
+ const baseRule = generateRule(token, config, true, interactIds);
9153
+ if (baseRule) {
9154
+ const wrappedRule = baseRule.replace(/^(\[[^\]]+\])/, `${darkSelector} $1`);
9155
+ css += wrappedRule;
9156
+ } else {
9157
+ errors.push({ type: "dark_rule", token: token.raw, message: "No rule generated" });
9158
+ }
9159
+ } catch (e) {
9160
+ errors.push({ type: "dark_rule", token: token.raw, message: e.message });
9161
+ console.warn(`[SenangStart] Error generating dark rule (selector): ${e.message}`);
9162
+ }
9163
+ }
9164
+ }
9165
+ } catch (e) {
9166
+ errors.push({ type: "dark_mode_generation", message: e.message });
9167
+ console.warn(`[SenangStart] Error generating dark mode rules: ${e.message}`);
8753
9168
  }
8754
9169
  }
9170
+ return { css, errors };
9171
+ } catch (e) {
9172
+ errors.push({ type: "fatal", message: e.message });
9173
+ console.error(`[SenangStart] Fatal error in generateCSSWithErrors: ${e.message}`);
9174
+ return { css: "", errors };
8755
9175
  }
9176
+ }
9177
+ function generateCSS(tokens, config) {
9178
+ const { css } = generateCSSWithErrors(tokens, config);
8756
9179
  return css;
8757
9180
  }
8758
9181
 
@@ -8953,6 +9376,8 @@ video {
8953
9376
  // Laptop
8954
9377
  "desk": "1280px",
8955
9378
  // Desktop
9379
+ "print": "print",
9380
+ // Print media query
8956
9381
  // Tailwind Compatibility
8957
9382
  "tw-sm": "640px",
8958
9383
  "tw-md": "768px",
@@ -8961,6 +9386,8 @@ video {
8961
9386
  "tw-2xl": "1536px"
8962
9387
  },
8963
9388
  // 7. COLORS: Palette Scales
9389
+ // Placeholder color for form inputs
9390
+ placeholder: "#9ca3af",
8964
9391
  colors: {
8965
9392
  // Base colors
8966
9393
  "white": "#FFFFFF",