@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.
Files changed (135) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +110 -2
  3. package/dist/src/api/index.js +4002 -0
  4. package/dist/src/charts/index.js +2717 -0
  5. package/dist/src/devtools/index.js +4677 -0
  6. package/dist/src/dom/index.js +1550 -0
  7. package/dist/src/form/index.js +1415 -0
  8. package/dist/src/index.js +11826 -0
  9. package/dist/src/jsx-runtime/index.js +1630 -0
  10. package/dist/src/query/index.js +2422 -0
  11. package/dist/src/router/index.js +1856 -0
  12. package/dist/src/rpc/index.js +3484 -0
  13. package/dist/src/server/index.js +1173 -0
  14. package/dist/src/signals/index.js +1077 -0
  15. package/dist/src/style/index.js +2340 -0
  16. package/dist/src/template/index.js +1149 -0
  17. package/dist/src/ui/index.js +4155 -0
  18. package/dist/src/virtual/index.js +1955 -0
  19. package/dist/src/vite/index.js +984 -0
  20. package/package.json +140 -4
  21. package/src/api/client.ts +371 -0
  22. package/src/api/file-router.ts +183 -0
  23. package/src/api/handler.ts +326 -0
  24. package/src/api/index.ts +71 -0
  25. package/src/api/middleware.ts +54 -0
  26. package/src/api/pragma.ts +155 -0
  27. package/src/api/procedure.ts +172 -0
  28. package/src/api/types.ts +249 -0
  29. package/src/charts/Area.tsx +111 -0
  30. package/src/charts/Axis.tsx +126 -0
  31. package/src/charts/Bar.tsx +86 -0
  32. package/src/charts/CartesianGrid.tsx +72 -0
  33. package/src/charts/Chart.tsx +269 -0
  34. package/src/charts/Cursor.tsx +42 -0
  35. package/src/charts/Legend.tsx +56 -0
  36. package/src/charts/Line.tsx +106 -0
  37. package/src/charts/Pie.tsx +88 -0
  38. package/src/charts/Tooltip.tsx +127 -0
  39. package/src/charts/context.ts +30 -0
  40. package/src/charts/index.ts +14 -0
  41. package/src/charts/path.ts +155 -0
  42. package/src/charts/scale.ts +133 -0
  43. package/src/charts/types.ts +50 -0
  44. package/src/devtools/DomTab.tsx +134 -0
  45. package/src/devtools/GraphInspector.tsx +196 -0
  46. package/src/devtools/GraphTab.tsx +315 -0
  47. package/src/devtools/QueryTab.tsx +200 -0
  48. package/src/devtools/RpcTab.tsx +190 -0
  49. package/src/devtools/SignalsTab.tsx +129 -0
  50. package/src/devtools/component.tsx +243 -0
  51. package/src/devtools/highlighter.ts +134 -0
  52. package/src/devtools/hub.ts +175 -0
  53. package/src/devtools/index.ts +20 -0
  54. package/src/devtools/styles.ts +313 -0
  55. package/src/devtools/types.ts +45 -0
  56. package/src/dom/async.ts +232 -0
  57. package/src/dom/control-flow.ts +353 -0
  58. package/src/dom/index.ts +32 -0
  59. package/src/dom/lazy.ts +82 -0
  60. package/src/dom/render.ts +286 -0
  61. package/src/dom/resource.ts +120 -0
  62. package/src/form/form.ts +218 -0
  63. package/src/form/index.ts +17 -0
  64. package/src/form/schema.ts +299 -0
  65. package/src/index.ts +413 -0
  66. package/src/jsx-dev-runtime/index.ts +1 -0
  67. package/src/jsx-runtime/index.ts +112 -0
  68. package/src/jsx-runtime/jsx.d.ts +278 -0
  69. package/src/query/create-mutation.ts +64 -0
  70. package/src/query/create-query.ts +426 -0
  71. package/src/query/focus-manager.ts +68 -0
  72. package/src/query/index.ts +63 -0
  73. package/src/query/mutation-cache.ts +138 -0
  74. package/src/query/online-manager.ts +67 -0
  75. package/src/query/query-cache.ts +369 -0
  76. package/src/query/query-client.ts +248 -0
  77. package/src/query/types.ts +221 -0
  78. package/src/query/utils.ts +132 -0
  79. package/src/router/index.ts +19 -0
  80. package/src/router/router.tsx +352 -0
  81. package/src/rpc/client.ts +317 -0
  82. package/src/rpc/error.ts +70 -0
  83. package/src/rpc/index.ts +52 -0
  84. package/src/rpc/procedure.ts +88 -0
  85. package/src/rpc/router.ts +105 -0
  86. package/src/rpc/server.ts +511 -0
  87. package/src/rpc/types.ts +328 -0
  88. package/src/server/hydrate.ts +21 -0
  89. package/src/server/index.ts +10 -0
  90. package/src/server/render-to-stream.ts +31 -0
  91. package/src/server/render-to-string.ts +125 -0
  92. package/src/signals/computed.ts +217 -0
  93. package/src/signals/context.ts +89 -0
  94. package/src/signals/effect.ts +161 -0
  95. package/src/signals/index.ts +57 -0
  96. package/src/signals/scope.ts +132 -0
  97. package/src/signals/signal.ts +203 -0
  98. package/src/signals/store.ts +163 -0
  99. package/src/signals/system.ts +124 -0
  100. package/src/signals/types.ts +64 -0
  101. package/src/style/component.tsx +122 -0
  102. package/src/style/create-style.ts +229 -0
  103. package/src/style/cx.ts +75 -0
  104. package/src/style/hash.ts +19 -0
  105. package/src/style/index.ts +8 -0
  106. package/src/style/layout.tsx +406 -0
  107. package/src/style/manager.ts +87 -0
  108. package/src/style/parser.ts +257 -0
  109. package/src/style/scale.ts +237 -0
  110. package/src/template/index.ts +4 -0
  111. package/src/template/template.ts +126 -0
  112. package/src/ui/accordion.tsx +286 -0
  113. package/src/ui/command-dialog.tsx +49 -0
  114. package/src/ui/command.tsx +400 -0
  115. package/src/ui/data-table.tsx +322 -0
  116. package/src/ui/dialog.tsx +362 -0
  117. package/src/ui/dropdown-menu.tsx +381 -0
  118. package/src/ui/icon.tsx +69 -0
  119. package/src/ui/index.ts +138 -0
  120. package/src/ui/layout.tsx +13 -0
  121. package/src/ui/popover.tsx +249 -0
  122. package/src/ui/switch.tsx +114 -0
  123. package/src/ui/tabs.tsx +297 -0
  124. package/src/ui/toast.tsx +280 -0
  125. package/src/ui/tooltip.tsx +262 -0
  126. package/src/ui/utils.ts +110 -0
  127. package/src/virtual/index.ts +12 -0
  128. package/src/virtual/virtual-list.tsx +185 -0
  129. package/src/virtual/virtualizer.ts +274 -0
  130. package/src/vite/hmr.ts +38 -0
  131. package/src/vite/index.ts +3 -0
  132. package/src/vite/lucide.ts +124 -0
  133. package/src/vite/plugin.ts +102 -0
  134. package/src/vite/rpc-middleware.ts +82 -0
  135. package/src/vite/types.ts +65 -0
