@epoch32/visage 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +373 -0
- package/README.md +110 -2
- package/dist/src/api/index.js +4002 -0
- package/dist/src/charts/index.js +2717 -0
- package/dist/src/devtools/index.js +4677 -0
- package/dist/src/dom/index.js +1550 -0
- package/dist/src/form/index.js +1415 -0
- package/dist/src/index.js +11826 -0
- package/dist/src/jsx-runtime/index.js +1630 -0
- package/dist/src/query/index.js +2422 -0
- package/dist/src/router/index.js +1856 -0
- package/dist/src/rpc/index.js +3484 -0
- package/dist/src/server/index.js +1173 -0
- package/dist/src/signals/index.js +1077 -0
- package/dist/src/style/index.js +2340 -0
- package/dist/src/template/index.js +1149 -0
- package/dist/src/ui/index.js +4155 -0
- package/dist/src/virtual/index.js +1955 -0
- package/dist/src/vite/index.js +984 -0
- package/package.json +140 -4
- package/src/api/client.ts +371 -0
- package/src/api/file-router.ts +183 -0
- package/src/api/handler.ts +326 -0
- package/src/api/index.ts +71 -0
- package/src/api/middleware.ts +54 -0
- package/src/api/pragma.ts +155 -0
- package/src/api/procedure.ts +172 -0
- package/src/api/types.ts +249 -0
- package/src/charts/Area.tsx +111 -0
- package/src/charts/Axis.tsx +126 -0
- package/src/charts/Bar.tsx +86 -0
- package/src/charts/CartesianGrid.tsx +72 -0
- package/src/charts/Chart.tsx +269 -0
- package/src/charts/Cursor.tsx +42 -0
- package/src/charts/Legend.tsx +56 -0
- package/src/charts/Line.tsx +106 -0
- package/src/charts/Pie.tsx +88 -0
- package/src/charts/Tooltip.tsx +127 -0
- package/src/charts/context.ts +30 -0
- package/src/charts/index.ts +14 -0
- package/src/charts/path.ts +155 -0
- package/src/charts/scale.ts +133 -0
- package/src/charts/types.ts +50 -0
- package/src/devtools/DomTab.tsx +134 -0
- package/src/devtools/GraphInspector.tsx +196 -0
- package/src/devtools/GraphTab.tsx +315 -0
- package/src/devtools/QueryTab.tsx +200 -0
- package/src/devtools/RpcTab.tsx +190 -0
- package/src/devtools/SignalsTab.tsx +129 -0
- package/src/devtools/component.tsx +243 -0
- package/src/devtools/highlighter.ts +134 -0
- package/src/devtools/hub.ts +175 -0
- package/src/devtools/index.ts +20 -0
- package/src/devtools/styles.ts +313 -0
- package/src/devtools/types.ts +45 -0
- package/src/dom/async.ts +232 -0
- package/src/dom/control-flow.ts +353 -0
- package/src/dom/index.ts +32 -0
- package/src/dom/lazy.ts +82 -0
- package/src/dom/render.ts +286 -0
- package/src/dom/resource.ts +120 -0
- package/src/form/form.ts +218 -0
- package/src/form/index.ts +17 -0
- package/src/form/schema.ts +299 -0
- package/src/index.ts +413 -0
- package/src/jsx-dev-runtime/index.ts +1 -0
- package/src/jsx-runtime/index.ts +112 -0
- package/src/jsx-runtime/jsx.d.ts +278 -0
- package/src/query/create-mutation.ts +64 -0
- package/src/query/create-query.ts +426 -0
- package/src/query/focus-manager.ts +68 -0
- package/src/query/index.ts +63 -0
- package/src/query/mutation-cache.ts +138 -0
- package/src/query/online-manager.ts +67 -0
- package/src/query/query-cache.ts +369 -0
- package/src/query/query-client.ts +248 -0
- package/src/query/types.ts +221 -0
- package/src/query/utils.ts +132 -0
- package/src/router/index.ts +19 -0
- package/src/router/router.tsx +352 -0
- package/src/rpc/client.ts +317 -0
- package/src/rpc/error.ts +70 -0
- package/src/rpc/index.ts +52 -0
- package/src/rpc/procedure.ts +88 -0
- package/src/rpc/router.ts +105 -0
- package/src/rpc/server.ts +511 -0
- package/src/rpc/types.ts +328 -0
- package/src/server/hydrate.ts +21 -0
- package/src/server/index.ts +10 -0
- package/src/server/render-to-stream.ts +31 -0
- package/src/server/render-to-string.ts +125 -0
- package/src/signals/computed.ts +217 -0
- package/src/signals/context.ts +89 -0
- package/src/signals/effect.ts +161 -0
- package/src/signals/index.ts +57 -0
- package/src/signals/scope.ts +132 -0
- package/src/signals/signal.ts +203 -0
- package/src/signals/store.ts +163 -0
- package/src/signals/system.ts +124 -0
- package/src/signals/types.ts +64 -0
- package/src/style/component.tsx +122 -0
- package/src/style/create-style.ts +229 -0
- package/src/style/cx.ts +75 -0
- package/src/style/hash.ts +19 -0
- package/src/style/index.ts +8 -0
- package/src/style/layout.tsx +406 -0
- package/src/style/manager.ts +87 -0
- package/src/style/parser.ts +257 -0
- package/src/style/scale.ts +237 -0
- package/src/template/index.ts +4 -0
- package/src/template/template.ts +126 -0
- package/src/ui/accordion.tsx +286 -0
- package/src/ui/command-dialog.tsx +49 -0
- package/src/ui/command.tsx +400 -0
- package/src/ui/data-table.tsx +322 -0
- package/src/ui/dialog.tsx +362 -0
- package/src/ui/dropdown-menu.tsx +381 -0
- package/src/ui/icon.tsx +69 -0
- package/src/ui/index.ts +138 -0
- package/src/ui/layout.tsx +13 -0
- package/src/ui/popover.tsx +249 -0
- package/src/ui/switch.tsx +114 -0
- package/src/ui/tabs.tsx +297 -0
- package/src/ui/toast.tsx +280 -0
- package/src/ui/tooltip.tsx +262 -0
- package/src/ui/utils.ts +110 -0
- package/src/virtual/index.ts +12 -0
- package/src/virtual/virtual-list.tsx +185 -0
- package/src/virtual/virtualizer.ts +274 -0
- package/src/vite/hmr.ts +38 -0
- package/src/vite/index.ts +3 -0
- package/src/vite/lucide.ts +124 -0
- package/src/vite/plugin.ts +102 -0
- package/src/vite/rpc-middleware.ts +82 -0
- package/src/vite/types.ts +65 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import type * as CSS from "csstype";
|
|
2
|
+
import { onCleanup } from "../signals";
|
|
3
|
+
import { type ClassValue, cx } from "./cx";
|
|
4
|
+
import { getScopeId } from "./hash";
|
|
5
|
+
import { styleManager } from "./manager";
|
|
6
|
+
import { scopeCSS } from "./parser";
|
|
7
|
+
import { formatStyleProp } from "./scale";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Standard CSS Properties interface with full TypeScript & VS Code IntelliSense,
|
|
11
|
+
* supporting nested pseudo-classes, descendant selectors, and custom CSS variables.
|
|
12
|
+
*/
|
|
13
|
+
export type CSSProperties = CSS.Properties<string | number> & {
|
|
14
|
+
[key: `&${string}`]: CSSProperties | undefined;
|
|
15
|
+
[key: `.${string}`]: CSSProperties | undefined;
|
|
16
|
+
[key: `:${string}`]: CSSProperties | undefined;
|
|
17
|
+
[key: `@media${string}`]: CSSProperties | undefined;
|
|
18
|
+
[key: `@keyframes${string}`]: Record<string, CSSProperties> | undefined;
|
|
19
|
+
[key: `${number}%`]: CSSProperties | undefined;
|
|
20
|
+
from?: CSSProperties;
|
|
21
|
+
to?: CSSProperties;
|
|
22
|
+
[customProp: `--${string}`]: string | number | undefined;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type StyleDefinition = Record<string, CSSProperties>;
|
|
26
|
+
|
|
27
|
+
export type StyleClasses<T extends string = string> = {
|
|
28
|
+
[K in T]: string;
|
|
29
|
+
} & Record<string, any> & {
|
|
30
|
+
scope: string;
|
|
31
|
+
scopeAttr: string;
|
|
32
|
+
css: string;
|
|
33
|
+
cx: (...args: ClassValue[]) => string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function formatCSSValue(prop: string, val: any): string {
|
|
37
|
+
return formatStyleProp(prop, val);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Convert a JavaScript object style dictionary into standard CSS
|
|
42
|
+
*/
|
|
43
|
+
export function objectToCSS(classes: Record<string, any>): string {
|
|
44
|
+
let css = "";
|
|
45
|
+
for (const [selector, rules] of Object.entries(classes)) {
|
|
46
|
+
if (typeof rules !== "object" || rules === null) continue;
|
|
47
|
+
const sel =
|
|
48
|
+
selector.startsWith(".") ||
|
|
49
|
+
selector.startsWith("@") ||
|
|
50
|
+
selector.startsWith(":") ||
|
|
51
|
+
selector.includes(" ") ||
|
|
52
|
+
selector === "*"
|
|
53
|
+
? selector
|
|
54
|
+
: `.${selector}`;
|
|
55
|
+
|
|
56
|
+
let mainRules = "";
|
|
57
|
+
let nestedRules = "";
|
|
58
|
+
|
|
59
|
+
for (const [prop, val] of Object.entries(rules)) {
|
|
60
|
+
if (typeof val === "object" && val !== null) {
|
|
61
|
+
const nestedSel = prop.startsWith("&")
|
|
62
|
+
? prop.replace(/&/g, sel)
|
|
63
|
+
: prop.startsWith(":")
|
|
64
|
+
? `${sel}${prop}`
|
|
65
|
+
: `${sel} ${prop}`;
|
|
66
|
+
|
|
67
|
+
nestedRules += `${nestedSel} {\n`;
|
|
68
|
+
for (const [np, nv] of Object.entries(val as Record<string, any>)) {
|
|
69
|
+
if (nv !== undefined && nv !== null) {
|
|
70
|
+
const kebab = np.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
71
|
+
nestedRules += ` ${kebab}: ${formatCSSValue(np, nv)};\n`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
nestedRules += `}\n`;
|
|
75
|
+
} else if (val !== undefined && val !== null) {
|
|
76
|
+
const kebab = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
77
|
+
mainRules += ` ${kebab}: ${formatCSSValue(prop, val)};\n`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (mainRules) {
|
|
82
|
+
css += `${sel} {\n${mainRules}}\n`;
|
|
83
|
+
}
|
|
84
|
+
if (nestedRules) {
|
|
85
|
+
css += nestedRules;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return css;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Define scoped CSS styles with type-safe class name mappings
|
|
93
|
+
*
|
|
94
|
+
* Supports tagged template literals, string CSS, or JavaScript style objects:
|
|
95
|
+
*
|
|
96
|
+
* 1. Object syntax with full VS Code CSS IntelliSense:
|
|
97
|
+
* ```tsx
|
|
98
|
+
* const styles = createStyle({
|
|
99
|
+
* card: { background: "var(--card-bg)", padding: "16px", display: "flex" },
|
|
100
|
+
* button: { background: "var(--primary)", "&:hover": { background: "var(--primary-hover)" } }
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* 2. Tagged template literal syntax:
|
|
105
|
+
* ```tsx
|
|
106
|
+
* const styles = createStyle`
|
|
107
|
+
* .card { padding: 16px; border-radius: 8px; }
|
|
108
|
+
* .active { color: var(--primary); }
|
|
109
|
+
* `;
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export function createStyle<T extends string = string>(
|
|
113
|
+
templateOrObject: string | TemplateStringsArray | StyleDefinition,
|
|
114
|
+
...valuesOrOptions: any[]
|
|
115
|
+
): StyleClasses<T> {
|
|
116
|
+
let cssInput = "";
|
|
117
|
+
let options: { passToChildren?: boolean; id?: string } | undefined;
|
|
118
|
+
|
|
119
|
+
if (typeof templateOrObject === "object" && !Array.isArray(templateOrObject)) {
|
|
120
|
+
// Object style definition
|
|
121
|
+
cssInput = objectToCSS(templateOrObject);
|
|
122
|
+
options = valuesOrOptions[0];
|
|
123
|
+
} else if (typeof templateOrObject === "string") {
|
|
124
|
+
cssInput = templateOrObject;
|
|
125
|
+
options = valuesOrOptions[0];
|
|
126
|
+
} else {
|
|
127
|
+
const template = templateOrObject as unknown as TemplateStringsArray;
|
|
128
|
+
for (let i = 0; i < template.length; i++) {
|
|
129
|
+
cssInput += template[i];
|
|
130
|
+
if (i < valuesOrOptions.length) {
|
|
131
|
+
cssInput += String(valuesOrOptions[i]);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const scopeId = options?.id ?? getScopeId(cssInput);
|
|
137
|
+
const scopeAttr = `data-${scopeId}`;
|
|
138
|
+
const classMap: Record<string, string> = {};
|
|
139
|
+
|
|
140
|
+
// Extract class names defined in the CSS
|
|
141
|
+
const classRegex = /\.([a-zA-Z0-9_-]+)/g;
|
|
142
|
+
let match: RegExpExecArray | null = classRegex.exec(cssInput);
|
|
143
|
+
while (match !== null) {
|
|
144
|
+
const className = match[1];
|
|
145
|
+
if (className && !classMap[className]) {
|
|
146
|
+
// Scoped class name
|
|
147
|
+
classMap[className] = `${className}_${scopeId}`;
|
|
148
|
+
}
|
|
149
|
+
match = classRegex.exec(cssInput);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Rewrite CSS classes to use scoped class names
|
|
153
|
+
let transformedCSS = cssInput;
|
|
154
|
+
for (const [orig, scoped] of Object.entries(classMap)) {
|
|
155
|
+
const replaceRegex = new RegExp(`\\.${orig}\\b`, "g");
|
|
156
|
+
transformedCSS = transformedCSS.replace(replaceRegex, `.${scoped}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const finalScopedCSS = scopeCSS(transformedCSS, {
|
|
160
|
+
scopeId,
|
|
161
|
+
passToChildren: options?.passToChildren ?? false
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Inject into StyleManager
|
|
165
|
+
styleManager.inject(scopeId, finalScopedCSS);
|
|
166
|
+
|
|
167
|
+
const result: any = {
|
|
168
|
+
...classMap,
|
|
169
|
+
scope: scopeId,
|
|
170
|
+
scopeAttr,
|
|
171
|
+
css: finalScopedCSS,
|
|
172
|
+
cx: (...args: ClassValue[]) => cx(...args)
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return result as StyleClasses<T>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Tagged template for defining a single scoped CSS class
|
|
180
|
+
*/
|
|
181
|
+
export function css(strings: TemplateStringsArray, ...values: any[]): string {
|
|
182
|
+
let rawCSS = "";
|
|
183
|
+
for (let i = 0; i < strings.length; i++) {
|
|
184
|
+
rawCSS += strings[i];
|
|
185
|
+
if (i < values.length) {
|
|
186
|
+
rawCSS += String(values[i]);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const scopeId = getScopeId(rawCSS, "cls");
|
|
191
|
+
const className = `visage_${scopeId}`;
|
|
192
|
+
|
|
193
|
+
// Wrap inside class selector
|
|
194
|
+
const fullCSS = rawCSS.includes("&")
|
|
195
|
+
? rawCSS.replace(/&/g, `.${className}`)
|
|
196
|
+
: `.${className} { ${rawCSS} }`;
|
|
197
|
+
|
|
198
|
+
const scoped = scopeCSS(fullCSS, { scopeId });
|
|
199
|
+
styleManager.inject(scopeId, scoped);
|
|
200
|
+
|
|
201
|
+
return className;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Hook to inject dynamic or component-level CSS with automatic cleanup
|
|
206
|
+
*/
|
|
207
|
+
export function useStyle(
|
|
208
|
+
cssInput: string | StyleDefinition | (() => string | StyleDefinition),
|
|
209
|
+
options?: { passToChildren?: boolean; id?: string }
|
|
210
|
+
): string {
|
|
211
|
+
const getRaw = () => {
|
|
212
|
+
const val = typeof cssInput === "function" ? cssInput() : cssInput;
|
|
213
|
+
return typeof val === "object" ? objectToCSS(val) : val;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const raw = getRaw();
|
|
217
|
+
const scopeId = options?.id ?? getScopeId(raw);
|
|
218
|
+
const scopedCSS = scopeCSS(raw, {
|
|
219
|
+
scopeId,
|
|
220
|
+
passToChildren: options?.passToChildren ?? false
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const cleanup = styleManager.inject(scopeId, scopedCSS);
|
|
224
|
+
onCleanup(() => {
|
|
225
|
+
cleanup();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return scopeId;
|
|
229
|
+
}
|
package/src/style/cx.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export type ClassValue =
|
|
2
|
+
| string
|
|
3
|
+
| number
|
|
4
|
+
| boolean
|
|
5
|
+
| null
|
|
6
|
+
| undefined
|
|
7
|
+
| (() => any)
|
|
8
|
+
| ClassValue[]
|
|
9
|
+
| Record<string, any>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if a class value tree contains any reactive signal or function getters
|
|
13
|
+
*/
|
|
14
|
+
export function hasReactiveClass(val: any): boolean {
|
|
15
|
+
if (typeof val === "function") return true;
|
|
16
|
+
if (Array.isArray(val)) {
|
|
17
|
+
for (let i = 0; i < val.length; i++) {
|
|
18
|
+
if (hasReactiveClass(val[i])) return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (typeof val === "object" && val !== null) {
|
|
23
|
+
for (const k in val) {
|
|
24
|
+
if (typeof val[k] === "function") return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Normalize dynamic classes from strings, numbers, arrays, and objects
|
|
32
|
+
*/
|
|
33
|
+
export function normalizeClass(val: any): string {
|
|
34
|
+
if (!val) return "";
|
|
35
|
+
if (typeof val === "function") return normalizeClass(val());
|
|
36
|
+
if (typeof val === "string") return val.trim();
|
|
37
|
+
if (typeof val === "number") return String(val);
|
|
38
|
+
|
|
39
|
+
if (Array.isArray(val)) {
|
|
40
|
+
let res = "";
|
|
41
|
+
for (let i = 0; i < val.length; i++) {
|
|
42
|
+
const item = typeof val[i] === "function" ? val[i]() : val[i];
|
|
43
|
+
const itemStr = normalizeClass(item);
|
|
44
|
+
if (itemStr) {
|
|
45
|
+
res = res ? `${res} ${itemStr}` : itemStr;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return res;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof val === "object") {
|
|
52
|
+
let res = "";
|
|
53
|
+
for (const key in val) {
|
|
54
|
+
const condition = typeof val[key] === "function" ? val[key]() : val[key];
|
|
55
|
+
if (condition) {
|
|
56
|
+
res = res ? `${res} ${key}` : key;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return res;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Flexible classnames utility for combining conditional classes
|
|
67
|
+
*
|
|
68
|
+
* Example:
|
|
69
|
+
* ```ts
|
|
70
|
+
* cx("btn", { active: isActive(), disabled: !isEnabled() }, ["extra-1", extraClass])
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export function cx(...args: ClassValue[]): string {
|
|
74
|
+
return normalizeClass(args);
|
|
75
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fast 32-bit FNV-1a deterministic string hashing algorithm
|
|
3
|
+
*/
|
|
4
|
+
export function hashString(str: string): string {
|
|
5
|
+
let hash = 0x811c9dc5;
|
|
6
|
+
for (let i = 0; i < str.length; i++) {
|
|
7
|
+
hash ^= str.charCodeAt(i);
|
|
8
|
+
hash = Math.imul(hash, 0x01000193);
|
|
9
|
+
}
|
|
10
|
+
return (hash >>> 0).toString(36);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Generate a deterministic scope identifier for CSS blocks
|
|
15
|
+
*/
|
|
16
|
+
export function getScopeId(css: string, prefix = "v"): string {
|
|
17
|
+
const hash = hashString(css.trim());
|
|
18
|
+
return `${prefix}-${hash}`;
|
|
19
|
+
}
|