@hypen-space/web 0.3.7 → 0.3.9
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/src/dom/applicators/advanced-layout.js +195 -110
- package/dist/src/dom/applicators/advanced-layout.js.map +5 -4
- package/dist/src/dom/applicators/background.js +33 -42
- package/dist/src/dom/applicators/background.js.map +3 -3
- package/dist/src/dom/applicators/border.js +58 -67
- package/dist/src/dom/applicators/border.js.map +3 -3
- package/dist/src/dom/applicators/color.js +15 -24
- package/dist/src/dom/applicators/color.js.map +3 -3
- package/dist/src/dom/applicators/display.js +36 -45
- package/dist/src/dom/applicators/display.js.map +3 -3
- package/dist/src/dom/applicators/effects.js +103 -112
- package/dist/src/dom/applicators/effects.js.map +3 -3
- package/dist/src/dom/applicators/events.js +36 -45
- package/dist/src/dom/applicators/events.js.map +4 -4
- package/dist/src/dom/applicators/font.js +76 -86
- package/dist/src/dom/applicators/font.js.map +3 -3
- package/dist/src/dom/applicators/index.js +774 -888
- package/dist/src/dom/applicators/index.js.map +19 -19
- package/dist/src/dom/applicators/layout.js +64 -72
- package/dist/src/dom/applicators/layout.js.map +3 -3
- package/dist/src/dom/applicators/margin.js +1 -5
- package/dist/src/dom/applicators/margin.js.map +3 -3
- package/dist/src/dom/applicators/padding.js +1 -5
- package/dist/src/dom/applicators/padding.js.map +3 -3
- package/dist/src/dom/applicators/size.js +69 -77
- package/dist/src/dom/applicators/size.js.map +3 -3
- package/dist/src/dom/applicators/transform.js +71 -80
- package/dist/src/dom/applicators/transform.js.map +3 -3
- package/dist/src/dom/applicators/transition.js +45 -54
- package/dist/src/dom/applicators/transition.js.map +3 -3
- package/dist/src/dom/applicators/types.js +2 -0
- package/dist/src/dom/applicators/types.js.map +9 -0
- package/dist/src/dom/applicators/typography.js +65 -74
- package/dist/src/dom/applicators/typography.js.map +3 -3
- package/dist/src/dom/components/avatar.js +4 -3
- package/dist/src/dom/components/avatar.js.map +3 -3
- package/dist/src/dom/components/button.js +11 -1
- package/dist/src/dom/components/button.js.map +3 -3
- package/dist/src/dom/components/column.js +2 -1
- package/dist/src/dom/components/column.js.map +3 -3
- package/dist/src/dom/components/container.js +4 -1
- package/dist/src/dom/components/container.js.map +3 -3
- package/dist/src/dom/components/index.js +44 -20
- package/dist/src/dom/components/index.js.map +9 -9
- package/dist/src/dom/components/list.js +3 -1
- package/dist/src/dom/components/list.js.map +3 -3
- package/dist/src/dom/components/row.js +2 -1
- package/dist/src/dom/components/row.js.map +3 -3
- package/dist/src/dom/components/stack.js +24 -18
- package/dist/src/dom/components/stack.js.map +3 -3
- package/dist/src/dom/element-data.js +6 -11
- package/dist/src/dom/element-data.js.map +3 -3
- package/dist/src/dom/index.js +906 -998
- package/dist/src/dom/index.js.map +27 -27
- package/dist/src/dom/renderer.js +906 -998
- package/dist/src/dom/renderer.js.map +27 -27
- package/dist/src/hypen.js +906 -998
- package/dist/src/hypen.js.map +27 -27
- package/dist/src/index.js +906 -998
- package/dist/src/index.js.map +27 -27
- package/package.json +2 -2
- package/src/dom/applicators/advanced-layout.ts +3 -2
- package/src/dom/applicators/background.ts +1 -1
- package/src/dom/applicators/border.ts +1 -1
- package/src/dom/applicators/color.ts +1 -1
- package/src/dom/applicators/display.ts +1 -1
- package/src/dom/applicators/effects.ts +1 -1
- package/src/dom/applicators/events.ts +2 -2
- package/src/dom/applicators/font.ts +1 -1
- package/src/dom/applicators/index.ts +49 -17
- package/src/dom/applicators/layout.ts +28 -9
- package/src/dom/applicators/margin.ts +56 -6
- package/src/dom/applicators/padding.ts +56 -6
- package/src/dom/applicators/size.ts +14 -4
- package/src/dom/applicators/transform.ts +1 -1
- package/src/dom/applicators/transition.ts +1 -1
- package/src/dom/applicators/types.ts +7 -0
- package/src/dom/applicators/typography.ts +1 -1
- package/src/dom/components/avatar.ts +4 -3
- package/src/dom/components/button.ts +17 -0
- package/src/dom/components/column.ts +9 -0
- package/src/dom/components/container.ts +2 -0
- package/src/dom/components/list.ts +3 -0
- package/src/dom/components/row.ts +4 -0
- package/src/dom/components/stack.ts +31 -19
- package/src/dom/components/text.ts +7 -0
- package/src/dom/element-data.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypen-space/web",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Hypen web renderers - DOM and Canvas rendering for browsers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"clean": "rm -rf dist"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@hypen-space/core": "^0.3.
|
|
51
|
+
"@hypen-space/core": "^0.3.9"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/bun": "latest",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ApplicatorHandler } from "./index.js";
|
|
6
|
+
import { mapAlignmentValue } from "./layout.js";
|
|
6
7
|
|
|
7
8
|
export const advancedLayoutHandlers: Record<string, ApplicatorHandler> = {
|
|
8
9
|
// Flexbox properties
|
|
@@ -19,11 +20,11 @@ export const advancedLayoutHandlers: Record<string, ApplicatorHandler> = {
|
|
|
19
20
|
},
|
|
20
21
|
|
|
21
22
|
justifyContent: (el, value) => {
|
|
22
|
-
el.style.justifyContent = String(value);
|
|
23
|
+
el.style.justifyContent = mapAlignmentValue(String(value));
|
|
23
24
|
},
|
|
24
25
|
|
|
25
26
|
alignItems: (el, value) => {
|
|
26
|
-
el.style.alignItems = String(value);
|
|
27
|
+
el.style.alignItems = mapAlignmentValue(String(value));
|
|
27
28
|
},
|
|
28
29
|
|
|
29
30
|
alignContent: (el, value) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Border Applicators
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { ApplicatorHandler } from "./
|
|
5
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
6
6
|
|
|
7
7
|
export const borderHandlers: Record<string, ApplicatorHandler> = {
|
|
8
8
|
// Compound border applicator - can take width, color, style, radius
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Visual Effects Applicators (Shadows, Filters, Blend Modes)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { ApplicatorHandler } from "./
|
|
5
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
6
6
|
|
|
7
7
|
export const effectsHandlers: Record<string, ApplicatorHandler> = {
|
|
8
8
|
// Shadow effects
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* Uses a factory pattern to reduce boilerplate and ensure consistency.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { ApplicatorHandler } from "./
|
|
8
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
9
9
|
import {
|
|
10
10
|
getElementDisposables,
|
|
11
11
|
disposableListener,
|
|
12
12
|
disposableTimeout,
|
|
13
13
|
type Disposable,
|
|
14
|
-
} from "@hypen-space/core";
|
|
14
|
+
} from "@hypen-space/core/disposable";
|
|
15
15
|
import {
|
|
16
16
|
type IEngine,
|
|
17
17
|
getEngine,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Font Applicators with Google Fonts support
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { ApplicatorHandler } from "./
|
|
5
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
6
6
|
|
|
7
7
|
// Track loaded Google Fonts to avoid duplicate link tags
|
|
8
8
|
const loadedGoogleFonts = new Set<string>();
|
|
@@ -4,7 +4,42 @@
|
|
|
4
4
|
* Handles style applicators (modifiers) for Hypen components
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export type
|
|
7
|
+
// Re-export the type from types.ts to maintain API compatibility
|
|
8
|
+
export type { ApplicatorHandler } from "./types.js";
|
|
9
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
10
|
+
|
|
11
|
+
// Static imports for all applicator handlers (avoids circular dependency)
|
|
12
|
+
import {
|
|
13
|
+
paddingHandler,
|
|
14
|
+
paddingTopHandler,
|
|
15
|
+
paddingBottomHandler,
|
|
16
|
+
paddingLeftHandler,
|
|
17
|
+
paddingRightHandler,
|
|
18
|
+
paddingHorizontalHandler,
|
|
19
|
+
paddingVerticalHandler,
|
|
20
|
+
} from "./padding.js";
|
|
21
|
+
import {
|
|
22
|
+
marginHandler,
|
|
23
|
+
marginTopHandler,
|
|
24
|
+
marginBottomHandler,
|
|
25
|
+
marginLeftHandler,
|
|
26
|
+
marginRightHandler,
|
|
27
|
+
marginHorizontalHandler,
|
|
28
|
+
marginVerticalHandler,
|
|
29
|
+
} from "./margin.js";
|
|
30
|
+
import { colorHandlers } from "./color.js";
|
|
31
|
+
import { borderHandlers } from "./border.js";
|
|
32
|
+
import { sizeHandlers } from "./size.js";
|
|
33
|
+
import { fontHandlers } from "./font.js";
|
|
34
|
+
import { layoutHandlers } from "./layout.js";
|
|
35
|
+
import { eventHandlers } from "./events.js";
|
|
36
|
+
import { typographyHandlers } from "./typography.js";
|
|
37
|
+
import { transformHandlers } from "./transform.js";
|
|
38
|
+
import { effectsHandlers } from "./effects.js";
|
|
39
|
+
import { advancedLayoutHandlers } from "./advanced-layout.js";
|
|
40
|
+
import { backgroundHandlers } from "./background.js";
|
|
41
|
+
import { displayHandlers } from "./display.js";
|
|
42
|
+
import { transitionHandlers } from "./transition.js";
|
|
8
43
|
|
|
9
44
|
/**
|
|
10
45
|
* Tailwind breakpoint values for responsive variants
|
|
@@ -388,26 +423,23 @@ export class ApplicatorRegistry {
|
|
|
388
423
|
|
|
389
424
|
/**
|
|
390
425
|
* Register default applicator handlers
|
|
426
|
+
* Uses statically imported handlers (defined at top of file) to avoid circular dependencies
|
|
391
427
|
*/
|
|
392
428
|
private registerDefaults(): void {
|
|
393
|
-
const { paddingHandler } = require("./padding.js");
|
|
394
|
-
const { marginHandler } = require("./margin.js");
|
|
395
|
-
const { colorHandlers } = require("./color.js");
|
|
396
|
-
const { borderHandlers } = require("./border.js");
|
|
397
|
-
const { sizeHandlers } = require("./size.js");
|
|
398
|
-
const { fontHandlers } = require("./font.js");
|
|
399
|
-
const { layoutHandlers } = require("./layout.js");
|
|
400
|
-
const { eventHandlers } = require("./events.js");
|
|
401
|
-
const { typographyHandlers } = require("./typography.js");
|
|
402
|
-
const { transformHandlers } = require("./transform.js");
|
|
403
|
-
const { effectsHandlers } = require("./effects.js");
|
|
404
|
-
const { advancedLayoutHandlers } = require("./advanced-layout.js");
|
|
405
|
-
const { backgroundHandlers } = require("./background.js");
|
|
406
|
-
const { displayHandlers } = require("./display.js");
|
|
407
|
-
const { transitionHandlers } = require("./transition.js");
|
|
408
|
-
|
|
409
429
|
this.register("padding", paddingHandler);
|
|
430
|
+
this.register("paddingTop", paddingTopHandler);
|
|
431
|
+
this.register("paddingBottom", paddingBottomHandler);
|
|
432
|
+
this.register("paddingLeft", paddingLeftHandler);
|
|
433
|
+
this.register("paddingRight", paddingRightHandler);
|
|
434
|
+
this.register("paddingHorizontal", paddingHorizontalHandler);
|
|
435
|
+
this.register("paddingVertical", paddingVerticalHandler);
|
|
410
436
|
this.register("margin", marginHandler);
|
|
437
|
+
this.register("marginTop", marginTopHandler);
|
|
438
|
+
this.register("marginBottom", marginBottomHandler);
|
|
439
|
+
this.register("marginLeft", marginLeftHandler);
|
|
440
|
+
this.register("marginRight", marginRightHandler);
|
|
441
|
+
this.register("marginHorizontal", marginHorizontalHandler);
|
|
442
|
+
this.register("marginVertical", marginVerticalHandler);
|
|
411
443
|
|
|
412
444
|
for (const [name, handler] of Object.entries(colorHandlers)) {
|
|
413
445
|
this.register(name, handler as ApplicatorHandler);
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* Layout Applicators (Flexbox/Grid)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { ApplicatorHandler } from "./
|
|
5
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Maps Hypen alignment values to CSS flexbox values.
|
|
9
9
|
* Ensures consistent cross-platform API (Android/iOS/Web).
|
|
10
10
|
*/
|
|
11
|
-
function mapAlignmentValue(value: string): string {
|
|
11
|
+
export function mapAlignmentValue(value: string): string {
|
|
12
12
|
const v = String(value).toLowerCase();
|
|
13
13
|
switch (v) {
|
|
14
14
|
// Positional values -> CSS equivalents
|
|
@@ -44,9 +44,14 @@ export const layoutHandlers: Record<string, ApplicatorHandler> = {
|
|
|
44
44
|
// Unified alignment API - works for both Column and Row
|
|
45
45
|
verticalAlignment: (el, value) => {
|
|
46
46
|
const val = mapAlignmentValue(String(value));
|
|
47
|
-
// Check flex-direction to determine which CSS property to set
|
|
48
|
-
const
|
|
49
|
-
|
|
47
|
+
// Check display and flex-direction to determine which CSS property to set
|
|
48
|
+
const display = el.style.display || getComputedStyle(el).display;
|
|
49
|
+
const flexDirection = el.style.flexDirection || getComputedStyle(el).flexDirection;
|
|
50
|
+
|
|
51
|
+
if (display === "grid") {
|
|
52
|
+
// For Grid (Stack): use align-items to align children vertically
|
|
53
|
+
el.style.alignItems = val;
|
|
54
|
+
} else if (flexDirection === "column" || flexDirection === "column-reverse") {
|
|
50
55
|
// For column: vertical is the main axis (justify-content)
|
|
51
56
|
el.style.justifyContent = val;
|
|
52
57
|
} else {
|
|
@@ -57,14 +62,28 @@ export const layoutHandlers: Record<string, ApplicatorHandler> = {
|
|
|
57
62
|
|
|
58
63
|
horizontalAlignment: (el, value) => {
|
|
59
64
|
const val = mapAlignmentValue(String(value));
|
|
60
|
-
// Check flex-direction to determine which CSS property to set
|
|
61
|
-
const
|
|
62
|
-
|
|
65
|
+
// Check display and flex-direction to determine which CSS property to set
|
|
66
|
+
const display = el.style.display || getComputedStyle(el).display;
|
|
67
|
+
const flexDirection = el.style.flexDirection || getComputedStyle(el).flexDirection;
|
|
68
|
+
|
|
69
|
+
if (display === "grid") {
|
|
70
|
+
// For Grid (Stack): use justify-items to align children horizontally
|
|
71
|
+
el.style.justifyItems = val;
|
|
72
|
+
} else if (flexDirection === "column" || flexDirection === "column-reverse") {
|
|
63
73
|
// For column: horizontal is the cross axis (align-items)
|
|
64
74
|
el.style.alignItems = val;
|
|
65
|
-
} else {
|
|
75
|
+
} else if (flexDirection === "row" || flexDirection === "row-reverse") {
|
|
66
76
|
// For row: horizontal is the main axis (justify-content)
|
|
67
77
|
el.style.justifyContent = val;
|
|
78
|
+
// For arrangement to have visible effect, Row needs to fill available width
|
|
79
|
+
// (matching iOS/Android behavior where non-start alignment auto-expands)
|
|
80
|
+
// Only auto-expand if not scrollable
|
|
81
|
+
if (val !== "flex-start" && el.style.overflow !== "auto" && el.style.overflowX !== "auto") {
|
|
82
|
+
el.style.width = "100%";
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
// Fallback for other display types
|
|
86
|
+
el.style.justifyContent = val;
|
|
68
87
|
}
|
|
69
88
|
},
|
|
70
89
|
|
|
@@ -1,18 +1,68 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Margin
|
|
2
|
+
* Margin Applicators
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { ApplicatorHandler } from "./
|
|
5
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
6
|
+
|
|
7
|
+
// Helper to extract numeric value from applicator value
|
|
8
|
+
const getNumericValue = (value: any): number | null => {
|
|
9
|
+
if (typeof value === "number") return value;
|
|
10
|
+
if (typeof value === "object" && value["0"] !== undefined) return Number(value["0"]);
|
|
11
|
+
if (typeof value === "string") return parseFloat(value);
|
|
12
|
+
return null;
|
|
13
|
+
};
|
|
6
14
|
|
|
7
15
|
export const marginHandler: ApplicatorHandler = (el, value) => {
|
|
8
16
|
if (typeof value === "number") {
|
|
9
17
|
el.style.margin = `${value}px`;
|
|
10
18
|
} else if (typeof value === "object") {
|
|
11
|
-
|
|
12
|
-
if (value
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
// Handle {0: value} format from .margin(value)
|
|
20
|
+
if (value["0"] !== undefined && Object.keys(value).length === 1) {
|
|
21
|
+
el.style.margin = `${value["0"]}px`;
|
|
22
|
+
} else {
|
|
23
|
+
if (value.left !== undefined) el.style.marginLeft = `${value.left}px`;
|
|
24
|
+
if (value.right !== undefined) el.style.marginRight = `${value.right}px`;
|
|
25
|
+
if (value.top !== undefined) el.style.marginTop = `${value.top}px`;
|
|
26
|
+
if (value.bottom !== undefined) el.style.marginBottom = `${value.bottom}px`;
|
|
27
|
+
}
|
|
15
28
|
} else {
|
|
16
29
|
el.style.margin = String(value);
|
|
17
30
|
}
|
|
18
31
|
};
|
|
32
|
+
|
|
33
|
+
// Directional margin handlers for .marginTop(8), .marginBottom(8), etc.
|
|
34
|
+
export const marginTopHandler: ApplicatorHandler = (el, value) => {
|
|
35
|
+
const v = getNumericValue(value);
|
|
36
|
+
if (v !== null) el.style.marginTop = `${v}px`;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const marginBottomHandler: ApplicatorHandler = (el, value) => {
|
|
40
|
+
const v = getNumericValue(value);
|
|
41
|
+
if (v !== null) el.style.marginBottom = `${v}px`;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const marginLeftHandler: ApplicatorHandler = (el, value) => {
|
|
45
|
+
const v = getNumericValue(value);
|
|
46
|
+
if (v !== null) el.style.marginLeft = `${v}px`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const marginRightHandler: ApplicatorHandler = (el, value) => {
|
|
50
|
+
const v = getNumericValue(value);
|
|
51
|
+
if (v !== null) el.style.marginRight = `${v}px`;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const marginHorizontalHandler: ApplicatorHandler = (el, value) => {
|
|
55
|
+
const v = getNumericValue(value);
|
|
56
|
+
if (v !== null) {
|
|
57
|
+
el.style.marginLeft = `${v}px`;
|
|
58
|
+
el.style.marginRight = `${v}px`;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const marginVerticalHandler: ApplicatorHandler = (el, value) => {
|
|
63
|
+
const v = getNumericValue(value);
|
|
64
|
+
if (v !== null) {
|
|
65
|
+
el.style.marginTop = `${v}px`;
|
|
66
|
+
el.style.marginBottom = `${v}px`;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
@@ -1,18 +1,68 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Padding
|
|
2
|
+
* Padding Applicators
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { ApplicatorHandler } from "./
|
|
5
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
6
|
+
|
|
7
|
+
// Helper to extract numeric value from applicator value
|
|
8
|
+
const getNumericValue = (value: any): number | null => {
|
|
9
|
+
if (typeof value === "number") return value;
|
|
10
|
+
if (typeof value === "object" && value["0"] !== undefined) return Number(value["0"]);
|
|
11
|
+
if (typeof value === "string") return parseFloat(value);
|
|
12
|
+
return null;
|
|
13
|
+
};
|
|
6
14
|
|
|
7
15
|
export const paddingHandler: ApplicatorHandler = (el, value) => {
|
|
8
16
|
if (typeof value === "number") {
|
|
9
17
|
el.style.padding = `${value}px`;
|
|
10
18
|
} else if (typeof value === "object") {
|
|
11
|
-
|
|
12
|
-
if (value
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
// Handle {0: value} format from .padding(value)
|
|
20
|
+
if (value["0"] !== undefined && Object.keys(value).length === 1) {
|
|
21
|
+
el.style.padding = `${value["0"]}px`;
|
|
22
|
+
} else {
|
|
23
|
+
if (value.left !== undefined) el.style.paddingLeft = `${value.left}px`;
|
|
24
|
+
if (value.right !== undefined) el.style.paddingRight = `${value.right}px`;
|
|
25
|
+
if (value.top !== undefined) el.style.paddingTop = `${value.top}px`;
|
|
26
|
+
if (value.bottom !== undefined) el.style.paddingBottom = `${value.bottom}px`;
|
|
27
|
+
}
|
|
15
28
|
} else {
|
|
16
29
|
el.style.padding = String(value);
|
|
17
30
|
}
|
|
18
31
|
};
|
|
32
|
+
|
|
33
|
+
// Directional padding handlers for .paddingTop(8), .paddingBottom(8), etc.
|
|
34
|
+
export const paddingTopHandler: ApplicatorHandler = (el, value) => {
|
|
35
|
+
const v = getNumericValue(value);
|
|
36
|
+
if (v !== null) el.style.paddingTop = `${v}px`;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const paddingBottomHandler: ApplicatorHandler = (el, value) => {
|
|
40
|
+
const v = getNumericValue(value);
|
|
41
|
+
if (v !== null) el.style.paddingBottom = `${v}px`;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const paddingLeftHandler: ApplicatorHandler = (el, value) => {
|
|
45
|
+
const v = getNumericValue(value);
|
|
46
|
+
if (v !== null) el.style.paddingLeft = `${v}px`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const paddingRightHandler: ApplicatorHandler = (el, value) => {
|
|
50
|
+
const v = getNumericValue(value);
|
|
51
|
+
if (v !== null) el.style.paddingRight = `${v}px`;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const paddingHorizontalHandler: ApplicatorHandler = (el, value) => {
|
|
55
|
+
const v = getNumericValue(value);
|
|
56
|
+
if (v !== null) {
|
|
57
|
+
el.style.paddingLeft = `${v}px`;
|
|
58
|
+
el.style.paddingRight = `${v}px`;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const paddingVerticalHandler: ApplicatorHandler = (el, value) => {
|
|
63
|
+
const v = getNumericValue(value);
|
|
64
|
+
if (v !== null) {
|
|
65
|
+
el.style.paddingTop = `${v}px`;
|
|
66
|
+
el.style.paddingBottom = `${v}px`;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - "wrap" / "auto": fit content
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import type { ApplicatorHandler } from "./
|
|
14
|
+
import type { ApplicatorHandler } from "./types.js";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Parse a size value and return CSS-compatible string.
|
|
@@ -135,12 +135,22 @@ export const sizeHandlers: Record<string, ApplicatorHandler> = {
|
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
|
|
138
|
-
// Fill max width -
|
|
138
|
+
// Fill max width - stretch to fill parent width
|
|
139
139
|
fillMaxWidth: (el, value) => {
|
|
140
140
|
if (value === false) return;
|
|
141
|
-
// Value can be a fraction (0-1) or boolean
|
|
142
141
|
const fraction = typeof value === "number" ? value : 1;
|
|
143
|
-
|
|
142
|
+
if (fraction === 1) {
|
|
143
|
+
// For 100% width: use align-self stretch in Column (cross-axis)
|
|
144
|
+
// and width 100% as fallback for Row and other contexts
|
|
145
|
+
el.style.alignSelf = "stretch";
|
|
146
|
+
el.style.width = "100%";
|
|
147
|
+
el.style.minWidth = "0"; // Prevent flex item from overflowing
|
|
148
|
+
} else {
|
|
149
|
+
// For fractional width, use percentage
|
|
150
|
+
el.style.width = `${fraction * 100}%`;
|
|
151
|
+
}
|
|
152
|
+
// For grid containers (Stack)
|
|
153
|
+
el.style.justifySelf = "stretch";
|
|
144
154
|
},
|
|
145
155
|
|
|
146
156
|
// Fill max height - shorthand for height: 100%
|
|
@@ -23,10 +23,11 @@ export const avatarHandler: ComponentHandler = {
|
|
|
23
23
|
},
|
|
24
24
|
|
|
25
25
|
applyProps(el: HTMLElement, props: Record<string, any>): void {
|
|
26
|
-
// Image source
|
|
27
|
-
|
|
26
|
+
// Image source - support named arg with .0 suffix, positional arg, or plain name
|
|
27
|
+
const src = props["src.0"] || props["0"] || props.src || props.source;
|
|
28
|
+
if (src !== undefined) {
|
|
28
29
|
const img = document.createElement("img");
|
|
29
|
-
img.src = String(
|
|
30
|
+
img.src = String(src);
|
|
30
31
|
img.style.width = "100%";
|
|
31
32
|
img.style.height = "100%";
|
|
32
33
|
img.style.objectFit = "cover";
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Button Component
|
|
3
|
+
*
|
|
4
|
+
* Renders as a flex container. Children align to start by default (matching iOS).
|
|
5
|
+
* Use .horizontalAlignment("center") to center content.
|
|
6
|
+
* Reset default HTML button styles for cross-platform consistency.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
9
|
import type { ComponentHandler } from "./index.js";
|
|
@@ -7,6 +11,19 @@ import type { ComponentHandler } from "./index.js";
|
|
|
7
11
|
export const buttonHandler: ComponentHandler = {
|
|
8
12
|
create(): HTMLElement {
|
|
9
13
|
const el = document.createElement("button");
|
|
14
|
+
// Reset default button styles for cross-platform consistency
|
|
15
|
+
el.style.border = "none";
|
|
16
|
+
el.style.background = "none";
|
|
17
|
+
el.style.padding = "0";
|
|
18
|
+
el.style.margin = "0";
|
|
19
|
+
el.style.font = "inherit";
|
|
20
|
+
el.style.color = "inherit";
|
|
21
|
+
el.style.cursor = "pointer";
|
|
22
|
+
// Make it a flex container - align to start by default (matching iOS)
|
|
23
|
+
// Use .horizontalAlignment("center") to center content
|
|
24
|
+
el.style.display = "flex";
|
|
25
|
+
el.style.flexDirection = "column";
|
|
26
|
+
el.style.alignItems = "flex-start";
|
|
10
27
|
el.dataset.hypenType = "button";
|
|
11
28
|
return el;
|
|
12
29
|
},
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Column Component - Vertical Stack
|
|
3
|
+
*
|
|
4
|
+
* Children wrap to content by default (matching Android/iOS behavior).
|
|
5
|
+
* Column stretches to fill parent's width so children with fillMaxWidth work.
|
|
6
|
+
* Use .fillMaxWidth() on children or .horizontalAlignment("stretch") to stretch.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
9
|
import type { ComponentHandler } from "./index.js";
|
|
@@ -9,6 +13,11 @@ export const columnHandler: ComponentHandler = {
|
|
|
9
13
|
const el = document.createElement("div");
|
|
10
14
|
el.style.display = "flex";
|
|
11
15
|
el.style.flexDirection = "column";
|
|
16
|
+
// Wrap children to content by default (match iOS/Android behavior)
|
|
17
|
+
el.style.alignItems = "flex-start";
|
|
18
|
+
// Stretch to fill parent's width so children with fillMaxWidth can reference it
|
|
19
|
+
// This matches iOS/Android where Column expands to accommodate children that want to stretch
|
|
20
|
+
el.style.alignSelf = "stretch";
|
|
12
21
|
el.dataset.hypenType = "column";
|
|
13
22
|
return el;
|
|
14
23
|
},
|
|
@@ -7,6 +7,8 @@ import type { ComponentHandler } from "./index.js";
|
|
|
7
7
|
export const containerHandler: ComponentHandler = {
|
|
8
8
|
create(): HTMLElement {
|
|
9
9
|
const el = document.createElement("div");
|
|
10
|
+
// Simple block container - wraps to content by default
|
|
11
|
+
// Use .fillMaxWidth(true) to stretch
|
|
10
12
|
el.dataset.hypenType = "container";
|
|
11
13
|
return el;
|
|
12
14
|
},
|
|
@@ -8,6 +8,9 @@ export const listHandler: ComponentHandler = {
|
|
|
8
8
|
create(): HTMLElement {
|
|
9
9
|
const el = document.createElement("div");
|
|
10
10
|
el.style.display = "flex";
|
|
11
|
+
el.style.flexDirection = "column"; // Default to vertical (like Android)
|
|
12
|
+
// Default to flex-start to match Android/iOS behavior
|
|
13
|
+
el.style.alignItems = "flex-start";
|
|
11
14
|
el.style.overflow = "auto";
|
|
12
15
|
el.dataset.hypenType = "list";
|
|
13
16
|
return el;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Row Component - Horizontal Stack
|
|
3
|
+
* Children keep their intrinsic size by default (matching iOS/Android behavior).
|
|
4
|
+
* Use .weight(1) on children to make them expand equally.
|
|
3
5
|
*/
|
|
4
6
|
|
|
5
7
|
import type { ComponentHandler } from "./index.js";
|
|
@@ -9,6 +11,8 @@ export const rowHandler: ComponentHandler = {
|
|
|
9
11
|
const el = document.createElement("div");
|
|
10
12
|
el.style.display = "flex";
|
|
11
13
|
el.style.flexDirection = "row";
|
|
14
|
+
// Wrap to content by default (match iOS/Android behavior)
|
|
15
|
+
el.style.alignItems = "flex-start";
|
|
12
16
|
el.dataset.hypenType = "row";
|
|
13
17
|
return el;
|
|
14
18
|
},
|
|
@@ -4,29 +4,41 @@
|
|
|
4
4
|
|
|
5
5
|
import type { ComponentHandler } from "./index.js";
|
|
6
6
|
|
|
7
|
+
// Inject global styles once
|
|
8
|
+
let stackStylesInjected = false;
|
|
9
|
+
function ensureStackStyles(): void {
|
|
10
|
+
if (stackStylesInjected) return;
|
|
11
|
+
stackStylesInjected = true;
|
|
12
|
+
|
|
13
|
+
const style = document.createElement("style");
|
|
14
|
+
style.id = "hypen-stack-styles";
|
|
15
|
+
style.textContent = `
|
|
16
|
+
[data-hypen-type="stack"] {
|
|
17
|
+
position: relative;
|
|
18
|
+
display: grid;
|
|
19
|
+
grid-template-areas: "stack";
|
|
20
|
+
/* Default alignment: top-left (matching iOS/Android ZStack default) */
|
|
21
|
+
justify-items: start;
|
|
22
|
+
align-items: start;
|
|
23
|
+
/* Ensure Stack participates properly in flex layouts (Row/Column) */
|
|
24
|
+
min-width: 0;
|
|
25
|
+
min-height: 0;
|
|
26
|
+
}
|
|
27
|
+
[data-hypen-type="stack"] > * {
|
|
28
|
+
grid-area: stack;
|
|
29
|
+
/* Don't set justify-self/align-self here - let parent's justify-items/align-items control */
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
document.head.appendChild(style);
|
|
33
|
+
}
|
|
34
|
+
|
|
7
35
|
export const stackHandler: ComponentHandler = {
|
|
8
36
|
create(): HTMLElement {
|
|
37
|
+
ensureStackStyles();
|
|
38
|
+
|
|
9
39
|
const el = document.createElement("div");
|
|
10
|
-
el.style.position = "relative";
|
|
11
|
-
el.style.display = "flex";
|
|
12
40
|
el.dataset.hypenType = "stack";
|
|
13
|
-
|
|
14
|
-
// Children will be absolutely positioned
|
|
15
|
-
const style = document.createElement("style");
|
|
16
|
-
style.textContent = `
|
|
17
|
-
[data-hypen-type="stack"] > * {
|
|
18
|
-
position: absolute;
|
|
19
|
-
top: 0;
|
|
20
|
-
left: 0;
|
|
21
|
-
width: 100%;
|
|
22
|
-
height: 100%;
|
|
23
|
-
}
|
|
24
|
-
[data-hypen-type="stack"] > *:first-child {
|
|
25
|
-
position: relative;
|
|
26
|
-
}
|
|
27
|
-
`;
|
|
28
|
-
el.appendChild(style);
|
|
29
|
-
|
|
41
|
+
|
|
30
42
|
return el;
|
|
31
43
|
},
|
|
32
44
|
};
|