uraniyum 1.0.0 → 1.0.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/dist/helpers.d.ts +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +170 -29
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +172 -28
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/router.d.ts +4 -2
- package/dist/styles.d.ts +20 -0
- package/package.json +2 -2
- package/src/helpers.ts +13 -17
- package/src/index.ts +2 -1
- package/src/router.ts +43 -14
- package/src/styles.ts +164 -0
package/dist/helpers.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.esm.js
CHANGED
|
@@ -41,49 +41,190 @@ const tags = new Proxy({}, {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
function router(routes) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const container = document.createElement("div");
|
|
45
|
+
const routePatterns = [];
|
|
46
|
+
for (const path in routes) {
|
|
47
|
+
const keys = [];
|
|
48
|
+
const pattern = path
|
|
49
|
+
.replace(/\/:[^\/]+/g, (match) => {
|
|
50
|
+
keys.push(match.slice(2));
|
|
51
|
+
return "/([^/]+)";
|
|
52
|
+
})
|
|
53
|
+
.replace(/\*/g, ".*");
|
|
54
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
55
|
+
routePatterns.push({ regex, keys, handler: routes[path] });
|
|
56
|
+
}
|
|
47
57
|
const renderRoute = () => {
|
|
48
58
|
const path = window.location.pathname;
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
let matched = false;
|
|
60
|
+
for (const { regex, keys, handler } of routePatterns) {
|
|
61
|
+
const match = path.match(regex);
|
|
62
|
+
if (match) {
|
|
63
|
+
const params = {};
|
|
64
|
+
keys.forEach((key, i) => {
|
|
65
|
+
params[key] = match[i + 1];
|
|
66
|
+
});
|
|
67
|
+
container.innerHTML = "";
|
|
68
|
+
container.appendChild(handler(params));
|
|
69
|
+
matched = true;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!matched && routes["*"]) {
|
|
74
|
+
container.innerHTML = "";
|
|
75
|
+
container.appendChild(routes["*"]());
|
|
76
|
+
}
|
|
56
77
|
};
|
|
57
78
|
window.addEventListener("popstate", renderRoute);
|
|
79
|
+
renderRoute();
|
|
58
80
|
return {
|
|
59
81
|
render: renderRoute,
|
|
60
|
-
|
|
61
|
-
history.pushState(null, "", path);
|
|
62
|
-
renderRoute();
|
|
63
|
-
}
|
|
82
|
+
element: container
|
|
64
83
|
};
|
|
65
84
|
}
|
|
66
85
|
|
|
67
|
-
function add(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
86
|
+
function add(component) {
|
|
87
|
+
if (typeof component === "function") {
|
|
88
|
+
const el = component();
|
|
89
|
+
if (!(el instanceof Node)) {
|
|
90
|
+
throw new Error("Component function must return an HTMLElement");
|
|
91
|
+
}
|
|
92
|
+
document.body.appendChild(el);
|
|
93
|
+
}
|
|
94
|
+
else if ("render" in component && typeof component.render === "function") {
|
|
95
|
+
document.body.appendChild(component.element || document.createElement("div"));
|
|
96
|
+
component.render();
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
throw new Error("Invalid component passed to add()");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const styleCache = new Map();
|
|
104
|
+
const keyframeCache = new Map();
|
|
105
|
+
let styleElement = null;
|
|
106
|
+
const ALLOWED_PREFIXES = [
|
|
107
|
+
'root', 'button', 'icon', 'text', 'container', 'wrapper',
|
|
108
|
+
'card', 'header', 'section'
|
|
109
|
+
];
|
|
110
|
+
function ensureStyleElement() {
|
|
111
|
+
if (!styleElement) {
|
|
112
|
+
styleElement = document.createElement('style');
|
|
113
|
+
styleElement.id = 'styles';
|
|
114
|
+
document.head.appendChild(styleElement);
|
|
115
|
+
}
|
|
116
|
+
return styleElement;
|
|
117
|
+
}
|
|
118
|
+
function hashString(str) {
|
|
119
|
+
let hash = 5381;
|
|
120
|
+
for (let i = 0; i < str.length; i++)
|
|
121
|
+
hash = (hash * 33) ^ str.charCodeAt(i);
|
|
122
|
+
return (hash >>> 0).toString(36);
|
|
123
|
+
}
|
|
124
|
+
const kebabCache = new Map();
|
|
125
|
+
function camelToKebab(str) {
|
|
126
|
+
if (!kebabCache.has(str)) {
|
|
127
|
+
kebabCache.set(str, str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase());
|
|
128
|
+
}
|
|
129
|
+
return kebabCache.get(str);
|
|
130
|
+
}
|
|
131
|
+
function stringifyDecls(props, keyframes) {
|
|
132
|
+
const out = [];
|
|
133
|
+
for (const [key, raw] of Object.entries(props)) {
|
|
134
|
+
if (raw == null || typeof raw === "object")
|
|
135
|
+
continue;
|
|
136
|
+
let val = typeof raw === "function" ? raw() : raw;
|
|
137
|
+
if (typeof val === "string") {
|
|
138
|
+
for (const [orig, uniq] of keyframes) {
|
|
139
|
+
val = val.replaceAll(`$${orig}`, uniq);
|
|
76
140
|
}
|
|
77
|
-
app.appendChild(el);
|
|
78
141
|
}
|
|
79
|
-
|
|
80
|
-
|
|
142
|
+
out.push(`${camelToKebab(key)}:${val}`);
|
|
143
|
+
}
|
|
144
|
+
return out.join(";");
|
|
145
|
+
}
|
|
146
|
+
const KEYFRAMES_REGEX = /^@keyframes /;
|
|
147
|
+
function registerKeyframes(name, frames) {
|
|
148
|
+
const hash = hashString(name + JSON.stringify(frames));
|
|
149
|
+
const unique = `${name}-${hash}`;
|
|
150
|
+
if (keyframeCache.has(unique))
|
|
151
|
+
return unique;
|
|
152
|
+
const rules = Object.entries(frames)
|
|
153
|
+
.map(([step, styles]) => `${step}{${stringifyDecls(styles, new Map())}}`)
|
|
154
|
+
.join("");
|
|
155
|
+
ensureStyleElement().appendChild(document.createTextNode(`@keyframes ${unique}{${rules}}\n`));
|
|
156
|
+
keyframeCache.set(unique, unique);
|
|
157
|
+
return unique;
|
|
158
|
+
}
|
|
159
|
+
function buildRules(className, rule, keyframes) {
|
|
160
|
+
const rules = [];
|
|
161
|
+
const base = {};
|
|
162
|
+
for (const [key, val] of Object.entries(rule)) {
|
|
163
|
+
if (KEYFRAMES_REGEX.test(key))
|
|
164
|
+
continue;
|
|
165
|
+
if (key.startsWith(':') && typeof val === "object") {
|
|
166
|
+
rules.push(`.${className}${key}{${stringifyDecls(val, keyframes)}}`);
|
|
167
|
+
}
|
|
168
|
+
else if (key.startsWith('@media') && typeof val === "object") {
|
|
169
|
+
rules.push(`${key}{.${className}{${stringifyDecls(val, keyframes)}}}`);
|
|
170
|
+
}
|
|
171
|
+
else if (key.includes('&') && typeof val === "object") {
|
|
172
|
+
const selector = key.replaceAll("&", `.${className}`);
|
|
173
|
+
rules.push(`${selector}{${stringifyDecls(val, keyframes)}}`);
|
|
174
|
+
}
|
|
175
|
+
else if (!key.startsWith('@')) {
|
|
176
|
+
base[key] = val;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (Object.keys(base).length > 0) {
|
|
180
|
+
rules.push(`.${className}{${stringifyDecls(base, keyframes)}}`);
|
|
181
|
+
}
|
|
182
|
+
return rules;
|
|
183
|
+
}
|
|
184
|
+
function makeStyles(styles) {
|
|
185
|
+
return () => {
|
|
186
|
+
const classNames = {};
|
|
187
|
+
const collectedRules = [];
|
|
188
|
+
const keyframesMap = new Map();
|
|
189
|
+
for (const [key, val] of Object.entries(styles)) {
|
|
190
|
+
if (KEYFRAMES_REGEX.test(key)) {
|
|
191
|
+
const name = key.replace('@keyframes ', '');
|
|
192
|
+
const unique = registerKeyframes(name, val);
|
|
193
|
+
keyframesMap.set(name, unique);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
for (const [slot, rule] of Object.entries(styles)) {
|
|
197
|
+
if (KEYFRAMES_REGEX.test(slot))
|
|
198
|
+
continue;
|
|
199
|
+
const hash = hashString(JSON.stringify(rule));
|
|
200
|
+
const className = ALLOWED_PREFIXES.includes(slot) ? `${slot}-${hash}` : `css-${hash}`;
|
|
201
|
+
if (!styleCache.has(className)) {
|
|
202
|
+
const rules = buildRules(className, rule, keyframesMap);
|
|
203
|
+
collectedRules.push(...rules);
|
|
204
|
+
styleCache.set(className, className);
|
|
205
|
+
}
|
|
206
|
+
classNames[slot] = className;
|
|
207
|
+
}
|
|
208
|
+
if (collectedRules.length) {
|
|
209
|
+
const el = ensureStyleElement();
|
|
210
|
+
for (const r of collectedRules)
|
|
211
|
+
el.appendChild(document.createTextNode(r + "\n"));
|
|
81
212
|
}
|
|
82
|
-
|
|
83
|
-
|
|
213
|
+
return classNames;
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
const mergeClasses = (...classes) => classes.filter(Boolean).join(" ");
|
|
217
|
+
function mergeStyleSets(...sets) {
|
|
218
|
+
const merged = {};
|
|
219
|
+
for (const set of sets) {
|
|
220
|
+
if (!set)
|
|
221
|
+
continue;
|
|
222
|
+
for (const k in set) {
|
|
223
|
+
merged[k] = { ...(merged[k] || {}), ...set[k] };
|
|
84
224
|
}
|
|
85
225
|
}
|
|
226
|
+
return makeStyles(merged)();
|
|
86
227
|
}
|
|
87
228
|
|
|
88
|
-
export { add, router, state, tags };
|
|
229
|
+
export { add, makeStyles, mergeClasses, mergeStyleSets, router, state, tags };
|
|
89
230
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/state.ts","../src/tags.ts","../src/router.ts","../src/helpers.ts"],"sourcesContent":["export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}","export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","export function router(routes: Record<string, () => HTMLElement>) {\r\n const getRoute = (path: string) => {\r\n return routes[path] || routes[\"*\"]\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n const pageFn = getRoute(path)\r\n const page = pageFn()\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n app.innerHTML = \"\"\r\n app.appendChild(page)\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n\r\n return {\r\n render: renderRoute,\r\n navigate: (path: string) => {\r\n history.pushState(null, \"\", path)\r\n renderRoute()\r\n }\r\n }\r\n}","type Component = (() => HTMLElement) | { render: () => void }\r\n\r\nexport function add(...components: Component[]) {\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n\r\n for (const c of components) {\r\n if (typeof c === \"function\") {\r\n const el = c()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n app.appendChild(el)\r\n } else if (\"render\" in c && typeof c.render === \"function\") {\r\n c.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/state.ts","../src/tags.ts","../src/router.ts","../src/helpers.ts","../src/styles.ts"],"sourcesContent":["export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}","export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","type RouteHandler = (params?: Record<string, string>) => HTMLElement\r\n\r\nexport function router(routes: Record<string, RouteHandler>) {\r\n const container = document.createElement(\"div\")\r\n const routePatterns: {\r\n regex: RegExp\r\n keys: string[]\r\n handler: RouteHandler\r\n }[] = []\r\n\r\n for (const path in routes) {\r\n const keys: string[] = []\r\n const pattern = path\r\n .replace(/\\/:[^\\/]+/g, (match) => {\r\n keys.push(match.slice(2))\r\n return \"/([^/]+)\"\r\n })\r\n .replace(/\\*/g, \".*\")\r\n const regex = new RegExp(`^${pattern}$`)\r\n routePatterns.push({ regex, keys, handler: routes[path] })\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n let matched = false\r\n\r\n for (const { regex, keys, handler } of routePatterns) {\r\n const match = path.match(regex)\r\n if (match) {\r\n const params: Record<string, string> = {}\r\n keys.forEach((key, i) => {\r\n params[key] = match[i + 1]\r\n })\r\n container.innerHTML = \"\"\r\n container.appendChild(handler(params))\r\n matched = true\r\n break\r\n }\r\n }\r\n\r\n if (!matched && routes[\"*\"]) {\r\n container.innerHTML = \"\"\r\n container.appendChild(routes[\"*\"]())\r\n }\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n renderRoute()\r\n\r\n return {\r\n render: renderRoute,\r\n element: container\r\n }\r\n}\r\n","type Component = (() => HTMLElement) | { render: () => void; element?: HTMLElement }\r\n\r\nexport function add(component: Component) {\r\n if (typeof component === \"function\") {\r\n const el = component()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n document.body.appendChild(el)\r\n } else if (\"render\" in component && typeof component.render === \"function\") {\r\n document.body.appendChild(component.element || document.createElement(\"div\"))\r\n component.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n}","export type CSSValue = string | number | (() => string | number);\r\nexport interface CSSProperties {\r\n [key: string]: CSSValue | CSSProperties;\r\n}\r\nexport type StyleRule = CSSProperties & {\r\n ':hover'?: CSSProperties;\r\n ':focus'?: CSSProperties;\r\n ':active'?: CSSProperties;\r\n ':disabled'?: CSSProperties;\r\n [key: string]: any;\r\n};\r\nexport type StylesMap<T extends Record<string, any> = {}> = {\r\n [K in keyof T]: StyleRule;\r\n};\r\nexport type ClassNames<T extends Record<string, any>> = { [K in keyof T]: string };\r\n\r\nconst styleCache = new Map<string, string>();\r\nconst keyframeCache = new Map<string, string>();\r\nlet styleElement: HTMLStyleElement | null = null;\r\n\r\nconst ALLOWED_PREFIXES = [\r\n 'root', 'button', 'icon', 'text', 'container', 'wrapper',\r\n 'card', 'header', 'section'\r\n];\r\n\r\nfunction ensureStyleElement() {\r\n if (!styleElement) {\r\n styleElement = document.createElement('style');\r\n styleElement.id = 'styles';\r\n document.head.appendChild(styleElement);\r\n }\r\n return styleElement;\r\n}\r\n\r\nfunction hashString(str: string): string {\r\n let hash = 5381;\r\n for (let i = 0; i < str.length; i++) hash = (hash * 33) ^ str.charCodeAt(i);\r\n return (hash >>> 0).toString(36);\r\n}\r\n\r\nconst kebabCache = new Map<string, string>();\r\nfunction camelToKebab(str: string): string {\r\n if (!kebabCache.has(str)) {\r\n kebabCache.set(str, str.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase());\r\n }\r\n return kebabCache.get(str)!;\r\n}\r\n\r\nfunction stringifyDecls(props: CSSProperties, keyframes: Map<string, string>): string {\r\n const out: string[] = [];\r\n for (const [key, raw] of Object.entries(props)) {\r\n if (raw == null || typeof raw === \"object\") continue;\r\n let val = typeof raw === \"function\" ? raw() : raw;\r\n\r\n if (typeof val === \"string\") {\r\n for (const [orig, uniq] of keyframes) {\r\n val = val.replaceAll(`$${orig}`, uniq);\r\n }\r\n }\r\n out.push(`${camelToKebab(key)}:${val}`);\r\n }\r\n return out.join(\";\");\r\n}\r\n\r\nconst KEYFRAMES_REGEX = /^@keyframes /;\r\n\r\nfunction registerKeyframes(name: string, frames: Record<string, CSSProperties>): string {\r\n const hash = hashString(name + JSON.stringify(frames));\r\n const unique = `${name}-${hash}`;\r\n\r\n if (keyframeCache.has(unique)) return unique;\r\n\r\n const rules = Object.entries(frames)\r\n .map(([step, styles]) => `${step}{${stringifyDecls(styles, new Map())}}`)\r\n .join(\"\");\r\n\r\n ensureStyleElement().appendChild(\r\n document.createTextNode(`@keyframes ${unique}{${rules}}\\n`)\r\n );\r\n keyframeCache.set(unique, unique);\r\n return unique;\r\n}\r\n\r\nfunction buildRules(className: string, rule: StyleRule, keyframes: Map<string, string>): string[] {\r\n const rules: string[] = [];\r\n const base: CSSProperties = {};\r\n\r\n for (const [key, val] of Object.entries(rule)) {\r\n if (KEYFRAMES_REGEX.test(key)) continue;\r\n\r\n if (key.startsWith(':') && typeof val === \"object\") {\r\n rules.push(`.${className}${key}{${stringifyDecls(val, keyframes)}}`);\r\n }\r\n else if (key.startsWith('@media') && typeof val === \"object\") {\r\n rules.push(`${key}{.${className}{${stringifyDecls(val, keyframes)}}}`);\r\n }\r\n else if (key.includes('&') && typeof val === \"object\") {\r\n const selector = key.replaceAll(\"&\", `.${className}`);\r\n rules.push(`${selector}{${stringifyDecls(val, keyframes)}}`);\r\n }\r\n else if (!key.startsWith('@')) {\r\n base[key] = val;\r\n }\r\n }\r\n\r\n if (Object.keys(base).length > 0) {\r\n rules.push(`.${className}{${stringifyDecls(base, keyframes)}}`);\r\n }\r\n\r\n return rules;\r\n}\r\n\r\nexport function makeStyles<T extends StylesMap>(styles: T) {\r\n return () => {\r\n const classNames = {} as ClassNames<T>;\r\n const collectedRules: string[] = [];\r\n const keyframesMap = new Map<string, string>();\r\n\r\n for (const [key, val] of Object.entries(styles)) {\r\n if (KEYFRAMES_REGEX.test(key)) {\r\n const name = key.replace('@keyframes ', '');\r\n const unique = registerKeyframes(name, val as any);\r\n keyframesMap.set(name, unique);\r\n }\r\n }\r\n\r\n for (const [slot, rule] of Object.entries(styles)) {\r\n if (KEYFRAMES_REGEX.test(slot)) continue;\r\n\r\n const hash = hashString(JSON.stringify(rule));\r\n const className =\r\n ALLOWED_PREFIXES.includes(slot) ? `${slot}-${hash}` : `css-${hash}`;\r\n\r\n if (!styleCache.has(className)) {\r\n const rules = buildRules(className, rule as StyleRule, keyframesMap);\r\n collectedRules.push(...rules);\r\n styleCache.set(className, className);\r\n }\r\n\r\n classNames[slot as keyof T] = className;\r\n }\r\n\r\n if (collectedRules.length) {\r\n const el = ensureStyleElement();\r\n for (const r of collectedRules) el.appendChild(document.createTextNode(r + \"\\n\"));\r\n }\r\n\r\n return classNames;\r\n };\r\n}\r\n\r\nexport const mergeClasses = (...classes: (string | undefined | null | false)[]) =>\r\n classes.filter(Boolean).join(\" \");\r\n\r\nexport function mergeStyleSets<T extends StylesMap>(...sets: (T | undefined)[]) {\r\n const merged: any = {};\r\n for (const set of sets) {\r\n if (!set) continue;\r\n for (const k in set) {\r\n merged[k] = { ...(merged[k] || {}), ...set[k] };\r\n }\r\n }\r\n return makeStyles(merged)();\r\n}"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -45,51 +45,195 @@ const tags = new Proxy({}, {
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
function router(routes) {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
const container = document.createElement("div");
|
|
49
|
+
const routePatterns = [];
|
|
50
|
+
for (const path in routes) {
|
|
51
|
+
const keys = [];
|
|
52
|
+
const pattern = path
|
|
53
|
+
.replace(/\/:[^\/]+/g, (match) => {
|
|
54
|
+
keys.push(match.slice(2));
|
|
55
|
+
return "/([^/]+)";
|
|
56
|
+
})
|
|
57
|
+
.replace(/\*/g, ".*");
|
|
58
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
59
|
+
routePatterns.push({ regex, keys, handler: routes[path] });
|
|
60
|
+
}
|
|
51
61
|
const renderRoute = () => {
|
|
52
62
|
const path = window.location.pathname;
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
let matched = false;
|
|
64
|
+
for (const { regex, keys, handler } of routePatterns) {
|
|
65
|
+
const match = path.match(regex);
|
|
66
|
+
if (match) {
|
|
67
|
+
const params = {};
|
|
68
|
+
keys.forEach((key, i) => {
|
|
69
|
+
params[key] = match[i + 1];
|
|
70
|
+
});
|
|
71
|
+
container.innerHTML = "";
|
|
72
|
+
container.appendChild(handler(params));
|
|
73
|
+
matched = true;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!matched && routes["*"]) {
|
|
78
|
+
container.innerHTML = "";
|
|
79
|
+
container.appendChild(routes["*"]());
|
|
80
|
+
}
|
|
60
81
|
};
|
|
61
82
|
window.addEventListener("popstate", renderRoute);
|
|
83
|
+
renderRoute();
|
|
62
84
|
return {
|
|
63
85
|
render: renderRoute,
|
|
64
|
-
|
|
65
|
-
history.pushState(null, "", path);
|
|
66
|
-
renderRoute();
|
|
67
|
-
}
|
|
86
|
+
element: container
|
|
68
87
|
};
|
|
69
88
|
}
|
|
70
89
|
|
|
71
|
-
function add(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
function add(component) {
|
|
91
|
+
if (typeof component === "function") {
|
|
92
|
+
const el = component();
|
|
93
|
+
if (!(el instanceof Node)) {
|
|
94
|
+
throw new Error("Component function must return an HTMLElement");
|
|
95
|
+
}
|
|
96
|
+
document.body.appendChild(el);
|
|
97
|
+
}
|
|
98
|
+
else if ("render" in component && typeof component.render === "function") {
|
|
99
|
+
document.body.appendChild(component.element || document.createElement("div"));
|
|
100
|
+
component.render();
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw new Error("Invalid component passed to add()");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const styleCache = new Map();
|
|
108
|
+
const keyframeCache = new Map();
|
|
109
|
+
let styleElement = null;
|
|
110
|
+
const ALLOWED_PREFIXES = [
|
|
111
|
+
'root', 'button', 'icon', 'text', 'container', 'wrapper',
|
|
112
|
+
'card', 'header', 'section'
|
|
113
|
+
];
|
|
114
|
+
function ensureStyleElement() {
|
|
115
|
+
if (!styleElement) {
|
|
116
|
+
styleElement = document.createElement('style');
|
|
117
|
+
styleElement.id = 'styles';
|
|
118
|
+
document.head.appendChild(styleElement);
|
|
119
|
+
}
|
|
120
|
+
return styleElement;
|
|
121
|
+
}
|
|
122
|
+
function hashString(str) {
|
|
123
|
+
let hash = 5381;
|
|
124
|
+
for (let i = 0; i < str.length; i++)
|
|
125
|
+
hash = (hash * 33) ^ str.charCodeAt(i);
|
|
126
|
+
return (hash >>> 0).toString(36);
|
|
127
|
+
}
|
|
128
|
+
const kebabCache = new Map();
|
|
129
|
+
function camelToKebab(str) {
|
|
130
|
+
if (!kebabCache.has(str)) {
|
|
131
|
+
kebabCache.set(str, str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase());
|
|
132
|
+
}
|
|
133
|
+
return kebabCache.get(str);
|
|
134
|
+
}
|
|
135
|
+
function stringifyDecls(props, keyframes) {
|
|
136
|
+
const out = [];
|
|
137
|
+
for (const [key, raw] of Object.entries(props)) {
|
|
138
|
+
if (raw == null || typeof raw === "object")
|
|
139
|
+
continue;
|
|
140
|
+
let val = typeof raw === "function" ? raw() : raw;
|
|
141
|
+
if (typeof val === "string") {
|
|
142
|
+
for (const [orig, uniq] of keyframes) {
|
|
143
|
+
val = val.replaceAll(`$${orig}`, uniq);
|
|
80
144
|
}
|
|
81
|
-
app.appendChild(el);
|
|
82
145
|
}
|
|
83
|
-
|
|
84
|
-
|
|
146
|
+
out.push(`${camelToKebab(key)}:${val}`);
|
|
147
|
+
}
|
|
148
|
+
return out.join(";");
|
|
149
|
+
}
|
|
150
|
+
const KEYFRAMES_REGEX = /^@keyframes /;
|
|
151
|
+
function registerKeyframes(name, frames) {
|
|
152
|
+
const hash = hashString(name + JSON.stringify(frames));
|
|
153
|
+
const unique = `${name}-${hash}`;
|
|
154
|
+
if (keyframeCache.has(unique))
|
|
155
|
+
return unique;
|
|
156
|
+
const rules = Object.entries(frames)
|
|
157
|
+
.map(([step, styles]) => `${step}{${stringifyDecls(styles, new Map())}}`)
|
|
158
|
+
.join("");
|
|
159
|
+
ensureStyleElement().appendChild(document.createTextNode(`@keyframes ${unique}{${rules}}\n`));
|
|
160
|
+
keyframeCache.set(unique, unique);
|
|
161
|
+
return unique;
|
|
162
|
+
}
|
|
163
|
+
function buildRules(className, rule, keyframes) {
|
|
164
|
+
const rules = [];
|
|
165
|
+
const base = {};
|
|
166
|
+
for (const [key, val] of Object.entries(rule)) {
|
|
167
|
+
if (KEYFRAMES_REGEX.test(key))
|
|
168
|
+
continue;
|
|
169
|
+
if (key.startsWith(':') && typeof val === "object") {
|
|
170
|
+
rules.push(`.${className}${key}{${stringifyDecls(val, keyframes)}}`);
|
|
171
|
+
}
|
|
172
|
+
else if (key.startsWith('@media') && typeof val === "object") {
|
|
173
|
+
rules.push(`${key}{.${className}{${stringifyDecls(val, keyframes)}}}`);
|
|
174
|
+
}
|
|
175
|
+
else if (key.includes('&') && typeof val === "object") {
|
|
176
|
+
const selector = key.replaceAll("&", `.${className}`);
|
|
177
|
+
rules.push(`${selector}{${stringifyDecls(val, keyframes)}}`);
|
|
178
|
+
}
|
|
179
|
+
else if (!key.startsWith('@')) {
|
|
180
|
+
base[key] = val;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (Object.keys(base).length > 0) {
|
|
184
|
+
rules.push(`.${className}{${stringifyDecls(base, keyframes)}}`);
|
|
185
|
+
}
|
|
186
|
+
return rules;
|
|
187
|
+
}
|
|
188
|
+
function makeStyles(styles) {
|
|
189
|
+
return () => {
|
|
190
|
+
const classNames = {};
|
|
191
|
+
const collectedRules = [];
|
|
192
|
+
const keyframesMap = new Map();
|
|
193
|
+
for (const [key, val] of Object.entries(styles)) {
|
|
194
|
+
if (KEYFRAMES_REGEX.test(key)) {
|
|
195
|
+
const name = key.replace('@keyframes ', '');
|
|
196
|
+
const unique = registerKeyframes(name, val);
|
|
197
|
+
keyframesMap.set(name, unique);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
for (const [slot, rule] of Object.entries(styles)) {
|
|
201
|
+
if (KEYFRAMES_REGEX.test(slot))
|
|
202
|
+
continue;
|
|
203
|
+
const hash = hashString(JSON.stringify(rule));
|
|
204
|
+
const className = ALLOWED_PREFIXES.includes(slot) ? `${slot}-${hash}` : `css-${hash}`;
|
|
205
|
+
if (!styleCache.has(className)) {
|
|
206
|
+
const rules = buildRules(className, rule, keyframesMap);
|
|
207
|
+
collectedRules.push(...rules);
|
|
208
|
+
styleCache.set(className, className);
|
|
209
|
+
}
|
|
210
|
+
classNames[slot] = className;
|
|
211
|
+
}
|
|
212
|
+
if (collectedRules.length) {
|
|
213
|
+
const el = ensureStyleElement();
|
|
214
|
+
for (const r of collectedRules)
|
|
215
|
+
el.appendChild(document.createTextNode(r + "\n"));
|
|
85
216
|
}
|
|
86
|
-
|
|
87
|
-
|
|
217
|
+
return classNames;
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const mergeClasses = (...classes) => classes.filter(Boolean).join(" ");
|
|
221
|
+
function mergeStyleSets(...sets) {
|
|
222
|
+
const merged = {};
|
|
223
|
+
for (const set of sets) {
|
|
224
|
+
if (!set)
|
|
225
|
+
continue;
|
|
226
|
+
for (const k in set) {
|
|
227
|
+
merged[k] = { ...(merged[k] || {}), ...set[k] };
|
|
88
228
|
}
|
|
89
229
|
}
|
|
230
|
+
return makeStyles(merged)();
|
|
90
231
|
}
|
|
91
232
|
|
|
92
233
|
exports.add = add;
|
|
234
|
+
exports.makeStyles = makeStyles;
|
|
235
|
+
exports.mergeClasses = mergeClasses;
|
|
236
|
+
exports.mergeStyleSets = mergeStyleSets;
|
|
93
237
|
exports.router = router;
|
|
94
238
|
exports.state = state;
|
|
95
239
|
exports.tags = tags;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/state.ts","../src/tags.ts","../src/router.ts","../src/helpers.ts"],"sourcesContent":["export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}","export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","export function router(routes: Record<string, () => HTMLElement>) {\r\n const getRoute = (path: string) => {\r\n return routes[path] || routes[\"*\"]\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n const pageFn = getRoute(path)\r\n const page = pageFn()\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n app.innerHTML = \"\"\r\n app.appendChild(page)\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n\r\n return {\r\n render: renderRoute,\r\n navigate: (path: string) => {\r\n history.pushState(null, \"\", path)\r\n renderRoute()\r\n }\r\n }\r\n}","type Component = (() => HTMLElement) | { render: () => void }\r\n\r\nexport function add(...components: Component[]) {\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n\r\n for (const c of components) {\r\n if (typeof c === \"function\") {\r\n const el = c()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n app.appendChild(el)\r\n } else if (\"render\" in c && typeof c.render === \"function\") {\r\n c.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/state.ts","../src/tags.ts","../src/router.ts","../src/helpers.ts","../src/styles.ts"],"sourcesContent":["export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}","export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","type RouteHandler = (params?: Record<string, string>) => HTMLElement\r\n\r\nexport function router(routes: Record<string, RouteHandler>) {\r\n const container = document.createElement(\"div\")\r\n const routePatterns: {\r\n regex: RegExp\r\n keys: string[]\r\n handler: RouteHandler\r\n }[] = []\r\n\r\n for (const path in routes) {\r\n const keys: string[] = []\r\n const pattern = path\r\n .replace(/\\/:[^\\/]+/g, (match) => {\r\n keys.push(match.slice(2))\r\n return \"/([^/]+)\"\r\n })\r\n .replace(/\\*/g, \".*\")\r\n const regex = new RegExp(`^${pattern}$`)\r\n routePatterns.push({ regex, keys, handler: routes[path] })\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n let matched = false\r\n\r\n for (const { regex, keys, handler } of routePatterns) {\r\n const match = path.match(regex)\r\n if (match) {\r\n const params: Record<string, string> = {}\r\n keys.forEach((key, i) => {\r\n params[key] = match[i + 1]\r\n })\r\n container.innerHTML = \"\"\r\n container.appendChild(handler(params))\r\n matched = true\r\n break\r\n }\r\n }\r\n\r\n if (!matched && routes[\"*\"]) {\r\n container.innerHTML = \"\"\r\n container.appendChild(routes[\"*\"]())\r\n }\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n renderRoute()\r\n\r\n return {\r\n render: renderRoute,\r\n element: container\r\n }\r\n}\r\n","type Component = (() => HTMLElement) | { render: () => void; element?: HTMLElement }\r\n\r\nexport function add(component: Component) {\r\n if (typeof component === \"function\") {\r\n const el = component()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n document.body.appendChild(el)\r\n } else if (\"render\" in component && typeof component.render === \"function\") {\r\n document.body.appendChild(component.element || document.createElement(\"div\"))\r\n component.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n}","export type CSSValue = string | number | (() => string | number);\r\nexport interface CSSProperties {\r\n [key: string]: CSSValue | CSSProperties;\r\n}\r\nexport type StyleRule = CSSProperties & {\r\n ':hover'?: CSSProperties;\r\n ':focus'?: CSSProperties;\r\n ':active'?: CSSProperties;\r\n ':disabled'?: CSSProperties;\r\n [key: string]: any;\r\n};\r\nexport type StylesMap<T extends Record<string, any> = {}> = {\r\n [K in keyof T]: StyleRule;\r\n};\r\nexport type ClassNames<T extends Record<string, any>> = { [K in keyof T]: string };\r\n\r\nconst styleCache = new Map<string, string>();\r\nconst keyframeCache = new Map<string, string>();\r\nlet styleElement: HTMLStyleElement | null = null;\r\n\r\nconst ALLOWED_PREFIXES = [\r\n 'root', 'button', 'icon', 'text', 'container', 'wrapper',\r\n 'card', 'header', 'section'\r\n];\r\n\r\nfunction ensureStyleElement() {\r\n if (!styleElement) {\r\n styleElement = document.createElement('style');\r\n styleElement.id = 'styles';\r\n document.head.appendChild(styleElement);\r\n }\r\n return styleElement;\r\n}\r\n\r\nfunction hashString(str: string): string {\r\n let hash = 5381;\r\n for (let i = 0; i < str.length; i++) hash = (hash * 33) ^ str.charCodeAt(i);\r\n return (hash >>> 0).toString(36);\r\n}\r\n\r\nconst kebabCache = new Map<string, string>();\r\nfunction camelToKebab(str: string): string {\r\n if (!kebabCache.has(str)) {\r\n kebabCache.set(str, str.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase());\r\n }\r\n return kebabCache.get(str)!;\r\n}\r\n\r\nfunction stringifyDecls(props: CSSProperties, keyframes: Map<string, string>): string {\r\n const out: string[] = [];\r\n for (const [key, raw] of Object.entries(props)) {\r\n if (raw == null || typeof raw === \"object\") continue;\r\n let val = typeof raw === \"function\" ? raw() : raw;\r\n\r\n if (typeof val === \"string\") {\r\n for (const [orig, uniq] of keyframes) {\r\n val = val.replaceAll(`$${orig}`, uniq);\r\n }\r\n }\r\n out.push(`${camelToKebab(key)}:${val}`);\r\n }\r\n return out.join(\";\");\r\n}\r\n\r\nconst KEYFRAMES_REGEX = /^@keyframes /;\r\n\r\nfunction registerKeyframes(name: string, frames: Record<string, CSSProperties>): string {\r\n const hash = hashString(name + JSON.stringify(frames));\r\n const unique = `${name}-${hash}`;\r\n\r\n if (keyframeCache.has(unique)) return unique;\r\n\r\n const rules = Object.entries(frames)\r\n .map(([step, styles]) => `${step}{${stringifyDecls(styles, new Map())}}`)\r\n .join(\"\");\r\n\r\n ensureStyleElement().appendChild(\r\n document.createTextNode(`@keyframes ${unique}{${rules}}\\n`)\r\n );\r\n keyframeCache.set(unique, unique);\r\n return unique;\r\n}\r\n\r\nfunction buildRules(className: string, rule: StyleRule, keyframes: Map<string, string>): string[] {\r\n const rules: string[] = [];\r\n const base: CSSProperties = {};\r\n\r\n for (const [key, val] of Object.entries(rule)) {\r\n if (KEYFRAMES_REGEX.test(key)) continue;\r\n\r\n if (key.startsWith(':') && typeof val === \"object\") {\r\n rules.push(`.${className}${key}{${stringifyDecls(val, keyframes)}}`);\r\n }\r\n else if (key.startsWith('@media') && typeof val === \"object\") {\r\n rules.push(`${key}{.${className}{${stringifyDecls(val, keyframes)}}}`);\r\n }\r\n else if (key.includes('&') && typeof val === \"object\") {\r\n const selector = key.replaceAll(\"&\", `.${className}`);\r\n rules.push(`${selector}{${stringifyDecls(val, keyframes)}}`);\r\n }\r\n else if (!key.startsWith('@')) {\r\n base[key] = val;\r\n }\r\n }\r\n\r\n if (Object.keys(base).length > 0) {\r\n rules.push(`.${className}{${stringifyDecls(base, keyframes)}}`);\r\n }\r\n\r\n return rules;\r\n}\r\n\r\nexport function makeStyles<T extends StylesMap>(styles: T) {\r\n return () => {\r\n const classNames = {} as ClassNames<T>;\r\n const collectedRules: string[] = [];\r\n const keyframesMap = new Map<string, string>();\r\n\r\n for (const [key, val] of Object.entries(styles)) {\r\n if (KEYFRAMES_REGEX.test(key)) {\r\n const name = key.replace('@keyframes ', '');\r\n const unique = registerKeyframes(name, val as any);\r\n keyframesMap.set(name, unique);\r\n }\r\n }\r\n\r\n for (const [slot, rule] of Object.entries(styles)) {\r\n if (KEYFRAMES_REGEX.test(slot)) continue;\r\n\r\n const hash = hashString(JSON.stringify(rule));\r\n const className =\r\n ALLOWED_PREFIXES.includes(slot) ? `${slot}-${hash}` : `css-${hash}`;\r\n\r\n if (!styleCache.has(className)) {\r\n const rules = buildRules(className, rule as StyleRule, keyframesMap);\r\n collectedRules.push(...rules);\r\n styleCache.set(className, className);\r\n }\r\n\r\n classNames[slot as keyof T] = className;\r\n }\r\n\r\n if (collectedRules.length) {\r\n const el = ensureStyleElement();\r\n for (const r of collectedRules) el.appendChild(document.createTextNode(r + \"\\n\"));\r\n }\r\n\r\n return classNames;\r\n };\r\n}\r\n\r\nexport const mergeClasses = (...classes: (string | undefined | null | false)[]) =>\r\n classes.filter(Boolean).join(\" \");\r\n\r\nexport function mergeStyleSets<T extends StylesMap>(...sets: (T | undefined)[]) {\r\n const merged: any = {};\r\n for (const set of sets) {\r\n if (!set) continue;\r\n for (const k in set) {\r\n merged[k] = { ...(merged[k] || {}), ...set[k] };\r\n }\r\n }\r\n return makeStyles(merged)();\r\n}"],"names":[],"mappings":";;;;AAAM,SAAU,KAAK,CAAI,OAAU,EAAA;IAC/B,IAAI,KAAK,GAAG,OAAO,CAAA;IACnB,MAAM,SAAS,GAAe,EAAE,CAAA;AAEhC,IAAA,MAAM,GAAG,GAAG,CAAC,QAAW,KAAI;QACxB,KAAK,GAAG,QAAQ,CAAA;AAChB,QAAA,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;AACtC,KAAC,CAAA;AAED,IAAA,MAAM,GAAG,GAAG,MAAM,KAAK,CAAA;AAEvB,IAAA,MAAM,SAAS,GAAG,CAAC,EAAY,KAAI;AAC/B,QAAA,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAClB,QAAA,OAAO,MAAK;YACR,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACnC,IAAI,KAAK,GAAG,CAAC,CAAC;AAAE,gBAAA,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;AAC9C,SAAC,CAAA;AACL,KAAC,CAAA;AAED,IAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,CAAA;AAClC;;MCpBa,IAAI,GAAG,IAAI,KAAK,CAAC,EAAE,EAAE;IAC9B,GAAG,CAAC,CAAC,EAAE,GAAW,EAAA;AACd,QAAA,OAAO,CAAC,YAAkB,EAAE,GAAG,QAAe,KAAI;YAC9C,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;YACtC,IAAI,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,YAAY,IAAI,CAAC,EAAE;AACrH,gBAAA,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;AAC/C,oBAAA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAW,CAAC,CAAA;iBAClC;aACJ;AAAM,iBAAA,IAAI,YAAY,IAAI,IAAI,EAAE;AAC7B,gBAAA,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;aACjC;YAED,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE;gBACjC,IAAI,KAAK,YAAY,IAAI;AAAE,oBAAA,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;;AAC3C,oBAAA,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;aAC9D;AACD,YAAA,OAAO,EAAE,CAAA;AACb,SAAC,CAAA;KACJ;AACJ,CAAA;;ACjBK,SAAU,MAAM,CAAC,MAAoC,EAAA;IACvD,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC/C,MAAM,aAAa,GAIb,EAAE,CAAA;AAER,IAAA,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE;QACvB,MAAM,IAAI,GAAa,EAAE,CAAA;QACzB,MAAM,OAAO,GAAG,IAAI;AACf,aAAA,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,KAAI;YAC7B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AACzB,YAAA,OAAO,UAAU,CAAA;AACrB,SAAC,CAAC;AACD,aAAA,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QACzB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,CAAI,CAAA,EAAA,OAAO,CAAG,CAAA,CAAA,CAAC,CAAA;AACxC,QAAA,aAAa,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;KAC7D;IAED,MAAM,WAAW,GAAG,MAAK;AACrB,QAAA,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAA;QACrC,IAAI,OAAO,GAAG,KAAK,CAAA;QAEnB,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,aAAa,EAAE;YAClD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC/B,IAAI,KAAK,EAAE;gBACP,MAAM,MAAM,GAA2B,EAAE,CAAA;gBACzC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,KAAI;oBACpB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;AAC9B,iBAAC,CAAC,CAAA;AACF,gBAAA,SAAS,CAAC,SAAS,GAAG,EAAE,CAAA;gBACxB,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;gBACtC,OAAO,GAAG,IAAI,CAAA;gBACd,MAAK;aACR;SACJ;QAED,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE;AACzB,YAAA,SAAS,CAAC,SAAS,GAAG,EAAE,CAAA;YACxB,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;SACvC;AACL,KAAC,CAAA;AAED,IAAA,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;AAChD,IAAA,WAAW,EAAE,CAAA;IAEb,OAAO;AACH,QAAA,MAAM,EAAE,WAAW;AACnB,QAAA,OAAO,EAAE,SAAS;KACrB,CAAA;AACL;;ACnDM,SAAU,GAAG,CAAC,SAAoB,EAAA;AACpC,IAAA,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE;AACjC,QAAA,MAAM,EAAE,GAAG,SAAS,EAAE,CAAA;AACtB,QAAA,IAAI,EAAE,EAAE,YAAY,IAAI,CAAC,EAAE;AACvB,YAAA,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;SACnE;AACD,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;KAChC;SAAM,IAAI,QAAQ,IAAI,SAAS,IAAI,OAAO,SAAS,CAAC,MAAM,KAAK,UAAU,EAAE;AACxE,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,IAAI,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAA;QAC7E,SAAS,CAAC,MAAM,EAAE,CAAA;KACrB;SAAM;AACH,QAAA,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;KACvD;AACL;;ACCA,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;AAC7C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;AAChD,IAAI,YAAY,GAA4B,IAAI,CAAC;AAEjD,MAAM,gBAAgB,GAAG;IACrB,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS;IACxD,MAAM,EAAE,QAAQ,EAAE,SAAS;CAC9B,CAAC;AAEF,SAAS,kBAAkB,GAAA;IACvB,IAAI,CAAC,YAAY,EAAE;AACf,QAAA,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;AAC/C,QAAA,YAAY,CAAC,EAAE,GAAG,QAAQ,CAAC;AAC3B,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;KAC3C;AACD,IAAA,OAAO,YAAY,CAAC;AACxB,CAAC;AAED,SAAS,UAAU,CAAC,GAAW,EAAA;IAC3B,IAAI,IAAI,GAAG,IAAI,CAAC;AAChB,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;AAAE,QAAA,IAAI,GAAG,CAAC,IAAI,GAAG,EAAE,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;AAC7C,SAAS,YAAY,CAAC,GAAW,EAAA;IAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACtB,QAAA,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;KACjF;AACD,IAAA,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;AAChC,CAAC;AAED,SAAS,cAAc,CAAC,KAAoB,EAAE,SAA8B,EAAA;IACxE,MAAM,GAAG,GAAa,EAAE,CAAC;AACzB,IAAA,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AAC5C,QAAA,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,SAAS;AACrD,QAAA,IAAI,GAAG,GAAG,OAAO,GAAG,KAAK,UAAU,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;AAElD,QAAA,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;YACzB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,SAAS,EAAE;gBAClC,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,CAAI,CAAA,EAAA,IAAI,CAAE,CAAA,EAAE,IAAI,CAAC,CAAC;aAC1C;SACJ;AACD,QAAA,GAAG,CAAC,IAAI,CAAC,CAAA,EAAG,YAAY,CAAC,GAAG,CAAC,CAAI,CAAA,EAAA,GAAG,CAAE,CAAA,CAAC,CAAC;KAC3C;AACD,IAAA,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,eAAe,GAAG,cAAc,CAAC;AAEvC,SAAS,iBAAiB,CAAC,IAAY,EAAE,MAAqC,EAAA;AAC1E,IAAA,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACvD,IAAA,MAAM,MAAM,GAAG,CAAA,EAAG,IAAI,CAAI,CAAA,EAAA,IAAI,EAAE,CAAC;AAEjC,IAAA,IAAI,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;AAAE,QAAA,OAAO,MAAM,CAAC;AAE7C,IAAA,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAA,EAAG,IAAI,CAAI,CAAA,EAAA,cAAc,CAAC,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC,CAAA,CAAA,CAAG,CAAC;SACxE,IAAI,CAAC,EAAE,CAAC,CAAC;AAEd,IAAA,kBAAkB,EAAE,CAAC,WAAW,CAC5B,QAAQ,CAAC,cAAc,CAAC,CAAA,WAAA,EAAc,MAAM,CAAI,CAAA,EAAA,KAAK,CAAK,GAAA,CAAA,CAAC,CAC9D,CAAC;AACF,IAAA,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAClC,IAAA,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,SAAS,UAAU,CAAC,SAAiB,EAAE,IAAe,EAAE,SAA8B,EAAA;IAClF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAkB,EAAE,CAAC;AAE/B,IAAA,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC3C,QAAA,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;AAExC,QAAA,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAChD,YAAA,KAAK,CAAC,IAAI,CAAC,CAAI,CAAA,EAAA,SAAS,GAAG,GAAG,CAAA,CAAA,EAAI,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA,CAAA,CAAG,CAAC,CAAC;SACxE;AACI,aAAA,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC1D,YAAA,KAAK,CAAC,IAAI,CAAC,CAAG,EAAA,GAAG,KAAK,SAAS,CAAA,CAAA,EAAI,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA,EAAA,CAAI,CAAC,CAAC;SAC1E;AACI,aAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AACnD,YAAA,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,CAAI,CAAA,EAAA,SAAS,CAAE,CAAA,CAAC,CAAC;AACtD,YAAA,KAAK,CAAC,IAAI,CAAC,CAAA,EAAG,QAAQ,CAAI,CAAA,EAAA,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA,CAAA,CAAG,CAAC,CAAC;SAChE;aACI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AAC3B,YAAA,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;SACnB;KACJ;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AAC9B,QAAA,KAAK,CAAC,IAAI,CAAC,CAAA,CAAA,EAAI,SAAS,CAAI,CAAA,EAAA,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA,CAAA,CAAG,CAAC,CAAC;KACnE;AAED,IAAA,OAAO,KAAK,CAAC;AACjB,CAAC;AAEK,SAAU,UAAU,CAAsB,MAAS,EAAA;AACrD,IAAA,OAAO,MAAK;QACR,MAAM,UAAU,GAAG,EAAmB,CAAC;QACvC,MAAM,cAAc,GAAa,EAAE,CAAC;AACpC,QAAA,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE/C,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAC7C,YAAA,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;gBAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,EAAE,GAAU,CAAC,CAAC;AACnD,gBAAA,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;aAClC;SACJ;AAED,QAAA,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAC/C,YAAA,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,SAAS;YAEzC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9C,MAAM,SAAS,GACX,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAA,CAAA,EAAI,IAAI,CAAE,CAAA,GAAG,CAAA,IAAA,EAAO,IAAI,CAAA,CAAE,CAAC;YAExE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;gBAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,EAAE,IAAiB,EAAE,YAAY,CAAC,CAAC;AACrE,gBAAA,cAAc,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;AAC9B,gBAAA,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;aACxC;AAED,YAAA,UAAU,CAAC,IAAe,CAAC,GAAG,SAAS,CAAC;SAC3C;AAED,QAAA,IAAI,cAAc,CAAC,MAAM,EAAE;AACvB,YAAA,MAAM,EAAE,GAAG,kBAAkB,EAAE,CAAC;YAChC,KAAK,MAAM,CAAC,IAAI,cAAc;AAAE,gBAAA,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;SACrF;AAED,QAAA,OAAO,UAAU,CAAC;AACtB,KAAC,CAAC;AACN,CAAC;MAEY,YAAY,GAAG,CAAC,GAAG,OAA8C,KAC1E,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;AAEtB,SAAA,cAAc,CAAsB,GAAG,IAAuB,EAAA;IAC1E,MAAM,MAAM,GAAQ,EAAE,CAAC;AACvB,IAAA,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;AACpB,QAAA,IAAI,CAAC,GAAG;YAAE,SAAS;AACnB,QAAA,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE;YACjB,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;SACnD;KACJ;AACD,IAAA,OAAO,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;AAChC;;;;;;;;;;"}
|
package/dist/index.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).MiniUI={})}(this,function(e){"use strict";const t=new Proxy({},{get:(e,t)=>(e,...n)=>{const o=document.createElement(t);if(!e||"object"!=typeof e||Array.isArray(e)||e instanceof Node)null!=e&&n.unshift(e);else for(const[t,n]of Object.entries(e))o.setAttribute(t,n);for(const e of n.flat())e instanceof Node?o.appendChild(e):o.appendChild(document.createTextNode(String(e)));return o}});const n=new Map,o=new Map;let s=null;const r=["root","button","icon","text","container","wrapper","card","header","section"];function c(){return s||(s=document.createElement("style"),s.id="styles",document.head.appendChild(s)),s}function i(e){let t=5381;for(let n=0;n<e.length;n++)t=33*t^e.charCodeAt(n);return(t>>>0).toString(36)}const f=new Map;function a(e){return f.has(e)||f.set(e,e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()),f.get(e)}function d(e,t){const n=[];for(const[o,s]of Object.entries(e)){if(null==s||"object"==typeof s)continue;let e="function"==typeof s?s():s;if("string"==typeof e)for(const[n,o]of t)e=e.replaceAll(`$${n}`,o);n.push(`${a(o)}:${e}`)}return n.join(";")}const l=/^@keyframes /;function u(e,t){const n=`${e}-${i(e+JSON.stringify(t))}`;if(o.has(n))return n;const s=Object.entries(t).map(([e,t])=>`${e}{${d(t,new Map)}}`).join("");return c().appendChild(document.createTextNode(`@keyframes ${n}{${s}}\n`)),o.set(n,n),n}function p(e,t,n){const o=[],s={};for(const[r,c]of Object.entries(t))if(!l.test(r))if(r.startsWith(":")&&"object"==typeof c)o.push(`.${e}${r}{${d(c,n)}}`);else if(r.startsWith("@media")&&"object"==typeof c)o.push(`${r}{.${e}{${d(c,n)}}}`);else if(r.includes("&")&&"object"==typeof c){const t=r.replaceAll("&",`.${e}`);o.push(`${t}{${d(c,n)}}`)}else r.startsWith("@")||(s[r]=c);return Object.keys(s).length>0&&o.push(`.${e}{${d(s,n)}}`),o}function h(e){return()=>{const t={},o=[],s=new Map;for(const[t,n]of Object.entries(e))if(l.test(t)){const e=t.replace("@keyframes ",""),o=u(e,n);s.set(e,o)}for(const[c,f]of Object.entries(e)){if(l.test(c))continue;const e=i(JSON.stringify(f)),a=r.includes(c)?`${c}-${e}`:`css-${e}`;if(!n.has(a)){const e=p(a,f,s);o.push(...e),n.set(a,a)}t[c]=a}if(o.length){const e=c();for(const t of o)e.appendChild(document.createTextNode(t+"\n"))}return t}}e.add=function(e){if("function"==typeof e){const t=e();if(!(t instanceof Node))throw new Error("Component function must return an HTMLElement");document.body.appendChild(t)}else{if(!("render"in e)||"function"!=typeof e.render)throw new Error("Invalid component passed to add()");document.body.appendChild(e.element||document.createElement("div")),e.render()}},e.makeStyles=h,e.mergeClasses=(...e)=>e.filter(Boolean).join(" "),e.mergeStyleSets=function(...e){const t={};for(const n of e)if(n)for(const e in n)t[e]={...t[e]||{},...n[e]};return h(t)()},e.router=function(e){const t=document.createElement("div"),n=[];for(const t in e){const o=[],s=t.replace(/\/:[^\/]+/g,e=>(o.push(e.slice(2)),"/([^/]+)")).replace(/\*/g,".*"),r=new RegExp(`^${s}$`);n.push({regex:r,keys:o,handler:e[t]})}const o=()=>{const o=window.location.pathname;let s=!1;for(const{regex:e,keys:r,handler:c}of n){const n=o.match(e);if(n){const e={};r.forEach((t,o)=>{e[t]=n[o+1]}),t.innerHTML="",t.appendChild(c(e)),s=!0;break}}!s&&e["*"]&&(t.innerHTML="",t.appendChild(e["*"]()))};return window.addEventListener("popstate",o),o(),{render:o,element:t}},e.state=function(e){let t=e;const n=[];return{get:()=>t,set:e=>{t=e,n.forEach(e=>e(t))},subscribe:e=>(n.push(e),()=>{const t=n.indexOf(e);t>-1&&n.splice(t,1)})}},e.tags=t,Object.defineProperty(e,"__esModule",{value:!0})});
|
|
2
2
|
//# sourceMappingURL=index.min.js.map
|
package/dist/index.min.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.min.js","sources":["../src/tags.ts","../src/helpers.ts","../src/router.ts","../src/state.ts"],"sourcesContent":["export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","type Component = (() => HTMLElement) | { render: () => void }\r\n\r\nexport function add(...components: Component[]) {\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n\r\n for (const c of components) {\r\n if (typeof c === \"function\") {\r\n const el = c()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n app.appendChild(el)\r\n } else if (\"render\" in c && typeof c.render === \"function\") {\r\n c.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n }\r\n}\r\n","export function router(routes: Record<string, () => HTMLElement>) {\r\n const getRoute = (path: string) => {\r\n return routes[path] || routes[\"*\"]\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n const pageFn = getRoute(path)\r\n const page = pageFn()\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n app.innerHTML = \"\"\r\n app.appendChild(page)\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n\r\n return {\r\n render: renderRoute,\r\n navigate: (path: string) => {\r\n history.pushState(null, \"\", path)\r\n renderRoute()\r\n }\r\n }\r\n}","export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}"],"names":["tags","Proxy","get","_","tag","attrsOrChild","children","el","document","createElement","Array","isArray","Node","unshift","k","v","Object","entries","setAttribute","child","flat","appendChild","createTextNode","String","components","app","getElementById","Error","c","render","routes","renderRoute","pageFn","path","getRoute","window","location","pathname","page","innerHTML","addEventListener","navigate","history","pushState","initial","value","listeners","set","newValue","forEach","fn","subscribe","push","index","indexOf","splice"],"mappings":"mPAAaA,EAAO,IAAIC,MAAM,GAAI,CAC9BC,IAAG,CAACC,EAAGC,IACI,CAACC,KAAuBC,KAC3B,MAAMC,EAAKC,SAASC,cAAcL,GAClC,IAAIC,GAAwC,iBAAjBA,GAA8BK,MAAMC,QAAQN,IAAmBA,aAAwBO,KAIvF,MAAhBP,GACPC,EAASO,QAAQR,QAJjB,IAAK,MAAOS,EAAGC,KAAMC,OAAOC,QAAQZ,GAChCE,EAAGW,aAAaJ,EAAGC,GAM3B,IAAK,MAAMI,KAASb,EAASc,OACrBD,aAAiBP,KAAML,EAAGc,YAAYF,GACrCZ,EAAGc,YAAYb,SAASc,eAAeC,OAAOJ,KAEvD,OAAOZ,WCdH,YAAOiB,GACnB,MAAMC,EAAMjB,SAASkB,eAAe,OACpC,IAAKD,EAAK,MAAM,IAAIE,MAAM,yBAE1B,IAAK,MAAMC,KAAKJ,EACZ,GAAiB,mBAANI,EAAkB,CACzB,MAAMrB,EAAKqB,IACX,KAAMrB,aAAcK,MAChB,MAAM,IAAIe,MAAM,iDAEpBF,EAAIJ,YAAYd,EACnB,KAAM,MAAI,WAAYqB,IAAyB,mBAAbA,EAAEC,OAGjC,MAAM,IAAIF,MAAM,qCAFhBC,EAAEC,QAGL,CAET,WCnBM,SAAiBC,GACnB,MAIMC,EAAc,KAChB,MACMC,EANO,CAACC,GACPH,EAAOG,IAASH,EAAO,KAKfI,CADFC,OAAOC,SAASC,UAEvBC,EAAON,IACPP,EAAMjB,SAASkB,eAAe,OACpC,IAAKD,EAAK,MAAM,IAAIE,MAAM,yBAC1BF,EAAIc,UAAY,GAChBd,EAAIJ,YAAYiB,IAKpB,OAFAH,OAAOK,iBAAiB,WAAYT,GAE7B,CACHF,OAAQE,EACRU,SAAWR,IACPS,QAAQC,UAAU,KAAM,GAAIV,GAC5BF,KAGZ,UCxBM,SAAmBa,GACrB,IAAIC,EAAQD,EACZ,MAAME,EAAwB,GAiB9B,MAAO,CAAE5C,IAVG,IAAM2C,EAUJE,IAfDC,IACTH,EAAQG,EACRF,EAAUG,QAAQC,GAAMA,EAAGL,KAaZM,UARAD,IACfJ,EAAUM,KAAKF,GACR,KACH,MAAMG,EAAQP,EAAUQ,QAAQJ,GAC5BG,GAAS,GAAGP,EAAUS,OAAOF,EAAO,KAKpD"}
|
|
1
|
+
{"version":3,"file":"index.min.js","sources":["../src/tags.ts","../src/styles.ts","../src/helpers.ts","../src/router.ts","../src/state.ts"],"sourcesContent":["export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","export type CSSValue = string | number | (() => string | number);\r\nexport interface CSSProperties {\r\n [key: string]: CSSValue | CSSProperties;\r\n}\r\nexport type StyleRule = CSSProperties & {\r\n ':hover'?: CSSProperties;\r\n ':focus'?: CSSProperties;\r\n ':active'?: CSSProperties;\r\n ':disabled'?: CSSProperties;\r\n [key: string]: any;\r\n};\r\nexport type StylesMap<T extends Record<string, any> = {}> = {\r\n [K in keyof T]: StyleRule;\r\n};\r\nexport type ClassNames<T extends Record<string, any>> = { [K in keyof T]: string };\r\n\r\nconst styleCache = new Map<string, string>();\r\nconst keyframeCache = new Map<string, string>();\r\nlet styleElement: HTMLStyleElement | null = null;\r\n\r\nconst ALLOWED_PREFIXES = [\r\n 'root', 'button', 'icon', 'text', 'container', 'wrapper',\r\n 'card', 'header', 'section'\r\n];\r\n\r\nfunction ensureStyleElement() {\r\n if (!styleElement) {\r\n styleElement = document.createElement('style');\r\n styleElement.id = 'styles';\r\n document.head.appendChild(styleElement);\r\n }\r\n return styleElement;\r\n}\r\n\r\nfunction hashString(str: string): string {\r\n let hash = 5381;\r\n for (let i = 0; i < str.length; i++) hash = (hash * 33) ^ str.charCodeAt(i);\r\n return (hash >>> 0).toString(36);\r\n}\r\n\r\nconst kebabCache = new Map<string, string>();\r\nfunction camelToKebab(str: string): string {\r\n if (!kebabCache.has(str)) {\r\n kebabCache.set(str, str.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase());\r\n }\r\n return kebabCache.get(str)!;\r\n}\r\n\r\nfunction stringifyDecls(props: CSSProperties, keyframes: Map<string, string>): string {\r\n const out: string[] = [];\r\n for (const [key, raw] of Object.entries(props)) {\r\n if (raw == null || typeof raw === \"object\") continue;\r\n let val = typeof raw === \"function\" ? raw() : raw;\r\n\r\n if (typeof val === \"string\") {\r\n for (const [orig, uniq] of keyframes) {\r\n val = val.replaceAll(`$${orig}`, uniq);\r\n }\r\n }\r\n out.push(`${camelToKebab(key)}:${val}`);\r\n }\r\n return out.join(\";\");\r\n}\r\n\r\nconst KEYFRAMES_REGEX = /^@keyframes /;\r\n\r\nfunction registerKeyframes(name: string, frames: Record<string, CSSProperties>): string {\r\n const hash = hashString(name + JSON.stringify(frames));\r\n const unique = `${name}-${hash}`;\r\n\r\n if (keyframeCache.has(unique)) return unique;\r\n\r\n const rules = Object.entries(frames)\r\n .map(([step, styles]) => `${step}{${stringifyDecls(styles, new Map())}}`)\r\n .join(\"\");\r\n\r\n ensureStyleElement().appendChild(\r\n document.createTextNode(`@keyframes ${unique}{${rules}}\\n`)\r\n );\r\n keyframeCache.set(unique, unique);\r\n return unique;\r\n}\r\n\r\nfunction buildRules(className: string, rule: StyleRule, keyframes: Map<string, string>): string[] {\r\n const rules: string[] = [];\r\n const base: CSSProperties = {};\r\n\r\n for (const [key, val] of Object.entries(rule)) {\r\n if (KEYFRAMES_REGEX.test(key)) continue;\r\n\r\n if (key.startsWith(':') && typeof val === \"object\") {\r\n rules.push(`.${className}${key}{${stringifyDecls(val, keyframes)}}`);\r\n }\r\n else if (key.startsWith('@media') && typeof val === \"object\") {\r\n rules.push(`${key}{.${className}{${stringifyDecls(val, keyframes)}}}`);\r\n }\r\n else if (key.includes('&') && typeof val === \"object\") {\r\n const selector = key.replaceAll(\"&\", `.${className}`);\r\n rules.push(`${selector}{${stringifyDecls(val, keyframes)}}`);\r\n }\r\n else if (!key.startsWith('@')) {\r\n base[key] = val;\r\n }\r\n }\r\n\r\n if (Object.keys(base).length > 0) {\r\n rules.push(`.${className}{${stringifyDecls(base, keyframes)}}`);\r\n }\r\n\r\n return rules;\r\n}\r\n\r\nexport function makeStyles<T extends StylesMap>(styles: T) {\r\n return () => {\r\n const classNames = {} as ClassNames<T>;\r\n const collectedRules: string[] = [];\r\n const keyframesMap = new Map<string, string>();\r\n\r\n for (const [key, val] of Object.entries(styles)) {\r\n if (KEYFRAMES_REGEX.test(key)) {\r\n const name = key.replace('@keyframes ', '');\r\n const unique = registerKeyframes(name, val as any);\r\n keyframesMap.set(name, unique);\r\n }\r\n }\r\n\r\n for (const [slot, rule] of Object.entries(styles)) {\r\n if (KEYFRAMES_REGEX.test(slot)) continue;\r\n\r\n const hash = hashString(JSON.stringify(rule));\r\n const className =\r\n ALLOWED_PREFIXES.includes(slot) ? `${slot}-${hash}` : `css-${hash}`;\r\n\r\n if (!styleCache.has(className)) {\r\n const rules = buildRules(className, rule as StyleRule, keyframesMap);\r\n collectedRules.push(...rules);\r\n styleCache.set(className, className);\r\n }\r\n\r\n classNames[slot as keyof T] = className;\r\n }\r\n\r\n if (collectedRules.length) {\r\n const el = ensureStyleElement();\r\n for (const r of collectedRules) el.appendChild(document.createTextNode(r + \"\\n\"));\r\n }\r\n\r\n return classNames;\r\n };\r\n}\r\n\r\nexport const mergeClasses = (...classes: (string | undefined | null | false)[]) =>\r\n classes.filter(Boolean).join(\" \");\r\n\r\nexport function mergeStyleSets<T extends StylesMap>(...sets: (T | undefined)[]) {\r\n const merged: any = {};\r\n for (const set of sets) {\r\n if (!set) continue;\r\n for (const k in set) {\r\n merged[k] = { ...(merged[k] || {}), ...set[k] };\r\n }\r\n }\r\n return makeStyles(merged)();\r\n}","type Component = (() => HTMLElement) | { render: () => void; element?: HTMLElement }\r\n\r\nexport function add(component: Component) {\r\n if (typeof component === \"function\") {\r\n const el = component()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n document.body.appendChild(el)\r\n } else if (\"render\" in component && typeof component.render === \"function\") {\r\n document.body.appendChild(component.element || document.createElement(\"div\"))\r\n component.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n}","type RouteHandler = (params?: Record<string, string>) => HTMLElement\r\n\r\nexport function router(routes: Record<string, RouteHandler>) {\r\n const container = document.createElement(\"div\")\r\n const routePatterns: {\r\n regex: RegExp\r\n keys: string[]\r\n handler: RouteHandler\r\n }[] = []\r\n\r\n for (const path in routes) {\r\n const keys: string[] = []\r\n const pattern = path\r\n .replace(/\\/:[^\\/]+/g, (match) => {\r\n keys.push(match.slice(2))\r\n return \"/([^/]+)\"\r\n })\r\n .replace(/\\*/g, \".*\")\r\n const regex = new RegExp(`^${pattern}$`)\r\n routePatterns.push({ regex, keys, handler: routes[path] })\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n let matched = false\r\n\r\n for (const { regex, keys, handler } of routePatterns) {\r\n const match = path.match(regex)\r\n if (match) {\r\n const params: Record<string, string> = {}\r\n keys.forEach((key, i) => {\r\n params[key] = match[i + 1]\r\n })\r\n container.innerHTML = \"\"\r\n container.appendChild(handler(params))\r\n matched = true\r\n break\r\n }\r\n }\r\n\r\n if (!matched && routes[\"*\"]) {\r\n container.innerHTML = \"\"\r\n container.appendChild(routes[\"*\"]())\r\n }\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n renderRoute()\r\n\r\n return {\r\n render: renderRoute,\r\n element: container\r\n }\r\n}\r\n","export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}"],"names":["tags","Proxy","get","_","tag","attrsOrChild","children","el","document","createElement","Array","isArray","Node","unshift","k","v","Object","entries","setAttribute","child","flat","appendChild","createTextNode","String","styleCache","Map","keyframeCache","styleElement","ALLOWED_PREFIXES","ensureStyleElement","id","head","hashString","str","hash","i","length","charCodeAt","toString","kebabCache","camelToKebab","has","set","replace","toLowerCase","stringifyDecls","props","keyframes","out","key","raw","val","orig","uniq","replaceAll","push","join","KEYFRAMES_REGEX","registerKeyframes","name","frames","unique","JSON","stringify","rules","map","step","styles","buildRules","className","rule","base","test","startsWith","includes","selector","keys","makeStyles","classNames","collectedRules","keyframesMap","slot","r","component","Error","body","render","element","classes","filter","Boolean","sets","merged","routes","container","routePatterns","path","pattern","match","slice","regex","RegExp","handler","renderRoute","window","location","pathname","matched","params","forEach","innerHTML","addEventListener","initial","value","listeners","newValue","fn","subscribe","index","indexOf","splice"],"mappings":"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"}
|
package/dist/router.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
type RouteHandler = (params?: Record<string, string>) => HTMLElement;
|
|
2
|
+
export declare function router(routes: Record<string, RouteHandler>): {
|
|
2
3
|
render: () => void;
|
|
3
|
-
|
|
4
|
+
element: HTMLDivElement;
|
|
4
5
|
};
|
|
6
|
+
export {};
|
package/dist/styles.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type CSSValue = string | number | (() => string | number);
|
|
2
|
+
export interface CSSProperties {
|
|
3
|
+
[key: string]: CSSValue | CSSProperties;
|
|
4
|
+
}
|
|
5
|
+
export type StyleRule = CSSProperties & {
|
|
6
|
+
':hover'?: CSSProperties;
|
|
7
|
+
':focus'?: CSSProperties;
|
|
8
|
+
':active'?: CSSProperties;
|
|
9
|
+
':disabled'?: CSSProperties;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
};
|
|
12
|
+
export type StylesMap<T extends Record<string, any> = {}> = {
|
|
13
|
+
[K in keyof T]: StyleRule;
|
|
14
|
+
};
|
|
15
|
+
export type ClassNames<T extends Record<string, any>> = {
|
|
16
|
+
[K in keyof T]: string;
|
|
17
|
+
};
|
|
18
|
+
export declare function makeStyles<T extends StylesMap>(styles: T): () => ClassNames<T>;
|
|
19
|
+
export declare const mergeClasses: (...classes: (string | undefined | null | false)[]) => string;
|
|
20
|
+
export declare function mergeStyleSets<T extends StylesMap>(...sets: (T | undefined)[]): ClassNames<any>;
|
package/package.json
CHANGED
package/src/helpers.ts
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
type Component = (() => HTMLElement) | { render: () => void }
|
|
1
|
+
type Component = (() => HTMLElement) | { render: () => void; element?: HTMLElement }
|
|
2
2
|
|
|
3
|
-
export function add(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (typeof c === "function") {
|
|
9
|
-
const el = c()
|
|
10
|
-
if (!(el instanceof Node)) {
|
|
11
|
-
throw new Error("Component function must return an HTMLElement")
|
|
12
|
-
}
|
|
13
|
-
app.appendChild(el)
|
|
14
|
-
} else if ("render" in c && typeof c.render === "function") {
|
|
15
|
-
c.render()
|
|
16
|
-
} else {
|
|
17
|
-
throw new Error("Invalid component passed to add()")
|
|
3
|
+
export function add(component: Component) {
|
|
4
|
+
if (typeof component === "function") {
|
|
5
|
+
const el = component()
|
|
6
|
+
if (!(el instanceof Node)) {
|
|
7
|
+
throw new Error("Component function must return an HTMLElement")
|
|
18
8
|
}
|
|
9
|
+
document.body.appendChild(el)
|
|
10
|
+
} else if ("render" in component && typeof component.render === "function") {
|
|
11
|
+
document.body.appendChild(component.element || document.createElement("div"))
|
|
12
|
+
component.render()
|
|
13
|
+
} else {
|
|
14
|
+
throw new Error("Invalid component passed to add()")
|
|
19
15
|
}
|
|
20
|
-
}
|
|
16
|
+
}
|
package/src/index.ts
CHANGED
package/src/router.ts
CHANGED
|
@@ -1,25 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
type RouteHandler = (params?: Record<string, string>) => HTMLElement
|
|
2
|
+
|
|
3
|
+
export function router(routes: Record<string, RouteHandler>) {
|
|
4
|
+
const container = document.createElement("div")
|
|
5
|
+
const routePatterns: {
|
|
6
|
+
regex: RegExp
|
|
7
|
+
keys: string[]
|
|
8
|
+
handler: RouteHandler
|
|
9
|
+
}[] = []
|
|
10
|
+
|
|
11
|
+
for (const path in routes) {
|
|
12
|
+
const keys: string[] = []
|
|
13
|
+
const pattern = path
|
|
14
|
+
.replace(/\/:[^\/]+/g, (match) => {
|
|
15
|
+
keys.push(match.slice(2))
|
|
16
|
+
return "/([^/]+)"
|
|
17
|
+
})
|
|
18
|
+
.replace(/\*/g, ".*")
|
|
19
|
+
const regex = new RegExp(`^${pattern}$`)
|
|
20
|
+
routePatterns.push({ regex, keys, handler: routes[path] })
|
|
4
21
|
}
|
|
5
22
|
|
|
6
23
|
const renderRoute = () => {
|
|
7
24
|
const path = window.location.pathname
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
let matched = false
|
|
26
|
+
|
|
27
|
+
for (const { regex, keys, handler } of routePatterns) {
|
|
28
|
+
const match = path.match(regex)
|
|
29
|
+
if (match) {
|
|
30
|
+
const params: Record<string, string> = {}
|
|
31
|
+
keys.forEach((key, i) => {
|
|
32
|
+
params[key] = match[i + 1]
|
|
33
|
+
})
|
|
34
|
+
container.innerHTML = ""
|
|
35
|
+
container.appendChild(handler(params))
|
|
36
|
+
matched = true
|
|
37
|
+
break
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!matched && routes["*"]) {
|
|
42
|
+
container.innerHTML = ""
|
|
43
|
+
container.appendChild(routes["*"]())
|
|
44
|
+
}
|
|
14
45
|
}
|
|
15
46
|
|
|
16
47
|
window.addEventListener("popstate", renderRoute)
|
|
48
|
+
renderRoute()
|
|
17
49
|
|
|
18
50
|
return {
|
|
19
51
|
render: renderRoute,
|
|
20
|
-
|
|
21
|
-
history.pushState(null, "", path)
|
|
22
|
-
renderRoute()
|
|
23
|
-
}
|
|
52
|
+
element: container
|
|
24
53
|
}
|
|
25
|
-
}
|
|
54
|
+
}
|
package/src/styles.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
export type CSSValue = string | number | (() => string | number);
|
|
2
|
+
export interface CSSProperties {
|
|
3
|
+
[key: string]: CSSValue | CSSProperties;
|
|
4
|
+
}
|
|
5
|
+
export type StyleRule = CSSProperties & {
|
|
6
|
+
':hover'?: CSSProperties;
|
|
7
|
+
':focus'?: CSSProperties;
|
|
8
|
+
':active'?: CSSProperties;
|
|
9
|
+
':disabled'?: CSSProperties;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
};
|
|
12
|
+
export type StylesMap<T extends Record<string, any> = {}> = {
|
|
13
|
+
[K in keyof T]: StyleRule;
|
|
14
|
+
};
|
|
15
|
+
export type ClassNames<T extends Record<string, any>> = { [K in keyof T]: string };
|
|
16
|
+
|
|
17
|
+
const styleCache = new Map<string, string>();
|
|
18
|
+
const keyframeCache = new Map<string, string>();
|
|
19
|
+
let styleElement: HTMLStyleElement | null = null;
|
|
20
|
+
|
|
21
|
+
const ALLOWED_PREFIXES = [
|
|
22
|
+
'root', 'button', 'icon', 'text', 'container', 'wrapper',
|
|
23
|
+
'card', 'header', 'section'
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
function ensureStyleElement() {
|
|
27
|
+
if (!styleElement) {
|
|
28
|
+
styleElement = document.createElement('style');
|
|
29
|
+
styleElement.id = 'styles';
|
|
30
|
+
document.head.appendChild(styleElement);
|
|
31
|
+
}
|
|
32
|
+
return styleElement;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function hashString(str: string): string {
|
|
36
|
+
let hash = 5381;
|
|
37
|
+
for (let i = 0; i < str.length; i++) hash = (hash * 33) ^ str.charCodeAt(i);
|
|
38
|
+
return (hash >>> 0).toString(36);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const kebabCache = new Map<string, string>();
|
|
42
|
+
function camelToKebab(str: string): string {
|
|
43
|
+
if (!kebabCache.has(str)) {
|
|
44
|
+
kebabCache.set(str, str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase());
|
|
45
|
+
}
|
|
46
|
+
return kebabCache.get(str)!;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function stringifyDecls(props: CSSProperties, keyframes: Map<string, string>): string {
|
|
50
|
+
const out: string[] = [];
|
|
51
|
+
for (const [key, raw] of Object.entries(props)) {
|
|
52
|
+
if (raw == null || typeof raw === "object") continue;
|
|
53
|
+
let val = typeof raw === "function" ? raw() : raw;
|
|
54
|
+
|
|
55
|
+
if (typeof val === "string") {
|
|
56
|
+
for (const [orig, uniq] of keyframes) {
|
|
57
|
+
val = val.replaceAll(`$${orig}`, uniq);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
out.push(`${camelToKebab(key)}:${val}`);
|
|
61
|
+
}
|
|
62
|
+
return out.join(";");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const KEYFRAMES_REGEX = /^@keyframes /;
|
|
66
|
+
|
|
67
|
+
function registerKeyframes(name: string, frames: Record<string, CSSProperties>): string {
|
|
68
|
+
const hash = hashString(name + JSON.stringify(frames));
|
|
69
|
+
const unique = `${name}-${hash}`;
|
|
70
|
+
|
|
71
|
+
if (keyframeCache.has(unique)) return unique;
|
|
72
|
+
|
|
73
|
+
const rules = Object.entries(frames)
|
|
74
|
+
.map(([step, styles]) => `${step}{${stringifyDecls(styles, new Map())}}`)
|
|
75
|
+
.join("");
|
|
76
|
+
|
|
77
|
+
ensureStyleElement().appendChild(
|
|
78
|
+
document.createTextNode(`@keyframes ${unique}{${rules}}\n`)
|
|
79
|
+
);
|
|
80
|
+
keyframeCache.set(unique, unique);
|
|
81
|
+
return unique;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function buildRules(className: string, rule: StyleRule, keyframes: Map<string, string>): string[] {
|
|
85
|
+
const rules: string[] = [];
|
|
86
|
+
const base: CSSProperties = {};
|
|
87
|
+
|
|
88
|
+
for (const [key, val] of Object.entries(rule)) {
|
|
89
|
+
if (KEYFRAMES_REGEX.test(key)) continue;
|
|
90
|
+
|
|
91
|
+
if (key.startsWith(':') && typeof val === "object") {
|
|
92
|
+
rules.push(`.${className}${key}{${stringifyDecls(val, keyframes)}}`);
|
|
93
|
+
}
|
|
94
|
+
else if (key.startsWith('@media') && typeof val === "object") {
|
|
95
|
+
rules.push(`${key}{.${className}{${stringifyDecls(val, keyframes)}}}`);
|
|
96
|
+
}
|
|
97
|
+
else if (key.includes('&') && typeof val === "object") {
|
|
98
|
+
const selector = key.replaceAll("&", `.${className}`);
|
|
99
|
+
rules.push(`${selector}{${stringifyDecls(val, keyframes)}}`);
|
|
100
|
+
}
|
|
101
|
+
else if (!key.startsWith('@')) {
|
|
102
|
+
base[key] = val;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (Object.keys(base).length > 0) {
|
|
107
|
+
rules.push(`.${className}{${stringifyDecls(base, keyframes)}}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return rules;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function makeStyles<T extends StylesMap>(styles: T) {
|
|
114
|
+
return () => {
|
|
115
|
+
const classNames = {} as ClassNames<T>;
|
|
116
|
+
const collectedRules: string[] = [];
|
|
117
|
+
const keyframesMap = new Map<string, string>();
|
|
118
|
+
|
|
119
|
+
for (const [key, val] of Object.entries(styles)) {
|
|
120
|
+
if (KEYFRAMES_REGEX.test(key)) {
|
|
121
|
+
const name = key.replace('@keyframes ', '');
|
|
122
|
+
const unique = registerKeyframes(name, val as any);
|
|
123
|
+
keyframesMap.set(name, unique);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const [slot, rule] of Object.entries(styles)) {
|
|
128
|
+
if (KEYFRAMES_REGEX.test(slot)) continue;
|
|
129
|
+
|
|
130
|
+
const hash = hashString(JSON.stringify(rule));
|
|
131
|
+
const className =
|
|
132
|
+
ALLOWED_PREFIXES.includes(slot) ? `${slot}-${hash}` : `css-${hash}`;
|
|
133
|
+
|
|
134
|
+
if (!styleCache.has(className)) {
|
|
135
|
+
const rules = buildRules(className, rule as StyleRule, keyframesMap);
|
|
136
|
+
collectedRules.push(...rules);
|
|
137
|
+
styleCache.set(className, className);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
classNames[slot as keyof T] = className;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (collectedRules.length) {
|
|
144
|
+
const el = ensureStyleElement();
|
|
145
|
+
for (const r of collectedRules) el.appendChild(document.createTextNode(r + "\n"));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return classNames;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export const mergeClasses = (...classes: (string | undefined | null | false)[]) =>
|
|
153
|
+
classes.filter(Boolean).join(" ");
|
|
154
|
+
|
|
155
|
+
export function mergeStyleSets<T extends StylesMap>(...sets: (T | undefined)[]) {
|
|
156
|
+
const merged: any = {};
|
|
157
|
+
for (const set of sets) {
|
|
158
|
+
if (!set) continue;
|
|
159
|
+
for (const k in set) {
|
|
160
|
+
merged[k] = { ...(merged[k] || {}), ...set[k] };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return makeStyles(merged)();
|
|
164
|
+
}
|