@tekton-ui/core 0.2.0
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/README.md +758 -0
- package/dist/blueprint.d.ts +44 -0
- package/dist/blueprint.d.ts.map +1 -0
- package/dist/blueprint.js +163 -0
- package/dist/blueprint.js.map +1 -0
- package/dist/component-schemas.d.ts +78 -0
- package/dist/component-schemas.d.ts.map +1 -0
- package/dist/component-schemas.js +1037 -0
- package/dist/component-schemas.js.map +1 -0
- package/dist/css-generator.d.ts +42 -0
- package/dist/css-generator.d.ts.map +1 -0
- package/dist/css-generator.js +339 -0
- package/dist/css-generator.js.map +1 -0
- package/dist/icon-library.d.ts +109 -0
- package/dist/icon-library.d.ts.map +1 -0
- package/dist/icon-library.js +204 -0
- package/dist/icon-library.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/layout-css-generator.d.ts +158 -0
- package/dist/layout-css-generator.d.ts.map +1 -0
- package/dist/layout-css-generator.js +901 -0
- package/dist/layout-css-generator.js.map +1 -0
- package/dist/layout-resolver.d.ts +92 -0
- package/dist/layout-resolver.d.ts.map +1 -0
- package/dist/layout-resolver.js +275 -0
- package/dist/layout-resolver.js.map +1 -0
- package/dist/layout-tokens/index.d.ts +16 -0
- package/dist/layout-tokens/index.d.ts.map +1 -0
- package/dist/layout-tokens/index.js +16 -0
- package/dist/layout-tokens/index.js.map +1 -0
- package/dist/layout-tokens/keyboard.d.ts +254 -0
- package/dist/layout-tokens/keyboard.d.ts.map +1 -0
- package/dist/layout-tokens/keyboard.js +407 -0
- package/dist/layout-tokens/keyboard.js.map +1 -0
- package/dist/layout-tokens/mobile-shells.d.ts +78 -0
- package/dist/layout-tokens/mobile-shells.d.ts.map +1 -0
- package/dist/layout-tokens/mobile-shells.js +635 -0
- package/dist/layout-tokens/mobile-shells.js.map +1 -0
- package/dist/layout-tokens/pages.d.ts +100 -0
- package/dist/layout-tokens/pages.d.ts.map +1 -0
- package/dist/layout-tokens/pages.js +576 -0
- package/dist/layout-tokens/pages.js.map +1 -0
- package/dist/layout-tokens/responsive.d.ts +109 -0
- package/dist/layout-tokens/responsive.d.ts.map +1 -0
- package/dist/layout-tokens/responsive.js +167 -0
- package/dist/layout-tokens/responsive.js.map +1 -0
- package/dist/layout-tokens/safe-area.d.ts +156 -0
- package/dist/layout-tokens/safe-area.d.ts.map +1 -0
- package/dist/layout-tokens/safe-area.js +316 -0
- package/dist/layout-tokens/safe-area.js.map +1 -0
- package/dist/layout-tokens/sections-advanced.d.ts +277 -0
- package/dist/layout-tokens/sections-advanced.d.ts.map +1 -0
- package/dist/layout-tokens/sections-advanced.js +593 -0
- package/dist/layout-tokens/sections-advanced.js.map +1 -0
- package/dist/layout-tokens/sections.d.ts +137 -0
- package/dist/layout-tokens/sections.d.ts.map +1 -0
- package/dist/layout-tokens/sections.js +694 -0
- package/dist/layout-tokens/sections.js.map +1 -0
- package/dist/layout-tokens/shells.d.ts +77 -0
- package/dist/layout-tokens/shells.d.ts.map +1 -0
- package/dist/layout-tokens/shells.js +408 -0
- package/dist/layout-tokens/shells.js.map +1 -0
- package/dist/layout-tokens/touch-target.d.ts +119 -0
- package/dist/layout-tokens/touch-target.d.ts.map +1 -0
- package/dist/layout-tokens/touch-target.js +156 -0
- package/dist/layout-tokens/touch-target.js.map +1 -0
- package/dist/layout-tokens/types.d.ts +632 -0
- package/dist/layout-tokens/types.d.ts.map +1 -0
- package/dist/layout-tokens/types.js +49 -0
- package/dist/layout-tokens/types.js.map +1 -0
- package/dist/layout-validation.d.ts +1547 -0
- package/dist/layout-validation.d.ts.map +1 -0
- package/dist/layout-validation.js +628 -0
- package/dist/layout-validation.js.map +1 -0
- package/dist/render.d.ts +23 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +244 -0
- package/dist/render.js.map +1 -0
- package/dist/schema-validation.d.ts +208 -0
- package/dist/schema-validation.d.ts.map +1 -0
- package/dist/schema-validation.js +205 -0
- package/dist/schema-validation.js.map +1 -0
- package/dist/screen-generation/generators/css-in-js-generator.d.ts +82 -0
- package/dist/screen-generation/generators/css-in-js-generator.d.ts.map +1 -0
- package/dist/screen-generation/generators/css-in-js-generator.js +335 -0
- package/dist/screen-generation/generators/css-in-js-generator.js.map +1 -0
- package/dist/screen-generation/generators/index.d.ts +13 -0
- package/dist/screen-generation/generators/index.d.ts.map +1 -0
- package/dist/screen-generation/generators/index.js +32 -0
- package/dist/screen-generation/generators/index.js.map +1 -0
- package/dist/screen-generation/generators/react-generator.d.ts +100 -0
- package/dist/screen-generation/generators/react-generator.d.ts.map +1 -0
- package/dist/screen-generation/generators/react-generator.js +379 -0
- package/dist/screen-generation/generators/react-generator.js.map +1 -0
- package/dist/screen-generation/generators/tailwind-generator.d.ts +105 -0
- package/dist/screen-generation/generators/tailwind-generator.d.ts.map +1 -0
- package/dist/screen-generation/generators/tailwind-generator.js +355 -0
- package/dist/screen-generation/generators/tailwind-generator.js.map +1 -0
- package/dist/screen-generation/generators/types.d.ts +136 -0
- package/dist/screen-generation/generators/types.d.ts.map +1 -0
- package/dist/screen-generation/generators/types.js +18 -0
- package/dist/screen-generation/generators/types.js.map +1 -0
- package/dist/screen-generation/generators/utils.d.ts +187 -0
- package/dist/screen-generation/generators/utils.d.ts.map +1 -0
- package/dist/screen-generation/generators/utils.js +312 -0
- package/dist/screen-generation/generators/utils.js.map +1 -0
- package/dist/screen-generation/index.d.ts +14 -0
- package/dist/screen-generation/index.d.ts.map +1 -0
- package/dist/screen-generation/index.js +33 -0
- package/dist/screen-generation/index.js.map +1 -0
- package/dist/screen-generation/resolver/component-resolver.d.ts +157 -0
- package/dist/screen-generation/resolver/component-resolver.d.ts.map +1 -0
- package/dist/screen-generation/resolver/component-resolver.js +295 -0
- package/dist/screen-generation/resolver/component-resolver.js.map +1 -0
- package/dist/screen-generation/resolver/index.d.ts +10 -0
- package/dist/screen-generation/resolver/index.d.ts.map +1 -0
- package/dist/screen-generation/resolver/index.js +46 -0
- package/dist/screen-generation/resolver/index.js.map +1 -0
- package/dist/screen-generation/resolver/layout-resolver.d.ts +155 -0
- package/dist/screen-generation/resolver/layout-resolver.d.ts.map +1 -0
- package/dist/screen-generation/resolver/layout-resolver.js +193 -0
- package/dist/screen-generation/resolver/layout-resolver.js.map +1 -0
- package/dist/screen-generation/resolver/screen-resolver.d.ts +174 -0
- package/dist/screen-generation/resolver/screen-resolver.d.ts.map +1 -0
- package/dist/screen-generation/resolver/screen-resolver.js +373 -0
- package/dist/screen-generation/resolver/screen-resolver.js.map +1 -0
- package/dist/screen-generation/resolver/token-resolver.d.ts +170 -0
- package/dist/screen-generation/resolver/token-resolver.d.ts.map +1 -0
- package/dist/screen-generation/resolver/token-resolver.js +260 -0
- package/dist/screen-generation/resolver/token-resolver.js.map +1 -0
- package/dist/screen-generation/types.d.ts +116 -0
- package/dist/screen-generation/types.d.ts.map +1 -0
- package/dist/screen-generation/types.js +33 -0
- package/dist/screen-generation/types.js.map +1 -0
- package/dist/screen-generation/validators.d.ts +286 -0
- package/dist/screen-generation/validators.d.ts.map +1 -0
- package/dist/screen-generation/validators.js +323 -0
- package/dist/screen-generation/validators.js.map +1 -0
- package/dist/screen-templates/__tests__/registry.test.d.ts +6 -0
- package/dist/screen-templates/__tests__/registry.test.d.ts.map +1 -0
- package/dist/screen-templates/__tests__/registry.test.js +247 -0
- package/dist/screen-templates/__tests__/registry.test.js.map +1 -0
- package/dist/screen-templates/__tests__/templates.test.d.ts +6 -0
- package/dist/screen-templates/__tests__/templates.test.d.ts.map +1 -0
- package/dist/screen-templates/__tests__/templates.test.js +179 -0
- package/dist/screen-templates/__tests__/templates.test.js.map +1 -0
- package/dist/screen-templates/index.d.ts +39 -0
- package/dist/screen-templates/index.d.ts.map +1 -0
- package/dist/screen-templates/index.js +79 -0
- package/dist/screen-templates/index.js.map +1 -0
- package/dist/screen-templates/registry.d.ts +177 -0
- package/dist/screen-templates/registry.d.ts.map +1 -0
- package/dist/screen-templates/registry.js +274 -0
- package/dist/screen-templates/registry.js.map +1 -0
- package/dist/screen-templates/templates/account/index.d.ts +6 -0
- package/dist/screen-templates/templates/account/index.d.ts.map +1 -0
- package/dist/screen-templates/templates/account/index.js +6 -0
- package/dist/screen-templates/templates/account/index.js.map +1 -0
- package/dist/screen-templates/templates/account/profile.d.ts +23 -0
- package/dist/screen-templates/templates/account/profile.d.ts.map +1 -0
- package/dist/screen-templates/templates/account/profile.js +249 -0
- package/dist/screen-templates/templates/account/profile.js.map +1 -0
- package/dist/screen-templates/templates/auth/forgot-password.d.ts +23 -0
- package/dist/screen-templates/templates/auth/forgot-password.d.ts.map +1 -0
- package/dist/screen-templates/templates/auth/forgot-password.js +203 -0
- package/dist/screen-templates/templates/auth/forgot-password.js.map +1 -0
- package/dist/screen-templates/templates/auth/index.d.ts +9 -0
- package/dist/screen-templates/templates/auth/index.d.ts.map +1 -0
- package/dist/screen-templates/templates/auth/index.js +9 -0
- package/dist/screen-templates/templates/auth/index.js.map +1 -0
- package/dist/screen-templates/templates/auth/login.d.ts +24 -0
- package/dist/screen-templates/templates/auth/login.d.ts.map +1 -0
- package/dist/screen-templates/templates/auth/login.js +254 -0
- package/dist/screen-templates/templates/auth/login.js.map +1 -0
- package/dist/screen-templates/templates/auth/signup.d.ts +24 -0
- package/dist/screen-templates/templates/auth/signup.d.ts.map +1 -0
- package/dist/screen-templates/templates/auth/signup.js +315 -0
- package/dist/screen-templates/templates/auth/signup.js.map +1 -0
- package/dist/screen-templates/templates/auth/verification.d.ts +23 -0
- package/dist/screen-templates/templates/auth/verification.d.ts.map +1 -0
- package/dist/screen-templates/templates/auth/verification.js +239 -0
- package/dist/screen-templates/templates/auth/verification.js.map +1 -0
- package/dist/screen-templates/templates/feedback/confirmation.d.ts +9 -0
- package/dist/screen-templates/templates/feedback/confirmation.d.ts.map +1 -0
- package/dist/screen-templates/templates/feedback/confirmation.js +107 -0
- package/dist/screen-templates/templates/feedback/confirmation.js.map +1 -0
- package/dist/screen-templates/templates/feedback/empty.d.ts +9 -0
- package/dist/screen-templates/templates/feedback/empty.d.ts.map +1 -0
- package/dist/screen-templates/templates/feedback/empty.js +90 -0
- package/dist/screen-templates/templates/feedback/empty.js.map +1 -0
- package/dist/screen-templates/templates/feedback/error.d.ts +9 -0
- package/dist/screen-templates/templates/feedback/error.d.ts.map +1 -0
- package/dist/screen-templates/templates/feedback/error.js +99 -0
- package/dist/screen-templates/templates/feedback/error.js.map +1 -0
- package/dist/screen-templates/templates/feedback/index.d.ts +10 -0
- package/dist/screen-templates/templates/feedback/index.d.ts.map +1 -0
- package/dist/screen-templates/templates/feedback/index.js +10 -0
- package/dist/screen-templates/templates/feedback/index.js.map +1 -0
- package/dist/screen-templates/templates/feedback/loading.d.ts +9 -0
- package/dist/screen-templates/templates/feedback/loading.d.ts.map +1 -0
- package/dist/screen-templates/templates/feedback/loading.js +77 -0
- package/dist/screen-templates/templates/feedback/loading.js.map +1 -0
- package/dist/screen-templates/templates/feedback/success.d.ts +9 -0
- package/dist/screen-templates/templates/feedback/success.d.ts.map +1 -0
- package/dist/screen-templates/templates/feedback/success.js +99 -0
- package/dist/screen-templates/templates/feedback/success.js.map +1 -0
- package/dist/screen-templates/templates/home/index.d.ts +6 -0
- package/dist/screen-templates/templates/home/index.d.ts.map +1 -0
- package/dist/screen-templates/templates/home/index.js +6 -0
- package/dist/screen-templates/templates/home/index.js.map +1 -0
- package/dist/screen-templates/templates/home/landing.d.ts +24 -0
- package/dist/screen-templates/templates/home/landing.d.ts.map +1 -0
- package/dist/screen-templates/templates/home/landing.js +197 -0
- package/dist/screen-templates/templates/home/landing.js.map +1 -0
- package/dist/screen-templates/templates/settings/index.d.ts +6 -0
- package/dist/screen-templates/templates/settings/index.d.ts.map +1 -0
- package/dist/screen-templates/templates/settings/index.js +6 -0
- package/dist/screen-templates/templates/settings/index.js.map +1 -0
- package/dist/screen-templates/templates/settings/preferences.d.ts +24 -0
- package/dist/screen-templates/templates/settings/preferences.d.ts.map +1 -0
- package/dist/screen-templates/templates/settings/preferences.js +265 -0
- package/dist/screen-templates/templates/settings/preferences.js.map +1 -0
- package/dist/screen-templates/types.d.ts +229 -0
- package/dist/screen-templates/types.d.ts.map +1 -0
- package/dist/screen-templates/types.js +7 -0
- package/dist/screen-templates/types.js.map +1 -0
- package/dist/theme-v2.d.ts +228 -0
- package/dist/theme-v2.d.ts.map +1 -0
- package/dist/theme-v2.js +158 -0
- package/dist/theme-v2.js.map +1 -0
- package/dist/theme.d.ts +60 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +76 -0
- package/dist/theme.js.map +1 -0
- package/dist/token-resolver.d.ts +69 -0
- package/dist/token-resolver.d.ts.map +1 -0
- package/dist/token-resolver.js +122 -0
- package/dist/token-resolver.js.map +1 -0
- package/dist/token-validation.d.ts +432 -0
- package/dist/token-validation.d.ts.map +1 -0
- package/dist/token-validation.js +140 -0
- package/dist/token-validation.js.map +1 -0
- package/dist/tokens.d.ts +158 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +10 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,901 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tekton-ui/core - Layout CSS Generator
|
|
3
|
+
* Generates CSS from layout tokens (shells, pages, sections)
|
|
4
|
+
* [SPEC-LAYOUT-001] [PHASE-8]
|
|
5
|
+
*/
|
|
6
|
+
import { resolveTokenReference } from './layout-resolver.js';
|
|
7
|
+
import { getAllShellTokens } from './layout-tokens/shells.js';
|
|
8
|
+
import { getAllPageLayoutTokens } from './layout-tokens/pages.js';
|
|
9
|
+
import { getAllSectionPatternTokens } from './layout-tokens/sections.js';
|
|
10
|
+
import { getAllAdvancedSectionPatternTokens } from './layout-tokens/sections-advanced.js';
|
|
11
|
+
import { BREAKPOINT_VALUES } from './layout-tokens/responsive.js';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Utility Functions
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Extract CSS variable references from token references in an object
|
|
17
|
+
*
|
|
18
|
+
* @param obj - Object to extract token references from
|
|
19
|
+
* @returns Set of unique CSS variable names
|
|
20
|
+
*/
|
|
21
|
+
function extractCSSVariables(obj) {
|
|
22
|
+
const vars = new Set();
|
|
23
|
+
function traverse(value) {
|
|
24
|
+
if (typeof value === 'string' && /^[a-z]+\.[a-z-]+(\.[a-z0-9-]+)*$/.test(value)) {
|
|
25
|
+
// This is a token reference - convert to CSS variable
|
|
26
|
+
vars.add(resolveTokenReference(value));
|
|
27
|
+
}
|
|
28
|
+
else if (typeof value === 'object' && value !== null) {
|
|
29
|
+
for (const prop of Object.values(value)) {
|
|
30
|
+
traverse(prop);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
traverse(obj);
|
|
35
|
+
return vars;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Convert token reference to CSS var() function call
|
|
39
|
+
*
|
|
40
|
+
* @param ref - Token reference (e.g., "atomic.spacing.16")
|
|
41
|
+
* @returns CSS var() function (e.g., "var(--atomic-spacing-16)")
|
|
42
|
+
*/
|
|
43
|
+
function tokenRefToVar(ref) {
|
|
44
|
+
return `var(${resolveTokenReference(ref)})`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validate CSS syntax (balanced braces)
|
|
48
|
+
*
|
|
49
|
+
* @param css - CSS string to validate
|
|
50
|
+
* @returns true if valid, false otherwise
|
|
51
|
+
*/
|
|
52
|
+
export function validateCSS(css) {
|
|
53
|
+
const openBraces = (css.match(/{/g) || []).length;
|
|
54
|
+
const closeBraces = (css.match(/}/g) || []).length;
|
|
55
|
+
return openBraces === closeBraces;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Format CSS with proper indentation
|
|
59
|
+
*
|
|
60
|
+
* @param css - CSS string to format
|
|
61
|
+
* @param indent - Indentation string (default: 2 spaces)
|
|
62
|
+
* @returns Formatted CSS
|
|
63
|
+
*/
|
|
64
|
+
export function formatCSS(css, indent = ' ') {
|
|
65
|
+
let formatted = '';
|
|
66
|
+
let indentLevel = 0;
|
|
67
|
+
let inMediaQuery = false;
|
|
68
|
+
// Split by lines and process each
|
|
69
|
+
const lines = css
|
|
70
|
+
.split('\n')
|
|
71
|
+
.map(line => line.trim())
|
|
72
|
+
.filter(line => line.length > 0);
|
|
73
|
+
for (const line of lines) {
|
|
74
|
+
// Decrease indent for closing braces
|
|
75
|
+
if (line === '}') {
|
|
76
|
+
indentLevel--;
|
|
77
|
+
if (inMediaQuery && indentLevel === 0) {
|
|
78
|
+
inMediaQuery = false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Add indented line
|
|
82
|
+
formatted += indent.repeat(indentLevel) + line + '\n';
|
|
83
|
+
// Increase indent for opening braces
|
|
84
|
+
if (line.endsWith('{')) {
|
|
85
|
+
indentLevel++;
|
|
86
|
+
if (line.startsWith('@media')) {
|
|
87
|
+
inMediaQuery = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return formatted;
|
|
92
|
+
}
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// CSS Generation Functions
|
|
95
|
+
// ============================================================================
|
|
96
|
+
/**
|
|
97
|
+
* Generate CSS custom properties in :root from layout tokens
|
|
98
|
+
*
|
|
99
|
+
* @param tokens - Array of layout tokens
|
|
100
|
+
* @returns CSS :root block with custom properties
|
|
101
|
+
*/
|
|
102
|
+
export function generateCSSVariables(tokens) {
|
|
103
|
+
const vars = new Set();
|
|
104
|
+
// Extract all CSS variables from all tokens
|
|
105
|
+
for (const token of tokens) {
|
|
106
|
+
const tokenVars = extractCSSVariables(token);
|
|
107
|
+
tokenVars.forEach(v => vars.add(v));
|
|
108
|
+
}
|
|
109
|
+
if (vars.size === 0) {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
// Generate :root block
|
|
113
|
+
let css = ':root {\n';
|
|
114
|
+
// Sort variables for consistent output
|
|
115
|
+
const sortedVars = Array.from(vars).sort();
|
|
116
|
+
for (const cssVar of sortedVars) {
|
|
117
|
+
// Extract original token reference from CSS variable name
|
|
118
|
+
// --atomic-spacing-16 → atomic.spacing.16
|
|
119
|
+
const tokenRef = cssVar.replace(/^--/, '').replace(/-/g, '.');
|
|
120
|
+
css += ` ${cssVar}: ${tokenRef};\n`;
|
|
121
|
+
}
|
|
122
|
+
css += '}\n';
|
|
123
|
+
return css;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Generate utility classes for shell tokens
|
|
127
|
+
*
|
|
128
|
+
* @param shells - Array of shell tokens
|
|
129
|
+
* @returns CSS classes for shells
|
|
130
|
+
*/
|
|
131
|
+
export function generateShellClasses(shells) {
|
|
132
|
+
let css = '';
|
|
133
|
+
for (const shell of shells) {
|
|
134
|
+
// Generate class name: .shell-{platform}-{name}
|
|
135
|
+
// shell.web.dashboard → .shell-web-dashboard
|
|
136
|
+
const className = shell.id.replace(/\./g, '-');
|
|
137
|
+
css += `.${className} {\n`;
|
|
138
|
+
css += ` display: grid;\n`;
|
|
139
|
+
// Generate grid template areas based on regions
|
|
140
|
+
const areas = [];
|
|
141
|
+
const positions = new Map();
|
|
142
|
+
// Group regions by position
|
|
143
|
+
for (const region of shell.regions) {
|
|
144
|
+
const pos = region.position;
|
|
145
|
+
if (!positions.has(pos)) {
|
|
146
|
+
positions.set(pos, []);
|
|
147
|
+
}
|
|
148
|
+
positions.get(pos).push(region.name);
|
|
149
|
+
}
|
|
150
|
+
// Build grid template areas
|
|
151
|
+
// Example: "header header" "sidebar main"
|
|
152
|
+
if (positions.has('top')) {
|
|
153
|
+
const topRegions = positions.get('top');
|
|
154
|
+
areas.push(`"${topRegions.join(' ')}"`);
|
|
155
|
+
}
|
|
156
|
+
// Middle row with left, center, right
|
|
157
|
+
const middleRow = [];
|
|
158
|
+
if (positions.has('left')) {
|
|
159
|
+
middleRow.push(...positions.get('left'));
|
|
160
|
+
}
|
|
161
|
+
if (positions.has('center')) {
|
|
162
|
+
middleRow.push(...positions.get('center'));
|
|
163
|
+
}
|
|
164
|
+
if (positions.has('right')) {
|
|
165
|
+
middleRow.push(...positions.get('right'));
|
|
166
|
+
}
|
|
167
|
+
if (middleRow.length > 0) {
|
|
168
|
+
areas.push(`"${middleRow.join(' ')}"`);
|
|
169
|
+
}
|
|
170
|
+
if (positions.has('bottom')) {
|
|
171
|
+
const bottomRegions = positions.get('bottom');
|
|
172
|
+
areas.push(`"${bottomRegions.join(' ')}"`);
|
|
173
|
+
}
|
|
174
|
+
if (areas.length > 0) {
|
|
175
|
+
css += ` grid-template-areas:\n`;
|
|
176
|
+
for (const area of areas) {
|
|
177
|
+
css += ` ${area}\n`;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
css += `}\n\n`;
|
|
181
|
+
}
|
|
182
|
+
return css;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Generate utility classes for page tokens
|
|
186
|
+
*
|
|
187
|
+
* @param pages - Array of page layout tokens
|
|
188
|
+
* @returns CSS classes for pages
|
|
189
|
+
*/
|
|
190
|
+
export function generatePageClasses(pages) {
|
|
191
|
+
let css = '';
|
|
192
|
+
for (const page of pages) {
|
|
193
|
+
// Generate class name: .page-{name}
|
|
194
|
+
// page.dashboard → .page-dashboard
|
|
195
|
+
const className = page.id.replace(/\./g, '-');
|
|
196
|
+
css += `.${className} {\n`;
|
|
197
|
+
css += ` display: flex;\n`;
|
|
198
|
+
css += ` flex-direction: column;\n`;
|
|
199
|
+
// Add gap if specified in tokenBindings
|
|
200
|
+
if (page.tokenBindings.sectionSpacing) {
|
|
201
|
+
const gapVar = tokenRefToVar(page.tokenBindings.sectionSpacing);
|
|
202
|
+
css += ` gap: ${gapVar};\n`;
|
|
203
|
+
}
|
|
204
|
+
css += `}\n\n`;
|
|
205
|
+
}
|
|
206
|
+
return css;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Generate utility classes for section pattern tokens
|
|
210
|
+
*
|
|
211
|
+
* @param sections - Array of section pattern tokens
|
|
212
|
+
* @returns CSS classes for sections
|
|
213
|
+
*/
|
|
214
|
+
export function generateSectionClasses(sections) {
|
|
215
|
+
let css = '';
|
|
216
|
+
for (const section of sections) {
|
|
217
|
+
// Generate class name: .section-{pattern}
|
|
218
|
+
// section.grid-3 → .section-grid-3
|
|
219
|
+
const className = section.id.replace(/\./g, '-');
|
|
220
|
+
css += `.${className} {\n`;
|
|
221
|
+
// Add CSS properties from section.css
|
|
222
|
+
const sectionCSS = section.css;
|
|
223
|
+
if (sectionCSS.display) {
|
|
224
|
+
css += ` display: ${sectionCSS.display};\n`;
|
|
225
|
+
}
|
|
226
|
+
if (sectionCSS.gridTemplateColumns) {
|
|
227
|
+
css += ` grid-template-columns: ${sectionCSS.gridTemplateColumns};\n`;
|
|
228
|
+
}
|
|
229
|
+
if (sectionCSS.gridTemplateRows) {
|
|
230
|
+
css += ` grid-template-rows: ${sectionCSS.gridTemplateRows};\n`;
|
|
231
|
+
}
|
|
232
|
+
if (sectionCSS.gap) {
|
|
233
|
+
const gapValue = tokenRefToVar(sectionCSS.gap);
|
|
234
|
+
css += ` gap: ${gapValue};\n`;
|
|
235
|
+
}
|
|
236
|
+
if (sectionCSS.flexDirection) {
|
|
237
|
+
css += ` flex-direction: ${sectionCSS.flexDirection};\n`;
|
|
238
|
+
}
|
|
239
|
+
if (sectionCSS.alignItems) {
|
|
240
|
+
css += ` align-items: ${sectionCSS.alignItems};\n`;
|
|
241
|
+
}
|
|
242
|
+
if (sectionCSS.justifyContent) {
|
|
243
|
+
css += ` justify-content: ${sectionCSS.justifyContent};\n`;
|
|
244
|
+
}
|
|
245
|
+
if (sectionCSS.maxWidth) {
|
|
246
|
+
const maxWidthValue = tokenRefToVar(sectionCSS.maxWidth);
|
|
247
|
+
css += ` max-width: ${maxWidthValue};\n`;
|
|
248
|
+
}
|
|
249
|
+
if (sectionCSS.padding) {
|
|
250
|
+
const paddingValue = tokenRefToVar(sectionCSS.padding);
|
|
251
|
+
css += ` padding: ${paddingValue};\n`;
|
|
252
|
+
}
|
|
253
|
+
css += `}\n\n`;
|
|
254
|
+
}
|
|
255
|
+
return css;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Check if a token is an advanced section pattern
|
|
259
|
+
*
|
|
260
|
+
* @param token - Token to check
|
|
261
|
+
* @returns true if the token is an advanced section pattern (masonry, sticky, collapsible)
|
|
262
|
+
*/
|
|
263
|
+
function isAdvancedSectionToken(token) {
|
|
264
|
+
if (!('type' in token)) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
const advancedTypes = ['masonry', 'sticky', 'collapsible'];
|
|
268
|
+
return advancedTypes.includes(token.type);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Generate utility classes for advanced section pattern tokens
|
|
272
|
+
* Handles masonry, sticky, and collapsible patterns
|
|
273
|
+
*
|
|
274
|
+
* @param sections - Array of advanced section pattern tokens
|
|
275
|
+
* @returns CSS classes for advanced sections
|
|
276
|
+
*/
|
|
277
|
+
export function generateAdvancedSectionClasses(sections) {
|
|
278
|
+
let css = '';
|
|
279
|
+
for (const section of sections) {
|
|
280
|
+
// Generate class name: .section-{pattern}
|
|
281
|
+
// section.masonry → .section-masonry
|
|
282
|
+
const className = section.id.replace(/\./g, '-');
|
|
283
|
+
css += `.${className} {\n`;
|
|
284
|
+
const sectionCSS = section.css;
|
|
285
|
+
// Handle based on section type
|
|
286
|
+
if (section.type === 'masonry') {
|
|
287
|
+
const masonryCSS = sectionCSS;
|
|
288
|
+
// Masonry-specific properties
|
|
289
|
+
if (masonryCSS.columnCount) {
|
|
290
|
+
css += ` column-count: ${masonryCSS.columnCount};\n`;
|
|
291
|
+
}
|
|
292
|
+
if (masonryCSS.columnGap) {
|
|
293
|
+
const columnGapValue = tokenRefToVar(masonryCSS.columnGap);
|
|
294
|
+
css += ` column-gap: ${columnGapValue};\n`;
|
|
295
|
+
}
|
|
296
|
+
if (masonryCSS.breakInside) {
|
|
297
|
+
css += ` break-inside: ${masonryCSS.breakInside};\n`;
|
|
298
|
+
}
|
|
299
|
+
if (masonryCSS.columnFill) {
|
|
300
|
+
css += ` column-fill: ${masonryCSS.columnFill};\n`;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else if (section.type === 'sticky') {
|
|
304
|
+
const stickyCSS = sectionCSS;
|
|
305
|
+
// Common flex properties first
|
|
306
|
+
if (stickyCSS.display) {
|
|
307
|
+
css += ` display: ${stickyCSS.display};\n`;
|
|
308
|
+
}
|
|
309
|
+
if (stickyCSS.flexDirection) {
|
|
310
|
+
css += ` flex-direction: ${stickyCSS.flexDirection};\n`;
|
|
311
|
+
}
|
|
312
|
+
if (stickyCSS.alignItems) {
|
|
313
|
+
css += ` align-items: ${stickyCSS.alignItems};\n`;
|
|
314
|
+
}
|
|
315
|
+
if (stickyCSS.justifyContent) {
|
|
316
|
+
css += ` justify-content: ${stickyCSS.justifyContent};\n`;
|
|
317
|
+
}
|
|
318
|
+
if (stickyCSS.gap) {
|
|
319
|
+
const gapValue = tokenRefToVar(stickyCSS.gap);
|
|
320
|
+
css += ` gap: ${gapValue};\n`;
|
|
321
|
+
}
|
|
322
|
+
// Sticky-specific properties
|
|
323
|
+
if (stickyCSS.position) {
|
|
324
|
+
css += ` position: ${stickyCSS.position};\n`;
|
|
325
|
+
}
|
|
326
|
+
if (stickyCSS.top) {
|
|
327
|
+
const topValue = tokenRefToVar(stickyCSS.top);
|
|
328
|
+
css += ` top: ${topValue};\n`;
|
|
329
|
+
}
|
|
330
|
+
if (stickyCSS.bottom) {
|
|
331
|
+
const bottomValue = tokenRefToVar(stickyCSS.bottom);
|
|
332
|
+
css += ` bottom: ${bottomValue};\n`;
|
|
333
|
+
}
|
|
334
|
+
if (stickyCSS.zIndex !== undefined) {
|
|
335
|
+
css += ` z-index: ${stickyCSS.zIndex};\n`;
|
|
336
|
+
}
|
|
337
|
+
if (stickyCSS.padding) {
|
|
338
|
+
const paddingValue = tokenRefToVar(stickyCSS.padding);
|
|
339
|
+
css += ` padding: ${paddingValue};\n`;
|
|
340
|
+
}
|
|
341
|
+
if (stickyCSS.backgroundColor) {
|
|
342
|
+
const bgValue = tokenRefToVar(stickyCSS.backgroundColor);
|
|
343
|
+
css += ` background-color: ${bgValue};\n`;
|
|
344
|
+
}
|
|
345
|
+
if (stickyCSS.boxShadow) {
|
|
346
|
+
const shadowValue = tokenRefToVar(stickyCSS.boxShadow);
|
|
347
|
+
css += ` box-shadow: ${shadowValue};\n`;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
else if (section.type === 'collapsible') {
|
|
351
|
+
const collapsibleCSS = sectionCSS;
|
|
352
|
+
// Common flex properties first
|
|
353
|
+
if (collapsibleCSS.display) {
|
|
354
|
+
css += ` display: ${collapsibleCSS.display};\n`;
|
|
355
|
+
}
|
|
356
|
+
if (collapsibleCSS.flexDirection) {
|
|
357
|
+
css += ` flex-direction: ${collapsibleCSS.flexDirection};\n`;
|
|
358
|
+
}
|
|
359
|
+
// Collapsible-specific properties
|
|
360
|
+
if (collapsibleCSS.width) {
|
|
361
|
+
const widthValue = tokenRefToVar(collapsibleCSS.width);
|
|
362
|
+
css += ` width: ${widthValue};\n`;
|
|
363
|
+
}
|
|
364
|
+
if (collapsibleCSS.minWidth) {
|
|
365
|
+
const minWidthValue = tokenRefToVar(collapsibleCSS.minWidth);
|
|
366
|
+
css += ` min-width: ${minWidthValue};\n`;
|
|
367
|
+
}
|
|
368
|
+
if (collapsibleCSS.transition) {
|
|
369
|
+
css += ` transition: ${collapsibleCSS.transition};\n`;
|
|
370
|
+
}
|
|
371
|
+
if (collapsibleCSS.overflow) {
|
|
372
|
+
css += ` overflow: ${collapsibleCSS.overflow};\n`;
|
|
373
|
+
}
|
|
374
|
+
if (collapsibleCSS.willChange) {
|
|
375
|
+
css += ` will-change: ${collapsibleCSS.willChange};\n`;
|
|
376
|
+
}
|
|
377
|
+
if (collapsibleCSS.padding) {
|
|
378
|
+
const paddingValue = tokenRefToVar(collapsibleCSS.padding);
|
|
379
|
+
css += ` padding: ${paddingValue};\n`;
|
|
380
|
+
}
|
|
381
|
+
if (collapsibleCSS.gap) {
|
|
382
|
+
const gapValue = tokenRefToVar(collapsibleCSS.gap);
|
|
383
|
+
css += ` gap: ${gapValue};\n`;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
css += `}\n\n`;
|
|
387
|
+
}
|
|
388
|
+
return css;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Generate state classes for interactive advanced section patterns
|
|
392
|
+
* Handles stuck states for sticky patterns and collapsed states for collapsible patterns
|
|
393
|
+
*
|
|
394
|
+
* @param sections - Array of advanced section pattern tokens
|
|
395
|
+
* @returns CSS state classes for advanced sections
|
|
396
|
+
*/
|
|
397
|
+
export function generateAdvancedSectionStateClasses(sections) {
|
|
398
|
+
let css = '';
|
|
399
|
+
for (const section of sections) {
|
|
400
|
+
if (!section.states) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const className = section.id.replace(/\./g, '-');
|
|
404
|
+
// Generate stuck state for sticky patterns
|
|
405
|
+
if (section.states.stuck) {
|
|
406
|
+
css += `.${className}.is-stuck {\n`;
|
|
407
|
+
const stuckCSS = section.states.stuck;
|
|
408
|
+
if (stuckCSS.boxShadow) {
|
|
409
|
+
const shadowValue = tokenRefToVar(stuckCSS.boxShadow);
|
|
410
|
+
css += ` box-shadow: ${shadowValue};\n`;
|
|
411
|
+
}
|
|
412
|
+
if (stuckCSS.backgroundColor) {
|
|
413
|
+
const bgValue = tokenRefToVar(stuckCSS.backgroundColor);
|
|
414
|
+
css += ` background-color: ${bgValue};\n`;
|
|
415
|
+
}
|
|
416
|
+
if (stuckCSS.zIndex !== undefined) {
|
|
417
|
+
css += ` z-index: ${stuckCSS.zIndex};\n`;
|
|
418
|
+
}
|
|
419
|
+
css += `}\n\n`;
|
|
420
|
+
}
|
|
421
|
+
// Generate collapsed state for collapsible patterns
|
|
422
|
+
if (section.states.collapsed) {
|
|
423
|
+
css += `.${className}.is-collapsed {\n`;
|
|
424
|
+
const collapsedCSS = section.states.collapsed;
|
|
425
|
+
if (collapsedCSS.width) {
|
|
426
|
+
const widthValue = tokenRefToVar(collapsedCSS.width);
|
|
427
|
+
css += ` width: ${widthValue};\n`;
|
|
428
|
+
}
|
|
429
|
+
if (collapsedCSS.minWidth) {
|
|
430
|
+
const minWidthValue = tokenRefToVar(collapsedCSS.minWidth);
|
|
431
|
+
css += ` min-width: ${minWidthValue};\n`;
|
|
432
|
+
}
|
|
433
|
+
if (collapsedCSS.overflow) {
|
|
434
|
+
css += ` overflow: ${collapsedCSS.overflow};\n`;
|
|
435
|
+
}
|
|
436
|
+
if (collapsedCSS.padding) {
|
|
437
|
+
const paddingValue = tokenRefToVar(collapsedCSS.padding);
|
|
438
|
+
css += ` padding: ${paddingValue};\n`;
|
|
439
|
+
}
|
|
440
|
+
css += `}\n\n`;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return css;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Generate media query CSS for advanced section patterns
|
|
447
|
+
* Internal helper function for generateMediaQueries
|
|
448
|
+
*
|
|
449
|
+
* @param className - CSS class name for the section
|
|
450
|
+
* @param type - Section type ('masonry', 'sticky', 'collapsible')
|
|
451
|
+
* @param responsiveConfig - Responsive configuration for this breakpoint
|
|
452
|
+
* @returns CSS string for the media query content
|
|
453
|
+
*/
|
|
454
|
+
function generateAdvancedSectionMediaQueryCSS(className, type, responsiveConfig) {
|
|
455
|
+
let css = '';
|
|
456
|
+
if (!responsiveConfig || Object.keys(responsiveConfig).length === 0) {
|
|
457
|
+
return css;
|
|
458
|
+
}
|
|
459
|
+
css += ` .${className} {\n`;
|
|
460
|
+
if (type === 'masonry') {
|
|
461
|
+
const masonryConfig = responsiveConfig;
|
|
462
|
+
if (masonryConfig.columnCount) {
|
|
463
|
+
css += ` column-count: ${masonryConfig.columnCount};\n`;
|
|
464
|
+
}
|
|
465
|
+
if (masonryConfig.columnGap) {
|
|
466
|
+
const columnGapValue = tokenRefToVar(masonryConfig.columnGap);
|
|
467
|
+
css += ` column-gap: ${columnGapValue};\n`;
|
|
468
|
+
}
|
|
469
|
+
if (masonryConfig.breakInside) {
|
|
470
|
+
css += ` break-inside: ${masonryConfig.breakInside};\n`;
|
|
471
|
+
}
|
|
472
|
+
if (masonryConfig.columnFill) {
|
|
473
|
+
css += ` column-fill: ${masonryConfig.columnFill};\n`;
|
|
474
|
+
}
|
|
475
|
+
// Common section properties
|
|
476
|
+
if (masonryConfig.display) {
|
|
477
|
+
css += ` display: ${masonryConfig.display};\n`;
|
|
478
|
+
}
|
|
479
|
+
if (masonryConfig.gap) {
|
|
480
|
+
const gapValue = tokenRefToVar(masonryConfig.gap);
|
|
481
|
+
css += ` gap: ${gapValue};\n`;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
else if (type === 'sticky') {
|
|
485
|
+
const stickyConfig = responsiveConfig;
|
|
486
|
+
if (stickyConfig.display) {
|
|
487
|
+
css += ` display: ${stickyConfig.display};\n`;
|
|
488
|
+
}
|
|
489
|
+
if (stickyConfig.flexDirection) {
|
|
490
|
+
css += ` flex-direction: ${stickyConfig.flexDirection};\n`;
|
|
491
|
+
}
|
|
492
|
+
if (stickyConfig.alignItems) {
|
|
493
|
+
css += ` align-items: ${stickyConfig.alignItems};\n`;
|
|
494
|
+
}
|
|
495
|
+
if (stickyConfig.justifyContent) {
|
|
496
|
+
css += ` justify-content: ${stickyConfig.justifyContent};\n`;
|
|
497
|
+
}
|
|
498
|
+
if (stickyConfig.gap) {
|
|
499
|
+
const gapValue = tokenRefToVar(stickyConfig.gap);
|
|
500
|
+
css += ` gap: ${gapValue};\n`;
|
|
501
|
+
}
|
|
502
|
+
if (stickyConfig.position) {
|
|
503
|
+
css += ` position: ${stickyConfig.position};\n`;
|
|
504
|
+
}
|
|
505
|
+
if (stickyConfig.top) {
|
|
506
|
+
const topValue = tokenRefToVar(stickyConfig.top);
|
|
507
|
+
css += ` top: ${topValue};\n`;
|
|
508
|
+
}
|
|
509
|
+
if (stickyConfig.bottom) {
|
|
510
|
+
const bottomValue = tokenRefToVar(stickyConfig.bottom);
|
|
511
|
+
css += ` bottom: ${bottomValue};\n`;
|
|
512
|
+
}
|
|
513
|
+
if (stickyConfig.zIndex !== undefined) {
|
|
514
|
+
css += ` z-index: ${stickyConfig.zIndex};\n`;
|
|
515
|
+
}
|
|
516
|
+
if (stickyConfig.padding) {
|
|
517
|
+
const paddingValue = tokenRefToVar(stickyConfig.padding);
|
|
518
|
+
css += ` padding: ${paddingValue};\n`;
|
|
519
|
+
}
|
|
520
|
+
if (stickyConfig.backgroundColor) {
|
|
521
|
+
const bgValue = tokenRefToVar(stickyConfig.backgroundColor);
|
|
522
|
+
css += ` background-color: ${bgValue};\n`;
|
|
523
|
+
}
|
|
524
|
+
if (stickyConfig.boxShadow) {
|
|
525
|
+
const shadowValue = tokenRefToVar(stickyConfig.boxShadow);
|
|
526
|
+
css += ` box-shadow: ${shadowValue};\n`;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
else if (type === 'collapsible') {
|
|
530
|
+
const collapsibleConfig = responsiveConfig;
|
|
531
|
+
if (collapsibleConfig.display) {
|
|
532
|
+
css += ` display: ${collapsibleConfig.display};\n`;
|
|
533
|
+
}
|
|
534
|
+
if (collapsibleConfig.flexDirection) {
|
|
535
|
+
css += ` flex-direction: ${collapsibleConfig.flexDirection};\n`;
|
|
536
|
+
}
|
|
537
|
+
if (collapsibleConfig.width) {
|
|
538
|
+
const widthValue = tokenRefToVar(collapsibleConfig.width);
|
|
539
|
+
css += ` width: ${widthValue};\n`;
|
|
540
|
+
}
|
|
541
|
+
if (collapsibleConfig.minWidth) {
|
|
542
|
+
const minWidthValue = tokenRefToVar(collapsibleConfig.minWidth);
|
|
543
|
+
css += ` min-width: ${minWidthValue};\n`;
|
|
544
|
+
}
|
|
545
|
+
if (collapsibleConfig.transition) {
|
|
546
|
+
css += ` transition: ${collapsibleConfig.transition};\n`;
|
|
547
|
+
}
|
|
548
|
+
if (collapsibleConfig.overflow) {
|
|
549
|
+
css += ` overflow: ${collapsibleConfig.overflow};\n`;
|
|
550
|
+
}
|
|
551
|
+
if (collapsibleConfig.willChange) {
|
|
552
|
+
css += ` will-change: ${collapsibleConfig.willChange};\n`;
|
|
553
|
+
}
|
|
554
|
+
if (collapsibleConfig.padding) {
|
|
555
|
+
const paddingValue = tokenRefToVar(collapsibleConfig.padding);
|
|
556
|
+
css += ` padding: ${paddingValue};\n`;
|
|
557
|
+
}
|
|
558
|
+
if (collapsibleConfig.gap) {
|
|
559
|
+
const gapValue = tokenRefToVar(collapsibleConfig.gap);
|
|
560
|
+
css += ` gap: ${gapValue};\n`;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
css += ` }\n\n`;
|
|
564
|
+
return css;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Generate responsive media queries for all breakpoints
|
|
568
|
+
*
|
|
569
|
+
* @param tokens - Array of layout tokens
|
|
570
|
+
* @returns CSS media queries
|
|
571
|
+
*/
|
|
572
|
+
export function generateMediaQueries(tokens) {
|
|
573
|
+
let css = '';
|
|
574
|
+
// Breakpoint names in order
|
|
575
|
+
const breakpoints = ['sm', 'md', 'lg', 'xl', '2xl'];
|
|
576
|
+
for (const bp of breakpoints) {
|
|
577
|
+
const minWidth = BREAKPOINT_VALUES[bp];
|
|
578
|
+
let mediaQueryContent = '';
|
|
579
|
+
// Process each token
|
|
580
|
+
for (const token of tokens) {
|
|
581
|
+
// Get responsive config for this breakpoint
|
|
582
|
+
const responsiveConfig = token.responsive[bp];
|
|
583
|
+
if (!responsiveConfig || Object.keys(responsiveConfig).length === 0) {
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
// Generate class name based on token type
|
|
587
|
+
let className = '';
|
|
588
|
+
if ('platform' in token) {
|
|
589
|
+
// ShellToken
|
|
590
|
+
className = token.id.replace(/\./g, '-');
|
|
591
|
+
}
|
|
592
|
+
else if ('purpose' in token) {
|
|
593
|
+
// PageLayoutToken
|
|
594
|
+
className = token.id.replace(/\./g, '-');
|
|
595
|
+
}
|
|
596
|
+
else if ('type' in token) {
|
|
597
|
+
// SectionPatternToken or AdvancedSectionPatternToken
|
|
598
|
+
const sectionToken = token;
|
|
599
|
+
className = sectionToken.id.replace(/\./g, '-');
|
|
600
|
+
// Check if this is an advanced section pattern
|
|
601
|
+
if (isAdvancedSectionToken(token)) {
|
|
602
|
+
const advancedToken = token;
|
|
603
|
+
mediaQueryContent += generateAdvancedSectionMediaQueryCSS(className, advancedToken.type, responsiveConfig);
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
// Generate standard section CSS for this breakpoint
|
|
607
|
+
const responsiveCss = responsiveConfig;
|
|
608
|
+
if (Object.keys(responsiveCss).length > 0) {
|
|
609
|
+
mediaQueryContent += ` .${className} {\n`;
|
|
610
|
+
if (responsiveCss.display) {
|
|
611
|
+
mediaQueryContent += ` display: ${responsiveCss.display};\n`;
|
|
612
|
+
}
|
|
613
|
+
if (responsiveCss.gridTemplateColumns) {
|
|
614
|
+
mediaQueryContent += ` grid-template-columns: ${responsiveCss.gridTemplateColumns};\n`;
|
|
615
|
+
}
|
|
616
|
+
if (responsiveCss.gridTemplateRows) {
|
|
617
|
+
mediaQueryContent += ` grid-template-rows: ${responsiveCss.gridTemplateRows};\n`;
|
|
618
|
+
}
|
|
619
|
+
if (responsiveCss.gap) {
|
|
620
|
+
const gapValue = tokenRefToVar(responsiveCss.gap);
|
|
621
|
+
mediaQueryContent += ` gap: ${gapValue};\n`;
|
|
622
|
+
}
|
|
623
|
+
if (responsiveCss.flexDirection) {
|
|
624
|
+
mediaQueryContent += ` flex-direction: ${responsiveCss.flexDirection};\n`;
|
|
625
|
+
}
|
|
626
|
+
if (responsiveCss.alignItems) {
|
|
627
|
+
mediaQueryContent += ` align-items: ${responsiveCss.alignItems};\n`;
|
|
628
|
+
}
|
|
629
|
+
if (responsiveCss.justifyContent) {
|
|
630
|
+
mediaQueryContent += ` justify-content: ${responsiveCss.justifyContent};\n`;
|
|
631
|
+
}
|
|
632
|
+
if (responsiveCss.maxWidth) {
|
|
633
|
+
const maxWidthValue = tokenRefToVar(responsiveCss.maxWidth);
|
|
634
|
+
mediaQueryContent += ` max-width: ${maxWidthValue};\n`;
|
|
635
|
+
}
|
|
636
|
+
if (responsiveCss.padding) {
|
|
637
|
+
const paddingValue = tokenRefToVar(responsiveCss.padding);
|
|
638
|
+
mediaQueryContent += ` padding: ${paddingValue};\n`;
|
|
639
|
+
}
|
|
640
|
+
mediaQueryContent += ` }\n\n`;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
// Only add media query if there's content
|
|
646
|
+
if (mediaQueryContent.trim().length > 0) {
|
|
647
|
+
css += `@media (min-width: ${minWidth}px) {\n`;
|
|
648
|
+
css += mediaQueryContent;
|
|
649
|
+
css += `}\n\n`;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return css;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Generate complete CSS from layout tokens
|
|
656
|
+
*
|
|
657
|
+
* @param tokens - Array of layout tokens (shells, pages, sections)
|
|
658
|
+
* @param options - CSS generation options
|
|
659
|
+
* @returns Complete CSS string with variables, utilities, and media queries
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```typescript
|
|
663
|
+
* import { getAllShellTokens, getAllPageLayoutTokens, getAllSectionPatternTokens } from './layout-tokens/index.js';
|
|
664
|
+
*
|
|
665
|
+
* const shells = getAllShellTokens();
|
|
666
|
+
* const pages = getAllPageLayoutTokens();
|
|
667
|
+
* const sections = getAllSectionPatternTokens();
|
|
668
|
+
*
|
|
669
|
+
* const css = generateLayoutCSS([...shells, ...pages, ...sections]);
|
|
670
|
+
* console.log(css);
|
|
671
|
+
* ```
|
|
672
|
+
*/
|
|
673
|
+
export function generateLayoutCSS(tokens, options = {}) {
|
|
674
|
+
const { includeVariables = true, includeClasses = true, includeMediaQueries = true, indent = ' ', } = options;
|
|
675
|
+
let css = '';
|
|
676
|
+
// Separate tokens by type
|
|
677
|
+
const shells = tokens.filter(t => 'platform' in t);
|
|
678
|
+
const pages = tokens.filter(t => 'purpose' in t);
|
|
679
|
+
// Separate standard sections from advanced sections
|
|
680
|
+
const allSections = tokens.filter(t => 'type' in t);
|
|
681
|
+
const advancedTypes = ['masonry', 'sticky', 'collapsible'];
|
|
682
|
+
const standardSections = allSections.filter(t => !advancedTypes.includes(t.type));
|
|
683
|
+
const advancedSections = allSections.filter(t => advancedTypes.includes(t.type));
|
|
684
|
+
// 1. Generate CSS variables
|
|
685
|
+
if (includeVariables) {
|
|
686
|
+
const variablesCSS = generateCSSVariables(tokens);
|
|
687
|
+
if (variablesCSS) {
|
|
688
|
+
css += variablesCSS + '\n';
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
// 2. Generate utility classes
|
|
692
|
+
if (includeClasses) {
|
|
693
|
+
// Shell classes
|
|
694
|
+
if (shells.length > 0) {
|
|
695
|
+
const shellCSS = generateShellClasses(shells);
|
|
696
|
+
if (shellCSS) {
|
|
697
|
+
css += shellCSS;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
// Page classes
|
|
701
|
+
if (pages.length > 0) {
|
|
702
|
+
const pageCSS = generatePageClasses(pages);
|
|
703
|
+
if (pageCSS) {
|
|
704
|
+
css += pageCSS;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
// Standard section classes
|
|
708
|
+
if (standardSections.length > 0) {
|
|
709
|
+
const sectionCSS = generateSectionClasses(standardSections);
|
|
710
|
+
if (sectionCSS) {
|
|
711
|
+
css += sectionCSS;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
// Advanced section classes (masonry, sticky, collapsible)
|
|
715
|
+
if (advancedSections.length > 0) {
|
|
716
|
+
const advancedCSS = generateAdvancedSectionClasses(advancedSections);
|
|
717
|
+
if (advancedCSS) {
|
|
718
|
+
css += advancedCSS;
|
|
719
|
+
}
|
|
720
|
+
// Generate state classes for interactive patterns
|
|
721
|
+
const stateCSS = generateAdvancedSectionStateClasses(advancedSections);
|
|
722
|
+
if (stateCSS) {
|
|
723
|
+
css += stateCSS;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
// 3. Generate responsive media queries (only if includeClasses is true)
|
|
728
|
+
if (includeMediaQueries && includeClasses) {
|
|
729
|
+
const mediaCSS = generateMediaQueries(tokens);
|
|
730
|
+
if (mediaCSS) {
|
|
731
|
+
css += mediaCSS;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
// 4. Format CSS with proper indentation
|
|
735
|
+
const formatted = formatCSS(css, indent);
|
|
736
|
+
// 5. Validate CSS syntax
|
|
737
|
+
if (!validateCSS(formatted)) {
|
|
738
|
+
throw new Error('Generated CSS has unbalanced braces');
|
|
739
|
+
}
|
|
740
|
+
return formatted;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Generate CSS for all layout tokens in the system
|
|
744
|
+
*
|
|
745
|
+
* @param options - CSS generation options
|
|
746
|
+
* @returns Complete CSS for all shells, pages, and sections
|
|
747
|
+
*
|
|
748
|
+
* @example
|
|
749
|
+
* ```typescript
|
|
750
|
+
* const css = generateAllLayoutCSS();
|
|
751
|
+
* // Write to file or use in application
|
|
752
|
+
* ```
|
|
753
|
+
*/
|
|
754
|
+
export function generateAllLayoutCSS(options = {}) {
|
|
755
|
+
const shells = getAllShellTokens();
|
|
756
|
+
const pages = getAllPageLayoutTokens();
|
|
757
|
+
const sections = getAllSectionPatternTokens();
|
|
758
|
+
const advancedSections = getAllAdvancedSectionPatternTokens();
|
|
759
|
+
return generateLayoutCSS([...shells, ...pages, ...sections, ...advancedSections], options);
|
|
760
|
+
}
|
|
761
|
+
// ============================================================================
|
|
762
|
+
// Container Query CSS Generation (SPEC-LAYOUT-003 Phase 3)
|
|
763
|
+
// ============================================================================
|
|
764
|
+
/**
|
|
765
|
+
* Generate CSS container queries with browser fallback
|
|
766
|
+
* Uses @supports for progressive enhancement
|
|
767
|
+
*
|
|
768
|
+
* @param config - Container query configuration
|
|
769
|
+
* @returns CSS string with container queries and fallback
|
|
770
|
+
*/
|
|
771
|
+
export function generateContainerQueryCSS(config) {
|
|
772
|
+
const rules = [];
|
|
773
|
+
// Container definition
|
|
774
|
+
rules.push(` container-type: ${config.type};`);
|
|
775
|
+
rules.push(` container-name: ${config.name};`);
|
|
776
|
+
// Container query rules with @supports progressive enhancement
|
|
777
|
+
const queryRules = [];
|
|
778
|
+
for (const [_bp, bpConfig] of Object.entries(config.breakpoints)) {
|
|
779
|
+
if (bpConfig) {
|
|
780
|
+
const cssProps = Object.entries(bpConfig.css)
|
|
781
|
+
.map(([prop, value]) => ` ${prop}: ${value};`)
|
|
782
|
+
.join('\n');
|
|
783
|
+
queryRules.push(`
|
|
784
|
+
@container ${config.name} (min-width: ${bpConfig.minWidth}px) {
|
|
785
|
+
${cssProps}
|
|
786
|
+
}`);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
// Wrap in @supports for browser compatibility
|
|
790
|
+
if (queryRules.length > 0) {
|
|
791
|
+
rules.push(`
|
|
792
|
+
@supports (container-type: inline-size) {
|
|
793
|
+
${queryRules.join('\n')}
|
|
794
|
+
}`);
|
|
795
|
+
}
|
|
796
|
+
return rules.join('\n');
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Generate fallback CSS for browsers without container query support
|
|
800
|
+
* Uses viewport-based media queries as fallback
|
|
801
|
+
*
|
|
802
|
+
* @param config - Container query configuration
|
|
803
|
+
* @returns CSS string with media query fallbacks
|
|
804
|
+
*/
|
|
805
|
+
export function generateContainerQueryFallback(config) {
|
|
806
|
+
const fallbackRules = [];
|
|
807
|
+
// Map container breakpoints to approximate viewport breakpoints
|
|
808
|
+
const breakpointMapping = {
|
|
809
|
+
sm: 640,
|
|
810
|
+
md: 768,
|
|
811
|
+
lg: 1024,
|
|
812
|
+
xl: 1280,
|
|
813
|
+
};
|
|
814
|
+
for (const [bp, bpConfig] of Object.entries(config.breakpoints)) {
|
|
815
|
+
if (bpConfig) {
|
|
816
|
+
const viewportWidth = breakpointMapping[bp] || bpConfig.minWidth * 2;
|
|
817
|
+
const cssProps = Object.entries(bpConfig.css)
|
|
818
|
+
.map(([prop, value]) => ` ${prop}: ${value};`)
|
|
819
|
+
.join('\n');
|
|
820
|
+
fallbackRules.push(`
|
|
821
|
+
@supports not (container-type: inline-size) {
|
|
822
|
+
@media (min-width: ${viewportWidth}px) {
|
|
823
|
+
${cssProps}
|
|
824
|
+
}
|
|
825
|
+
}`);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return fallbackRules.join('\n');
|
|
829
|
+
}
|
|
830
|
+
// ============================================================================
|
|
831
|
+
// Orientation CSS Generation (SPEC-LAYOUT-003 Phase 3)
|
|
832
|
+
// ============================================================================
|
|
833
|
+
/**
|
|
834
|
+
* Generate orientation-specific CSS media queries
|
|
835
|
+
* Supports portrait (height >= width) and landscape (width > height)
|
|
836
|
+
*
|
|
837
|
+
* @param config - Orientation configuration
|
|
838
|
+
* @param cssGenerator - Function to convert config to CSS properties
|
|
839
|
+
* @returns CSS string with orientation media queries
|
|
840
|
+
*/
|
|
841
|
+
export function generateOrientationCSS(config, cssGenerator) {
|
|
842
|
+
const rules = [];
|
|
843
|
+
if (config.portrait) {
|
|
844
|
+
const portraitCSS = cssGenerator(config.portrait);
|
|
845
|
+
if (portraitCSS) {
|
|
846
|
+
rules.push(`
|
|
847
|
+
@media (orientation: portrait) {
|
|
848
|
+
${portraitCSS}
|
|
849
|
+
}`);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
if (config.landscape) {
|
|
853
|
+
const landscapeCSS = cssGenerator(config.landscape);
|
|
854
|
+
if (landscapeCSS) {
|
|
855
|
+
rules.push(`
|
|
856
|
+
@media (orientation: landscape) {
|
|
857
|
+
${landscapeCSS}
|
|
858
|
+
}`);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
return rules.join('\n');
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Generate complete responsive CSS with orientation support
|
|
865
|
+
* Combines viewport breakpoints, container queries, and orientation
|
|
866
|
+
*
|
|
867
|
+
* @param config - Full responsive configuration
|
|
868
|
+
* @param cssGenerator - Function to convert config to CSS properties
|
|
869
|
+
* @param containerConfig - Optional container query configuration
|
|
870
|
+
* @returns Complete CSS string
|
|
871
|
+
*/
|
|
872
|
+
export function generateAdvancedResponsiveCSS(config, cssGenerator, containerConfig) {
|
|
873
|
+
const sections = [];
|
|
874
|
+
// Base responsive CSS (viewport breakpoints)
|
|
875
|
+
sections.push(cssGenerator(config.default));
|
|
876
|
+
// Breakpoint overrides
|
|
877
|
+
const breakpoints = ['sm', 'md', 'lg', 'xl', '2xl'];
|
|
878
|
+
for (const bp of breakpoints) {
|
|
879
|
+
const override = config[bp];
|
|
880
|
+
if (override) {
|
|
881
|
+
const css = cssGenerator(override);
|
|
882
|
+
if (css) {
|
|
883
|
+
sections.push(`
|
|
884
|
+
@media (min-width: ${BREAKPOINT_VALUES[bp]}px) {
|
|
885
|
+
${css}
|
|
886
|
+
}`);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
// Container queries (if provided)
|
|
891
|
+
if (containerConfig) {
|
|
892
|
+
sections.push(generateContainerQueryCSS(containerConfig));
|
|
893
|
+
sections.push(generateContainerQueryFallback(containerConfig));
|
|
894
|
+
}
|
|
895
|
+
// Orientation overrides
|
|
896
|
+
if (config.orientation) {
|
|
897
|
+
sections.push(generateOrientationCSS(config.orientation, cssGenerator));
|
|
898
|
+
}
|
|
899
|
+
return sections.join('\n');
|
|
900
|
+
}
|
|
901
|
+
//# sourceMappingURL=layout-css-generator.js.map
|