@@ -0,0 +1,400 @@
1
+ import type { Child } from "../dom/render";
2
+ import type { ReadonlySignal } from "../signals";
3
+ import { createContext, useContext } from "../signals/context";
4
+ import { CommandDialog, type CommandDialogProps } from "./command-dialog";
5
+ import { createControllableSignal, createId } from "./utils";
6
+
7
+ export type { CommandDialogProps };
8
+ export { CommandDialog };
9
+
10
+ export interface CommandItemData {
11
+ value?: string;
12
+ label: Child | (() => Child);
13
+ icon?: Child | (() => Child);
14
+ shortcut?: string;
15
+ disabled?: boolean;
16
+ onSelect?: () => void;
17
+ keywords?: string[];
18
+ class?: any;
19
+ }
20
+
21
+ export interface CommandGroupData {
22
+ heading?: string;
23
+ items: CommandItemData[];
24
+ }
25
+
26
+ export interface CommandContextValue {
27
+ search: ReadonlySignal<string>;
28
+ setSearch: (query: string) => void;
29
+ activeValue: ReadonlySignal<string>;
30
+ setActiveValue: (val: string) => void;
31
+ filterMatches: (text: string, keywords?: string[]) => boolean;
32
+ commandId: string;
33
+ }
34
+
35
+ export const CommandContext = createContext<CommandContextValue | null>(null);
36
+
37
+ export function useCommandContext(): CommandContextValue | null {
38
+ return useContext(CommandContext);
39
+ }
40
+
41
+ export interface CommandProps {
42
+ value?: () => string | undefined;
43
+ defaultValue?: string;
44
+ onValueChange?: (value: string) => void;
45
+ search?: () => string | undefined;
46
+ onSearchChange?: (query: string) => void;
47
+ placeholder?: string;
48
+ groups?: CommandGroupData[];
49
+ items?: CommandItemData[];
50
+ emptyText?: string;
51
+ class?: any;
52
+ style?: any;
53
+ inputClass?: any;
54
+ listClass?: any;
55
+ itemClass?: any;
56
+ as?: string;
57
+ children?: Child | (() => Child);
58
+ [key: string]: any;
59
+ }
60
+
61
+ export function CommandRoot(props: CommandProps): Child {
62
+ const [search, setSearch] = createControllableSignal<string>({
63
+ value: props.search,
64
+ defaultValue: "",
65
+ onChange: props.onSearchChange
66
+ });
67
+
68
+ const [activeValue, setActiveValue] = createControllableSignal<string>({
69
+ value: props.value,
70
+ defaultValue: props.defaultValue ?? "",
71
+ onChange: props.onValueChange
72
+ });
73
+
74
+ const commandId = createId("command");
75
+
76
+ const filterMatches = (text: string, keywords?: string[]): boolean => {
77
+ const q = search().toLowerCase().trim();
78
+ if (!q) return true;
79
+ if (text.toLowerCase().includes(q)) return true;
80
+ if (keywords?.some((k) => k.toLowerCase().includes(q))) return true;
81
+ return false;
82
+ };
83
+
84
+ const ctx: CommandContextValue = {
85
+ search,
86
+ setSearch,
87
+ activeValue,
88
+ setActiveValue,
89
+ filterMatches,
90
+ commandId
91
+ };
92
+
93
+ const {
94
+ as: Tag = "div",
95
+ placeholder = "Type a command or search...",
96
+ groups,
97
+ items,
98
+ emptyText = "No results found.",
99
+ class: className,
100
+ style,
101
+ inputClass,
102
+ listClass,
103
+ itemClass,
104
+ children,
105
+ ...rest
106
+ } = props;
107
+
108
+ // Ergonomic Shorthand renderer
109
+ if (groups || items) {
110
+ return CommandContext.Provider({
111
+ value: ctx,
112
+ children: () => (
113
+ <Tag
114
+ class={className}
115
+ style={{ display: "flex", flexDirection: "column", overflow: "hidden", ...style }}
116
+ {...rest}
117
+ >
118
+ <CommandInput placeholder={placeholder} class={inputClass} />
119
+ <CommandList class={listClass}>
120
+ <CommandEmpty>{emptyText}</CommandEmpty>
121
+ {groups?.map((grp) => (
122
+ <CommandGroup heading={grp.heading}>
123
+ {grp.items.map((item) => (
124
+ <CommandItem
125
+ value={item.value}
126
+ shortcut={item.shortcut}
127
+ disabled={item.disabled}
128
+ onSelect={item.onSelect}
129
+ keywords={item.keywords}
130
+ class={item.class ?? itemClass}
131
+ >
132
+ {item.icon ? (
133
+ <span
134
+ style={{ display: "inline-flex", alignItems: "center", marginRight: "8px" }}
135
+ >
136
+ {typeof item.icon === "function" ? item.icon() : item.icon}
137
+ </span>
138
+ ) : null}
139
+ {typeof item.label === "function" ? item.label() : item.label}
140
+ </CommandItem>
141
+ ))}
142
+ </CommandGroup>
143
+ ))}
144
+ {items?.map((item) => (
145
+ <CommandItem
146
+ value={item.value}
147
+ shortcut={item.shortcut}
148
+ disabled={item.disabled}
149
+ onSelect={item.onSelect}
150
+ keywords={item.keywords}
151
+ class={item.class ?? itemClass}
152
+ >
153
+ {item.icon ? (
154
+ <span
155
+ style={{ display: "inline-flex", alignItems: "center", marginRight: "8px" }}
156
+ >
157
+ {typeof item.icon === "function" ? item.icon() : item.icon}
158
+ </span>
159
+ ) : null}
160
+ {typeof item.label === "function" ? item.label() : item.label}
161
+ </CommandItem>
162
+ ))}
163
+ {typeof children === "function" ? children() : children}
164
+ </CommandList>
165
+ </Tag>
166
+ )
167
+ });
168
+ }
169
+
170
+ return CommandContext.Provider({
171
+ value: ctx,
172
+ children: () => (
173
+ <Tag class={className} style={style} {...rest}>
174
+ {typeof children === "function" ? children() : children}
175
+ </Tag>
176
+ )
177
+ });
178
+ }
179
+
180
+ export interface CommandInputProps {
181
+ placeholder?: string;
182
+ class?: any;
183
+ style?: any;
184
+ [key: string]: any;
185
+ }
186
+
187
+ export function CommandInput(props: CommandInputProps): Child {
188
+ const ctx = useContext(CommandContext);
189
+
190
+ const handleKeyDown = (e: KeyboardEvent) => {
191
+ const list = (e.currentTarget as HTMLElement)
192
+ .closest('[role="combobox"], [data-command-root], div')
193
+ ?.querySelector('[role="listbox"]');
194
+ if (!list) return;
195
+
196
+ const items = Array.from(
197
+ list.querySelectorAll<HTMLElement>(
198
+ '[role="option"]:not([aria-disabled="true"]):not([style*="display: none"])'
199
+ )
200
+ );
201
+ if (items.length === 0) return;
202
+
203
+ const currentActive =
204
+ items.find((el) => el.getAttribute("aria-selected") === "true") ?? items[0];
205
+ const index = currentActive ? items.indexOf(currentActive) : 0;
206
+
207
+ if (e.key === "ArrowDown") {
208
+ e.preventDefault();
209
+ const nextIndex = (index + 1) % items.length;
210
+ const nextItem = items[nextIndex];
211
+ if (nextItem && ctx) {
212
+ ctx.setActiveValue(nextItem.getAttribute("data-value") ?? "");
213
+ nextItem.scrollIntoView({ block: "nearest" });
214
+ }
215
+ } else if (e.key === "ArrowUp") {
216
+ e.preventDefault();
217
+ const prevIndex = (index - 1 + items.length) % items.length;
218
+ const prevItem = items[prevIndex];
219
+ if (prevItem && ctx) {
220
+ ctx.setActiveValue(prevItem.getAttribute("data-value") ?? "");
221
+ prevItem.scrollIntoView({ block: "nearest" });
222
+ }
223
+ } else if (e.key === "Enter" && currentActive) {
224
+ e.preventDefault();
225
+ currentActive.click();
226
+ }
227
+ };
228
+
229
+ const { placeholder = "Type a command...", class: className, style, ...rest } = props;
230
+
231
+ return (
232
+ <input
233
+ type="text"
234
+ role="searchbox"
235
+ placeholder={placeholder}
236
+ value={() => ctx?.search() ?? ""}
237
+ onInput={(e: any) => ctx?.setSearch(e.target.value)}
238
+ onKeyDown={handleKeyDown}
239
+ class={className}
240
+ style={style}
241
+ {...rest}
242
+ />
243
+ );
244
+ }
245
+
246
+ export interface CommandListProps {
247
+ as?: string;
248
+ class?: any;
249
+ style?: any;
250
+ children: Child | (() => Child);
251
+ [key: string]: any;
252
+ }
253
+
254
+ export function CommandList(props: CommandListProps): Child {
255
+ const { as: Tag = "div", children, class: className, style, ...rest } = props;
256
+ return (
257
+ <Tag role="listbox" class={className} style={{ overflowY: "auto", ...style }} {...rest}>
258
+ {children}
259
+ </Tag>
260
+ );
261
+ }
262
+
263
+ export interface CommandEmptyProps {
264
+ as?: string;
265
+ class?: any;
266
+ style?: any;
267
+ children: Child | (() => Child);
268
+ [key: string]: any;
269
+ }
270
+
271
+ export function CommandEmpty(props: CommandEmptyProps): Child {
272
+ const ctx = useContext(CommandContext);
273
+ const { as: Tag = "div", children, class: className, style, ...rest } = props;
274
+
275
+ return (
276
+ <Tag
277
+ class={className}
278
+ style={() => ({
279
+ display: ctx && ctx.search().trim().length > 0 ? undefined : "none",
280
+ textAlign: "center",
281
+ padding: "16px",
282
+ color: "#94a3b8",
283
+ ...style
284
+ })}
285
+ {...rest}
286
+ >
287
+ {children}
288
+ </Tag>
289
+ );
290
+ }
291
+
292
+ export interface CommandGroupProps {
293
+ heading?: string;
294
+ as?: string;
295
+ class?: any;
296
+ style?: any;
297
+ children: Child | (() => Child);
298
+ [key: string]: any;
299
+ }
300
+
301
+ export function CommandGroup(props: CommandGroupProps): Child {
302
+ const { heading, as: Tag = "div", children, class: className, style, ...rest } = props;
303
+ return (
304
+ <Tag role="group" class={className} style={style} {...rest}>
305
+ {heading ? (
306
+ <div
307
+ style={{
308
+ fontSize: "11px",
309
+ fontWeight: 700,
310
+ textTransform: "uppercase",
311
+ letterSpacing: "0.05em",
312
+ color: "#64748b",
313
+ padding: "6px 10px"
314
+ }}
315
+ >
316
+ {heading}
317
+ </div>
318
+ ) : null}
319
+ {children}
320
+ </Tag>
321
+ );
322
+ }
323
+
324
+ export interface CommandItemProps {
325
+ value?: string;
326
+ shortcut?: string;
327
+ disabled?: boolean;
328
+ onSelect?: () => void;
329
+ keywords?: string[];
330
+ as?: string;
331
+ class?: any;
332
+ style?: any;
333
+ children: Child | (() => Child);
334
+ [key: string]: any;
335
+ }
336
+
337
+ export function CommandItem(props: CommandItemProps): Child {
338
+ const ctx = useContext(CommandContext);
339
+ const itemValue =
340
+ props.value ?? (typeof props.children === "string" ? props.children : createId("item"));
341
+
342
+ const isVisible = () => {
343
+ if (!ctx) return true;
344
+ const text = typeof props.children === "string" ? props.children : itemValue;
345
+ return ctx.filterMatches(text, props.keywords);
346
+ };
347
+
348
+ const isSelected = () => (ctx ? ctx.activeValue() === itemValue : false);
349
+
350
+ const handleClick = () => {
351
+ if (props.disabled) return;
352
+ if (props.onSelect) props.onSelect();
353
+ };
354
+
355
+ const { as: Tag = "div", shortcut, disabled, children, class: className, style, ...rest } = props;
356
+
357
+ return (
358
+ <Tag
359
+ role="option"
360
+ data-value={itemValue}
361
+ aria-selected={isSelected}
362
+ aria-disabled={disabled}
363
+ class={className}
364
+ style={() => ({
365
+ display: isVisible() ? "flex" : "none",
366
+ alignItems: "center",
367
+ justifyContent: "space-between",
368
+ cursor: disabled ? "not-allowed" : "pointer",
369
+ ...style
370
+ })}
371
+ onClick={handleClick}
372
+ {...rest}
373
+ >
374
+ <div style={{ display: "flex", alignItems: "center" }}>{children}</div>
375
+ {shortcut ? (
376
+ <span
377
+ style={{
378
+ fontSize: "11px",
379
+ color: "#64748b",
380
+ background: "#1e293b",
381
+ padding: "2px 6px",
382
+ borderRadius: "4px"
383
+ }}
384
+ >
385
+ {shortcut}
386
+ </span>
387
+ ) : null}
388
+ </Tag>
389
+ );
390
+ }
391
+
392
+ export const Command = Object.assign(CommandRoot, {
393
+ Root: CommandRoot,
394
+ Dialog: CommandDialog,
395
+ Input: CommandInput,
396
+ List: CommandList,
397
+ Empty: CommandEmpty,
398
+ Group: CommandGroup,
399
+ Item: CommandItem
400
+ });