@epoch32/visage 1.1.0 → 1.1.1

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.
@@ -0,0 +1,278 @@
1
+ import type { Child } from "../dom";
2
+ import type { ReadonlySignal } from "../signals";
3
+
4
+ /**
5
+ * Fine-grained reactive property value.
6
+ *
7
+ * Can be a static value `T`, a reactive `ReadonlySignal<T>`, or a dynamic getter function `() => T`.
8
+ * Visage binds reactive props directly to the DOM attribute or property via fine-grained effects,
9
+ * updating only the exact target attribute when the signal changes without re-rendering the component.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const count = signal(5);
14
+ *
15
+ * // Direct signal
16
+ * <input disabled={count} />
17
+ *
18
+ * // Getter function
19
+ * <div title={() => `Item count: ${count()}`} />
20
+ * ```
21
+ */
22
+ export type ReactiveProp<T> = T | ReadonlySignal<T> | (() => T);
23
+
24
+ /**
25
+ * Flexible reactive class value supporting strings, conditional objects, arrays, and getters.
26
+ */
27
+ export type ClassValue =
28
+ | string
29
+ | number
30
+ | boolean
31
+ | null
32
+ | undefined
33
+ | (() => any)
34
+ | ClassValue[]
35
+ | Record<string, any>;
36
+
37
+ /**
38
+ * Reactive class / className property.
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * // Object conditional syntax
43
+ * <div class={{ active: isActive(), hidden: isHidden() }} />
44
+ *
45
+ * // Array syntax
46
+ * <div class={["btn", isPrimary() ? "btn-primary" : "btn-secondary"]} />
47
+ *
48
+ * // Signal / Getter syntax
49
+ * <div class={() => `theme-${theme()}`} />
50
+ * ```
51
+ */
52
+ export type ClassProp = ReactiveProp<
53
+ string | number | boolean | undefined | null | ClassValue[] | Record<string, any>
54
+ >;
55
+
56
+ /**
57
+ * Standard HTML Element attributes with fine-grained reactive property bindings.
58
+ */
59
+ export type HTMLAttributes<T extends HTMLElement = HTMLElement> = {
60
+ [K in keyof HTMLElementTagNameMap[keyof HTMLElementTagNameMap]]?: any;
61
+ } & {
62
+ class?: ClassProp;
63
+ className?: ClassProp;
64
+ id?: ReactiveProp<string | undefined | null>;
65
+ title?: ReactiveProp<string | undefined | null>;
66
+ tabIndex?: ReactiveProp<number | undefined | null>;
67
+ role?: ReactiveProp<string | undefined | null>;
68
+ hidden?: ReactiveProp<boolean | undefined | null>;
69
+ disabled?: ReactiveProp<boolean | undefined | null>;
70
+ style?: ReactiveProp<
71
+ string | Record<string, ReactiveProp<string | number | undefined | null>> | undefined | null
72
+ >;
73
+ ref?: (el: T) => void;
74
+ dangerouslySetInnerHTML?: { __html: string };
75
+
76
+ // Events
77
+ onClick?: (e: MouseEvent) => void;
78
+ onDblClick?: (e: MouseEvent) => void;
79
+ onMouseDown?: (e: MouseEvent) => void;
80
+ onMouseUp?: (e: MouseEvent) => void;
81
+ onMouseMove?: (e: MouseEvent) => void;
82
+ onMouseEnter?: (e: MouseEvent) => void;
83
+ onMouseLeave?: (e: MouseEvent) => void;
84
+ onKeyDown?: (e: KeyboardEvent) => void;
85
+ onKeyUp?: (e: KeyboardEvent) => void;
86
+ onKeyPress?: (e: KeyboardEvent) => void;
87
+ onInput?: (e: InputEvent & { target: T }) => void;
88
+ onChange?: (e: Event & { target: T }) => void;
89
+ onSubmit?: (e: SubmitEvent) => void;
90
+ onFocus?: (e: FocusEvent) => void;
91
+ onBlur?: (e: FocusEvent) => void;
92
+ onScroll?: (e: Event) => void;
93
+
94
+ children?: Child;
95
+ [attr: string]: any;
96
+ };
97
+
98
+ export type InputAttributes = HTMLAttributes<HTMLInputElement> & {
99
+ type?: ReactiveProp<string>;
100
+ value?: ReactiveProp<string | number | readonly string[] | undefined | null>;
101
+ checked?: ReactiveProp<boolean | undefined | null>;
102
+ placeholder?: ReactiveProp<string | undefined | null>;
103
+ name?: ReactiveProp<string | undefined | null>;
104
+ disabled?: ReactiveProp<boolean | undefined | null>;
105
+ readOnly?: ReactiveProp<boolean | undefined | null>;
106
+ required?: ReactiveProp<boolean | undefined | null>;
107
+ min?: ReactiveProp<string | number | undefined | null>;
108
+ max?: ReactiveProp<string | number | undefined | null>;
109
+ step?: ReactiveProp<string | number | undefined | null>;
110
+ pattern?: ReactiveProp<string | undefined | null>;
111
+ autoFocus?: ReactiveProp<boolean | undefined | null>;
112
+ autoComplete?: ReactiveProp<string | undefined | null>;
113
+ };
114
+
115
+ export type ButtonAttributes = HTMLAttributes<HTMLButtonElement> & {
116
+ type?: ReactiveProp<"button" | "submit" | "reset" | undefined>;
117
+ disabled?: ReactiveProp<boolean | undefined | null>;
118
+ name?: ReactiveProp<string | undefined | null>;
119
+ value?: ReactiveProp<string | number | undefined | null>;
120
+ };
121
+
122
+ export type AnchorAttributes = HTMLAttributes<HTMLAnchorElement> & {
123
+ href?: ReactiveProp<string | undefined | null>;
124
+ target?: ReactiveProp<"_blank" | "_self" | "_parent" | "_top" | string | undefined | null>;
125
+ rel?: ReactiveProp<string | undefined | null>;
126
+ download?: ReactiveProp<any>;
127
+ };
128
+
129
+ export interface VisageIntrinsicElements {
130
+ // HTML tags
131
+ div: HTMLAttributes<HTMLDivElement>;
132
+ span: HTMLAttributes<HTMLSpanElement>;
133
+ p: HTMLAttributes<HTMLParagraphElement>;
134
+ a: AnchorAttributes;
135
+ button: ButtonAttributes;
136
+ input: InputAttributes;
137
+ textarea: HTMLAttributes<HTMLTextAreaElement> & {
138
+ value?: ReactiveProp<string | number | undefined | null>;
139
+ placeholder?: ReactiveProp<string | undefined | null>;
140
+ rows?: ReactiveProp<number | undefined | null>;
141
+ cols?: ReactiveProp<number | undefined | null>;
142
+ };
143
+ select: HTMLAttributes<HTMLSelectElement> & {
144
+ value?: ReactiveProp<any>;
145
+ multiple?: ReactiveProp<boolean | undefined | null>;
146
+ };
147
+ option: HTMLAttributes<HTMLOptionElement> & {
148
+ value?: ReactiveProp<any>;
149
+ selected?: ReactiveProp<boolean | undefined | null>;
150
+ };
151
+ form: HTMLAttributes<HTMLFormElement> & {
152
+ action?: ReactiveProp<string | undefined | null>;
153
+ method?: ReactiveProp<string | undefined | null>;
154
+ };
155
+ label: HTMLAttributes<HTMLLabelElement> & {
156
+ htmlFor?: ReactiveProp<string | undefined | null>;
157
+ for?: ReactiveProp<string | undefined | null>;
158
+ };
159
+ h1: HTMLAttributes<HTMLHeadingElement>;
160
+ h2: HTMLAttributes<HTMLHeadingElement>;
161
+ h3: HTMLAttributes<HTMLHeadingElement>;
162
+ h4: HTMLAttributes<HTMLHeadingElement>;
163
+ h5: HTMLAttributes<HTMLHeadingElement>;
164
+ h6: HTMLAttributes<HTMLHeadingElement>;
165
+ header: HTMLAttributes<HTMLElement>;
166
+ footer: HTMLAttributes<HTMLElement>;
167
+ main: HTMLAttributes<HTMLElement>;
168
+ nav: HTMLAttributes<HTMLElement>;
169
+ section: HTMLAttributes<HTMLElement>;
170
+ article: HTMLAttributes<HTMLElement>;
171
+ aside: HTMLAttributes<HTMLElement>;
172
+ ul: HTMLAttributes<HTMLUListElement>;
173
+ ol: HTMLAttributes<HTMLOListElement>;
174
+ li: HTMLAttributes<HTMLLIElement>;
175
+ table: HTMLAttributes<HTMLTableElement>;
176
+ thead: HTMLAttributes<HTMLTableSectionElement>;
177
+ tbody: HTMLAttributes<HTMLTableSectionElement>;
178
+ tfoot: HTMLAttributes<HTMLTableSectionElement>;
179
+ tr: HTMLAttributes<HTMLTableRowElement>;
180
+ td: HTMLAttributes<HTMLTableCellElement>;
181
+ th: HTMLAttributes<HTMLTableCellElement>;
182
+ img: HTMLAttributes<HTMLImageElement> & {
183
+ src?: ReactiveProp<string | undefined | null>;
184
+ alt?: ReactiveProp<string | undefined | null>;
185
+ width?: ReactiveProp<number | string | undefined | null>;
186
+ height?: ReactiveProp<number | string | undefined | null>;
187
+ loading?: ReactiveProp<"lazy" | "eager" | undefined | null>;
188
+ };
189
+ iframe: HTMLAttributes<HTMLIFrameElement> & {
190
+ src?: ReactiveProp<string | undefined | null>;
191
+ title?: ReactiveProp<string | undefined | null>;
192
+ };
193
+ canvas: HTMLAttributes<HTMLCanvasElement> & {
194
+ width?: ReactiveProp<number | undefined | null>;
195
+ height?: ReactiveProp<number | undefined | null>;
196
+ };
197
+ code: HTMLAttributes<HTMLElement>;
198
+ pre: HTMLAttributes<HTMLPreElement>;
199
+ blockquote: HTMLAttributes<HTMLQuoteElement>;
200
+ strong: HTMLAttributes<HTMLElement>;
201
+ em: HTMLAttributes<HTMLElement>;
202
+ small: HTMLAttributes<HTMLElement>;
203
+ hr: HTMLAttributes<HTMLHRElement>;
204
+ br: HTMLAttributes<HTMLBRElement>;
205
+
206
+ // SVG Tags
207
+ svg: HTMLAttributes<SVGElement> & {
208
+ viewBox?: ReactiveProp<string>;
209
+ xmlns?: ReactiveProp<string>;
210
+ width?: ReactiveProp<number | string>;
211
+ height?: ReactiveProp<number | string>;
212
+ fill?: ReactiveProp<string>;
213
+ stroke?: ReactiveProp<string>;
214
+ };
215
+ path: HTMLAttributes<SVGElement> & {
216
+ d?: ReactiveProp<string>;
217
+ fill?: ReactiveProp<string>;
218
+ stroke?: ReactiveProp<string>;
219
+ strokeWidth?: ReactiveProp<number | string>;
220
+ };
221
+ circle: HTMLAttributes<SVGElement> & {
222
+ cx?: ReactiveProp<number | string>;
223
+ cy?: ReactiveProp<number | string>;
224
+ r?: ReactiveProp<number | string>;
225
+ fill?: ReactiveProp<string>;
226
+ };
227
+ rect: HTMLAttributes<SVGElement> & {
228
+ x?: ReactiveProp<number | string>;
229
+ y?: ReactiveProp<number | string>;
230
+ width?: ReactiveProp<number | string>;
231
+ height?: ReactiveProp<number | string>;
232
+ fill?: ReactiveProp<string>;
233
+ };
234
+
235
+ // Catch-all for other tags
236
+ [elemName: string]: HTMLAttributes<HTMLElement>;
237
+ }
238
+
239
+ /**
240
+ * Visage JSX Namespace Definitions
241
+ */
242
+ export namespace JSX {
243
+ /**
244
+ * Represents any valid JSX element in Visage (DOM Node, Signal, Function Getter, VNode, string, number, null, undefined).
245
+ */
246
+ export type Element = Node | Child;
247
+
248
+ export interface ElementChildrenAttribute {
249
+ children: unknown;
250
+ }
251
+
252
+ export interface IntrinsicAttributes {
253
+ key?: any;
254
+ [key: string]: any;
255
+ }
256
+
257
+ export interface IntrinsicElements extends VisageIntrinsicElements {}
258
+ }
259
+
260
+ declare global {
261
+ namespace JSX {
262
+ /**
263
+ * Represents any valid JSX element in Visage (DOM Node, Signal, Function Getter, VNode, string, number, null, undefined).
264
+ */
265
+ type Element = Node | Child;
266
+
267
+ interface ElementChildrenAttribute {
268
+ children: unknown;
269
+ }
270
+
271
+ interface IntrinsicAttributes {
272
+ key?: any;
273
+ [key: string]: any;
274
+ }
275
+
276
+ interface IntrinsicElements extends VisageIntrinsicElements {}
277
+ }
278
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epoch32/visage",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Lightning-fast, zero-VDOM, fine-grained reactive UI library with full TypeScript support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -100,7 +100,7 @@
100
100
  "package.json"
101
101
  ],
102
102
  "scripts": {
103
- "build": "bun build src/index.ts src/signals/index.ts src/dom/index.ts src/template/index.ts src/api/index.ts src/rpc/index.ts src/query/index.ts src/style/index.ts src/devtools/index.ts src/ui/index.ts src/virtual/index.ts src/form/index.ts src/server/index.ts src/router/index.ts src/vite/index.ts src/jsx-runtime/index.ts src/charts/index.ts --root src --outdir dist/ && bun x tsc -p tsconfig.build.json",
103
+ "build": "bun build src/index.ts src/signals/index.ts src/dom/index.ts src/template/index.ts src/api/index.ts src/rpc/index.ts src/query/index.ts src/style/index.ts src/devtools/index.ts src/ui/index.ts src/virtual/index.ts src/form/index.ts src/server/index.ts src/router/index.ts src/vite/index.ts src/jsx-runtime/index.ts src/charts/index.ts --root src --outdir dist/ && bun x tsc -p tsconfig.build.json && cp src/jsx-runtime/jsx.d.ts dist/jsx-runtime/jsx.d.ts",
104
104
  "test": "bun test",
105
105
  "test:watch": "bun test --watch",
106
106
  "test:coverage": "bun test --coverage",