@bookklik/senangstart-css 0.2.4 → 0.2.5

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 (128) hide show
  1. package/dist/senangstart-css.js +82 -6
  2. package/dist/senangstart-css.min.js +24 -20
  3. package/dist/senangstart-tw.js +200 -52
  4. package/dist/senangstart-tw.min.js +1 -1
  5. package/docs/guide/cdn.md +1 -1
  6. package/docs/ms/guide/cdn.md +1 -1
  7. package/docs/ms/reference/layout/position.md +4 -4
  8. package/docs/ms/reference/layout/z-index.md +8 -8
  9. package/docs/ms/reference/space/gap.md +1 -1
  10. package/docs/ms/reference/space/height.md +1 -1
  11. package/docs/ms/reference/space/margin.md +1 -1
  12. package/docs/ms/reference/space/padding.md +1 -1
  13. package/docs/ms/reference/space/scale-reference.md +46 -17
  14. package/docs/ms/reference/space/width.md +1 -1
  15. package/docs/ms/reference/space.md +1 -1
  16. package/docs/ms/reference/spacing.md +103 -21
  17. package/docs/ms/reference/visual/animation-fill.md +8 -8
  18. package/docs/ms/reference/visual/backdrop-blur.md +4 -4
  19. package/docs/ms/reference/visual/backdrop-brightness.md +8 -8
  20. package/docs/ms/reference/visual/backdrop-grayscale.md +6 -6
  21. package/docs/ms/reference/visual/backdrop-sepia.md +6 -6
  22. package/docs/ms/reference/visual/background-clip.md +2 -2
  23. package/docs/ms/reference/visual/background-image.md +4 -4
  24. package/docs/ms/reference/visual/filter-brightness.md +4 -4
  25. package/docs/ms/reference/visual/filter-contrast.md +4 -4
  26. package/docs/ms/reference/visual/filter-drop-shadow.md +6 -6
  27. package/docs/ms/reference/visual/filter-grayscale.md +4 -4
  28. package/docs/ms/reference/visual/filter-hue-rotate.md +4 -4
  29. package/docs/ms/reference/visual/filter-invert.md +2 -2
  30. package/docs/ms/reference/visual/filter-saturate.md +4 -4
  31. package/docs/ms/reference/visual/filter-sepia.md +4 -4
  32. package/docs/ms/reference/visual/font-family.md +2 -2
  33. package/docs/ms/reference/visual/gradient-from.md +57 -57
  34. package/docs/ms/reference/visual/gradient-to.md +57 -57
  35. package/docs/ms/reference/visual/gradient-via.md +54 -54
  36. package/docs/ms/reference/visual/letter-spacing.md +2 -2
  37. package/docs/ms/reference/visual/line-clamp.md +2 -2
  38. package/docs/ms/reference/visual/line-height.md +2 -2
  39. package/docs/ms/reference/visual/outline.md +2 -2
  40. package/docs/ms/reference/visual/ring-color.md +29 -0
  41. package/docs/ms/reference/visual/ring-offset.md +30 -0
  42. package/docs/ms/reference/visual/ring.md +62 -0
  43. package/docs/ms/reference/visual/stroke-width.md +6 -6
  44. package/docs/ms/reference/visual/stroke.md +4 -4
  45. package/docs/ms/reference/visual/text-indent.md +2 -2
  46. package/docs/ms/reference/visual/text-overflow.md +2 -2
  47. package/docs/ms/reference/visual/text-size.md +2 -2
  48. package/docs/ms/reference/visual/text-wrap.md +2 -2
  49. package/docs/ms/reference/visual/transform-backface.md +4 -4
  50. package/docs/ms/reference/visual/transform-perspective-origin.md +6 -6
  51. package/docs/ms/reference/visual/transform-perspective.md +6 -6
  52. package/docs/ms/reference/visual/transform-rotate-3d.md +6 -6
  53. package/docs/ms/reference/visual/transform-style.md +4 -4
  54. package/docs/ms/reference/visual/transform-translate-z.md +6 -6
  55. package/docs/ms/reference/visual/transform-translate.md +2 -2
  56. package/docs/ms/reference/visual/whitespace.md +2 -2
  57. package/docs/ms/reference/visual/word-break.md +2 -2
  58. package/docs/public/assets/senangstart-css.min.js +24 -20
  59. package/docs/public/llms.txt +1718 -0
  60. package/docs/reference/layout/position.md +4 -4
  61. package/docs/reference/layout/z-index.md +8 -8
  62. package/docs/reference/space/gap.md +1 -1
  63. package/docs/reference/space/height.md +1 -1
  64. package/docs/reference/space/margin.md +1 -1
  65. package/docs/reference/space/padding.md +1 -1
  66. package/docs/reference/space/scale-reference.md +46 -17
  67. package/docs/reference/space/width.md +1 -1
  68. package/docs/reference/space.md +1 -1
  69. package/docs/reference/spacing.md +103 -21
  70. package/docs/reference/visual/animation-fill.md +8 -8
  71. package/docs/reference/visual/backdrop-blur.md +4 -4
  72. package/docs/reference/visual/backdrop-brightness.md +8 -8
  73. package/docs/reference/visual/backdrop-grayscale.md +6 -6
  74. package/docs/reference/visual/backdrop-sepia.md +6 -6
  75. package/docs/reference/visual/background-clip.md +2 -2
  76. package/docs/reference/visual/background-image.md +4 -4
  77. package/docs/reference/visual/filter-brightness.md +4 -4
  78. package/docs/reference/visual/filter-contrast.md +4 -4
  79. package/docs/reference/visual/filter-drop-shadow.md +6 -6
  80. package/docs/reference/visual/filter-grayscale.md +4 -4
  81. package/docs/reference/visual/filter-hue-rotate.md +4 -4
  82. package/docs/reference/visual/filter-invert.md +2 -2
  83. package/docs/reference/visual/filter-saturate.md +4 -4
  84. package/docs/reference/visual/filter-sepia.md +4 -4
  85. package/docs/reference/visual/font-family.md +2 -2
  86. package/docs/reference/visual/gradient-from.md +57 -57
  87. package/docs/reference/visual/gradient-to.md +57 -57
  88. package/docs/reference/visual/gradient-via.md +54 -54
  89. package/docs/reference/visual/letter-spacing.md +2 -2
  90. package/docs/reference/visual/line-clamp.md +2 -2
  91. package/docs/reference/visual/line-height.md +2 -2
  92. package/docs/reference/visual/outline.md +2 -2
  93. package/docs/reference/visual/ring-color.md +29 -0
  94. package/docs/reference/visual/ring-offset.md +30 -0
  95. package/docs/reference/visual/ring.md +62 -0
  96. package/docs/reference/visual/stroke-width.md +6 -6
  97. package/docs/reference/visual/stroke.md +4 -4
  98. package/docs/reference/visual/text-indent.md +2 -2
  99. package/docs/reference/visual/text-overflow.md +2 -2
  100. package/docs/reference/visual/text-size.md +2 -2
  101. package/docs/reference/visual/text-wrap.md +2 -2
  102. package/docs/reference/visual/transform-backface.md +4 -4
  103. package/docs/reference/visual/transform-perspective-origin.md +6 -6
  104. package/docs/reference/visual/transform-perspective.md +6 -6
  105. package/docs/reference/visual/transform-rotate-3d.md +6 -6
  106. package/docs/reference/visual/transform-style.md +4 -4
  107. package/docs/reference/visual/transform-translate-z.md +6 -6
  108. package/docs/reference/visual/transform-translate.md +2 -2
  109. package/docs/reference/visual/whitespace.md +2 -2
  110. package/docs/reference/visual/word-break.md +2 -2
  111. package/package.json +4 -2
  112. package/scripts/build-dist.js +2 -2
  113. package/scripts/bundle-jit.js +3 -3
  114. package/scripts/convert-tailwind.js +157 -2
  115. package/scripts/generate-llms-txt.js +264 -0
  116. package/src/cdn/{jit.js → senangstart-engine.js} +81 -11
  117. package/src/cdn/tw-conversion-engine.js +203 -68
  118. package/src/compiler/generators/css.js +27 -0
  119. package/src/config/defaults.js +37 -11
  120. package/src/core/constants.js +37 -8
  121. package/src/definitions/space.js +46 -5
  122. package/src/definitions/visual-borders.js +80 -1
  123. package/src/definitions/visual-transform3d.js +16 -16
  124. package/src/definitions/visual-transforms.js +1 -1
  125. package/src/definitions/visual-transitions.js +4 -4
  126. package/src/definitions/visual-typography.js +6 -6
  127. package/src/definitions/visual.js +4 -4
  128. package/tests/unit/compiler/generators/css.test.js +192 -0
