@vertz/ui 0.2.0 → 0.2.2
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 +339 -857
- package/dist/css/public.d.ts +24 -27
- package/dist/css/public.js +5 -1
- package/dist/form/public.d.ts +94 -38
- package/dist/form/public.js +5 -3
- package/dist/index.d.ts +754 -167
- package/dist/index.js +606 -84
- package/dist/internals.d.ts +192 -23
- package/dist/internals.js +151 -102
- package/dist/jsx-runtime/index.d.ts +44 -17
- package/dist/jsx-runtime/index.js +26 -7
- package/dist/query/public.d.ts +73 -7
- package/dist/query/public.js +12 -4
- package/dist/router/public.d.ts +199 -26
- package/dist/router/public.js +22 -7
- package/dist/shared/chunk-0xcmwgdb.js +288 -0
- package/dist/shared/{chunk-j8vzvne3.js → chunk-9e92w0wt.js} +4 -1
- package/dist/shared/chunk-g4rch80a.js +33 -0
- package/dist/shared/chunk-hh0dhmb4.js +528 -0
- package/dist/shared/{chunk-pgymxpn1.js → chunk-hrd0mft1.js} +136 -34
- package/dist/shared/chunk-jrtrk5z4.js +125 -0
- package/dist/shared/chunk-ka5ked7n.js +188 -0
- package/dist/shared/chunk-n91rwj2r.js +483 -0
- package/dist/shared/chunk-prj7nm08.js +67 -0
- package/dist/shared/chunk-q6cpe5k7.js +230 -0
- package/dist/shared/{chunk-f1ynwam4.js → chunk-qacth5ah.js} +162 -36
- package/dist/shared/chunk-ryb49346.js +374 -0
- package/dist/shared/chunk-v3yyf79g.js +48 -0
- package/dist/test/index.d.ts +67 -6
- package/dist/test/index.js +4 -3
- package/package.json +14 -9
- package/dist/shared/chunk-bp3v6s9j.js +0 -62
- package/dist/shared/chunk-d8h2eh8d.js +0 -141
- package/dist/shared/chunk-tsdpgmks.js +0 -98
- package/dist/shared/chunk-xd9d7q5p.js +0 -115
- package/dist/shared/chunk-zbbvx05f.js +0 -202
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computed,
|
|
3
|
+
signal
|
|
4
|
+
} from "./chunk-hrd0mft1.js";
|
|
5
|
+
|
|
6
|
+
// src/form/field-state.ts
|
|
7
|
+
function createFieldState(_name, initialValue) {
|
|
8
|
+
const error = signal(undefined);
|
|
9
|
+
const dirty = signal(false);
|
|
10
|
+
const touched = signal(false);
|
|
11
|
+
const value = signal(initialValue);
|
|
12
|
+
return {
|
|
13
|
+
error,
|
|
14
|
+
dirty,
|
|
15
|
+
touched,
|
|
16
|
+
value,
|
|
17
|
+
setValue(newValue) {
|
|
18
|
+
value.value = newValue;
|
|
19
|
+
dirty.value = newValue !== initialValue;
|
|
20
|
+
},
|
|
21
|
+
reset() {
|
|
22
|
+
value.value = initialValue;
|
|
23
|
+
error.value = undefined;
|
|
24
|
+
dirty.value = false;
|
|
25
|
+
touched.value = false;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/form/form-data.ts
|
|
31
|
+
function formDataToObject(formData, options) {
|
|
32
|
+
const result = {};
|
|
33
|
+
const coerce = options?.coerce ?? false;
|
|
34
|
+
for (const [key, value] of formData.entries()) {
|
|
35
|
+
if (typeof value !== "string") {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
result[key] = coerce ? coerceValue(value) : value;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
function coerceValue(value) {
|
|
43
|
+
if (value === "true")
|
|
44
|
+
return true;
|
|
45
|
+
if (value === "false")
|
|
46
|
+
return false;
|
|
47
|
+
if (value !== "" && !Number.isNaN(Number(value))) {
|
|
48
|
+
return Number(value);
|
|
49
|
+
}
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/form/validation.ts
|
|
54
|
+
function validate(schema, data) {
|
|
55
|
+
const result = schema.parse(data);
|
|
56
|
+
if (result.ok) {
|
|
57
|
+
return { success: true, data: result.data, errors: {} };
|
|
58
|
+
}
|
|
59
|
+
const err = result.error;
|
|
60
|
+
if (err instanceof Error) {
|
|
61
|
+
const fieldErrors = err.fieldErrors;
|
|
62
|
+
if (fieldErrors && Object.keys(fieldErrors).length > 0) {
|
|
63
|
+
return { success: false, data: undefined, errors: fieldErrors };
|
|
64
|
+
}
|
|
65
|
+
const issues = err.issues;
|
|
66
|
+
if (Array.isArray(issues) && issues.length > 0) {
|
|
67
|
+
const errors = {};
|
|
68
|
+
for (const issue of issues) {
|
|
69
|
+
const key = Array.isArray(issue.path) && issue.path.length > 0 ? issue.path.join(".") : "_form";
|
|
70
|
+
if (!(key in errors)) {
|
|
71
|
+
errors[key] = issue.message ?? "Validation failed";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { success: false, data: undefined, errors };
|
|
75
|
+
}
|
|
76
|
+
return { success: false, data: undefined, errors: { _form: err.message } };
|
|
77
|
+
}
|
|
78
|
+
return { success: false, data: undefined, errors: { _form: "Validation failed" } };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/form/form.ts
|
|
82
|
+
function form(sdkMethod, options) {
|
|
83
|
+
const fieldCache = new Map;
|
|
84
|
+
const submitting = signal(false);
|
|
85
|
+
const fieldGeneration = signal(0);
|
|
86
|
+
const dirty = computed(() => {
|
|
87
|
+
fieldGeneration.value;
|
|
88
|
+
for (const field of fieldCache.values()) {
|
|
89
|
+
if (field.dirty.value)
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
});
|
|
94
|
+
const valid = computed(() => {
|
|
95
|
+
fieldGeneration.value;
|
|
96
|
+
for (const field of fieldCache.values()) {
|
|
97
|
+
if (field.error.value !== undefined)
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
});
|
|
102
|
+
function getOrCreateField(name) {
|
|
103
|
+
let field = fieldCache.get(name);
|
|
104
|
+
if (!field) {
|
|
105
|
+
const initialObj = typeof options?.initial === "function" ? options.initial() : options?.initial;
|
|
106
|
+
const initialValue = initialObj?.[name];
|
|
107
|
+
field = createFieldState(name, initialValue);
|
|
108
|
+
fieldCache.set(name, field);
|
|
109
|
+
fieldGeneration.value++;
|
|
110
|
+
}
|
|
111
|
+
return field;
|
|
112
|
+
}
|
|
113
|
+
const resolvedSchema = options?.schema ?? sdkMethod.meta?.bodySchema;
|
|
114
|
+
async function submitPipeline(formData) {
|
|
115
|
+
const data = formDataToObject(formData);
|
|
116
|
+
if (resolvedSchema) {
|
|
117
|
+
const result2 = validate(resolvedSchema, data);
|
|
118
|
+
if (!result2.success) {
|
|
119
|
+
for (const [fieldName, message] of Object.entries(result2.errors)) {
|
|
120
|
+
getOrCreateField(fieldName).error.value = message;
|
|
121
|
+
}
|
|
122
|
+
options?.onError?.(result2.errors);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
for (const field of fieldCache.values()) {
|
|
127
|
+
field.error.value = undefined;
|
|
128
|
+
}
|
|
129
|
+
submitting.value = true;
|
|
130
|
+
const result = await sdkMethod(data);
|
|
131
|
+
if (!result.ok) {
|
|
132
|
+
submitting.value = false;
|
|
133
|
+
const message = result.error.message;
|
|
134
|
+
getOrCreateField("_form").error.value = message;
|
|
135
|
+
options?.onError?.({ _form: message });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
submitting.value = false;
|
|
139
|
+
options?.onSuccess?.(result.data);
|
|
140
|
+
if (options?.resetOnSuccess) {
|
|
141
|
+
resetForm();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
let boundElement;
|
|
145
|
+
function resetForm() {
|
|
146
|
+
for (const field of fieldCache.values()) {
|
|
147
|
+
field.reset();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function submitPipelineWithReset(formData) {
|
|
151
|
+
await submitPipeline(formData);
|
|
152
|
+
if (options?.resetOnSuccess && !submitting.peek() && boundElement) {
|
|
153
|
+
const hasErrors = [...fieldCache.values()].some((f) => f.error.peek() !== undefined);
|
|
154
|
+
if (!hasErrors) {
|
|
155
|
+
boundElement.reset();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function handleInputOrChange(e) {
|
|
160
|
+
const target = e.target;
|
|
161
|
+
if (!target?.name)
|
|
162
|
+
return;
|
|
163
|
+
const field = getOrCreateField(target.name);
|
|
164
|
+
field.setValue(target.value);
|
|
165
|
+
}
|
|
166
|
+
function handleFocusout(e) {
|
|
167
|
+
const target = e.target;
|
|
168
|
+
if (!target?.name)
|
|
169
|
+
return;
|
|
170
|
+
const field = getOrCreateField(target.name);
|
|
171
|
+
field.touched.value = true;
|
|
172
|
+
}
|
|
173
|
+
const baseProperties = {
|
|
174
|
+
action: sdkMethod.url,
|
|
175
|
+
method: sdkMethod.method,
|
|
176
|
+
onSubmit: async (e) => {
|
|
177
|
+
e.preventDefault();
|
|
178
|
+
const formElement = e.target;
|
|
179
|
+
const formData = new FormData(formElement);
|
|
180
|
+
await submitPipeline(formData);
|
|
181
|
+
if (options?.resetOnSuccess && !submitting.peek()) {
|
|
182
|
+
const hasErrors = [...fieldCache.values()].some((f) => f.error.peek() !== undefined);
|
|
183
|
+
if (!hasErrors) {
|
|
184
|
+
formElement.reset();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
reset: resetForm,
|
|
189
|
+
setFieldError: (field, message) => {
|
|
190
|
+
getOrCreateField(field).error.value = message;
|
|
191
|
+
},
|
|
192
|
+
submit: async (formData) => {
|
|
193
|
+
if (formData) {
|
|
194
|
+
await submitPipeline(formData);
|
|
195
|
+
} else if (boundElement) {
|
|
196
|
+
await submitPipelineWithReset(new FormData(boundElement));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (options?.resetOnSuccess && formData && !submitting.peek()) {
|
|
200
|
+
const hasErrors = [...fieldCache.values()].some((f) => f.error.peek() !== undefined);
|
|
201
|
+
if (!hasErrors && boundElement) {
|
|
202
|
+
boundElement.reset();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
submitting,
|
|
207
|
+
dirty,
|
|
208
|
+
valid,
|
|
209
|
+
__bindElement: (el) => {
|
|
210
|
+
boundElement = el;
|
|
211
|
+
el.addEventListener("input", handleInputOrChange);
|
|
212
|
+
el.addEventListener("change", handleInputOrChange);
|
|
213
|
+
el.addEventListener("focusout", handleFocusout);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const knownProperties = new Set(Object.keys(baseProperties));
|
|
217
|
+
return new Proxy(baseProperties, {
|
|
218
|
+
get(target, prop, receiver) {
|
|
219
|
+
if (typeof prop === "string") {
|
|
220
|
+
if (knownProperties.has(prop)) {
|
|
221
|
+
return target[prop];
|
|
222
|
+
}
|
|
223
|
+
return getOrCreateField(prop);
|
|
224
|
+
}
|
|
225
|
+
return Reflect.get(target, prop, receiver);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export { createFieldState, formDataToObject, validate, form };
|
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__append,
|
|
3
|
+
__element,
|
|
4
|
+
__enterChildren,
|
|
5
|
+
__exitChildren
|
|
6
|
+
} from "./chunk-ryb49346.js";
|
|
7
|
+
|
|
8
|
+
// src/component/children.ts
|
|
9
|
+
var MAX_RESOLVE_DEPTH = 100;
|
|
10
|
+
function resolveChildren(value, _depth = 0) {
|
|
11
|
+
if (value == null) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === "function") {
|
|
15
|
+
if (_depth >= MAX_RESOLVE_DEPTH) {
|
|
16
|
+
throw new Error("resolveChildren: max recursion depth exceeded — possible circular thunk");
|
|
17
|
+
}
|
|
18
|
+
return resolveChildren(value(), _depth + 1);
|
|
19
|
+
}
|
|
20
|
+
if (typeof value === "string") {
|
|
21
|
+
return [document.createTextNode(value)];
|
|
22
|
+
}
|
|
23
|
+
if (typeof value === "number") {
|
|
24
|
+
return [document.createTextNode(String(value))];
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
const result = [];
|
|
28
|
+
for (const child of value) {
|
|
29
|
+
const resolved = resolveChildren(child, _depth);
|
|
30
|
+
for (const node of resolved) {
|
|
31
|
+
result.push(node);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
return [value];
|
|
37
|
+
}
|
|
38
|
+
function children(accessor) {
|
|
39
|
+
return () => resolveChildren(accessor());
|
|
40
|
+
}
|
|
41
|
+
|
|
1
42
|
// src/css/token-tables.ts
|
|
2
43
|
var PROPERTY_MAP = {
|
|
3
44
|
p: { properties: ["padding"], valueType: "spacing" },
|
|
@@ -37,6 +78,7 @@ var PROPERTY_MAP = {
|
|
|
37
78
|
weight: { properties: ["font-weight"], valueType: "font-weight" },
|
|
38
79
|
leading: { properties: ["line-height"], valueType: "line-height" },
|
|
39
80
|
tracking: { properties: ["letter-spacing"], valueType: "raw" },
|
|
81
|
+
decoration: { properties: ["text-decoration"], valueType: "raw" },
|
|
40
82
|
ring: { properties: ["outline"], valueType: "ring" },
|
|
41
83
|
cursor: { properties: ["cursor"], valueType: "raw" },
|
|
42
84
|
transition: { properties: ["transition"], valueType: "raw" },
|
|
@@ -65,7 +107,12 @@ var KEYWORD_MAP = {
|
|
|
65
107
|
uppercase: [{ property: "text-transform", value: "uppercase" }],
|
|
66
108
|
lowercase: [{ property: "text-transform", value: "lowercase" }],
|
|
67
109
|
capitalize: [{ property: "text-transform", value: "capitalize" }],
|
|
68
|
-
"outline-none": [{ property: "outline", value: "none" }]
|
|
110
|
+
"outline-none": [{ property: "outline", value: "none" }],
|
|
111
|
+
"overflow-hidden": [{ property: "overflow", value: "hidden" }],
|
|
112
|
+
"select-none": [{ property: "user-select", value: "none" }],
|
|
113
|
+
"pointer-events-none": [{ property: "pointer-events", value: "none" }],
|
|
114
|
+
"whitespace-nowrap": [{ property: "white-space", value: "nowrap" }],
|
|
115
|
+
"shrink-0": [{ property: "flex-shrink", value: "0" }]
|
|
69
116
|
};
|
|
70
117
|
var DISPLAY_MAP = {
|
|
71
118
|
flex: "flex",
|
|
@@ -114,7 +161,8 @@ var SPACING_SCALE = {
|
|
|
114
161
|
};
|
|
115
162
|
var RADIUS_SCALE = {
|
|
116
163
|
none: "0",
|
|
117
|
-
|
|
164
|
+
xs: "0.125rem",
|
|
165
|
+
sm: "0.25rem",
|
|
118
166
|
md: "0.375rem",
|
|
119
167
|
lg: "0.5rem",
|
|
120
168
|
xl: "0.75rem",
|
|
@@ -123,6 +171,7 @@ var RADIUS_SCALE = {
|
|
|
123
171
|
full: "9999px"
|
|
124
172
|
};
|
|
125
173
|
var SHADOW_SCALE = {
|
|
174
|
+
xs: "0 1px 1px 0 rgb(0 0 0 / 0.03)",
|
|
126
175
|
sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
|
|
127
176
|
md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
|
|
128
177
|
lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
|
@@ -209,7 +258,14 @@ var COLOR_NAMESPACES = new Set([
|
|
|
209
258
|
"input",
|
|
210
259
|
"card",
|
|
211
260
|
"popover",
|
|
212
|
-
"gray"
|
|
261
|
+
"gray",
|
|
262
|
+
"primary-foreground",
|
|
263
|
+
"secondary-foreground",
|
|
264
|
+
"accent-foreground",
|
|
265
|
+
"destructive-foreground",
|
|
266
|
+
"muted-foreground",
|
|
267
|
+
"card-foreground",
|
|
268
|
+
"popover-foreground"
|
|
213
269
|
]);
|
|
214
270
|
var CSS_COLOR_KEYWORDS = new Set([
|
|
215
271
|
"transparent",
|
|
@@ -244,8 +300,8 @@ var PSEUDO_MAP = {
|
|
|
244
300
|
};
|
|
245
301
|
|
|
246
302
|
// src/css/class-generator.ts
|
|
247
|
-
function generateClassName(filePath, blockName) {
|
|
248
|
-
const input = `${filePath}::${blockName}`;
|
|
303
|
+
function generateClassName(filePath, blockName, styleFingerprint = "") {
|
|
304
|
+
const input = styleFingerprint ? `${filePath}::${blockName}::${styleFingerprint}` : `${filePath}::${blockName}`;
|
|
249
305
|
const hash = djb2Hash(input);
|
|
250
306
|
return `_${hash}`;
|
|
251
307
|
}
|
|
@@ -558,20 +614,47 @@ function formatShorthand(parsed) {
|
|
|
558
614
|
// src/css/css.ts
|
|
559
615
|
var DEFAULT_FILE_PATH = "__runtime__";
|
|
560
616
|
var injectedCSS = new Set;
|
|
617
|
+
var vertzSheets = new Set;
|
|
561
618
|
function injectCSS(cssText) {
|
|
562
|
-
if (!cssText
|
|
619
|
+
if (!cssText)
|
|
620
|
+
return;
|
|
621
|
+
const isSSR = typeof globalThis.__SSR_URL__ === "string";
|
|
622
|
+
if (!isSSR && injectedCSS.has(cssText))
|
|
563
623
|
return;
|
|
564
624
|
injectedCSS.add(cssText);
|
|
625
|
+
if (typeof document === "undefined")
|
|
626
|
+
return;
|
|
627
|
+
if (typeof CSSStyleSheet !== "undefined" && document.adoptedStyleSheets !== undefined) {
|
|
628
|
+
const sheet = new CSSStyleSheet;
|
|
629
|
+
sheet.replaceSync(cssText);
|
|
630
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
631
|
+
vertzSheets.add(sheet);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
565
634
|
const style = document.createElement("style");
|
|
566
635
|
style.setAttribute("data-vertz-css", "");
|
|
567
636
|
style.textContent = cssText;
|
|
568
637
|
document.head.appendChild(style);
|
|
569
638
|
}
|
|
639
|
+
function resetInjectedStyles() {
|
|
640
|
+
injectedCSS.clear();
|
|
641
|
+
if (typeof document !== "undefined" && document.adoptedStyleSheets !== undefined) {
|
|
642
|
+
document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s) => !vertzSheets.has(s));
|
|
643
|
+
}
|
|
644
|
+
vertzSheets.clear();
|
|
645
|
+
}
|
|
646
|
+
function getInjectedCSS() {
|
|
647
|
+
return Array.from(injectedCSS);
|
|
648
|
+
}
|
|
570
649
|
function css(input, filePath = DEFAULT_FILE_PATH) {
|
|
650
|
+
if ("css" in input) {
|
|
651
|
+
throw new Error("css(): block name 'css' is reserved. Rename the block.");
|
|
652
|
+
}
|
|
571
653
|
const classNames = {};
|
|
572
654
|
const cssRules = [];
|
|
573
655
|
for (const [blockName, entries] of Object.entries(input)) {
|
|
574
|
-
const
|
|
656
|
+
const styleFingerprint = serializeEntries(entries);
|
|
657
|
+
const className = generateClassName(filePath, blockName, styleFingerprint);
|
|
575
658
|
classNames[blockName] = className;
|
|
576
659
|
const baseDeclarations = [];
|
|
577
660
|
const pseudoDeclarations = new Map;
|
|
@@ -591,12 +674,20 @@ function css(input, filePath = DEFAULT_FILE_PATH) {
|
|
|
591
674
|
for (const [selector, nestedEntries] of Object.entries(entry)) {
|
|
592
675
|
const nestedDecls = [];
|
|
593
676
|
for (const nestedEntry of nestedEntries) {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
677
|
+
if (typeof nestedEntry === "string") {
|
|
678
|
+
const parsed = parseShorthand(nestedEntry);
|
|
679
|
+
const resolved = resolveToken(parsed);
|
|
680
|
+
nestedDecls.push(...resolved.declarations);
|
|
681
|
+
} else if ("property" in nestedEntry && "value" in nestedEntry) {
|
|
682
|
+
nestedDecls.push({ property: nestedEntry.property, value: nestedEntry.value });
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (selector.startsWith("@")) {
|
|
686
|
+
nestedRules.push(formatAtRule(selector, `.${className}`, nestedDecls));
|
|
687
|
+
} else {
|
|
688
|
+
const resolvedSelector = selector.replaceAll("&", `.${className}`);
|
|
689
|
+
nestedRules.push(formatRule(resolvedSelector, nestedDecls));
|
|
597
690
|
}
|
|
598
|
-
const resolvedSelector = selector.replace("&", `.${className}`);
|
|
599
|
-
nestedRules.push(formatRule(resolvedSelector, nestedDecls));
|
|
600
691
|
}
|
|
601
692
|
}
|
|
602
693
|
}
|
|
@@ -611,10 +702,21 @@ function css(input, filePath = DEFAULT_FILE_PATH) {
|
|
|
611
702
|
const cssText = cssRules.join(`
|
|
612
703
|
`);
|
|
613
704
|
injectCSS(cssText);
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
705
|
+
const result = { ...classNames };
|
|
706
|
+
Object.defineProperty(result, "css", {
|
|
707
|
+
value: cssText,
|
|
708
|
+
enumerable: false,
|
|
709
|
+
configurable: false,
|
|
710
|
+
writable: false
|
|
711
|
+
});
|
|
712
|
+
return result;
|
|
713
|
+
}
|
|
714
|
+
function serializeEntries(entries) {
|
|
715
|
+
return entries.map((entry) => {
|
|
716
|
+
if (typeof entry === "string")
|
|
717
|
+
return entry;
|
|
718
|
+
return Object.entries(entry).map(([sel, vals]) => `${sel}:{${vals.map((v) => typeof v === "string" ? v : `${v.property}=${v.value}`).join(",")}}`).join(";");
|
|
719
|
+
}).join("|");
|
|
618
720
|
}
|
|
619
721
|
function formatRule(selector, declarations) {
|
|
620
722
|
const props = declarations.map((d) => ` ${d.property}: ${d.value};`).join(`
|
|
@@ -623,6 +725,15 @@ function formatRule(selector, declarations) {
|
|
|
623
725
|
${props}
|
|
624
726
|
}`;
|
|
625
727
|
}
|
|
728
|
+
function formatAtRule(atRule, classSelector, declarations) {
|
|
729
|
+
const props = declarations.map((d) => ` ${d.property}: ${d.value};`).join(`
|
|
730
|
+
`);
|
|
731
|
+
return `${atRule} {
|
|
732
|
+
${classSelector} {
|
|
733
|
+
${props}
|
|
734
|
+
}
|
|
735
|
+
}`;
|
|
736
|
+
}
|
|
626
737
|
|
|
627
738
|
// src/css/global-css.ts
|
|
628
739
|
function globalCss(input) {
|
|
@@ -677,6 +788,9 @@ class InlineStyleError extends Error {
|
|
|
677
788
|
}
|
|
678
789
|
|
|
679
790
|
// src/css/theme.ts
|
|
791
|
+
function sanitizeCssValue(value) {
|
|
792
|
+
return value.replace(/[;{}]/g, "").replace(/url\s*\(/gi, "").replace(/expression\s*\(/gi, "").replace(/@import/gi, "");
|
|
793
|
+
}
|
|
680
794
|
function defineTheme(input) {
|
|
681
795
|
return {
|
|
682
796
|
colors: input.colors,
|
|
@@ -687,21 +801,36 @@ function compileTheme(theme) {
|
|
|
687
801
|
const rootVars = [];
|
|
688
802
|
const darkVars = [];
|
|
689
803
|
const tokenPaths = [];
|
|
804
|
+
for (const name of Object.keys(theme.colors)) {
|
|
805
|
+
if (/[A-Z]/.test(name)) {
|
|
806
|
+
throw new Error(`Color token '${name}' uses camelCase. Use kebab-case to match CSS custom property naming.`);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
for (const [name, values] of Object.entries(theme.colors)) {
|
|
810
|
+
for (const key of Object.keys(values)) {
|
|
811
|
+
if (key === "DEFAULT" || key.startsWith("_"))
|
|
812
|
+
continue;
|
|
813
|
+
const compoundName = `${name}-${key}`;
|
|
814
|
+
if (COLOR_NAMESPACES.has(compoundName)) {
|
|
815
|
+
throw new Error(`Token collision: '${name}.${key}' produces CSS variable '--color-${name}-${key}' ` + `which conflicts with semantic token '${compoundName}'.`);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
690
819
|
for (const [name, values] of Object.entries(theme.colors)) {
|
|
691
820
|
for (const [key, value] of Object.entries(values)) {
|
|
692
821
|
if (key === "DEFAULT") {
|
|
693
822
|
const varName = `--color-${name}`;
|
|
694
|
-
rootVars.push(` ${varName}: ${value};`);
|
|
823
|
+
rootVars.push(` ${varName}: ${sanitizeCssValue(value)};`);
|
|
695
824
|
tokenPaths.push(name);
|
|
696
825
|
} else if (key.startsWith("_")) {
|
|
697
826
|
const variant = key.slice(1);
|
|
698
827
|
const varName = `--color-${name}`;
|
|
699
828
|
if (variant === "dark") {
|
|
700
|
-
darkVars.push(` ${varName}: ${value};`);
|
|
829
|
+
darkVars.push(` ${varName}: ${sanitizeCssValue(value)};`);
|
|
701
830
|
}
|
|
702
831
|
} else {
|
|
703
832
|
const varName = `--color-${name}-${key}`;
|
|
704
|
-
rootVars.push(` ${varName}: ${value};`);
|
|
833
|
+
rootVars.push(` ${varName}: ${sanitizeCssValue(value)};`);
|
|
705
834
|
tokenPaths.push(`${name}.${key}`);
|
|
706
835
|
}
|
|
707
836
|
}
|
|
@@ -709,7 +838,7 @@ function compileTheme(theme) {
|
|
|
709
838
|
if (theme.spacing) {
|
|
710
839
|
for (const [name, value] of Object.entries(theme.spacing)) {
|
|
711
840
|
const varName = `--spacing-${name}`;
|
|
712
|
-
rootVars.push(` ${varName}: ${value};`);
|
|
841
|
+
rootVars.push(` ${varName}: ${sanitizeCssValue(value)};`);
|
|
713
842
|
tokenPaths.push(`spacing.${name}`);
|
|
714
843
|
}
|
|
715
844
|
}
|
|
@@ -734,17 +863,14 @@ ${darkVars.join(`
|
|
|
734
863
|
}
|
|
735
864
|
|
|
736
865
|
// src/css/theme-provider.ts
|
|
737
|
-
function ThemeProvider(
|
|
738
|
-
const
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
for (const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
el.appendChild(child);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
866
|
+
function ThemeProvider({ theme = "light", children: children2 }) {
|
|
867
|
+
const el = __element("div", { "data-theme": theme });
|
|
868
|
+
__enterChildren(el);
|
|
869
|
+
const nodes = resolveChildren(children2);
|
|
870
|
+
for (const node of nodes) {
|
|
871
|
+
__append(el, node);
|
|
872
|
+
}
|
|
873
|
+
__exitChildren();
|
|
748
874
|
return el;
|
|
749
875
|
}
|
|
750
876
|
|
|
@@ -772,7 +898,7 @@ function deriveConfigKey(config) {
|
|
|
772
898
|
function variants(config) {
|
|
773
899
|
const { base, variants: variantDefs, defaultVariants, compoundVariants } = config;
|
|
774
900
|
const filePath = deriveConfigKey(config);
|
|
775
|
-
const baseResult =
|
|
901
|
+
const baseResult = css({ base }, filePath);
|
|
776
902
|
const variantResults = {};
|
|
777
903
|
for (const [variantName, options] of Object.entries(variantDefs)) {
|
|
778
904
|
variantResults[variantName] = {};
|
|
@@ -780,7 +906,7 @@ function variants(config) {
|
|
|
780
906
|
if (styles.length > 0) {
|
|
781
907
|
const blockName = `${variantName}_${optionName}`;
|
|
782
908
|
const result = css({ [blockName]: styles }, filePath);
|
|
783
|
-
const className = result
|
|
909
|
+
const className = result[blockName];
|
|
784
910
|
if (className) {
|
|
785
911
|
variantResults[variantName][optionName] = {
|
|
786
912
|
className,
|
|
@@ -800,7 +926,7 @@ function variants(config) {
|
|
|
800
926
|
if (styles.length > 0) {
|
|
801
927
|
const blockName = `compound_${i}`;
|
|
802
928
|
const result = css({ [blockName]: styles }, filePath);
|
|
803
|
-
const className = result
|
|
929
|
+
const className = result[blockName];
|
|
804
930
|
if (className) {
|
|
805
931
|
compoundResults.push({
|
|
806
932
|
conditions,
|
|
@@ -826,7 +952,7 @@ function variants(config) {
|
|
|
826
952
|
}
|
|
827
953
|
const fn = (props) => {
|
|
828
954
|
const classNames = [];
|
|
829
|
-
const baseClassName = baseResult.
|
|
955
|
+
const baseClassName = baseResult.base;
|
|
830
956
|
if (baseClassName) {
|
|
831
957
|
classNames.push(baseClassName);
|
|
832
958
|
}
|
|
@@ -869,4 +995,4 @@ function variants(config) {
|
|
|
869
995
|
return fn;
|
|
870
996
|
}
|
|
871
997
|
|
|
872
|
-
export { PROPERTY_MAP, KEYWORD_MAP, DISPLAY_MAP, SPACING_SCALE, RADIUS_SCALE, SHADOW_SCALE, FONT_SIZE_SCALE, FONT_WEIGHT_SCALE, LINE_HEIGHT_SCALE, ALIGNMENT_MAP, SIZE_KEYWORDS, HEIGHT_AXIS_PROPERTIES, COLOR_NAMESPACES, CSS_COLOR_KEYWORDS, CONTENT_MAP, PSEUDO_PREFIXES, PSEUDO_MAP, css, globalCss, s, defineTheme, compileTheme, ThemeProvider, variants };
|
|
998
|
+
export { resolveChildren, children, PROPERTY_MAP, KEYWORD_MAP, DISPLAY_MAP, SPACING_SCALE, RADIUS_SCALE, SHADOW_SCALE, FONT_SIZE_SCALE, FONT_WEIGHT_SCALE, LINE_HEIGHT_SCALE, ALIGNMENT_MAP, SIZE_KEYWORDS, HEIGHT_AXIS_PROPERTIES, COLOR_NAMESPACES, CSS_COLOR_KEYWORDS, CONTENT_MAP, PSEUDO_PREFIXES, PSEUDO_MAP, injectCSS, resetInjectedStyles, getInjectedCSS, css, globalCss, s, defineTheme, compileTheme, ThemeProvider, variants };
|