@hypen-space/web 0.2.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/dist/chunk-2s02mkzs.js +32 -0
- package/dist/chunk-2s02mkzs.js.map +9 -0
- package/dist/src/canvas/accessibility.js +152 -0
- package/dist/src/canvas/accessibility.js.map +10 -0
- package/dist/src/canvas/events.js +198 -0
- package/dist/src/canvas/events.js.map +10 -0
- package/dist/src/canvas/index.js +28 -0
- package/dist/src/canvas/index.js.map +9 -0
- package/dist/src/canvas/input.js +132 -0
- package/dist/src/canvas/input.js.map +10 -0
- package/dist/src/canvas/layout.js +309 -0
- package/dist/src/canvas/layout.js.map +10 -0
- package/dist/src/canvas/paint.js +878 -0
- package/dist/src/canvas/paint.js.map +10 -0
- package/dist/src/canvas/renderer.js +276 -0
- package/dist/src/canvas/renderer.js.map +10 -0
- package/dist/src/canvas/text.js +118 -0
- package/dist/src/canvas/text.js.map +10 -0
- package/dist/src/canvas/types.js +2 -0
- package/dist/src/canvas/types.js.map +9 -0
- package/dist/src/canvas/utils.js +139 -0
- package/dist/src/canvas/utils.js.map +10 -0
- package/dist/src/dom/applicators/advanced-layout.js +111 -0
- package/dist/src/dom/applicators/advanced-layout.js.map +10 -0
- package/dist/src/dom/applicators/background.js +54 -0
- package/dist/src/dom/applicators/background.js.map +10 -0
- package/dist/src/dom/applicators/border.js +33 -0
- package/dist/src/dom/applicators/border.js.map +10 -0
- package/dist/src/dom/applicators/color.js +36 -0
- package/dist/src/dom/applicators/color.js.map +10 -0
- package/dist/src/dom/applicators/display.js +57 -0
- package/dist/src/dom/applicators/display.js.map +10 -0
- package/dist/src/dom/applicators/effects.js +89 -0
- package/dist/src/dom/applicators/effects.js.map +10 -0
- package/dist/src/dom/applicators/events.js +518 -0
- package/dist/src/dom/applicators/events.js.map +10 -0
- package/dist/src/dom/applicators/font.js +39 -0
- package/dist/src/dom/applicators/font.js.map +10 -0
- package/dist/src/dom/applicators/index.js +296 -0
- package/dist/src/dom/applicators/index.js.map +10 -0
- package/dist/src/dom/applicators/layout.js +86 -0
- package/dist/src/dom/applicators/layout.js.map +10 -0
- package/dist/src/dom/applicators/margin.js +32 -0
- package/dist/src/dom/applicators/margin.js.map +10 -0
- package/dist/src/dom/applicators/padding.js +35 -0
- package/dist/src/dom/applicators/padding.js.map +10 -0
- package/dist/src/dom/applicators/size.js +42 -0
- package/dist/src/dom/applicators/size.js.map +10 -0
- package/dist/src/dom/applicators/transform.js +92 -0
- package/dist/src/dom/applicators/transform.js.map +10 -0
- package/dist/src/dom/applicators/transition.js +66 -0
- package/dist/src/dom/applicators/transition.js.map +10 -0
- package/dist/src/dom/applicators/typography.js +87 -0
- package/dist/src/dom/applicators/typography.js.map +10 -0
- package/dist/src/dom/canvas/index.js +50 -0
- package/dist/src/dom/canvas/index.js.map +10 -0
- package/dist/src/dom/components/audio.js +48 -0
- package/dist/src/dom/components/audio.js.map +10 -0
- package/dist/src/dom/components/avatar.js +58 -0
- package/dist/src/dom/components/avatar.js.map +10 -0
- package/dist/src/dom/components/badge.js +55 -0
- package/dist/src/dom/components/badge.js.map +10 -0
- package/dist/src/dom/components/button.js +29 -0
- package/dist/src/dom/components/button.js.map +10 -0
- package/dist/src/dom/components/card.js +33 -0
- package/dist/src/dom/components/card.js.map +10 -0
- package/dist/src/dom/components/center.js +32 -0
- package/dist/src/dom/components/center.js.map +10 -0
- package/dist/src/dom/components/checkbox.js +54 -0
- package/dist/src/dom/components/checkbox.js.map +10 -0
- package/dist/src/dom/components/column.js +31 -0
- package/dist/src/dom/components/column.js.map +10 -0
- package/dist/src/dom/components/container.js +29 -0
- package/dist/src/dom/components/container.js.map +10 -0
- package/dist/src/dom/components/divider.js +45 -0
- package/dist/src/dom/components/divider.js.map +10 -0
- package/dist/src/dom/components/grid.js +44 -0
- package/dist/src/dom/components/grid.js.map +10 -0
- package/dist/src/dom/components/heading.js +47 -0
- package/dist/src/dom/components/heading.js.map +10 -0
- package/dist/src/dom/components/image.js +39 -0
- package/dist/src/dom/components/image.js.map +10 -0
- package/dist/src/dom/components/index.js +217 -0
- package/dist/src/dom/components/index.js.map +10 -0
- package/dist/src/dom/components/input.js +41 -0
- package/dist/src/dom/components/input.js.map +10 -0
- package/dist/src/dom/components/link.js +42 -0
- package/dist/src/dom/components/link.js.map +10 -0
- package/dist/src/dom/components/list.js +42 -0
- package/dist/src/dom/components/list.js.map +10 -0
- package/dist/src/dom/components/paragraph.js +35 -0
- package/dist/src/dom/components/paragraph.js.map +10 -0
- package/dist/src/dom/components/progressbar.js +57 -0
- package/dist/src/dom/components/progressbar.js.map +10 -0
- package/dist/src/dom/components/route.js +44 -0
- package/dist/src/dom/components/route.js.map +10 -0
- package/dist/src/dom/components/router.js +33 -0
- package/dist/src/dom/components/router.js.map +10 -0
- package/dist/src/dom/components/row.js +31 -0
- package/dist/src/dom/components/row.js.map +10 -0
- package/dist/src/dom/components/select.js +57 -0
- package/dist/src/dom/components/select.js.map +10 -0
- package/dist/src/dom/components/slider.js +48 -0
- package/dist/src/dom/components/slider.js.map +10 -0
- package/dist/src/dom/components/spacer.js +30 -0
- package/dist/src/dom/components/spacer.js.map +10 -0
- package/dist/src/dom/components/spinner.js +65 -0
- package/dist/src/dom/components/spinner.js.map +10 -0
- package/dist/src/dom/components/stack.js +45 -0
- package/dist/src/dom/components/stack.js.map +10 -0
- package/dist/src/dom/components/switch.js +83 -0
- package/dist/src/dom/components/switch.js.map +10 -0
- package/dist/src/dom/components/text.js +37 -0
- package/dist/src/dom/components/text.js.map +10 -0
- package/dist/src/dom/components/textarea.js +51 -0
- package/dist/src/dom/components/textarea.js.map +10 -0
- package/dist/src/dom/components/video.js +51 -0
- package/dist/src/dom/components/video.js.map +10 -0
- package/dist/src/dom/debug.js +170 -0
- package/dist/src/dom/debug.js.map +10 -0
- package/dist/src/dom/events.js +112 -0
- package/dist/src/dom/events.js.map +10 -0
- package/dist/src/dom/index.js +73 -0
- package/dist/src/dom/index.js.map +9 -0
- package/dist/src/dom/renderer.js +277 -0
- package/dist/src/dom/renderer.js.map +10 -0
- package/dist/src/index.js +89 -0
- package/dist/src/index.js.map +9 -0
- package/package.json +84 -0
- package/src/canvas/QUICKSTART.md +421 -0
- package/src/canvas/README.md +376 -0
- package/src/canvas/accessibility.ts +218 -0
- package/src/canvas/events.ts +307 -0
- package/src/canvas/index.ts +35 -0
- package/src/canvas/input.ts +210 -0
- package/src/canvas/layout.ts +401 -0
- package/src/canvas/paint.ts +1321 -0
- package/src/canvas/renderer.ts +422 -0
- package/src/canvas/text.ts +182 -0
- package/src/canvas/types.ts +137 -0
- package/src/canvas/utils.ts +218 -0
- package/src/dom/README.md +265 -0
- package/src/dom/applicators/advanced-layout.ts +128 -0
- package/src/dom/applicators/background.ts +50 -0
- package/src/dom/applicators/border.ts +19 -0
- package/src/dom/applicators/color.ts +23 -0
- package/src/dom/applicators/display.ts +54 -0
- package/src/dom/applicators/effects.ts +97 -0
- package/src/dom/applicators/events.ts +689 -0
- package/src/dom/applicators/font.ts +27 -0
- package/src/dom/applicators/index.ts +354 -0
- package/src/dom/applicators/layout.ts +92 -0
- package/src/dom/applicators/margin.ts +18 -0
- package/src/dom/applicators/padding.ts +18 -0
- package/src/dom/applicators/size.ts +31 -0
- package/src/dom/applicators/transform.ts +93 -0
- package/src/dom/applicators/transition.ts +65 -0
- package/src/dom/applicators/typography.ts +91 -0
- package/src/dom/canvas/index.ts +60 -0
- package/src/dom/components/audio.ts +45 -0
- package/src/dom/components/avatar.ts +49 -0
- package/src/dom/components/badge.ts +45 -0
- package/src/dom/components/button.ts +13 -0
- package/src/dom/components/card.ts +19 -0
- package/src/dom/components/center.ts +16 -0
- package/src/dom/components/checkbox.ts +54 -0
- package/src/dom/components/column.ts +15 -0
- package/src/dom/components/container.ts +13 -0
- package/src/dom/components/divider.ts +37 -0
- package/src/dom/components/grid.ts +40 -0
- package/src/dom/components/heading.ts +41 -0
- package/src/dom/components/image.ts +27 -0
- package/src/dom/components/index.ts +115 -0
- package/src/dom/components/input.ts +29 -0
- package/src/dom/components/link.ts +35 -0
- package/src/dom/components/list.ts +30 -0
- package/src/dom/components/paragraph.ts +23 -0
- package/src/dom/components/progressbar.ts +51 -0
- package/src/dom/components/route.ts +37 -0
- package/src/dom/components/router.ts +22 -0
- package/src/dom/components/row.ts +15 -0
- package/src/dom/components/select.ts +56 -0
- package/src/dom/components/slider.ts +45 -0
- package/src/dom/components/spacer.ts +16 -0
- package/src/dom/components/spinner.ts +60 -0
- package/src/dom/components/stack.ts +34 -0
- package/src/dom/components/switch.ts +86 -0
- package/src/dom/components/text.ts +24 -0
- package/src/dom/components/textarea.ts +50 -0
- package/src/dom/components/video.ts +50 -0
- package/src/dom/debug.ts +247 -0
- package/src/dom/events.ts +168 -0
- package/src/dom/index.ts +11 -0
- package/src/dom/renderer.ts +327 -0
- package/src/index.ts +56 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Applicator Registry
|
|
3
|
+
*
|
|
4
|
+
* Handles style applicators (modifiers) for Hypen components
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type ApplicatorHandler = (element: HTMLElement, value: any) => void;
|
|
8
|
+
|
|
9
|
+
export class ApplicatorRegistry {
|
|
10
|
+
private handlers: Map<string, ApplicatorHandler> = new Map();
|
|
11
|
+
private elementState: WeakMap<HTMLElement, Map<string, any>> = new WeakMap();
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
this.registerDefaults();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Register an applicator handler
|
|
19
|
+
*/
|
|
20
|
+
register(name: string, handler: ApplicatorHandler): void {
|
|
21
|
+
this.handlers.set(name, handler);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Apply an applicator to an element
|
|
26
|
+
*/
|
|
27
|
+
apply(element: HTMLElement, name: string, value: any): void {
|
|
28
|
+
// Parse applicator metadata so we can normalize event arguments and retain legacy behavior
|
|
29
|
+
const { handlerName, argKey, aggregate, fallbackName } = this.parseApplicatorName(name);
|
|
30
|
+
|
|
31
|
+
const handler = this.handlers.get(handlerName);
|
|
32
|
+
const state = this.getElementState(element);
|
|
33
|
+
const previous = state.get(handlerName);
|
|
34
|
+
|
|
35
|
+
if (aggregate && argKey !== null) {
|
|
36
|
+
// Merge event payload updates with the previously applied arguments so handlers
|
|
37
|
+
// always receive the full payload object (prevents stale dispatch data)
|
|
38
|
+
const merged = this.mergeAggregateState(previous, argKey, this.normalizeValue(value));
|
|
39
|
+
|
|
40
|
+
state.set(handlerName, merged);
|
|
41
|
+
|
|
42
|
+
if (handler) {
|
|
43
|
+
handler(element, merged);
|
|
44
|
+
} else {
|
|
45
|
+
// Fallback: set as CSS property using the original name if no handler exists
|
|
46
|
+
this.setStyleProperty(element, fallbackName, value);
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (handler) {
|
|
52
|
+
if (this.isEventApplicator(handlerName)) {
|
|
53
|
+
const normalizedValue = this.normalizeEventValue(previous, value);
|
|
54
|
+
state.set(handlerName, normalizedValue);
|
|
55
|
+
handler(element, normalizedValue);
|
|
56
|
+
} else {
|
|
57
|
+
state.set(handlerName, value);
|
|
58
|
+
handler(element, value);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
// Fallback: set as CSS property
|
|
62
|
+
this.setStyleProperty(element, handlerName, value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parse applicator name to handle indexed and event argument formats
|
|
68
|
+
* e.g., "fontSize.0" -> { handlerName: "fontSize" }
|
|
69
|
+
* "onClick.id" -> { handlerName: "onClick", aggregate: true, argKey: "id" }
|
|
70
|
+
* Keeps compound names like "padding.top" as-is so they can fall back to CSS.
|
|
71
|
+
*/
|
|
72
|
+
private parseApplicatorName(name: string): {
|
|
73
|
+
handlerName: string;
|
|
74
|
+
argKey: string | null;
|
|
75
|
+
aggregate: boolean;
|
|
76
|
+
fallbackName: string;
|
|
77
|
+
} {
|
|
78
|
+
const dotIndex = name.indexOf('.');
|
|
79
|
+
if (dotIndex === -1) {
|
|
80
|
+
return { handlerName: name, argKey: null, aggregate: false, fallbackName: name };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const baseName = name.substring(0, dotIndex);
|
|
84
|
+
const argKey = name.substring(dotIndex + 1);
|
|
85
|
+
|
|
86
|
+
if (this.handlers.has(baseName) && this.isEventApplicator(baseName)) {
|
|
87
|
+
return { handlerName: baseName, argKey, aggregate: true, fallbackName: name };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (/^\d+$/.test(argKey)) {
|
|
91
|
+
return { handlerName: baseName, argKey: null, aggregate: false, fallbackName: baseName };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { handlerName: name, argKey: null, aggregate: false, fallbackName: name };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get or initialize per-element applicator state used for merging event payloads
|
|
99
|
+
*/
|
|
100
|
+
private getElementState(element: HTMLElement): Map<string, any> {
|
|
101
|
+
let state = this.elementState.get(element);
|
|
102
|
+
if (!state) {
|
|
103
|
+
state = new Map();
|
|
104
|
+
this.elementState.set(element, state);
|
|
105
|
+
}
|
|
106
|
+
return state;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Merge updated event argument into previously stored payload snapshot
|
|
111
|
+
*/
|
|
112
|
+
private mergeAggregateState(previous: any, argKey: string, value: any): Record<string, any> {
|
|
113
|
+
const base: Record<string, any> = this.cloneAggregateState(previous);
|
|
114
|
+
|
|
115
|
+
if (value === undefined) {
|
|
116
|
+
delete base[argKey];
|
|
117
|
+
} else {
|
|
118
|
+
base[argKey] = value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return base;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Convert stored state into a mutable payload object we can merge into
|
|
126
|
+
*/
|
|
127
|
+
private cloneAggregateState(previous: any): Record<string, any> {
|
|
128
|
+
if (previous && typeof previous === "object" && !Array.isArray(previous)) {
|
|
129
|
+
return { ...previous };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (typeof previous === "string") {
|
|
133
|
+
return { "0": previous };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Normalize event value updates so action payload arguments persist across SetProp orderings
|
|
141
|
+
*/
|
|
142
|
+
private normalizeEventValue(previous: any, value: any): Record<string, any> {
|
|
143
|
+
const normalizedInput = this.normalizeValue(value);
|
|
144
|
+
const base = this.cloneAggregateState(previous);
|
|
145
|
+
|
|
146
|
+
if (normalizedInput && typeof normalizedInput === "object" && !Array.isArray(normalizedInput)) {
|
|
147
|
+
const next = { ...base, ...normalizedInput } as Record<string, any>;
|
|
148
|
+
|
|
149
|
+
if (!Object.prototype.hasOwnProperty.call(next, "0") && base["0"] !== undefined) {
|
|
150
|
+
next["0"] = base["0"];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return next;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (normalizedInput !== undefined) {
|
|
157
|
+
base["0"] = normalizedInput;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return base;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Convert Maps (from WASM) and nested structures into plain JS values we can merge safely
|
|
165
|
+
*/
|
|
166
|
+
private normalizeValue(value: any): any {
|
|
167
|
+
if (value instanceof Map) {
|
|
168
|
+
const obj: Record<string, any> = {};
|
|
169
|
+
for (const [key, val] of value.entries()) {
|
|
170
|
+
obj[key] = this.normalizeValue(val);
|
|
171
|
+
}
|
|
172
|
+
return obj;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (Array.isArray(value)) {
|
|
176
|
+
return value.map((item) => this.normalizeValue(item));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (value && typeof value === "object") {
|
|
180
|
+
const obj: Record<string, any> = {};
|
|
181
|
+
for (const [key, val] of Object.entries(value)) {
|
|
182
|
+
obj[key] = this.normalizeValue(val);
|
|
183
|
+
}
|
|
184
|
+
return obj;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Determine if a handler name follows the event applicator naming convention
|
|
192
|
+
*/
|
|
193
|
+
private isEventApplicator(name: string): boolean {
|
|
194
|
+
return /^on[A-Z]/.test(name);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Apply multiple applicators
|
|
199
|
+
*/
|
|
200
|
+
applyAll(element: HTMLElement, applicators: Record<string, any>): void {
|
|
201
|
+
//console.log(`[ApplicatorRegistry] Applying applicators:`, applicators);
|
|
202
|
+
|
|
203
|
+
// Group applicators by their base name (treat applicators like components with arguments)
|
|
204
|
+
// e.g., "onClick.0", "onClick.id", "onClick.title" -> onClick: {0: ..., id: ..., title: ...}
|
|
205
|
+
const grouped = new Map<string, Record<string, any>>();
|
|
206
|
+
|
|
207
|
+
for (const [name, value] of Object.entries(applicators)) {
|
|
208
|
+
// Extract base name and argument key
|
|
209
|
+
const dotIndex = name.indexOf('.');
|
|
210
|
+
const baseName = dotIndex !== -1 ? name.substring(0, dotIndex) : name;
|
|
211
|
+
const argKey = dotIndex !== -1 ? name.substring(dotIndex + 1) : null;
|
|
212
|
+
|
|
213
|
+
if (!grouped.has(baseName)) {
|
|
214
|
+
grouped.set(baseName, {});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const args = grouped.get(baseName)!;
|
|
218
|
+
if (argKey !== null) {
|
|
219
|
+
// This is an argument (e.g., "onClick.0" or "onClick.id")
|
|
220
|
+
args[argKey] = value;
|
|
221
|
+
} else {
|
|
222
|
+
// This is a single-value applicator (e.g., "padding")
|
|
223
|
+
args['__value'] = value;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Apply each applicator with its arguments
|
|
228
|
+
for (const [baseName, args] of grouped.entries()) {
|
|
229
|
+
// If it's a single value (either __value or just "0"), pass just the value
|
|
230
|
+
if (Object.keys(args).length === 1) {
|
|
231
|
+
if ('__value' in args) {
|
|
232
|
+
this.apply(element, baseName, args['__value']);
|
|
233
|
+
} else if ('0' in args) {
|
|
234
|
+
// Single positional argument (e.g., padding.0 -> just pass the value)
|
|
235
|
+
this.apply(element, baseName, args['0']);
|
|
236
|
+
} else {
|
|
237
|
+
// Single named argument? Pass the whole object
|
|
238
|
+
this.apply(element, baseName, args);
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
// Multiple arguments - pass the entire args object
|
|
242
|
+
this.apply(element, baseName, args);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Set a CSS property with automatic unit handling
|
|
249
|
+
*/
|
|
250
|
+
private setStyleProperty(element: HTMLElement, name: string, value: any): void {
|
|
251
|
+
// Convert camelCase to kebab-case
|
|
252
|
+
const cssName = name.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
253
|
+
|
|
254
|
+
// Add units for numeric values on size properties
|
|
255
|
+
if (typeof value === "number" && this.needsUnit(cssName)) {
|
|
256
|
+
element.style.setProperty(cssName, `${value}px`);
|
|
257
|
+
} else {
|
|
258
|
+
element.style.setProperty(cssName, String(value));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Check if a property needs a unit
|
|
264
|
+
*/
|
|
265
|
+
private needsUnit(prop: string): boolean {
|
|
266
|
+
const unitless = [
|
|
267
|
+
"opacity",
|
|
268
|
+
"z-index",
|
|
269
|
+
"font-weight",
|
|
270
|
+
"line-height",
|
|
271
|
+
"flex",
|
|
272
|
+
"flex-grow",
|
|
273
|
+
"flex-shrink",
|
|
274
|
+
"order",
|
|
275
|
+
];
|
|
276
|
+
return !unitless.includes(prop);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Register default applicator handlers
|
|
281
|
+
*/
|
|
282
|
+
private registerDefaults(): void {
|
|
283
|
+
const { paddingHandler } = require("./padding.js");
|
|
284
|
+
const { marginHandler } = require("./margin.js");
|
|
285
|
+
const { colorHandlers } = require("./color.js");
|
|
286
|
+
const { borderHandlers } = require("./border.js");
|
|
287
|
+
const { sizeHandlers } = require("./size.js");
|
|
288
|
+
const { fontHandlers } = require("./font.js");
|
|
289
|
+
const { layoutHandlers } = require("./layout.js");
|
|
290
|
+
const { eventHandlers } = require("./events.js");
|
|
291
|
+
const { typographyHandlers } = require("./typography.js");
|
|
292
|
+
const { transformHandlers } = require("./transform.js");
|
|
293
|
+
const { effectsHandlers } = require("./effects.js");
|
|
294
|
+
const { advancedLayoutHandlers } = require("./advanced-layout.js");
|
|
295
|
+
const { backgroundHandlers } = require("./background.js");
|
|
296
|
+
const { displayHandlers } = require("./display.js");
|
|
297
|
+
const { transitionHandlers } = require("./transition.js");
|
|
298
|
+
|
|
299
|
+
this.register("padding", paddingHandler);
|
|
300
|
+
this.register("margin", marginHandler);
|
|
301
|
+
|
|
302
|
+
for (const [name, handler] of Object.entries(colorHandlers)) {
|
|
303
|
+
this.register(name, handler as ApplicatorHandler);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
for (const [name, handler] of Object.entries(borderHandlers)) {
|
|
307
|
+
this.register(name, handler as ApplicatorHandler);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
for (const [name, handler] of Object.entries(sizeHandlers)) {
|
|
311
|
+
this.register(name, handler as ApplicatorHandler);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
for (const [name, handler] of Object.entries(fontHandlers)) {
|
|
315
|
+
this.register(name, handler as ApplicatorHandler);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
for (const [name, handler] of Object.entries(layoutHandlers)) {
|
|
319
|
+
this.register(name, handler as ApplicatorHandler);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
for (const [name, handler] of Object.entries(eventHandlers)) {
|
|
323
|
+
this.register(name, handler as ApplicatorHandler);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
for (const [name, handler] of Object.entries(typographyHandlers)) {
|
|
327
|
+
this.register(name, handler as ApplicatorHandler);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
for (const [name, handler] of Object.entries(transformHandlers)) {
|
|
331
|
+
this.register(name, handler as ApplicatorHandler);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
for (const [name, handler] of Object.entries(effectsHandlers)) {
|
|
335
|
+
this.register(name, handler as ApplicatorHandler);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
for (const [name, handler] of Object.entries(advancedLayoutHandlers)) {
|
|
339
|
+
this.register(name, handler as ApplicatorHandler);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
for (const [name, handler] of Object.entries(backgroundHandlers)) {
|
|
343
|
+
this.register(name, handler as ApplicatorHandler);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
for (const [name, handler] of Object.entries(displayHandlers)) {
|
|
347
|
+
this.register(name, handler as ApplicatorHandler);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
for (const [name, handler] of Object.entries(transitionHandlers)) {
|
|
351
|
+
this.register(name, handler as ApplicatorHandler);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout Applicators (Flexbox/Grid)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ApplicatorHandler } from "./index.js";
|
|
6
|
+
|
|
7
|
+
export const layoutHandlers: Record<string, ApplicatorHandler> = {
|
|
8
|
+
// Unified alignment API - works for both Column and Row
|
|
9
|
+
verticalAlignment: (el, value) => {
|
|
10
|
+
const val = String(value);
|
|
11
|
+
// Check flex-direction to determine which CSS property to set
|
|
12
|
+
const flexDirection = getComputedStyle(el).flexDirection;
|
|
13
|
+
if (flexDirection === "column" || flexDirection === "column-reverse") {
|
|
14
|
+
// For column: vertical is the main axis (justify-content)
|
|
15
|
+
el.style.justifyContent = val;
|
|
16
|
+
} else {
|
|
17
|
+
// For row: vertical is the cross axis (align-items)
|
|
18
|
+
el.style.alignItems = val;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
horizontalAlignment: (el, value) => {
|
|
23
|
+
const val = String(value);
|
|
24
|
+
// Check flex-direction to determine which CSS property to set
|
|
25
|
+
const flexDirection = getComputedStyle(el).flexDirection;
|
|
26
|
+
if (flexDirection === "column" || flexDirection === "column-reverse") {
|
|
27
|
+
// For column: horizontal is the cross axis (align-items)
|
|
28
|
+
el.style.alignItems = val;
|
|
29
|
+
} else {
|
|
30
|
+
// For row: horizontal is the main axis (justify-content)
|
|
31
|
+
el.style.justifyContent = val;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// Legacy aliases (kept for backward compatibility)
|
|
36
|
+
horizontalAlign: (el, value) => {
|
|
37
|
+
el.style.justifyContent = String(value);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
verticalAlign: (el, value) => {
|
|
41
|
+
el.style.alignItems = String(value);
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
gap: (el, value) => {
|
|
45
|
+
el.style.gap = typeof value === "number" ? `${value}px` : String(value);
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// weight: unified cross-platform API (same as flex)
|
|
49
|
+
// Use .weight(1) to make element take remaining space in Row/Column
|
|
50
|
+
weight: (el, value) => {
|
|
51
|
+
el.style.flex = String(value);
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// flex: CSS flex shorthand (kept for CSS compatibility)
|
|
55
|
+
flex: (el, value) => {
|
|
56
|
+
el.style.flex = String(value);
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
flexGrow: (el, value) => {
|
|
60
|
+
el.style.flexGrow = String(value);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
flexShrink: (el, value) => {
|
|
64
|
+
el.style.flexShrink = String(value);
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
cursor: (el, value) => {
|
|
68
|
+
el.style.cursor = String(value);
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
overflow: (el, value) => {
|
|
72
|
+
el.style.overflow = String(value);
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
scrollable: (el, value) => {
|
|
76
|
+
if (value === true || value === "true") {
|
|
77
|
+
el.style.overflow = "auto";
|
|
78
|
+
} else if (value === false || value === "false") {
|
|
79
|
+
el.style.overflow = "hidden";
|
|
80
|
+
} else if (value === "vertical") {
|
|
81
|
+
el.style.overflowX = "hidden";
|
|
82
|
+
el.style.overflowY = "auto";
|
|
83
|
+
} else if (value === "horizontal") {
|
|
84
|
+
el.style.overflowX = "auto";
|
|
85
|
+
el.style.overflowY = "hidden";
|
|
86
|
+
} else if (value === "both") {
|
|
87
|
+
el.style.overflow = "auto";
|
|
88
|
+
} else {
|
|
89
|
+
el.style.overflow = String(value);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Margin Applicator
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ApplicatorHandler } from "./index.js";
|
|
6
|
+
|
|
7
|
+
export const marginHandler: ApplicatorHandler = (el, value) => {
|
|
8
|
+
if (typeof value === "number") {
|
|
9
|
+
el.style.margin = `${value}px`;
|
|
10
|
+
} else if (typeof value === "object") {
|
|
11
|
+
if (value.left !== undefined) el.style.marginLeft = `${value.left}px`;
|
|
12
|
+
if (value.right !== undefined) el.style.marginRight = `${value.right}px`;
|
|
13
|
+
if (value.top !== undefined) el.style.marginTop = `${value.top}px`;
|
|
14
|
+
if (value.bottom !== undefined) el.style.marginBottom = `${value.bottom}px`;
|
|
15
|
+
} else {
|
|
16
|
+
el.style.margin = String(value);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Padding Applicator
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ApplicatorHandler } from "./index.js";
|
|
6
|
+
|
|
7
|
+
export const paddingHandler: ApplicatorHandler = (el, value) => {
|
|
8
|
+
if (typeof value === "number") {
|
|
9
|
+
el.style.padding = `${value}px`;
|
|
10
|
+
} else if (typeof value === "object") {
|
|
11
|
+
if (value.left !== undefined) el.style.paddingLeft = `${value.left}px`;
|
|
12
|
+
if (value.right !== undefined) el.style.paddingRight = `${value.right}px`;
|
|
13
|
+
if (value.top !== undefined) el.style.paddingTop = `${value.top}px`;
|
|
14
|
+
if (value.bottom !== undefined) el.style.paddingBottom = `${value.bottom}px`;
|
|
15
|
+
} else {
|
|
16
|
+
el.style.padding = String(value);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Size Applicators
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ApplicatorHandler } from "./index.js";
|
|
6
|
+
|
|
7
|
+
export const sizeHandlers: Record<string, ApplicatorHandler> = {
|
|
8
|
+
width: (el, value) => {
|
|
9
|
+
el.style.width = typeof value === "number" ? `${value}px` : String(value);
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
height: (el, value) => {
|
|
13
|
+
el.style.height = typeof value === "number" ? `${value}px` : String(value);
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
minWidth: (el, value) => {
|
|
17
|
+
el.style.minWidth = typeof value === "number" ? `${value}px` : String(value);
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
minHeight: (el, value) => {
|
|
21
|
+
el.style.minHeight = typeof value === "number" ? `${value}px` : String(value);
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
maxWidth: (el, value) => {
|
|
25
|
+
el.style.maxWidth = typeof value === "number" ? `${value}px` : String(value);
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
maxHeight: (el, value) => {
|
|
29
|
+
el.style.maxHeight = typeof value === "number" ? `${value}px` : String(value);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform Applicators
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ApplicatorHandler } from "./index.js";
|
|
6
|
+
|
|
7
|
+
export const transformHandlers: Record<string, ApplicatorHandler> = {
|
|
8
|
+
transform: (el, value) => {
|
|
9
|
+
el.style.transform = String(value);
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
transformOrigin: (el, value) => {
|
|
13
|
+
el.style.transformOrigin = String(value);
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
translateX: (el, value) => {
|
|
17
|
+
const current = el.style.transform || "";
|
|
18
|
+
const val = typeof value === "number" ? `${value}px` : String(value);
|
|
19
|
+
el.style.transform = current ? `${current} translateX(${val})` : `translateX(${val})`;
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
translateY: (el, value) => {
|
|
23
|
+
const current = el.style.transform || "";
|
|
24
|
+
const val = typeof value === "number" ? `${value}px` : String(value);
|
|
25
|
+
el.style.transform = current ? `${current} translateY(${val})` : `translateY(${val})`;
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
translateZ: (el, value) => {
|
|
29
|
+
const current = el.style.transform || "";
|
|
30
|
+
const val = typeof value === "number" ? `${value}px` : String(value);
|
|
31
|
+
el.style.transform = current ? `${current} translateZ(${val})` : `translateZ(${val})`;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
rotate: (el, value) => {
|
|
35
|
+
const current = el.style.transform || "";
|
|
36
|
+
const val = String(value);
|
|
37
|
+
el.style.transform = current ? `${current} rotate(${val})` : `rotate(${val})`;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
rotateX: (el, value) => {
|
|
41
|
+
const current = el.style.transform || "";
|
|
42
|
+
const val = String(value);
|
|
43
|
+
el.style.transform = current ? `${current} rotateX(${val})` : `rotateX(${val})`;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
rotateY: (el, value) => {
|
|
47
|
+
const current = el.style.transform || "";
|
|
48
|
+
const val = String(value);
|
|
49
|
+
el.style.transform = current ? `${current} rotateY(${val})` : `rotateY(${val})`;
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
rotateZ: (el, value) => {
|
|
53
|
+
const current = el.style.transform || "";
|
|
54
|
+
const val = String(value);
|
|
55
|
+
el.style.transform = current ? `${current} rotateZ(${val})` : `rotateZ(${val})`;
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
scale: (el, value) => {
|
|
59
|
+
const current = el.style.transform || "";
|
|
60
|
+
el.style.transform = current ? `${current} scale(${value})` : `scale(${value})`;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
scaleX: (el, value) => {
|
|
64
|
+
const current = el.style.transform || "";
|
|
65
|
+
el.style.transform = current ? `${current} scaleX(${value})` : `scaleX(${value})`;
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
scaleY: (el, value) => {
|
|
69
|
+
const current = el.style.transform || "";
|
|
70
|
+
el.style.transform = current ? `${current} scaleY(${value})` : `scaleY(${value})`;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
skew: (el, value) => {
|
|
74
|
+
const current = el.style.transform || "";
|
|
75
|
+
el.style.transform = current ? `${current} skew(${value})` : `skew(${value})`;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
skewX: (el, value) => {
|
|
79
|
+
const current = el.style.transform || "";
|
|
80
|
+
el.style.transform = current ? `${current} skewX(${value})` : `skewX(${value})`;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
skewY: (el, value) => {
|
|
84
|
+
const current = el.style.transform || "";
|
|
85
|
+
el.style.transform = current ? `${current} skewY(${value})` : `skewY(${value})`;
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
perspective: (el, value) => {
|
|
89
|
+
el.style.perspective = typeof value === "number" ? `${value}px` : String(value);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transition and Animation Applicators
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ApplicatorHandler } from "./index.js";
|
|
6
|
+
|
|
7
|
+
export const transitionHandlers: Record<string, ApplicatorHandler> = {
|
|
8
|
+
transition: (el, value) => {
|
|
9
|
+
el.style.transition = String(value);
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
transitionProperty: (el, value) => {
|
|
13
|
+
el.style.transitionProperty = String(value);
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
transitionDuration: (el, value) => {
|
|
17
|
+
el.style.transitionDuration = String(value);
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
transitionTimingFunction: (el, value) => {
|
|
21
|
+
el.style.transitionTimingFunction = String(value);
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
transitionDelay: (el, value) => {
|
|
25
|
+
el.style.transitionDelay = String(value);
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
animation: (el, value) => {
|
|
29
|
+
el.style.animation = String(value);
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
animationName: (el, value) => {
|
|
33
|
+
el.style.animationName = String(value);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
animationDuration: (el, value) => {
|
|
37
|
+
el.style.animationDuration = String(value);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
animationTimingFunction: (el, value) => {
|
|
41
|
+
el.style.animationTimingFunction = String(value);
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
animationDelay: (el, value) => {
|
|
45
|
+
el.style.animationDelay = String(value);
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
animationIterationCount: (el, value) => {
|
|
49
|
+
el.style.animationIterationCount = String(value);
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
animationDirection: (el, value) => {
|
|
53
|
+
el.style.animationDirection = String(value);
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
animationFillMode: (el, value) => {
|
|
57
|
+
el.style.animationFillMode = String(value);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
animationPlayState: (el, value) => {
|
|
61
|
+
el.style.animationPlayState = String(value);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
|