@@ -318,7 +318,21 @@ const visualKeywordMappings = {
318
318
 
319
319
  // Appearance
320
320
  'appearance-none': 'appearance:none',
321
- 'appearance-auto': 'appearance:auto'
321
+ 'appearance-auto': 'appearance:auto',
322
+
323
+ // 3D Transforms
324
+ 'perspective': 'perspective',
325
+ 'perspective-origin': 'perspective-origin',
326
+ 'transform-style': 'transform-style',
327
+ 'backface-visibility': 'backface',
328
+ 'mask': 'mask',
329
+ 'mask-image': 'mask-image',
330
+ 'mask-mode': 'mask-mode',
331
+ 'mask-origin': 'mask-origin',
332
+ 'mask-position': 'mask-position',
333
+ 'mask-repeat': 'mask-repeat',
334
+ 'mask-size': 'mask-size',
335
+ 'mask-type': 'mask-type'
322
336
  };
323
337
 
324
338
  // ======================
@@ -606,7 +620,148 @@ function convertClass(twClass, options = {}) {
606
620
  if (toMatch) {
607
621
  return { category: 'visual', value: prefix + "to:" + toMatch[1] };
608
622
  }
609
-
623
+
624
+ // ======================
625
+ // 3D TRANSFORMS
626
+ // ======================
627
+
628
+ // Perspective
629
+ const perspectiveMatch = baseClass.match(/^perspective(?:-(.+))?$/);
630
+ if (perspectiveMatch) {
631
+ const val = perspectiveMatch[1] || 'normal';
632
+ return { category: 'visual', value: prefix + "perspective:" + val };
633
+ }
634
+
635
+ // Perspective origin
636
+ const perspectiveOriginMatch = baseClass.match(/^perspective-origin(?:-(.+))?$/);
637
+ if (perspectiveOriginMatch) {
638
+ const val = perspectiveOriginMatch[1] || 'center';
639
+ return { category: 'visual', value: prefix + "perspective-origin:" + val };
640
+ }
641
+
642
+ // Rotate X/Y/Z (3D rotation)
643
+ const rotateAxisMatch = baseClass.match(/^rotate-([xyz])(?:-(.+))?$/);
644
+ if (rotateAxisMatch) {
645
+ const axis = rotateAxisMatch[1].toLowerCase();
646
+ const val = rotateAxisMatch[2] || '0';
647
+ return { category: 'visual', value: prefix + `rotate-${axis}:${val}` };
648
+ }
649
+
650
+ // Rotate (2D)
651
+ const rotateMatch = baseClass.match(/^rotate(?:-(.+))?$/);
652
+ if (rotateMatch && !rotateAxisMatch) {
653
+ const val = rotateMatch[1] || '0';
654
+ return { category: 'visual', value: prefix + `rotate:${val}` };
655
+ }
656
+
657
+ // Scale X/Y
658
+ const scaleAxisMatch = baseClass.match(/^scale-([xy])(?:-(.+))?$/);
659
+ if (scaleAxisMatch) {
660
+ const axis = scaleAxisMatch[1].toLowerCase();
661
+ const val = scaleAxisMatch[2] || '100';
662
+ return { category: 'visual', value: prefix + `scale-${axis}:${val}` };
663
+ }
664
+
665
+ // Scale (uniform)
666
+ const scaleMatch = baseClass.match(/^scale(?:-(.+))?$/);
667
+ if (scaleMatch && !scaleAxisMatch) {
668
+ const val = scaleMatch[1] || '100';
669
+ return { category: 'visual', value: prefix + `scale:${val}` };
670
+ }
671
+
672
+ // Skew X/Y
673
+ const skewAxisMatch = baseClass.match(/^skew-([xy])(?:-(.+))?$/);
674
+ if (skewAxisMatch) {
675
+ const axis = skewAxisMatch[1].toLowerCase();
676
+ const val = skewAxisMatch[2] || '0';
677
+ return { category: 'visual', value: prefix + `skew-${axis}:${val}` };
678
+ }
679
+
680
+ // Translate X/Y/Z
681
+ const translateAxisMatch = baseClass.match(/^translate-([xyz])(?:-(.+))?$/);
682
+ if (translateAxisMatch) {
683
+ const axis = translateAxisMatch[1].toLowerCase();
684
+ const val = translateAxisMatch[2] || '0';
685
+ return { category: 'visual', value: prefix + `translate-${axis}:${val}` };
686
+ }
687
+
688
+ // Transform style
689
+ const transformStyleMatch = baseClass.match(/^transform-style(?:-(.+))?$/);
690
+ if (transformStyleMatch) {
691
+ const val = transformStyleMatch[1] || 'flat';
692
+ return { category: 'visual', value: prefix + "transform-style:" + val };
693
+ }
694
+
695
+ // Backface visibility
696
+ const backfaceMatch = baseClass.match(/^backface(?:-(.+))?$/);
697
+ if (backfaceMatch) {
698
+ const val = backfaceMatch[1] || 'hidden';
699
+ return { category: 'visual', value: prefix + "backface:" + val };
700
+ }
701
+
702
+ // Transform origin
703
+ const originMatch = baseClass.match(/^origin(?:-(.+))?$/);
704
+ if (originMatch) {
705
+ const val = originMatch[1] || 'center';
706
+ return { category: 'visual', value: prefix + "origin:" + val };
707
+ }
708
+
709
+ // Mask
710
+ const maskMatch = baseClass.match(/^mask(?:-(.+))?$/);
711
+ if (maskMatch) {
712
+ const val = maskMatch[1] || 'none';
713
+ return { category: 'visual', value: prefix + "mask:" + val };
714
+ }
715
+
716
+ // Mask image
717
+ const maskImageMatch = baseClass.match(/^mask-image(?:-(.+))?$/);
718
+ if (maskImageMatch) {
719
+ const val = maskImageMatch[1] || 'none';
720
+ return { category: 'visual', value: prefix + "mask-image:" + val };
721
+ }
722
+
723
+ // Mask mode
724
+ const maskModeMatch = baseClass.match(/^mask-mode(?:-(.+))?$/);
725
+ if (maskModeMatch) {
726
+ const val = maskModeMatch[1] || 'match';
727
+ return { category: 'visual', value: prefix + "mask-mode:" + val };
728
+ }
729
+
730
+ // Mask origin
731
+ const maskOriginMatch = baseClass.match(/^mask-origin(?:-(.+))?$/);
732
+ if (maskOriginMatch) {
733
+ const val = maskOriginMatch[1] || 'center';
734
+ return { category: 'visual', value: prefix + "mask-origin:" + val };
735
+ }
736
+
737
+ // Mask position
738
+ const maskPositionMatch = baseClass.match(/^mask-position(?:-(.+))?$/);
739
+ if (maskPositionMatch) {
740
+ const val = maskPositionMatch[1] || 'center';
741
+ return { category: 'visual', value: prefix + "mask-position:" + val };
742
+ }
743
+
744
+ // Mask repeat
745
+ const maskRepeatMatch = baseClass.match(/^mask-repeat(?:-(.+))?$/);
746
+ if (maskRepeatMatch) {
747
+ const val = maskRepeatMatch[1] || 'repeat';
748
+ return { category: 'visual', value: prefix + "mask-repeat:" + val };
749
+ }
750
+
751
+ // Mask size
752
+ const maskSizeMatch = baseClass.match(/^mask-size(?:-(.+))?$/);
753
+ if (maskSizeMatch) {
754
+ const val = maskSizeMatch[1] || 'auto';
755
+ return { category: 'visual', value: prefix + "mask-size:" + val };
756
+ }
757
+
758
+ // Mask type
759
+ const maskTypeMatch = baseClass.match(/^mask-type(?:-(.+))?$/);
760
+ if (maskTypeMatch) {
761
+ const val = maskTypeMatch[1] || 'luminance';
762
+ return { category: 'visual', value: prefix + "mask-type:" + val };
763
+ }
764
+
610
765
  return null;
611
766
  }
