@askrjs/themes 0.0.16 → 0.0.19
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 +25 -0
- package/THEMING.md +6 -5
- package/dist/components/_internal/block-layout.d.ts +1 -0
- package/dist/components/_internal/block-layout.js +14 -11
- package/dist/components/_internal/block-layout.js.map +1 -1
- package/dist/components/_internal/classes.js +8 -1
- package/dist/components/_internal/classes.js.map +1 -1
- package/dist/components/_internal/jsx.js.map +1 -1
- package/dist/components/_internal/style.js +185 -28
- package/dist/components/_internal/style.js.map +1 -1
- package/dist/components/alert/alert.d.ts +1 -0
- package/dist/components/alert/alert.js.map +1 -1
- package/dist/components/alert/alert.types.d.ts +1 -0
- package/dist/components/aside/aside.d.ts +1 -0
- package/dist/components/aside/aside.js.map +1 -1
- package/dist/components/aspect-ratio/aspect-ratio.d.ts +1 -0
- package/dist/components/aspect-ratio/aspect-ratio.js.map +1 -1
- package/dist/components/aspect-ratio/aspect-ratio.types.d.ts +1 -0
- package/dist/components/badge/badge.d.ts +1 -0
- package/dist/components/badge/badge.js.map +1 -1
- package/dist/components/badge/badge.types.d.ts +1 -0
- package/dist/components/block/block.d.ts +1 -0
- package/dist/components/block/block.js +2 -2
- package/dist/components/block/block.js.map +1 -1
- package/dist/components/block/block.types.d.ts +1 -0
- package/dist/components/brand/brand.d.ts +1 -0
- package/dist/components/brand/brand.js +2 -2
- package/dist/components/brand/brand.js.map +1 -1
- package/dist/components/brand/brand.types.d.ts +1 -0
- package/dist/components/button-group/button-group.d.ts +1 -0
- package/dist/components/button-group/button-group.js.map +1 -1
- package/dist/components/button-group/button-group.types.d.ts +1 -0
- package/dist/components/card/card.d.ts +1 -0
- package/dist/components/card/card.js.map +1 -1
- package/dist/components/card/card.types.d.ts +1 -0
- package/dist/components/catalog.d.ts +1 -0
- package/dist/components/catalog.js +22 -13
- package/dist/components/catalog.js.map +1 -1
- package/dist/components/close/close.d.ts +1 -0
- package/dist/components/close/close.js.map +1 -1
- package/dist/components/container/container.d.ts +1 -0
- package/dist/components/container/container.js.map +1 -1
- package/dist/components/empty-state/empty-state.d.ts +1 -0
- package/dist/components/empty-state/empty-state.js.map +1 -1
- package/dist/components/field/field.d.ts +1 -0
- package/dist/components/field/field.js.map +1 -1
- package/dist/components/field/field.types.d.ts +1 -0
- package/dist/components/footer/footer.d.ts +1 -0
- package/dist/components/footer/footer.js.map +1 -1
- package/dist/components/footer/footer.types.d.ts +1 -0
- package/dist/components/grid/grid.d.ts +1 -0
- package/dist/components/grid/grid.js.map +1 -1
- package/dist/components/grid/grid.types.d.ts +1 -0
- package/dist/components/header/header.d.ts +1 -0
- package/dist/components/header/header.js.map +1 -1
- package/dist/components/input-group/input-group.d.ts +1 -0
- package/dist/components/input-group/input-group.js.map +1 -1
- package/dist/components/input-group/input-group.types.d.ts +1 -0
- package/dist/components/jsx-types.d.ts +12 -0
- package/dist/components/main/main.d.ts +1 -0
- package/dist/components/main/main.js.map +1 -1
- package/dist/components/nav/nav.d.ts +1 -0
- package/dist/components/nav/nav.js +6 -2
- package/dist/components/nav/nav.js.map +1 -1
- package/dist/components/nav/nav.types.d.ts +2 -0
- package/dist/components/navbar/navbar.d.ts +1 -0
- package/dist/components/navbar/navbar.js +15 -10
- package/dist/components/navbar/navbar.js.map +1 -1
- package/dist/components/overlays/dropdown-content.d.ts +1 -0
- package/dist/components/overlays/dropdown-content.js.map +1 -1
- package/dist/components/page/page.d.ts +1 -0
- package/dist/components/page/page.js.map +1 -1
- package/dist/components/page-header/page-header.d.ts +1 -0
- package/dist/components/page-header/page-header.js.map +1 -1
- package/dist/components/section/section.d.ts +1 -0
- package/dist/components/section/section.js.map +1 -1
- package/dist/components/separator/separator.d.ts +1 -0
- package/dist/components/separator/separator.js.map +1 -1
- package/dist/components/separator/separator.types.d.ts +1 -0
- package/dist/components/sidebar/index.d.ts +2 -2
- package/dist/components/sidebar/sidebar.d.ts +2 -1
- package/dist/components/sidebar/sidebar.js +39 -13
- package/dist/components/sidebar/sidebar.js.map +1 -1
- package/dist/components/sidebar/sidebar.types.d.ts +3 -1
- package/dist/components/skeleton/skeleton.d.ts +1 -0
- package/dist/components/skeleton/skeleton.js.map +1 -1
- package/dist/components/skeleton/skeleton.types.d.ts +1 -0
- package/dist/components/spinner/spinner.d.ts +1 -0
- package/dist/components/spinner/spinner.js.map +1 -1
- package/dist/components/stat/stat.d.ts +1 -0
- package/dist/components/stat/stat.js.map +1 -1
- package/dist/components/stat/stat.types.d.ts +1 -0
- package/dist/components/text/text.d.ts +1 -0
- package/dist/components/text/text.js.map +1 -1
- package/dist/components/text/text.types.d.ts +1 -0
- package/dist/components/theme/theme.d.ts +2 -0
- package/dist/components/theme/theme.js +58 -19
- package/dist/components/theme/theme.js.map +1 -1
- package/dist/components/toolbar/toolbar.d.ts +1 -0
- package/dist/components/toolbar/toolbar.js.map +1 -1
- package/dist/components.d.ts +6 -3
- package/dist/core.d.ts +2 -2
- package/dist/ssr.d.ts +18 -0
- package/dist/ssr.js +63 -0
- package/dist/ssr.js.map +1 -0
- package/dist/themes/default/index.css +43 -7
- package/package.json +7 -3
- package/src/components/_internal/block-layout.ts +27 -16
- package/src/components/_internal/classes.ts +15 -2
- package/src/components/_internal/jsx.ts +1 -1
- package/src/components/_internal/style.ts +248 -27
- package/src/components/alert/alert.tsx +1 -0
- package/src/components/alert/alert.types.ts +1 -0
- package/src/components/aside/aside.tsx +1 -0
- package/src/components/aspect-ratio/aspect-ratio.tsx +1 -0
- package/src/components/aspect-ratio/aspect-ratio.types.ts +1 -0
- package/src/components/badge/badge.tsx +1 -0
- package/src/components/badge/badge.types.ts +1 -0
- package/src/components/block/block.tsx +4 -1
- package/src/components/block/block.types.ts +1 -0
- package/src/components/brand/brand.tsx +6 -2
- package/src/components/brand/brand.types.ts +1 -0
- package/src/components/button-group/button-group.tsx +1 -0
- package/src/components/button-group/button-group.types.ts +1 -0
- package/src/components/card/card.tsx +1 -0
- package/src/components/card/card.types.ts +1 -0
- package/src/components/catalog.tsx +15 -4
- package/src/components/close/close.tsx +1 -0
- package/src/components/container/container.tsx +1 -0
- package/src/components/empty-state/empty-state.tsx +1 -0
- package/src/components/field/field.tsx +1 -0
- package/src/components/field/field.types.ts +1 -0
- package/src/components/footer/footer.tsx +1 -0
- package/src/components/footer/footer.types.ts +1 -0
- package/src/components/grid/grid.tsx +1 -0
- package/src/components/grid/grid.types.ts +1 -0
- package/src/components/header/header.tsx +1 -0
- package/src/components/input-group/input-group.tsx +1 -0
- package/src/components/input-group/input-group.types.ts +1 -0
- package/src/components/jsx-types.ts +16 -0
- package/src/components/main/main.tsx +1 -0
- package/src/components/nav/nav.tsx +16 -2
- package/src/components/nav/nav.types.ts +2 -0
- package/src/components/navbar/navbar.tsx +19 -8
- package/src/components/overlays/dropdown-content.tsx +1 -0
- package/src/components/page/page.tsx +1 -0
- package/src/components/page-header/page-header.tsx +1 -0
- package/src/components/section/section.tsx +1 -0
- package/src/components/separator/separator.tsx +1 -0
- package/src/components/separator/separator.types.ts +1 -0
- package/src/components/sidebar/index.ts +1 -0
- package/src/components/sidebar/sidebar.tsx +45 -20
- package/src/components/sidebar/sidebar.types.ts +3 -0
- package/src/components/skeleton/skeleton.tsx +1 -0
- package/src/components/skeleton/skeleton.types.ts +1 -0
- package/src/components/spinner/spinner.tsx +1 -0
- package/src/components/stat/stat.tsx +1 -0
- package/src/components/stat/stat.types.ts +1 -0
- package/src/components/text/text.tsx +1 -0
- package/src/components/text/text.types.ts +1 -0
- package/src/components/theme/theme.tsx +85 -14
- package/src/components/toolbar/toolbar.tsx +1 -0
- package/src/components.ts +9 -0
- package/src/ssr.ts +102 -0
- package/src/themes/default/styles/base/text.css +4 -4
- package/src/themes/default/styles/display/coverage.css +3 -1
- package/src/themes/default/styles/layout/block.css +4 -0
- package/src/themes/default/styles/layout/layout.css +108 -0
- package/src/themes/default/styles/shell/navbar.css +4 -1
- package/src/themes/default/tokens.css +1 -1
- package/src/themes/presets/ginger.css +3 -3
- package/templates/theme/styles/base/text.css +4 -4
- package/templates/theme/styles/display/progress-circle.css +2 -0
- package/templates/theme/styles/forms/input-group.css +2 -1
- package/templates/theme/styles/layout/layout.css +108 -0
- package/templates/theme/styles/overlays/toast.css +11 -0
- package/templates/theme/styles/shell/navbar.css +4 -1
- package/templates/theme/styles/shell/sidebar.css +18 -1
- package/templates/theme/tokens.css +1 -1
|
@@ -1,6 +1,110 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Askr from "@askrjs/askr";
|
|
2
2
|
|
|
3
3
|
const cssPropertyNameCache = new Map<string, string>();
|
|
4
|
+
const MAX_PROPERTY_CACHE = 256;
|
|
5
|
+
|
|
6
|
+
const CSS_UNSAFE_RE = /[{}<>\\]/;
|
|
7
|
+
const CSS_URI_SCHEME_RE = /(?:^|[\s(,])([a-z][a-z0-9+.-]*):/i;
|
|
8
|
+
const CSS_FUNCTION_NAME_RE = /([a-z-][a-z0-9-]*)\s*\(/gi;
|
|
9
|
+
const CSS_ALLOWED_FUNCTIONS = new Set([
|
|
10
|
+
"var",
|
|
11
|
+
"calc",
|
|
12
|
+
"min",
|
|
13
|
+
"max",
|
|
14
|
+
"clamp",
|
|
15
|
+
"minmax",
|
|
16
|
+
"repeat",
|
|
17
|
+
"rgb",
|
|
18
|
+
"rgba",
|
|
19
|
+
"hsl",
|
|
20
|
+
"hsla",
|
|
21
|
+
"lab",
|
|
22
|
+
"lch",
|
|
23
|
+
"oklab",
|
|
24
|
+
"oklch",
|
|
25
|
+
"color",
|
|
26
|
+
"color-mix",
|
|
27
|
+
"translate",
|
|
28
|
+
"translatex",
|
|
29
|
+
"translatey",
|
|
30
|
+
"translatez",
|
|
31
|
+
"scale",
|
|
32
|
+
"scalex",
|
|
33
|
+
"scaley",
|
|
34
|
+
"scalez",
|
|
35
|
+
"rotate",
|
|
36
|
+
"rotatex",
|
|
37
|
+
"rotatey",
|
|
38
|
+
"rotatez",
|
|
39
|
+
"skew",
|
|
40
|
+
"skewx",
|
|
41
|
+
"skewy",
|
|
42
|
+
"matrix",
|
|
43
|
+
"matrix3d",
|
|
44
|
+
"linear-gradient",
|
|
45
|
+
"radial-gradient",
|
|
46
|
+
"conic-gradient",
|
|
47
|
+
"repeating-linear-gradient",
|
|
48
|
+
"repeating-radial-gradient",
|
|
49
|
+
"repeating-conic-gradient",
|
|
50
|
+
"cubic-bezier",
|
|
51
|
+
"steps",
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
function isSafeCssPropertyName(name: string): boolean {
|
|
55
|
+
if (name.startsWith("--")) return /^--[a-zA-Z0-9_-]+$/.test(name);
|
|
56
|
+
return /^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(name);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isSafeCssValue(value: string): boolean {
|
|
60
|
+
if (CSS_UNSAFE_RE.test(value) || CSS_URI_SCHEME_RE.test(value)) return false;
|
|
61
|
+
|
|
62
|
+
for (const match of value.matchAll(CSS_FUNCTION_NAME_RE)) {
|
|
63
|
+
if (!CSS_ALLOWED_FUNCTIONS.has(match[1]!.toLowerCase())) return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function splitCssDeclarations(value: string): string[] {
|
|
70
|
+
const declarations: string[] = [];
|
|
71
|
+
let start = 0;
|
|
72
|
+
let depth = 0;
|
|
73
|
+
let quote: string | undefined;
|
|
74
|
+
|
|
75
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
76
|
+
const char = value[index]!;
|
|
77
|
+
if (quote) {
|
|
78
|
+
if (char === quote && value[index - 1] !== "\\") quote = undefined;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (char === '"' || char === "'") {
|
|
82
|
+
quote = char;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (char === "(") depth += 1;
|
|
86
|
+
if (char === ")" && depth > 0) depth -= 1;
|
|
87
|
+
if (char === ";" && depth === 0) {
|
|
88
|
+
declarations.push(value.slice(start, index));
|
|
89
|
+
start = index + 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declarations.push(value.slice(start));
|
|
94
|
+
return declarations;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function serializeCssString(value: string): string {
|
|
98
|
+
const entries: Array<[string, string]> = [];
|
|
99
|
+
for (const candidate of splitCssDeclarations(value)) {
|
|
100
|
+
const separator = candidate.indexOf(":");
|
|
101
|
+
if (separator <= 0) continue;
|
|
102
|
+
const key = candidate.slice(0, separator).trim();
|
|
103
|
+
const cssValue = candidate.slice(separator + 1).trim();
|
|
104
|
+
if (key && cssValue) entries.push([key, cssValue]);
|
|
105
|
+
}
|
|
106
|
+
return serializeCssDeclarations(Object.fromEntries(entries));
|
|
107
|
+
}
|
|
4
108
|
|
|
5
109
|
function cssPropertyName(name: string): string {
|
|
6
110
|
let cached = cssPropertyNameCache.get(name);
|
|
@@ -20,7 +124,9 @@ function cssPropertyName(name: string): string {
|
|
|
20
124
|
}
|
|
21
125
|
}
|
|
22
126
|
|
|
23
|
-
cssPropertyNameCache.
|
|
127
|
+
if (cssPropertyNameCache.size < MAX_PROPERTY_CACHE) {
|
|
128
|
+
cssPropertyNameCache.set(name, result);
|
|
129
|
+
}
|
|
24
130
|
return result;
|
|
25
131
|
}
|
|
26
132
|
|
|
@@ -34,7 +140,17 @@ export function serializeCssDeclarations(styles: Record<string, unknown>): strin
|
|
|
34
140
|
continue;
|
|
35
141
|
}
|
|
36
142
|
|
|
37
|
-
const
|
|
143
|
+
const rawProperty = key.trim();
|
|
144
|
+
if (!isSafeCssPropertyName(rawProperty)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const property = cssPropertyName(rawProperty).trim();
|
|
148
|
+
const cssValue = String(value).trim();
|
|
149
|
+
if (!cssValue || !isSafeCssValue(cssValue)) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const declaration = `${property}:${cssValue}`;
|
|
38
154
|
result = result ? `${result};${declaration}` : declaration;
|
|
39
155
|
}
|
|
40
156
|
|
|
@@ -59,16 +175,86 @@ export function mergeCssVar(style: unknown, name: string, value: string): string
|
|
|
59
175
|
|
|
60
176
|
const STYLE_REGISTRY_ATTR = "data-askr-style-registry";
|
|
61
177
|
const STYLE_CLASS_PREFIX = "ak-style-";
|
|
178
|
+
const MAX_STYLE_RULES = 512;
|
|
179
|
+
const MAX_SSR_STYLE_CACHE = 4096;
|
|
62
180
|
|
|
63
|
-
|
|
181
|
+
type StyleRule = {
|
|
182
|
+
className: string;
|
|
183
|
+
declarations: string;
|
|
184
|
+
rule: string;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const styleRulesByClass = new Map<string, StyleRule>();
|
|
64
188
|
type StyleRegistry = {
|
|
65
189
|
element: HTMLStyleElement;
|
|
66
|
-
|
|
190
|
+
ruleCount: number;
|
|
191
|
+
rules: Map<string, StyleRule>;
|
|
67
192
|
};
|
|
68
193
|
const registries = new WeakMap<Document, Map<string, StyleRegistry>>();
|
|
69
|
-
|
|
194
|
+
function countRegisteredRules(value: string | null): number {
|
|
195
|
+
return value?.match(/\.ak-style-[a-z0-9]+\{/g)?.length ?? 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function styleClassName(declarations: string): string {
|
|
199
|
+
let first = 0xdeadbeef ^ declarations.length;
|
|
200
|
+
let second = 0x41c6ce57 ^ declarations.length;
|
|
201
|
+
|
|
202
|
+
for (let index = 0; index < declarations.length; index += 1) {
|
|
203
|
+
const code = declarations.charCodeAt(index);
|
|
204
|
+
first = Math.imul(first ^ code, 2_654_435_761);
|
|
205
|
+
second = Math.imul(second ^ code, 1_597_334_677);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
first =
|
|
209
|
+
Math.imul(first ^ (first >>> 16), 2_246_822_507) ^
|
|
210
|
+
Math.imul(second ^ (second >>> 13), 3_266_489_909);
|
|
211
|
+
second =
|
|
212
|
+
Math.imul(second ^ (second >>> 16), 2_246_822_507) ^
|
|
213
|
+
Math.imul(first ^ (first >>> 13), 3_266_489_909);
|
|
214
|
+
|
|
215
|
+
return `${STYLE_CLASS_PREFIX}${(second >>> 0).toString(36)}${(first >>> 0).toString(36)}`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function escapeStyleRawText(value: string): string {
|
|
219
|
+
return value.replace(/<\//g, "<\\/");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function styleRuleFor(declarations: string): StyleRule {
|
|
223
|
+
const className = styleClassName(declarations);
|
|
224
|
+
const existing = styleRulesByClass.get(className);
|
|
225
|
+
if (existing) {
|
|
226
|
+
if (existing.declarations !== declarations) {
|
|
227
|
+
throw new RangeError("Theme style class collision detected.");
|
|
228
|
+
}
|
|
229
|
+
return existing;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const entry = {
|
|
233
|
+
className,
|
|
234
|
+
declarations,
|
|
235
|
+
rule: `.${className}{${escapeStyleRawText(declarations)}}`,
|
|
236
|
+
};
|
|
237
|
+
return entry;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function rememberStyleRule(entry: StyleRule): void {
|
|
241
|
+
styleRulesByClass.delete(entry.className);
|
|
242
|
+
styleRulesByClass.set(entry.className, entry);
|
|
243
|
+
while (styleRulesByClass.size > MAX_SSR_STYLE_CACHE) {
|
|
244
|
+
const oldest = styleRulesByClass.keys().next().value;
|
|
245
|
+
if (oldest === undefined) break;
|
|
246
|
+
styleRulesByClass.delete(oldest);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
70
249
|
|
|
71
|
-
|
|
250
|
+
function registerSSRStyle(entry: StyleRule): void {
|
|
251
|
+
const register = (
|
|
252
|
+
Askr as typeof Askr & {
|
|
253
|
+
registerSSRStyle?: (id: string, cssText: string) => void;
|
|
254
|
+
}
|
|
255
|
+
).registerSSRStyle;
|
|
256
|
+
register?.(entry.className, entry.rule);
|
|
257
|
+
}
|
|
72
258
|
|
|
73
259
|
function ensureStyleRegistry(nonce: string | undefined): StyleRegistry | null {
|
|
74
260
|
if (typeof document === "undefined") return null;
|
|
@@ -81,17 +267,31 @@ function ensureStyleRegistry(nonce: string | undefined): StyleRegistry | null {
|
|
|
81
267
|
const current = documentRegistries.get(key);
|
|
82
268
|
if (current?.element.isConnected) return current;
|
|
83
269
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
270
|
+
const existingStyleElements = Array.from(
|
|
271
|
+
document.querySelectorAll<HTMLStyleElement>(`style[${STYLE_REGISTRY_ATTR}]`),
|
|
272
|
+
);
|
|
273
|
+
const styleElement =
|
|
274
|
+
existingStyleElements.find((element) => (element.nonce || undefined) === nonce) ??
|
|
275
|
+
(nonce === undefined && existingStyleElements.length === 1
|
|
276
|
+
? existingStyleElements[0]
|
|
277
|
+
: undefined) ??
|
|
278
|
+
document.createElement("style");
|
|
279
|
+
if (!styleElement.isConnected) {
|
|
280
|
+
styleElement.setAttribute(STYLE_REGISTRY_ATTR, "true");
|
|
281
|
+
if (nonce !== undefined) styleElement.nonce = nonce;
|
|
282
|
+
(document.head ?? document.documentElement).append(styleElement);
|
|
283
|
+
}
|
|
284
|
+
const registry: StyleRegistry = {
|
|
285
|
+
element: styleElement,
|
|
286
|
+
ruleCount: countRegisteredRules(styleElement.textContent),
|
|
287
|
+
rules: new Map(),
|
|
288
|
+
};
|
|
89
289
|
documentRegistries.set(key, registry);
|
|
90
290
|
return registry;
|
|
91
291
|
}
|
|
92
292
|
|
|
93
293
|
function normalizeDeclarations(declarations: string): string {
|
|
94
|
-
return declarations
|
|
294
|
+
return serializeCssString(declarations);
|
|
95
295
|
}
|
|
96
296
|
|
|
97
297
|
export function styleDeclarationsToClass(declarations: string | undefined): string | undefined {
|
|
@@ -100,27 +300,48 @@ export function styleDeclarationsToClass(declarations: string | undefined): stri
|
|
|
100
300
|
const normalized = normalizeDeclarations(declarations);
|
|
101
301
|
if (!normalized) return undefined;
|
|
102
302
|
|
|
103
|
-
const
|
|
303
|
+
const entry = styleRuleFor(normalized);
|
|
304
|
+
const nonce = Askr.cspNonce();
|
|
104
305
|
const registry = ensureStyleRegistry(nonce);
|
|
105
306
|
const registered = registry?.rules.get(normalized);
|
|
106
|
-
if (registered)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (className === undefined) {
|
|
110
|
-
className = `${STYLE_CLASS_PREFIX}${++nextStyleClassId}`;
|
|
111
|
-
styleClassCache.set(normalized, className);
|
|
307
|
+
if (registered) {
|
|
308
|
+
registerSSRStyle(registered);
|
|
309
|
+
return registered.className;
|
|
112
310
|
}
|
|
113
311
|
|
|
114
312
|
if (registry) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
313
|
+
if (!registry.rules.has(normalized) && !registry.element.textContent?.includes(entry.rule)) {
|
|
314
|
+
if (registry.ruleCount >= MAX_STYLE_RULES) {
|
|
315
|
+
throw new RangeError("Theme style registry capacity exceeded.");
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (!registry.element.textContent?.includes(entry.rule)) {
|
|
319
|
+
registry.element.append(entry.rule, "\n");
|
|
320
|
+
registry.ruleCount += 1;
|
|
321
|
+
}
|
|
322
|
+
registry.rules.set(normalized, entry);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
rememberStyleRule(entry);
|
|
326
|
+
registerSSRStyle(entry);
|
|
327
|
+
|
|
328
|
+
return entry.className;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function styleRulesForHtml(html: string): string[] {
|
|
332
|
+
const rules = new Map<string, string>();
|
|
333
|
+
const classAttributePattern = /\sclass=(?:"([^"]*)"|'([^']*)')/g;
|
|
334
|
+
|
|
335
|
+
for (const attribute of html.matchAll(classAttributePattern)) {
|
|
336
|
+
const value = attribute[1] ?? attribute[2] ?? "";
|
|
337
|
+
for (const className of value.split(/\s+/)) {
|
|
338
|
+
const entry = styleRulesByClass.get(className);
|
|
339
|
+
if (entry) rules.set(className, entry.rule);
|
|
340
|
+
if (rules.size > MAX_STYLE_RULES) {
|
|
118
341
|
throw new RangeError("Theme style registry capacity exceeded.");
|
|
119
|
-
|
|
120
|
-
registry.rules.set(normalized, { className, rule });
|
|
121
|
-
styleElement.append(rule, "\n");
|
|
342
|
+
}
|
|
122
343
|
}
|
|
123
344
|
}
|
|
124
345
|
|
|
125
|
-
return
|
|
346
|
+
return Array.from(rules.values());
|
|
126
347
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JSX } from "@askrjs/askr/jsx-runtime";
|
|
1
2
|
import { Slot } from "@askrjs/askr/foundations";
|
|
2
3
|
import { classes } from "../_internal/classes";
|
|
3
4
|
import {
|
|
@@ -15,8 +16,8 @@ const DEFAULT_ELEMENT = "div";
|
|
|
15
16
|
export function Block(props: BlockNativeProps): JSX.Element;
|
|
16
17
|
export function Block(props: BlockAsChildProps): JSX.Element;
|
|
17
18
|
export function Block(props: BlockNativeProps | BlockAsChildProps) {
|
|
18
|
-
const as = "as" in props ? props.as : DEFAULT_ELEMENT;
|
|
19
19
|
const {
|
|
20
|
+
as: asProp,
|
|
20
21
|
asChild,
|
|
21
22
|
children,
|
|
22
23
|
ref,
|
|
@@ -25,10 +26,12 @@ export function Block(props: BlockNativeProps | BlockAsChildProps) {
|
|
|
25
26
|
style: userStyle,
|
|
26
27
|
...rest
|
|
27
28
|
} = props as (BlockNativeProps | BlockAsChildProps) & {
|
|
29
|
+
as?: BlockNativeProps["as"];
|
|
28
30
|
class?: unknown;
|
|
29
31
|
className?: unknown;
|
|
30
32
|
style?: unknown;
|
|
31
33
|
};
|
|
34
|
+
const as = asProp ?? DEFAULT_ELEMENT;
|
|
32
35
|
|
|
33
36
|
const { blockProps, rest: passthroughProps } = splitBlockLayoutProps(rest);
|
|
34
37
|
const layoutStyle: Record<string, string | number> = {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JSX } from "@askrjs/askr/jsx-runtime";
|
|
1
2
|
import { Slot } from "@askrjs/askr/foundations";
|
|
2
3
|
import { classes } from "../_internal/classes";
|
|
3
4
|
import { mergeProps } from "../_internal/merge-props";
|
|
@@ -16,14 +17,17 @@ export function Brand<TElement extends "div" | "a" | "span" = "div">(
|
|
|
16
17
|
props: BrandProps<TElement>,
|
|
17
18
|
): JSX.Element {
|
|
18
19
|
const {
|
|
20
|
+
as: asProp,
|
|
19
21
|
asChild,
|
|
20
22
|
children,
|
|
21
23
|
class: classProp,
|
|
22
24
|
className,
|
|
23
25
|
ref,
|
|
24
26
|
...rest
|
|
25
|
-
} = props as BrandNativeProps | BrandAsChildProps
|
|
26
|
-
|
|
27
|
+
} = props as (BrandNativeProps | BrandAsChildProps) & {
|
|
28
|
+
as?: "div" | "a" | "span";
|
|
29
|
+
};
|
|
30
|
+
const as = asProp;
|
|
27
31
|
|
|
28
32
|
const finalProps = mergeProps(rest, {
|
|
29
33
|
ref,
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import type { JSX } from "@askrjs/askr/jsx-runtime";
|
|
1
2
|
import { Slot } from "@askrjs/askr/foundations";
|
|
2
3
|
import type { Ref } from "@askrjs/askr/foundations/utilities";
|
|
3
|
-
import { DialogContent } from "@askrjs/ui";
|
|
4
|
+
import { DialogContent, DialogDescription, DialogTitle } from "@askrjs/ui";
|
|
4
5
|
import { Block } from "./block";
|
|
5
6
|
import { classes } from "./_internal/classes";
|
|
6
7
|
import { mergeProps } from "./_internal/merge-props";
|
|
7
8
|
|
|
8
9
|
const CatalogDialogContent = DialogContent as (props: Record<string, unknown>) => JSX.Element;
|
|
10
|
+
const CatalogDialogTitle = DialogTitle as (props: Record<string, unknown>) => JSX.Element;
|
|
11
|
+
const CatalogDialogDescription = DialogDescription as (
|
|
12
|
+
props: Record<string, unknown>,
|
|
13
|
+
) => JSX.Element;
|
|
9
14
|
|
|
10
15
|
type CatalogElement = keyof JSX.IntrinsicElements;
|
|
11
16
|
|
|
@@ -42,13 +47,18 @@ function catalogPart(props: CatalogComponentProps, defaults: CatalogDefaults): J
|
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
function buttonPart(props: CatalogComponentProps, slot: string, className?: string): JSX.Element {
|
|
45
|
-
const { children, ref, class: classProp, type = "button", ...rest } = props;
|
|
50
|
+
const { as, asChild, children, ref, class: classProp, type = "button", ...rest } = props;
|
|
51
|
+
void as;
|
|
46
52
|
const finalProps = mergeProps(rest, {
|
|
47
53
|
ref,
|
|
48
54
|
class: classes(className, classProp),
|
|
49
55
|
"data-slot": slot,
|
|
50
56
|
});
|
|
51
57
|
|
|
58
|
+
if (asChild) {
|
|
59
|
+
return <Slot asChild {...finalProps} children={children as JSX.Element} />;
|
|
60
|
+
}
|
|
61
|
+
|
|
52
62
|
return (
|
|
53
63
|
<button type={type as "button" | "submit" | "reset"} {...finalProps}>
|
|
54
64
|
{children}
|
|
@@ -249,6 +259,7 @@ export function CalendarDay(
|
|
|
249
259
|
const { disabled, outside, rangeEnd, rangeMiddle, rangeStart, selected, today, ...rest } = props;
|
|
250
260
|
return buttonPart(
|
|
251
261
|
{
|
|
262
|
+
disabled,
|
|
252
263
|
"aria-disabled": disabled ? "true" : undefined,
|
|
253
264
|
"aria-selected": selected ? "true" : undefined,
|
|
254
265
|
"data-disabled": disabled ? "" : undefined,
|
|
@@ -661,11 +672,11 @@ export function SheetFooter(props: CatalogComponentProps): JSX.Element {
|
|
|
661
672
|
}
|
|
662
673
|
|
|
663
674
|
export function SheetTitle(props: CatalogComponentProps): JSX.Element {
|
|
664
|
-
return
|
|
675
|
+
return <CatalogDialogTitle {...props} data-slot="sheet-title" />;
|
|
665
676
|
}
|
|
666
677
|
|
|
667
678
|
export function SheetDescription(props: CatalogComponentProps): JSX.Element {
|
|
668
|
-
return
|
|
679
|
+
return <CatalogDialogDescription {...props} data-slot="sheet-description" />;
|
|
669
680
|
}
|
|
670
681
|
|
|
671
682
|
export function Toaster(props: CatalogComponentProps): JSX.Element {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { JSXElement } from "@askrjs/askr/foundations/structures";
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
namespace JSX {
|
|
5
|
+
interface Element extends JSXElement {
|
|
6
|
+
readonly __askrThemesJsxElementBrand?: never;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface IntrinsicElements {
|
|
10
|
+
// @ts-ignore The Askr source types already provide a compatible fallback index.
|
|
11
|
+
[element: string]: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export {};
|