@webmate-studio/builder 0.2.82 → 0.2.84
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/package.json +1 -1
- package/src/design-tokens.js +23 -15
- package/src/markdown.js +47 -2
package/package.json
CHANGED
package/src/design-tokens.js
CHANGED
|
@@ -7,6 +7,7 @@ function generateSemanticColorUtilities(tokens) {
|
|
|
7
7
|
if (!tokens.colors) return '';
|
|
8
8
|
|
|
9
9
|
let utilities = '\n/* Color Utilities */';
|
|
10
|
+
utilities += '\n@layer components {';
|
|
10
11
|
|
|
11
12
|
// Map of all colors: token name -> utility class base name
|
|
12
13
|
const colorMap = {
|
|
@@ -120,6 +121,8 @@ function generateSemanticColorUtilities(tokens) {
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
utilities += '\n}'; // Close @layer components
|
|
125
|
+
|
|
123
126
|
return utilities;
|
|
124
127
|
}
|
|
125
128
|
|
|
@@ -1091,9 +1094,11 @@ export function generateCSSFromTokens(tokens) {
|
|
|
1091
1094
|
lines.push('}');
|
|
1092
1095
|
|
|
1093
1096
|
// Generate utility classes for text styles
|
|
1097
|
+
// Wrap in @layer components so Tailwind utilities (@layer utilities) can override them
|
|
1094
1098
|
if (tokens.textStyles) {
|
|
1095
1099
|
lines.push('');
|
|
1096
1100
|
lines.push('/* Text Style Utilities */');
|
|
1101
|
+
lines.push('@layer components {');
|
|
1097
1102
|
for (const [styleName, style] of Object.entries(tokens.textStyles)) {
|
|
1098
1103
|
const kebabName = styleName
|
|
1099
1104
|
.replace(/([A-Z])/g, '-$1')
|
|
@@ -1102,35 +1107,36 @@ export function generateCSSFromTokens(tokens) {
|
|
|
1102
1107
|
.replace(/^-/, '');
|
|
1103
1108
|
const className = `text-${kebabName}`;
|
|
1104
1109
|
|
|
1105
|
-
lines.push(
|
|
1110
|
+
lines.push(` .${className} {`);
|
|
1106
1111
|
if (style.fontFamily) {
|
|
1107
1112
|
const fontVar = `--font-${style.fontFamily}`;
|
|
1108
|
-
lines.push(`
|
|
1113
|
+
lines.push(` font-family: var(${fontVar});`);
|
|
1109
1114
|
}
|
|
1110
1115
|
if (style.fontWeight) {
|
|
1111
|
-
lines.push(`
|
|
1116
|
+
lines.push(` font-weight: ${style.fontWeight};`);
|
|
1112
1117
|
}
|
|
1113
1118
|
if (style.fontSize) {
|
|
1114
1119
|
const fontSize = typeof style.fontSize === 'object' ? style.fontSize.base : style.fontSize;
|
|
1115
|
-
lines.push(`
|
|
1120
|
+
lines.push(` font-size: ${fontSize};`);
|
|
1116
1121
|
}
|
|
1117
1122
|
if (style.lineHeight) {
|
|
1118
1123
|
const lineHeight = typeof style.lineHeight === 'object' ? style.lineHeight.base : style.lineHeight;
|
|
1119
|
-
lines.push(`
|
|
1124
|
+
lines.push(` line-height: ${lineHeight};`);
|
|
1120
1125
|
}
|
|
1121
1126
|
if (style.letterSpacing) {
|
|
1122
1127
|
const letterSpacing = typeof style.letterSpacing === 'object' ? style.letterSpacing.base : style.letterSpacing;
|
|
1123
|
-
lines.push(`
|
|
1128
|
+
lines.push(` letter-spacing: ${letterSpacing};`);
|
|
1124
1129
|
}
|
|
1125
1130
|
if (style.textTransform) {
|
|
1126
|
-
lines.push(`
|
|
1131
|
+
lines.push(` text-transform: ${style.textTransform};`);
|
|
1127
1132
|
}
|
|
1128
1133
|
if (style.textColor) {
|
|
1129
1134
|
const colorVar = `--color-${style.textColor.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
|
|
1130
|
-
lines.push(`
|
|
1135
|
+
lines.push(` color: var(${colorVar});`);
|
|
1131
1136
|
}
|
|
1132
|
-
lines.push(
|
|
1137
|
+
lines.push(` }`);
|
|
1133
1138
|
}
|
|
1139
|
+
lines.push('}'); // Close @layer components
|
|
1134
1140
|
|
|
1135
1141
|
// Add responsive media queries for textStyles
|
|
1136
1142
|
const breakpointKeys = ['md', 'lg', 'xl', '2xl'];
|
|
@@ -1158,24 +1164,26 @@ export function generateCSSFromTokens(tokens) {
|
|
|
1158
1164
|
);
|
|
1159
1165
|
|
|
1160
1166
|
if (hasResponsive) {
|
|
1161
|
-
mediaQueryLines.push(`
|
|
1167
|
+
mediaQueryLines.push(` .${className} {`);
|
|
1162
1168
|
if (style.fontSize && typeof style.fontSize === 'object' && style.fontSize[bp]) {
|
|
1163
|
-
mediaQueryLines.push(`
|
|
1169
|
+
mediaQueryLines.push(` font-size: ${style.fontSize[bp]};`);
|
|
1164
1170
|
}
|
|
1165
1171
|
if (style.lineHeight && typeof style.lineHeight === 'object' && style.lineHeight[bp]) {
|
|
1166
|
-
mediaQueryLines.push(`
|
|
1172
|
+
mediaQueryLines.push(` line-height: ${style.lineHeight[bp]};`);
|
|
1167
1173
|
}
|
|
1168
1174
|
if (style.letterSpacing && typeof style.letterSpacing === 'object' && style.letterSpacing[bp]) {
|
|
1169
|
-
mediaQueryLines.push(`
|
|
1175
|
+
mediaQueryLines.push(` letter-spacing: ${style.letterSpacing[bp]};`);
|
|
1170
1176
|
}
|
|
1171
|
-
mediaQueryLines.push(`
|
|
1177
|
+
mediaQueryLines.push(` }`);
|
|
1172
1178
|
}
|
|
1173
1179
|
}
|
|
1174
1180
|
|
|
1175
1181
|
if (mediaQueryLines.length > 0) {
|
|
1176
1182
|
lines.push('');
|
|
1177
|
-
lines.push(`@
|
|
1183
|
+
lines.push(`@layer components {`);
|
|
1184
|
+
lines.push(` @media (min-width: ${breakpointValues[bp]}) {`);
|
|
1178
1185
|
lines.push(...mediaQueryLines);
|
|
1186
|
+
lines.push(` }`);
|
|
1179
1187
|
lines.push('}');
|
|
1180
1188
|
}
|
|
1181
1189
|
}
|
package/src/markdown.js
CHANGED
|
@@ -19,12 +19,44 @@ marked.setOptions({
|
|
|
19
19
|
mangle: false, // Email-Adressen nicht verschleiern
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Shift heading levels in HTML
|
|
24
|
+
* @param {string} html - HTML string
|
|
25
|
+
* @param {number} startLevel - The level that h1 should become (e.g., 2 means h1 → h2)
|
|
26
|
+
* @returns {string} HTML with shifted heading levels
|
|
27
|
+
*/
|
|
28
|
+
function shiftHeadingLevels(html, startLevel) {
|
|
29
|
+
if (!startLevel || startLevel === 1) return html;
|
|
30
|
+
|
|
31
|
+
const offset = startLevel - 1;
|
|
32
|
+
|
|
33
|
+
// Shift headings (h1 → h2, h2 → h3, etc.)
|
|
34
|
+
// We need to do this in reverse order to avoid double-shifting
|
|
35
|
+
for (let level = 6; level >= 1; level--) {
|
|
36
|
+
const newLevel = Math.min(level + offset, 6);
|
|
37
|
+
if (newLevel !== level) {
|
|
38
|
+
// Replace opening and closing tags
|
|
39
|
+
html = html.replace(
|
|
40
|
+
new RegExp(`<h${level}(\\s|>)`, 'gi'),
|
|
41
|
+
`<h${newLevel}$1`
|
|
42
|
+
);
|
|
43
|
+
html = html.replace(
|
|
44
|
+
new RegExp(`</h${level}>`, 'gi'),
|
|
45
|
+
`</h${newLevel}>`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return html;
|
|
51
|
+
}
|
|
52
|
+
|
|
22
53
|
/**
|
|
23
54
|
* Konvertiert Markdown zu sicherem HTML
|
|
24
55
|
*
|
|
25
56
|
* @param {string} markdown - Markdown-String
|
|
26
57
|
* @param {object} options - Optionale Konfiguration
|
|
27
58
|
* @param {boolean} options.sanitize - HTML sanitizen (default: true)
|
|
59
|
+
* @param {number} options.headingStartLevel - Start level for headings (1-6, default: 1)
|
|
28
60
|
* @returns {string} - Sicherer HTML-String
|
|
29
61
|
*/
|
|
30
62
|
export function markdownToHtml(markdown, options = {}) {
|
|
@@ -35,6 +67,11 @@ export function markdownToHtml(markdown, options = {}) {
|
|
|
35
67
|
// Markdown zu HTML
|
|
36
68
|
let html = marked.parse(markdown);
|
|
37
69
|
|
|
70
|
+
// Shift heading levels if requested
|
|
71
|
+
if (options.headingStartLevel) {
|
|
72
|
+
html = shiftHeadingLevels(html, options.headingStartLevel);
|
|
73
|
+
}
|
|
74
|
+
|
|
38
75
|
// XSS-Schutz mit DOMPurify
|
|
39
76
|
if (options.sanitize !== false) {
|
|
40
77
|
const config = {
|
|
@@ -66,9 +103,10 @@ export function markdownToHtml(markdown, options = {}) {
|
|
|
66
103
|
*
|
|
67
104
|
* @param {Object} props - Component props
|
|
68
105
|
* @param {Object} propSchema - Prop schema with format info (from component.json)
|
|
106
|
+
* @param {Object} componentMetadata - Component metadata (for headingStartLevel, etc.)
|
|
69
107
|
* @returns {Object} Props with markdown converted to HTML
|
|
70
108
|
*/
|
|
71
|
-
export function processMarkdownProps(props, propSchema = null) {
|
|
109
|
+
export function processMarkdownProps(props, propSchema = null, componentMetadata = null) {
|
|
72
110
|
if (!props || typeof props !== 'object') return props;
|
|
73
111
|
|
|
74
112
|
const processed = { ...props };
|
|
@@ -81,8 +119,15 @@ export function processMarkdownProps(props, propSchema = null) {
|
|
|
81
119
|
const isMarkdown = propSchema?.[key]?.format === 'markdown';
|
|
82
120
|
|
|
83
121
|
if (isMarkdown) {
|
|
122
|
+
const options = {};
|
|
123
|
+
|
|
124
|
+
// Apply headingStartLevel from component metadata
|
|
125
|
+
if (componentMetadata?.headingStartLevel) {
|
|
126
|
+
options.headingStartLevel = componentMetadata.headingStartLevel;
|
|
127
|
+
}
|
|
128
|
+
|
|
84
129
|
// Convert markdown to HTML
|
|
85
|
-
processed[key] = markdownToHtml(value);
|
|
130
|
+
processed[key] = markdownToHtml(value, options);
|
|
86
131
|
}
|
|
87
132
|
}
|
|
88
133
|
|