612
767
 
@@ -0,0 +1,264 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import { fileURLToPath } from 'node:url';
5
+ import { pathToFileURL } from 'node:url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+
11
+
12
+ const PACKAGE_JSON_PATH = path.resolve(__dirname, '../package.json');
13
+ const DEFINITIONS_DIR = path.resolve(__dirname, '../src/definitions');
14
+ const OUTPUT_PATH = path.resolve(__dirname, '../docs/public/llms.txt');
15
+
16
+ // Load defaults from package.json
17
+ let defaults = {
18
+ name: 'SenangStart CSS',
19
+ description: '',
20
+ license: 'MIT',
21
+ homepage: ''
22
+ };
23
+
24
+ try {
25
+ if (fs.existsSync(PACKAGE_JSON_PATH)) {
26
+ const pkg = JSON.parse(fs.readFileSync(PACKAGE_JSON_PATH, 'utf-8'));
27
+ if (pkg.name) defaults.name = pkg.name;
28
+ if (pkg.description) defaults.description = pkg.description;
29
+ if (pkg.license) defaults.license = pkg.license;
30
+ if (pkg.homepage) defaults.homepage = pkg.homepage;
31
+ }
32
+ } catch (e) {
33
+ console.warn('Warning: Could not read package.json for defaults.');
34
+ }
35
+
36
+
37
+
38
+ function formatDefinition(key, def) {
39
+ let output = `## ${def.title || def.name || key}\n`;
40
+ if (def.description) {
41
+ output += `> ${def.description}\n`;
42
+ }
43
+
44
+ // Add Syntax/Usage if available
45
+ if (def.syntax) {
46
+ output += `\n**Syntax:** \`${def.syntax}\`\n`;
47
+ }
48
+
49
+ if (def.values && Array.isArray(def.values)) {
50
+ output += `\n`;
51
+ def.values.forEach(val => {
52
+ let valDesc = val.description || '';
53
+ // If CSS is present, maybe show it, or keep it high level?
54
+ // Tailwind example had: `bg-none`: Removes background image (`background-image: none;`).
55
+ // Our values are like { value: 'none', css: '...', description: '...' }
56
+ // The utility class is constructed via syntax, usually properties like `text:left` or `bg:primary`.
57
+ // The 'value' field is just the suffix/argument.
58
+
59
+ // Let's try to infer the full utility format if possible, or just list the value.
60
+ // If syntax is visual="text:[alignment]", and value is 'left', then utility is text:left.
61
+
62
+ let displayValue = val.value;
63
+ // Attempt to contextualize the value based on syntax
64
+ // e.g. syntax="visual="text:[alignment]"", value="left" -> text:left
65
+ // This might be complex to regex universally, but let's try a simple approach if possible.
66
+ // For now, just listing the value is safe.
67
+
68
+ let line = `* \`${displayValue}\``;
69
+ if (valDesc) line += `: ${valDesc}`;
70
+ if (val.css && val.css.length < 50) line += ` (\`${val.css}\`)`; // only show if short
71
+
72
+ output += `${line}\n`;
73
+ });
74
+ }
75
+ output += `\n`;
76
+ return output;
77
+ }
78
+
79
+ async function loadDefinitions() {
80
+ const definitions = new Map();
81
+ if (!fs.existsSync(DEFINITIONS_DIR)) return [];
82
+
83
+ const files = fs.readdirSync(DEFINITIONS_DIR).filter(f => f.endsWith('.js'));
84
+
85
+ for (const file of files) {
86
+ try {
87
+ const filePath = path.join(DEFINITIONS_DIR, file);
88
+ const fileUrl = pathToFileURL(filePath).href;
89
+ const module = await import(fileUrl);
90
+
91
+ // Iterate over exports, skipping default if it's just a collection of others
92
+ for (const [key, value] of Object.entries(module)) {
93
+ if (key === 'default') continue;
94
+ // Check if it looks like a definition (has name/property/values)
95
+ if (value && value.name && value.property && Array.isArray(value.values)) {
96
+ // Use definition name as key to prevent duplicates from re-exports
97
+ // e.g. layout.js re-exports definition from layout-flex.js
98
+ const defName = value.name;
99
+ if (!definitions.has(defName)) {
100
+ definitions.set(defName, { key, ...value });
101
+ }
102
+ }
103
+ }
104
+ } catch (e) {
105
+ console.error(`Error loading definition ${file}:`, e);
106
+ }
107
+ }
108
+ return Array.from(definitions.values());
109
+ }
110
+
111
+ function getGuideContent() {
112
+ return `
113
+ # Framework Overview
114
+
115
+ SenangStart CSS is a utility-first framework that uses **Natural Adjectives** instead of abstract numbers.
116
+
117
+ ## Core Philosophy
118
+ - **Natural Scale**: Sizes map to physical mental models (e.g., \`tiny\` = pebble/4px, \`medium\` = smartphone/16px, \`giant\` = door/64px).
119
+ - **Intent-First**: Describe *what* you want ("give it air" -> scale up), not pixels.
120
+ - **Tri-Attribute Syntax**: Separation of concerns into three attributes:
121
+ 1. \`layout\`: Structure & position (flex, grid, block, sticky).
122
+ 2. \`space\`: Sizing, padding, margin, gap.
123
+ 3. \`visual\`: Colors, typography, borders, shadows, effects.
124
+
125
+ ## Syntax Reference
126
+
127
+ ### 1. Layout Attribute
128
+ Controls internal flow and external positioning.
129
+ - **Flex**: \`layout="flex col center"\` (Flexbox, column direction, centered).
130
+ - **Grid**: \`layout="grid"\`
131
+ - **Position**: \`layout="absolute z:top"\`
132
+
133
+ ### 2. Space Attribute
134
+ Controls dimensions and spacing using the Natural Scale.
135
+ - **Syntax**: \`[breakpoint]:[property]:[scale]\`
136
+ - **Properties**: \`p\` (padding), \`m\` (margin), \`g\` (gap), \`w\` (width), \`h\` (height).
137
+ - **Values**:
138
+ - \`none\` (0px)
139
+ - \`thin\` (1px), \`regular\` (2px), \`thick\` (3px)
140
+ - \`tiny\` (4px), \`tiny-2x\` (6px)
141
+ - \`small\` (8px), \`small-2x\` (10px), \`small-3x\` (12px), \`small-4x\` (14px)
142
+ - \`medium\` (16px), \`medium-2x\` (20px), \`medium-3x\` (24px), \`medium-4x\` (28px)
143
+ - \`large\` (32px), \`large-2x\` (36px), \`large-3x\` (40px), \`large-4x\` (44px)
144
+ - \`big\` (48px), \`big-2x\` (56px), \`big-3x\` (64px), \`big-4x\` (80px)
145
+ - \`giant\` (96px), \`giant-2x\` (112px), \`giant-3x\` (128px), \`giant-4x\` (144px)
146
+ - \`vast\` (160px), \`vast-2x\` (176px), \`vast-3x\` (192px), \`vast-4x\` (208px)
147
+ - \`vast-5x\` (224px), \`vast-6x\` (240px), \`vast-7x\` (256px), \`vast-8x\` (288px)
148
+ - \`vast-9x\` (320px), \`vast-10x\` (384px)
149
+ - **Arbitrary**: \`space="w:[350px]"\`
150
+
151
+ ### 3. Visual Attribute
152
+ Controls appearance.
153
+ - **Colors**: \`bg:primary\`, \`text:white\`, \`border:grey\`.
154
+ - **Typography**: \`font:bold\`, \`text-size:big\`.
155
+ - **Effects**: \`rounded:medium\`, \`shadow:big\`, \`opacity:[0.5]\`.
156
+
157
+ ## Modifiers
158
+
159
+ ### Responsive Prefixes
160
+ Mobile-first breakpoints:
161
+ - (default): 0px+
162
+ - \`mob:\`: 480px+ ("Large Mobile")
163
+ - \`tab:\`: 768px+ ("Tablet")
164
+ - \`lap:\`: 1024px+ ("Laptop")
165
+ - \`desk:\`: 1280px+ ("Desktop")
166
+
167
+ Example: \`space="p:small tab:p:medium lap:p:big"\`
168
+
169
+ ### State Prefixes
170
+ - \`hover:\`: \`visual="bg:primary hover:bg:primary-dark"\`
171
+ - \`focus:\`: \`visual="border:grey focus:border:brand"\`
172
+ - \`active:\`, \`disabled:\`, \`group-hover:\`
173
+ - \`dark:\`: \`visual="bg:white dark:bg:slate-900"\`
174
+
175
+ ## Configuration
176
+ Use \`senangstart.config.js\` to override defaults.
177
+ \`\`\`js
178
+ export default {
179
+ theme: {
180
+ colors: { brand: '#8B5CF6' },
181
+ spacing: { huge: '256px' }
182
+ }
183
+ }
184
+ \`\`\`
185
+ `.trim();
186
+ }
187
+
188
+ async function generate() {
189
+ console.log('Generating docs/public/llms.txt with references...\n');
190
+
191
+ const name = defaults.name;
192
+ const description = defaults.description;
193
+ const domain = defaults.homepage || 'https://bookklik-technologies.github.io/senangstart-css';
194
+ const docsUrls = `${domain}/guide`;
195
+ const apiEndpoints = '';
196
+ const repo = 'https://github.com/bookklik-technologies/senangstart-css';
197
+ const email = '';
198
+ const license = defaults.license;
199
+
200
+ let content = `# ${name}\n`;
201
+ content += `> ${description}\n\n`;
202
+
203
+ if (docsUrls) {
204
+ content += `## Docs\n`;
205
+ docsUrls.split(',').map(url => url.trim()).forEach(url => {
206
+ if (url) content += `- [Documentation](${url})\n`;
207
+ });
208
+ content += `\n`;
209
+ }
210
+
211
+ if (apiEndpoints) {
212
+ content += `## API\n`;
213
+ apiEndpoints.split(',').map(url => url.trim()).forEach(url => {
214
+ if (url) content += `- [API Endpoint](${url})\n`;
215
+ });
216
+ content += `\n`;
217
+ }
218
+
219
+ if (repo) {
220
+ content += `## Source\n`;
221
+ content += `- [Repository](${repo})\n\n`;
222
+ }
223
+
224
+ if (email) {
225
+ content += `## Contact\n`;
226
+ content += `- [Email](mailto:${email})\n`;
227
+ }
228
+
229
+ // Append Guide Content
230
+ console.log('Adding curated guide content...');
231
+ const guidesContent = getGuideContent();
232
+ if (guidesContent) {
233
+ content += `\n# Documentation Guides\n\n${guidesContent}\n`;
234
+ }
235
+
236
+ // Load and Append Definitions
237
+ const definitions = await loadDefinitions();
238
+ if (definitions.length > 0) {
239
+ content += `\n# Utility Definitions\n\n`;
240
+ // Sort by name or category?
241
+ definitions.sort((a, b) => (a.name || a.key).localeCompare(b.name || b.key));
242
+
243
+ for (const def of definitions) {
244
+ content += formatDefinition(def.key, def);
245
+ }
246
+ }
247
+
248
+ // Ensure directory exists
249
+ const dir = path.dirname(OUTPUT_PATH);
250
+ if (!fs.existsSync(dir)) {
251
+ fs.mkdirSync(dir, { recursive: true });
252
+ }
253
+
254
+ fs.writeFileSync(OUTPUT_PATH, content, 'utf-8');
255
+ console.log(`\nSuccessfully generated ${OUTPUT_PATH}`);
256
+ console.log(`Included guide content and ${definitions.length} utility definitions.`);
257
+ // console.log('-----------------------------------');
258
+ // console.log(content.substring(0, 500) + '...');
259
+ // console.log('-----------------------------------');
260
+
261
+
262
+ }
263
+
264
+ generate();
@@ -24,16 +24,42 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
24
24
  const defaultConfig = {
25
25
  theme: {
26
26
  spacing: {
27
- 'none': '0px',
28
- 'thin': '1px',
29
- 'regular': '2px',
30
- 'thick': '3px',
31
- 'tiny': '4px',
32
- 'small': '8px',
33
- 'medium': '16px',
34
- 'big': '32px',
35
- 'giant': '64px',
36
- 'vast': '128px'
27
+ 'none': '0px', // No space
28
+ 'thin': '1px', // Hairline (for borders)
29
+ 'regular': '2px', // Standard border
30
+ 'thick': '3px', // Bold border
31
+ 'tiny': '4px', // Small offsets
32
+ 'tiny-2x': '6px', // Tiny multiplied
33
+ 'small': '8px',
34
+ 'small-2x': '10px',
35
+ 'small-3x': '12px',
36
+ 'small-4x': '14px',
37
+ 'medium': '16px',
38
+ 'medium-2x': '20px',
39
+ 'medium-3x': '24px',
40
+ 'medium-4x': '28px',
41
+ 'large': '32px',
42
+ 'large-2x': '36px',
43
+ 'large-3x': '40px',
44
+ 'large-4x': '44px',
45
+ 'big': '48px',
46
+ 'big-2x': '56px',
47
+ 'big-3x': '64px',
48
+ 'big-4x': '80px',
49
+ 'giant': '96px',
50
+ 'giant-2x': '112px',
51
+ 'giant-3x': '128px',
52
+ 'giant-4x': '144px',
53
+ 'vast': '160px',
54
+ 'vast-2x': '176px',
55
+ 'vast-3x': '192px',
56
+ 'vast-4x': '208px',
57
+ 'vast-5x': '224px',
58
+ 'vast-6x': '240px',
59
+ 'vast-7x': '256px',
60
+ 'vast-8x': '288px',
61
+ 'vast-9x': '320px',
62
+ 'vast-10x': '384px'
37
63
  },
38
64
  radius: {
39
65
  'none': '0px',
@@ -205,6 +231,15 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
205
231
  'mid': '50',
206
232
  'high': '100',
207
233
  'top': '9999'
234
+ },
235
+ ring: {
236
+ 'none': '0px',
237
+ 'thin': '1px',
238
+ 'regular': '2px',
239
+ 'thick': '3px',
240
+ 'small': '4px',
241
+ 'medium': '6px',
242
+ 'big': '8px'
208
243
  }
209
244
  },
210
245
  // Dark mode configuration
@@ -232,7 +267,8 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
232
267
  fontWeight: { type: 'object' },
233
268
  screens: { type: 'object' },
234
269
  colors: { type: 'object' },
235
- zIndex: { type: 'object' }
270
+ zIndex: { type: 'object' },
271
+ ring: { type: 'object' }
236
272
  }
