@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.
- package/.agent/skills/add-utility/SKILL.md +65 -0
- package/.agent/workflows/add-utility.md +2 -0
- package/.agent/workflows/build.md +2 -0
- package/.agent/workflows/dev.md +2 -0
- package/AGENTS.md +30 -0
- package/dist/senangstart-css.js +607 -180
- package/dist/senangstart-css.min.js +234 -195
- package/dist/senangstart-tw.js +274 -8
- package/dist/senangstart-tw.min.js +1 -1
- package/docs/SYNTAX-REFERENCE.md +1731 -1590
- package/docs/guide/preflight.md +20 -1
- package/docs/ms/guide/preflight.md +19 -0
- package/docs/ms/reference/breakpoints.md +14 -0
- package/docs/ms/reference/visual/border-radius.md +50 -10
- package/docs/ms/reference/visual/contain.md +57 -0
- package/docs/ms/reference/visual/content-visibility.md +53 -0
- package/docs/ms/reference/visual/placeholder-color.md +92 -0
- package/docs/ms/reference/visual/ring-color.md +2 -2
- package/docs/ms/reference/visual/ring-offset.md +3 -3
- package/docs/ms/reference/visual/ring.md +5 -5
- package/docs/ms/reference/visual/writing-mode.md +53 -0
- package/docs/ms/reference/visual.md +6 -0
- package/docs/public/assets/senangstart-css.min.js +234 -195
- package/docs/public/llms.txt +45 -12
- package/docs/reference/breakpoints.md +14 -0
- package/docs/reference/visual/border-radius.md +50 -10
- package/docs/reference/visual/contain.md +57 -0
- package/docs/reference/visual/content-visibility.md +53 -0
- package/docs/reference/visual/placeholder-color.md +92 -0
- package/docs/reference/visual/ring-color.md +2 -2
- package/docs/reference/visual/ring-offset.md +3 -3
- package/docs/reference/visual/ring.md +5 -5
- package/docs/reference/visual/writing-mode.md +53 -0
- package/docs/reference/visual.md +7 -0
- package/docs/syntax-reference.json +2185 -2009
- package/package.json +1 -1
- package/scripts/convert-tailwind.js +300 -26
- package/scripts/generate-docs.js +403 -403
- package/src/cdn/senangstart-engine.js +5 -5
- package/src/cdn/tw-conversion-engine.js +305 -8
- package/src/cli/commands/build.js +51 -13
- package/src/cli/commands/dev.js +157 -93
- package/src/compiler/generators/css.js +467 -208
- package/src/compiler/generators/preflight.js +26 -13
- package/src/compiler/generators/typescript.js +3 -1
- package/src/compiler/index.js +27 -3
- package/src/compiler/parser.js +13 -6
- package/src/compiler/tokenizer.js +25 -23
- package/src/config/defaults.js +3 -0
- package/src/core/tokenizer-core.js +46 -19
- package/src/definitions/index.js +4 -1
- package/src/definitions/visual-borders.js +10 -10
- package/src/definitions/visual-performance.js +126 -0
- package/src/definitions/visual.js +25 -9
- package/src/utils/common.js +456 -27
- package/src/utils/node-io.js +82 -0
- package/tests/integration/dev-recovery.test.js +231 -0
- package/tests/unit/cli/memory-limits.test.js +169 -0
- package/tests/unit/compiler/css-generation-error-handling.test.js +204 -0
- package/tests/unit/compiler/generators/css-errors.test.js +102 -0
- package/tests/unit/compiler/generators/css.test.js +102 -5
- package/tests/unit/convert-tailwind.test.js +518 -431
- package/tests/unit/utils/common.test.js +376 -26
- package/tests/unit/utils/file-timeout.test.js +154 -0
- package/tests/unit/utils/theme-validation.test.js +181 -0
- package/tests/unit/compiler/generators/css.coverage.test.js +0 -833
- package/tests/unit/convert-tailwind.cli.test.js +0 -95
- package/tests/unit/security.test.js +0 -206
- /package/tests/unit/{convert-tailwind.coverage.test.js → convert-tailwind-edgecases.test.js} +0 -0
|
@@ -71,10 +71,13 @@ hr {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/*
|
|
74
|
-
*
|
|
74
|
+
* Set default placeholder color to a semi-transparent gray
|
|
75
|
+
* Uses theme variable for customization with fallback
|
|
75
76
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
input::placeholder,
|
|
78
|
+
textarea::placeholder {
|
|
79
|
+
opacity: 1; /* 1 */
|
|
80
|
+
color: var(--placeholder-color, #9ca3af); /* 2 */
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
/*
|
|
@@ -217,10 +220,17 @@ input:where([type='submit']) {
|
|
|
217
220
|
}
|
|
218
221
|
|
|
219
222
|
/*
|
|
220
|
-
* Add the correct
|
|
223
|
+
* Add the correct text decoration in Chrome, Edge, and Safari
|
|
221
224
|
*/
|
|
222
|
-
|
|
223
|
-
|
|
225
|
+
abbr:where([title]) {
|
|
226
|
+
text-decoration: underline dotted;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/*
|
|
230
|
+
* Make sure links don't get underlined in headings
|
|
231
|
+
*/
|
|
232
|
+
h1, h2, h3, h4, h5, h6 {
|
|
233
|
+
text-decoration: none;
|
|
224
234
|
}
|
|
225
235
|
|
|
226
236
|
/*
|
|
@@ -292,14 +302,17 @@ legend {
|
|
|
292
302
|
}
|
|
293
303
|
|
|
294
304
|
/*
|
|
295
|
-
*
|
|
305
|
+
* 1. Use a more sensible default box-sizing strategy
|
|
296
306
|
*/
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
padding:
|
|
307
|
+
*,
|
|
308
|
+
::before,
|
|
309
|
+
::after {
|
|
310
|
+
box-sizing: border-box;
|
|
311
|
+
/* Support safe-area-inset for modern devices with notches */
|
|
312
|
+
padding-top: env(safe-area-inset-top);
|
|
313
|
+
padding-right: env(safe-area-inset-right);
|
|
314
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
315
|
+
padding-left: env(safe-area-inset-left);
|
|
303
316
|
}
|
|
304
317
|
|
|
305
318
|
/*
|
|
@@ -19,7 +19,9 @@ export function generateTypeScript(config) {
|
|
|
19
19
|
|
|
20
20
|
// Generate radius unions
|
|
21
21
|
const radiusKeys = Object.keys(theme.radius);
|
|
22
|
-
const
|
|
22
|
+
const directions = ['t', 'b', 'l', 'r', 'tl', 'tr', 'bl', 'br'];
|
|
23
|
+
const roundedUnions = radiusKeys.map(k => `'rounded:${k}'`).join(' | ') +
|
|
24
|
+
' | ' + directions.flatMap(d => radiusKeys.map(k => `'rounded-${d}:${k}'`)).join(' | ');
|
|
23
25
|
|
|
24
26
|
// Generate shadow unions
|
|
25
27
|
const shadowKeys = Object.keys(theme.shadow);
|
package/src/compiler/index.js
CHANGED
|
@@ -18,11 +18,24 @@ import { generateTypeScript } from './generators/typescript.js';
|
|
|
18
18
|
export function compileSource(content, config) {
|
|
19
19
|
const parsed = parseSource(content);
|
|
20
20
|
const tokens = tokenizeAll(parsed);
|
|
21
|
+
|
|
22
|
+
// Check for invalid tokens and log warnings
|
|
23
|
+
const invalidTokens = tokens.filter(token => token.error);
|
|
24
|
+
if (invalidTokens.length > 0) {
|
|
25
|
+
if (typeof console !== 'undefined') {
|
|
26
|
+
console.warn(`\n${invalidTokens.length} error(s) found in source:`);
|
|
27
|
+
for (const token of invalidTokens) {
|
|
28
|
+
console.warn(` • ${token.raw} (${token.attrType}): ${token.error}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
21
33
|
const css = generateCSS(tokens, config);
|
|
22
34
|
|
|
23
35
|
return {
|
|
24
36
|
tokens,
|
|
25
37
|
css,
|
|
38
|
+
errors: invalidTokens.length > 0 ? invalidTokens : null,
|
|
26
39
|
minifiedCSS: config.output?.minify ? minifyCSS(css) : null
|
|
27
40
|
};
|
|
28
41
|
}
|
|
@@ -36,14 +49,25 @@ export function compileSource(content, config) {
|
|
|
36
49
|
export function compileMultiple(files, config) {
|
|
37
50
|
const parsed = parseMultipleSources(files);
|
|
38
51
|
const tokens = tokenizeAll(parsed);
|
|
52
|
+
|
|
53
|
+
// Check for invalid tokens and log warnings
|
|
54
|
+
const invalidTokens = tokens.filter(token => token.error);
|
|
55
|
+
if (invalidTokens.length > 0) {
|
|
56
|
+
if (typeof console !== 'undefined') {
|
|
57
|
+
console.warn(`\n${invalidTokens.length} error(s) found in source:`);
|
|
58
|
+
for (const token of invalidTokens) {
|
|
59
|
+
console.warn(` • ${token.raw} (${token.attrType}): ${token.error}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
39
64
|
const css = generateCSS(tokens, config);
|
|
40
65
|
|
|
41
66
|
return {
|
|
42
67
|
tokens,
|
|
43
68
|
css,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
typescript: generateTypeScript(config)
|
|
69
|
+
errors: invalidTokens.length > 0 ? invalidTokens : null,
|
|
70
|
+
minifiedCSS: config.output?.minify ? minifyCSS(css) : null
|
|
47
71
|
};
|
|
48
72
|
}
|
|
49
73
|
|
package/src/compiler/parser.js
CHANGED
|
@@ -18,11 +18,11 @@ const ATTRIBUTE_PATTERNS = {
|
|
|
18
18
|
*/
|
|
19
19
|
function createAttributePatterns() {
|
|
20
20
|
return {
|
|
21
|
-
layout: /layout\s*=\s*["'
|
|
22
|
-
space: /space\s*=\s*["'
|
|
23
|
-
visual: /visual\s*=\s*["'
|
|
24
|
-
interact: /interact\s*=\s*["'
|
|
25
|
-
listens: /listens\s*=\s*["'
|
|
21
|
+
layout: /layout\s*=\s*("[^"]*"|'[^']*')/g,
|
|
22
|
+
space: /space\s*=\s*("[^"]*"|'[^']*')/g,
|
|
23
|
+
visual: /visual\s*=\s*("[^"]*"|'[^']*')/g,
|
|
24
|
+
interact: /interact\s*=\s*("[^"]*"|'[^']*')/g,
|
|
25
|
+
listens: /listens\s*=\s*("[^"]*"|'[^']*')/g
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -45,7 +45,14 @@ export function parseSource(content) {
|
|
|
45
45
|
for (const [attr, pattern] of Object.entries(patterns)) {
|
|
46
46
|
let match;
|
|
47
47
|
while ((match = pattern.exec(content)) !== null) {
|
|
48
|
-
|
|
48
|
+
let value = match[1].trim();
|
|
49
|
+
if (value.length >= 2) {
|
|
50
|
+
const firstChar = value[0];
|
|
51
|
+
const lastChar = value[value.length - 1];
|
|
52
|
+
if ((firstChar === '"' && lastChar === '"') || (firstChar === "'" && lastChar === "'")) {
|
|
53
|
+
value = value.slice(1, -1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
49
56
|
if (value.length > 10000) {
|
|
50
57
|
continue;
|
|
51
58
|
}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SenangStart CSS - Tokenizer
|
|
3
|
-
* Re-exports core tokenizer functions with backward compatibility
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Re-export everything from core tokenizer
|
|
7
|
-
export {
|
|
8
|
-
tokenize,
|
|
9
|
-
tokenizeAll,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
/**
|
|
2
|
+
* SenangStart CSS - Tokenizer
|
|
3
|
+
* Re-exports core tokenizer functions with backward compatibility
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Re-export everything from core tokenizer
|
|
7
|
+
export {
|
|
8
|
+
tokenize,
|
|
9
|
+
tokenizeAll,
|
|
10
|
+
tokenizeAllWithBatching,
|
|
11
|
+
sanitizeValue,
|
|
12
|
+
isValidToken
|
|
13
|
+
} from '../core/tokenizer-core.js';
|
|
14
|
+
|
|
15
|
+
// Re-export constants for backward compatibility
|
|
16
|
+
export {
|
|
17
|
+
BREAKPOINTS,
|
|
18
|
+
STATES,
|
|
19
|
+
LAYOUT_KEYWORDS
|
|
20
|
+
} from '../core/constants.js';
|
|
21
|
+
|
|
22
|
+
// Default export for backward compatibility
|
|
23
|
+
import { tokenize, tokenizeAll, tokenizeAllWithBatching } from '../core/tokenizer-core.js';
|
|
24
|
+
export default { tokenize, tokenizeAll, tokenizeAllWithBatching };
|
|
25
|
+
|
package/src/config/defaults.js
CHANGED
|
@@ -138,6 +138,7 @@ export const defaultConfig = {
|
|
|
138
138
|
'tab': '768px', // Tablet
|
|
139
139
|
'lap': '1024px', // Laptop
|
|
140
140
|
'desk': '1280px', // Desktop
|
|
141
|
+
'print': 'print', // Print media query
|
|
141
142
|
|
|
142
143
|
// Tailwind Compatibility
|
|
143
144
|
'tw-sm': '640px',
|
|
@@ -148,6 +149,8 @@ export const defaultConfig = {
|
|
|
148
149
|
},
|
|
149
150
|
|
|
150
151
|
// 7. COLORS: Palette Scales
|
|
152
|
+
// Placeholder color for form inputs
|
|
153
|
+
placeholder: '#9ca3af',
|
|
151
154
|
colors: {
|
|
152
155
|
// Base colors
|
|
153
156
|
'white': '#FFFFFF',
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SenangStart CSS - Core Tokenizer
|
|
3
|
-
* Pure tokenizer functions shared by JIT runtime and build-time compiler
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { BREAKPOINTS, STATES, LAYOUT_KEYWORDS } from './constants.js';
|
|
7
|
-
import { sanitizeValue } from '../utils/common.js';
|
|
1
|
+
/**
|
|
2
|
+
* SenangStart CSS - Core Tokenizer
|
|
3
|
+
* Pure tokenizer functions shared by JIT runtime and build-time compiler
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { BREAKPOINTS, STATES, LAYOUT_KEYWORDS } from './constants.js';
|
|
7
|
+
import { sanitizeValue, batchProcessTokens } from '../utils/common.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Sanitize token value to prevent CSS injection
|
|
@@ -164,15 +164,42 @@ export function tokenize(raw, attrType) {
|
|
|
164
164
|
* @returns {Array} - Array of token objects
|
|
165
165
|
*/
|
|
166
166
|
export function tokenizeAll(parsed) {
|
|
167
|
-
const tokens = [];
|
|
168
|
-
|
|
169
|
-
for (const [attrType, values] of Object.entries(parsed)) {
|
|
170
|
-
for (const raw of values) {
|
|
171
|
-
tokens.push(tokenize(raw, attrType));
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return tokens;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
167
|
+
const tokens = [];
|
|
168
|
+
|
|
169
|
+
for (const [attrType, values] of Object.entries(parsed)) {
|
|
170
|
+
for (const raw of values) {
|
|
171
|
+
tokens.push(tokenize(raw, attrType));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return tokens;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Tokenize all values with memory-protected batch processing
|
|
180
|
+
* @param {Object} parsed - Parsed tokens from parser { layout: Set, space: Set, visual: Set }
|
|
181
|
+
* @param {number} batchSize - Number of tokens per batch (default: 1000)
|
|
182
|
+
* @returns {Promise<Array>} - Array of token objects
|
|
183
|
+
*/
|
|
184
|
+
export async function tokenizeAllWithBatching(parsed, batchSize = 1000) {
|
|
185
|
+
const rawTokens = [];
|
|
186
|
+
|
|
187
|
+
// Collect all raw tokens first
|
|
188
|
+
for (const [attrType, values] of Object.entries(parsed)) {
|
|
189
|
+
for (const raw of values) {
|
|
190
|
+
rawTokens.push({ raw, attrType });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Process tokens in batches with memory protection
|
|
195
|
+
const tokens = await batchProcessTokens(
|
|
196
|
+
rawTokens,
|
|
197
|
+
({ raw, attrType }) => tokenize(raw, attrType),
|
|
198
|
+
batchSize
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
return tokens;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export default { tokenize, tokenizeAll, tokenizeAllWithBatching, sanitizeValue, isValidToken };
|
|
205
|
+
|
package/src/definitions/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import transformDefinitions from './visual-transforms.js';
|
|
|
16
16
|
import borderDefinitions from './visual-borders.js';
|
|
17
17
|
import divideDefinitions from './visual-divide.js';
|
|
18
18
|
import svgDefinitions from './visual-svg.js';
|
|
19
|
+
import performanceDefinitions from './visual-performance.js';
|
|
19
20
|
|
|
20
21
|
// Import split layout definitions
|
|
21
22
|
import flexDefinitions from './layout-flex.js';
|
|
@@ -37,7 +38,8 @@ const allVisualDefinitions = {
|
|
|
37
38
|
...transformDefinitions,
|
|
38
39
|
...borderDefinitions,
|
|
39
40
|
...divideDefinitions,
|
|
40
|
-
...svgDefinitions
|
|
41
|
+
...svgDefinitions,
|
|
42
|
+
...performanceDefinitions
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
// Re-export all definitions
|
|
@@ -54,6 +56,7 @@ export { transformDefinitions } from './visual-transforms.js';
|
|
|
54
56
|
export { borderDefinitions } from './visual-borders.js';
|
|
55
57
|
export { divideDefinitions } from './visual-divide.js';
|
|
56
58
|
export { svgDefinitions } from './visual-svg.js';
|
|
59
|
+
export { performanceDefinitions } from './visual-performance.js';
|
|
57
60
|
|
|
58
61
|
// Re-export split layout definitions
|
|
59
62
|
export { flexDefinitions } from './layout-flex.js';
|
|
@@ -181,11 +181,11 @@ export const ring = {
|
|
|
181
181
|
supportsArbitrary: true,
|
|
182
182
|
values: [
|
|
183
183
|
{ value: 'none', css: 'box-shadow: 0 0 0 0 transparent;', description: 'No ring', descriptionMs: 'Tiada cincin' },
|
|
184
|
-
{ value: 'thin', css: 'box-shadow: 0 0 0 1px var(--ring-color);', description: 'Thin ring (1px)', descriptionMs: 'Cincin nipis (1px)' },
|
|
185
|
-
{ value: 'regular', css: 'box-shadow: 0 0 0 2px var(--ring-color);', description: 'Regular ring (2px)', descriptionMs: 'Cincin biasa (2px)' },
|
|
186
|
-
{ value: 'small', css: 'box-shadow: 0 0 0 4px var(--ring-color);', description: 'Small ring (4px)', descriptionMs: 'Cincin kecil (4px)' },
|
|
187
|
-
{ value: 'medium', css: 'box-shadow: 0 0 0 6px var(--ring-color);', description: 'Medium ring (6px)', descriptionMs: 'Cincin sederhana (6px)' },
|
|
188
|
-
{ value: 'big', css: 'box-shadow: 0 0 0 8px var(--ring-color);', description: 'Big ring (8px)', descriptionMs: 'Cincin besar (8px)' }
|
|
184
|
+
{ value: 'thin', css: 'box-shadow: var(--ring-inset) 0 0 0 1px var(--ss-ring-color);', description: 'Thin ring (1px)', descriptionMs: 'Cincin nipis (1px)' },
|
|
185
|
+
{ value: 'regular', css: 'box-shadow: var(--ring-inset) 0 0 0 2px var(--ss-ring-color);', description: 'Regular ring (2px)', descriptionMs: 'Cincin biasa (2px)' },
|
|
186
|
+
{ value: 'small', css: 'box-shadow: var(--ring-inset) 0 0 0 4px var(--ss-ring-color);', description: 'Small ring (4px)', descriptionMs: 'Cincin kecil (4px)' },
|
|
187
|
+
{ value: 'medium', css: 'box-shadow: var(--ring-inset) 0 0 0 6px var(--ss-ring-color);', description: 'Medium ring (6px)', descriptionMs: 'Cincin sederhana (6px)' },
|
|
188
|
+
{ value: 'big', css: 'box-shadow: var(--ring-inset) 0 0 0 8px var(--ss-ring-color);', description: 'Big ring (8px)', descriptionMs: 'Cincin besar (8px)' }
|
|
189
189
|
],
|
|
190
190
|
examples: [
|
|
191
191
|
{ code: '<button visual="focus-visible:ring:small ring-color:primary">Focus me</button>', description: 'Focus ring on keyboard focus' },
|
|
@@ -216,8 +216,8 @@ export const ringColor = {
|
|
|
216
216
|
usesScale: 'colors',
|
|
217
217
|
supportsArbitrary: true,
|
|
218
218
|
values: [
|
|
219
|
-
{ value: 'primary', css: '--ring-color: var(--c-primary);', description: 'Primary ring color', descriptionMs: 'Warna cincin utama' },
|
|
220
|
-
{ value: 'blue-500', css: '--ring-color: var(--c-blue-500);', description: 'Blue ring color', descriptionMs: 'Warna cincin biru' }
|
|
219
|
+
{ value: 'primary', css: '--ss-ring-color: var(--c-primary);', description: 'Primary ring color', descriptionMs: 'Warna cincin utama' },
|
|
220
|
+
{ value: 'blue-500', css: '--ss-ring-color: var(--c-blue-500);', description: 'Blue ring color', descriptionMs: 'Warna cincin biru' }
|
|
221
221
|
],
|
|
222
222
|
examples: [
|
|
223
223
|
{ code: '<button visual="ring:small ring-color:primary">Colored ring</button>', description: 'Ring with custom color' }
|
|
@@ -233,9 +233,9 @@ export const ringOffset = {
|
|
|
233
233
|
category: 'visual',
|
|
234
234
|
supportsArbitrary: true,
|
|
235
235
|
values: [
|
|
236
|
-
{ value: '0', css: '--ring-offset: 0px;', description: 'No offset', descriptionMs: 'Tiada ruang' },
|
|
237
|
-
{ value: '2', css: '--ring-offset: 2px;', description: '2px offset', descriptionMs: 'Ruang 2px' },
|
|
238
|
-
{ value: '4', css: '--ring-offset: 4px;', description: '4px offset', descriptionMs: 'Ruang 4px' }
|
|
236
|
+
{ value: '0', css: '--ss-ring-offset-width: 0px;', description: 'No offset', descriptionMs: 'Tiada ruang' },
|
|
237
|
+
{ value: '2', css: '--ss-ring-offset-width: 2px;', description: '2px offset', descriptionMs: 'Ruang 2px' },
|
|
238
|
+
{ value: '4', css: '--ss-ring-offset-width: 4px;', description: '4px offset', descriptionMs: 'Ruang 4px' }
|
|
239
239
|
],
|
|
240
240
|
examples: [
|
|
241
241
|
{ code: '<button visual="ring:small ring-offset:2 ring-color:primary">With offset</button>', description: 'Ring with offset' }
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SenangStart CSS - Performance Utility Definitions
|
|
3
|
+
* Content visibility, contain, and other performance optimizations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ======================
|
|
7
|
+
// CONTENT VISIBILITY
|
|
8
|
+
// ======================
|
|
9
|
+
|
|
10
|
+
export const contentVisibility = {
|
|
11
|
+
name: 'content-visibility',
|
|
12
|
+
property: 'visual',
|
|
13
|
+
syntax: 'visual="content-visibility:[value]"',
|
|
14
|
+
description: 'Optimize rendering by skipping off-screen content',
|
|
15
|
+
descriptionMs: 'Optimumkan rendering dengan melangkau kandungan luar skrin',
|
|
16
|
+
category: 'visual',
|
|
17
|
+
values: [
|
|
18
|
+
{ value: 'visible', css: 'content-visibility: visible;', description: 'Render all content', descriptionMs: 'Render semua kandungan' },
|
|
19
|
+
{ value: 'auto', css: 'content-visibility: auto;', description: 'Skip when off-screen', descriptionMs: 'Langkau bila luar skrin' },
|
|
20
|
+
{ value: 'hidden', css: 'content-visibility: hidden;', description: 'Never render off-screen', descriptionMs: 'Jangan render luar skrin' }
|
|
21
|
+
],
|
|
22
|
+
examples: [
|
|
23
|
+
{ code: '<section visual="content-visibility:auto">Large list</section>', description: 'Auto-optimize large content' },
|
|
24
|
+
{ code: '<div visual="content-visibility:hidden">Hidden until needed</div>', description: 'Hide until revealed' }
|
|
25
|
+
],
|
|
26
|
+
preview: [
|
|
27
|
+
{
|
|
28
|
+
title: 'Content Visibility',
|
|
29
|
+
titleMs: 'Ketampakan Kandungan',
|
|
30
|
+
description: 'Performance optimization for off-screen content',
|
|
31
|
+
descriptionMs: 'Pengoptimuman prestasi untuk kandungan luar skrin',
|
|
32
|
+
html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
|
|
33
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">visible</div>
|
|
34
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">auto</div>
|
|
35
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">hidden</div>
|
|
36
|
+
</div>`,
|
|
37
|
+
highlightValue: 'content-visibility:auto'
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// ======================
|
|
43
|
+
// CONTAIN
|
|
44
|
+
// ======================
|
|
45
|
+
|
|
46
|
+
export const contain = {
|
|
47
|
+
name: 'contain',
|
|
48
|
+
property: 'visual',
|
|
49
|
+
syntax: 'visual="contain:[value]"',
|
|
50
|
+
description: 'Isolate element rendering for performance',
|
|
51
|
+
descriptionMs: 'Pencil rendering elemen untuk prestasi',
|
|
52
|
+
category: 'visual',
|
|
53
|
+
values: [
|
|
54
|
+
{ value: 'none', css: 'contain: none;', description: 'No containment', descriptionMs: 'Tiada pengandungan' },
|
|
55
|
+
{ value: 'strict', css: 'contain: strict;', description: 'Full containment', descriptionMs: 'Pengandungan penuh' },
|
|
56
|
+
{ value: 'content', css: 'contain: content;', description: 'Content containment', descriptionMs: 'Pengandungan kandungan' },
|
|
57
|
+
{ value: 'size', css: 'contain: size;', description: 'Size containment', descriptionMs: 'Pengandungan saiz' },
|
|
58
|
+
{ value: 'layout', css: 'contain: layout;', description: 'Layout containment', descriptionMs: 'Pengandungan susun atur' },
|
|
59
|
+
{ value: 'style', css: 'contain: style;', description: 'Style containment', descriptionMs: 'Pengandungan gaya' },
|
|
60
|
+
{ value: 'paint', css: 'contain: paint;', description: 'Paint containment', descriptionMs: 'Pengandungan lukis' }
|
|
61
|
+
],
|
|
62
|
+
examples: [
|
|
63
|
+
{ code: '<div visual="contain:strict">Isolated rendering</div>', description: 'Full containment' },
|
|
64
|
+
{ code: '<div visual="contain:content">Content isolation</div>', description: 'Content only' }
|
|
65
|
+
],
|
|
66
|
+
preview: [
|
|
67
|
+
{
|
|
68
|
+
title: 'Contain',
|
|
69
|
+
titleMs: 'Mengandung',
|
|
70
|
+
description: 'Isolate element from rest of page for performance',
|
|
71
|
+
descriptionMs: 'Pencil elemen dari halaman lain untuk prestasi',
|
|
72
|
+
html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
|
|
73
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">none</div>
|
|
74
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">content</div>
|
|
75
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">strict</div>
|
|
76
|
+
</div>`,
|
|
77
|
+
highlightValue: 'contain:strict'
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// ======================
|
|
83
|
+
// WRITING MODE
|
|
84
|
+
// ======================
|
|
85
|
+
|
|
86
|
+
export const writingMode = {
|
|
87
|
+
name: 'writing-mode',
|
|
88
|
+
property: 'visual',
|
|
89
|
+
syntax: 'visual="writing-mode:[value]"',
|
|
90
|
+
description: 'Set writing direction for RTL/vertical text',
|
|
91
|
+
descriptionMs: 'Tetapkan arah penulisan untuk teks RTL/menegak',
|
|
92
|
+
category: 'visual',
|
|
93
|
+
values: [
|
|
94
|
+
{ value: 'horizontal-tb', css: 'writing-mode: horizontal-tb;', description: 'Left to right', descriptionMs: 'Kiri ke kanan' },
|
|
95
|
+
{ value: 'vertical-rl', css: 'writing-mode: vertical-rl;', description: 'Top to bottom RTL', descriptionMs: 'Atas ke bawah RTL' },
|
|
96
|
+
{ value: 'vertical-lr', css: 'writing-mode: vertical-lr;', description: 'Top to bottom LTR', descriptionMs: 'Atas ke bawah LTR' },
|
|
97
|
+
{ value: 'sideways-rl', css: 'writing-mode: sideways-rl;', description: 'Sideways RTL', descriptionMs: 'Menyerong RTL' },
|
|
98
|
+
{ value: 'sideways-lr', css: 'writing-mode: sideways-lr;', description: 'Sideways LTR', descriptionMs: 'Menyerong LTR' }
|
|
99
|
+
],
|
|
100
|
+
examples: [
|
|
101
|
+
{ code: '<div visual="writing-mode:vertical-rl">Vertical text</div>', description: 'Vertical text RTL' },
|
|
102
|
+
{ code: '<div visual="writing-mode:horizontal-tb">Horizontal text</div>', description: 'Horizontal text LTR' }
|
|
103
|
+
],
|
|
104
|
+
preview: [
|
|
105
|
+
{
|
|
106
|
+
title: 'Writing Mode',
|
|
107
|
+
titleMs: 'Mod Penulisan',
|
|
108
|
+
description: 'Control text direction and orientation',
|
|
109
|
+
descriptionMs: 'Kawal arah dan orientasi teks',
|
|
110
|
+
html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
|
|
111
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">horizontal-tb</div>
|
|
112
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">vertical-rl</div>
|
|
113
|
+
</div>`,
|
|
114
|
+
highlightValue: 'writing-mode:vertical-rl'
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Export all performance definitions
|
|
120
|
+
export const performanceDefinitions = {
|
|
121
|
+
contentVisibility,
|
|
122
|
+
contain,
|
|
123
|
+
writingMode
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default performanceDefinitions;
|
|
@@ -414,11 +414,12 @@ export const lineHeight = {
|
|
|
414
414
|
export const borderRadius = {
|
|
415
415
|
name: 'border-radius',
|
|
416
416
|
property: 'visual',
|
|
417
|
-
syntax: 'visual="rounded:[value]"',
|
|
418
|
-
description: 'Set border radius',
|
|
419
|
-
descriptionMs: 'Tetapkan jejari sempadan',
|
|
417
|
+
syntax: 'visual="rounded:[value]" | visual="rounded-{t|b|l|r|tl|tr|bl|br}:[value]"',
|
|
418
|
+
description: 'Set border radius for all corners or specific corners',
|
|
419
|
+
descriptionMs: 'Tetapkan jejari sempadan untuk semua bucu atau bucu tertentu',
|
|
420
420
|
category: 'visual',
|
|
421
421
|
usesScale: 'radius',
|
|
422
|
+
supportsArbitrary: true,
|
|
422
423
|
values: [
|
|
423
424
|
{ value: 'none', css: 'border-radius: var(--r-none);', description: 'No rounding', descriptionMs: 'Tiada pembulatan' },
|
|
424
425
|
{ value: 'small', css: 'border-radius: var(--r-small);', description: 'Small radius', descriptionMs: 'Jejari kecil' },
|
|
@@ -427,8 +428,10 @@ export const borderRadius = {
|
|
|
427
428
|
{ value: 'round', css: 'border-radius: var(--r-round);', description: 'Fully round', descriptionMs: 'Sepenuhnya bulat' }
|
|
428
429
|
],
|
|
429
430
|
examples: [
|
|
430
|
-
{ code: '<div visual="rounded:medium">Rounded corners</div>', description: '
|
|
431
|
-
{ code: '<div visual="rounded:round">Pill shape</div>', description: '
|
|
431
|
+
{ code: '<div visual="rounded:medium">Rounded corners</div>', description: 'All corners rounded' },
|
|
432
|
+
{ code: '<div visual="rounded:round">Pill shape</div>', description: 'Fully round' },
|
|
433
|
+
{ code: '<div visual="rounded-t:medium">Top rounded</div>', description: 'Top corners only' },
|
|
434
|
+
{ code: '<div visual="rounded-tl:big rounded-br:big">Opposite corners</div>', description: 'Specific corners' }
|
|
432
435
|
],
|
|
433
436
|
footnotes: [
|
|
434
437
|
{
|
|
@@ -446,12 +449,25 @@ export const borderRadius = {
|
|
|
446
449
|
description: 'Round element corners from subtle to pill-shaped',
|
|
447
450
|
descriptionMs: 'Bulatkan sudut elemen dari halus hingga berbentuk pil',
|
|
448
451
|
html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
452
|
+
<div space="p:small" visual="bg:primary text:white rounded:none">none</div>
|
|
453
|
+
<div space="p:small" visual="bg:primary text:white rounded:small">small</div>
|
|
454
|
+
<div space="p:small" visual="bg:primary text:white rounded:medium">medium</div>
|
|
455
|
+
<div space="p:small" visual="bg:primary text:white rounded:round">round</div>
|
|
453
456
|
</div>`,
|
|
454
457
|
highlightValue: 'rounded:medium'
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
title: 'Directional Border Radius',
|
|
461
|
+
titleMs: 'Jejari Sempadan Arah',
|
|
462
|
+
description: 'Round specific corners for unique shapes',
|
|
463
|
+
descriptionMs: 'Bulatkan bucu tertentu untuk bentuk unik',
|
|
464
|
+
html: `<div layout="flex" space="g:medium p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
|
|
465
|
+
<div space="p:small" visual="bg:primary text:white rounded-t:medium">top</div>
|
|
466
|
+
<div space="p:small" visual="bg:primary text:white rounded-b:medium">bottom</div>
|
|
467
|
+
<div space="p:small" visual="bg:primary text:white rounded-l:medium">left</div>
|
|
468
|
+
<div space="p:small" visual="bg:primary text:white rounded-r:medium">right</div>
|
|
469
|
+
</div>`,
|
|
470
|
+
highlightValue: 'rounded-t:medium'
|
|
455
471
|
}
|
|
456
472
|
]
|
|
457
473
|
};
|