237
273
  },
238
274
  darkMode: { type: 'string', enum: ['media', 'selector'] },
@@ -358,6 +394,17 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
358
394
  css += ` --z-${key}: ${value};\n`;
359
395
  }
360
396
 
397
+ // Ring (focus ring utilities)
398
+ if (theme.ring) {
399
+ for (const [key, value] of Object.entries(theme.ring)) {
400
+ css += ` --ring-${key}: ${value};\n`;
401
+ }
402
+ }
403
+ // Ring default values
404
+ css += ` --ring-color: var(--c-primary);\n`;
405
+ css += ` --ring-offset: 0px;\n`;
406
+ css += ` --ring-offset-color: #fff;\n`;
407
+
361
408
  // ============================================
362
409
  // TAILWIND SCALE COMPATIBILITY (tw-* prefix)
363
410
  // ============================================
@@ -1894,6 +1941,29 @@ img, video {
1894
1941
  return `outline-offset: ${cssValue};`;
1895
1942
  },
1896
1943
 
1944
+ // ============================================
1945
+ // RING UTILITIES (Focus Ring)
1946
+ // ============================================
1947
+ 'ring': () => {
1948
+ if (value === 'none') {
1949
+ return `box-shadow: 0 0 0 0 transparent;`;
1950
+ }
1951
+ const cssValue = isArbitrary ? value : `var(--ring-${value})`;
1952
+ return `box-shadow: 0 0 0 var(--ring-offset) var(--ring-offset-color), 0 0 0 calc(${cssValue} + var(--ring-offset)) var(--ring-color);`;
1953
+ },
1954
+ 'ring-color': () => {
1955
+ const cssValue = isArbitrary ? value : `var(--c-${value})`;
1956
+ return `--ring-color: ${cssValue};`;
1957
+ },
1958
+ 'ring-offset': () => {
1959
+ const cssValue = isArbitrary ? value : `${value}px`;
1960
+ return `--ring-offset: ${cssValue};`;
1961
+ },
1962
+ 'ring-offset-color': () => {
1963
+ const cssValue = isArbitrary ? value : `var(--c-${value})`;
1964
+ return `--ring-offset-color: ${cssValue};`;
1965
+ },
1966
+
1897
1967
  // ============================================
1898
1968
  // SVG UTILITIES
1899
1969
  // ============================================