@hedystia/view 2.1.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 (102) hide show
  1. package/dist/constants.cjs +13 -0
  2. package/dist/constants.cjs.map +1 -0
  3. package/dist/constants.mjs +13 -0
  4. package/dist/constants.mjs.map +1 -0
  5. package/dist/context/context.cjs +51 -0
  6. package/dist/context/context.cjs.map +1 -0
  7. package/dist/context/context.d.cts +25 -0
  8. package/dist/context/context.d.mts +25 -0
  9. package/dist/context/context.mjs +50 -0
  10. package/dist/context/context.mjs.map +1 -0
  11. package/dist/fetch/resource.cjs +89 -0
  12. package/dist/fetch/resource.cjs.map +1 -0
  13. package/dist/fetch/resource.d.cts +14 -0
  14. package/dist/fetch/resource.d.mts +14 -0
  15. package/dist/fetch/resource.mjs +88 -0
  16. package/dist/fetch/resource.mjs.map +1 -0
  17. package/dist/index.cjs +58 -0
  18. package/dist/index.d.cts +15 -0
  19. package/dist/index.d.mts +15 -0
  20. package/dist/index.mjs +14 -0
  21. package/dist/jsx/element.cjs +201 -0
  22. package/dist/jsx/element.cjs.map +1 -0
  23. package/dist/jsx/element.d.cts +48 -0
  24. package/dist/jsx/element.d.mts +48 -0
  25. package/dist/jsx/element.mjs +199 -0
  26. package/dist/jsx/element.mjs.map +1 -0
  27. package/dist/jsx-dev-runtime.cjs +40 -0
  28. package/dist/jsx-dev-runtime.cjs.map +1 -0
  29. package/dist/jsx-dev-runtime.d.cts +21 -0
  30. package/dist/jsx-dev-runtime.d.mts +21 -0
  31. package/dist/jsx-dev-runtime.mjs +36 -0
  32. package/dist/jsx-dev-runtime.mjs.map +1 -0
  33. package/dist/jsx-runtime.cjs +5 -0
  34. package/dist/jsx-runtime.d.cts +3 -0
  35. package/dist/jsx-runtime.d.mts +3 -0
  36. package/dist/jsx-runtime.mjs +2 -0
  37. package/dist/jsx.d.cts +942 -0
  38. package/dist/jsx.d.mts +942 -0
  39. package/dist/lifecycle/hooks.cjs +56 -0
  40. package/dist/lifecycle/hooks.cjs.map +1 -0
  41. package/dist/lifecycle/hooks.d.cts +37 -0
  42. package/dist/lifecycle/hooks.d.mts +37 -0
  43. package/dist/lifecycle/hooks.mjs +54 -0
  44. package/dist/lifecycle/hooks.mjs.map +1 -0
  45. package/dist/render/engine.cjs +52 -0
  46. package/dist/render/engine.cjs.map +1 -0
  47. package/dist/render/engine.d.cts +31 -0
  48. package/dist/render/engine.d.mts +31 -0
  49. package/dist/render/engine.mjs +51 -0
  50. package/dist/render/engine.mjs.map +1 -0
  51. package/dist/render/flow.cjs +286 -0
  52. package/dist/render/flow.cjs.map +1 -0
  53. package/dist/render/flow.d.cts +64 -0
  54. package/dist/render/flow.d.mts +64 -0
  55. package/dist/render/flow.mjs +279 -0
  56. package/dist/render/flow.mjs.map +1 -0
  57. package/dist/scheduler/scheduler.cjs +61 -0
  58. package/dist/scheduler/scheduler.cjs.map +1 -0
  59. package/dist/scheduler/scheduler.d.cts +31 -0
  60. package/dist/scheduler/scheduler.d.mts +31 -0
  61. package/dist/scheduler/scheduler.mjs +59 -0
  62. package/dist/scheduler/scheduler.mjs.map +1 -0
  63. package/dist/signal/signal.cjs +387 -0
  64. package/dist/signal/signal.cjs.map +1 -0
  65. package/dist/signal/signal.d.cts +44 -0
  66. package/dist/signal/signal.d.mts +44 -0
  67. package/dist/signal/signal.mjs +370 -0
  68. package/dist/signal/signal.mjs.map +1 -0
  69. package/dist/store/index.cjs +1 -0
  70. package/dist/store/index.mjs +2 -0
  71. package/dist/store/store.cjs +94 -0
  72. package/dist/store/store.cjs.map +1 -0
  73. package/dist/store/store.d.cts +22 -0
  74. package/dist/store/store.d.mts +22 -0
  75. package/dist/store/store.mjs +91 -0
  76. package/dist/store/store.mjs.map +1 -0
  77. package/dist/style/computed.cjs +65 -0
  78. package/dist/style/computed.cjs.map +1 -0
  79. package/dist/style/computed.d.cts +18 -0
  80. package/dist/style/computed.d.mts +18 -0
  81. package/dist/style/computed.mjs +63 -0
  82. package/dist/style/computed.mjs.map +1 -0
  83. package/dist/text/text.cjs +74 -0
  84. package/dist/text/text.cjs.map +1 -0
  85. package/dist/text/text.d.cts +31 -0
  86. package/dist/text/text.d.mts +31 -0
  87. package/dist/text/text.mjs +72 -0
  88. package/dist/text/text.mjs.map +1 -0
  89. package/dist/types.d.cts +185 -0
  90. package/dist/types.d.mts +185 -0
  91. package/dist/utils/index.cjs +34 -0
  92. package/dist/utils/index.cjs.map +1 -0
  93. package/dist/utils/index.mjs +33 -0
  94. package/dist/utils/index.mjs.map +1 -0
  95. package/dist/watch/watcher.cjs +71 -0
  96. package/dist/watch/watcher.cjs.map +1 -0
  97. package/dist/watch/watcher.d.cts +17 -0
  98. package/dist/watch/watcher.d.mts +17 -0
  99. package/dist/watch/watcher.mjs +70 -0
  100. package/dist/watch/watcher.mjs.map +1 -0
  101. package/package.json +34 -0
  102. package/readme.md +395 -0
@@ -0,0 +1,65 @@
1
+ const require_index = require("../utils/index.cjs");
2
+ const require_signal = require("../signal/signal.cjs");
3
+ //#region src/style/computed.ts
4
+ /**
5
+ * Computed style engine for @hedystia/view
6
+ *
7
+ * Provides reactive style computation and merging.
8
+ */
9
+ /**
10
+ * Create a reusable computed style
11
+ */
12
+ function style(base) {
13
+ if (typeof base === "function") return require_signal.memo(() => {
14
+ return normalizeStyle(base());
15
+ });
16
+ const normalized = normalizeStyle(base);
17
+ return () => normalized;
18
+ }
19
+ /**
20
+ * Merge multiple style objects
21
+ */
22
+ function merge(...styles) {
23
+ let result = {};
24
+ for (let i = 0; i < styles.length; i++) {
25
+ const style = styles[i];
26
+ if (style !== void 0 && style !== null) result = require_index.mergeStyles(result, style);
27
+ }
28
+ return result;
29
+ }
30
+ /** @internal */
31
+ function normalizeStyle(style) {
32
+ const result = {};
33
+ for (const key in style) {
34
+ if (!Object.hasOwn(style, key)) continue;
35
+ const value = style[key];
36
+ if (typeof value === "function") result[key] = value();
37
+ else if (value !== void 0 && value !== null) result[key] = value;
38
+ }
39
+ return result;
40
+ }
41
+ /**
42
+ * Convert a style object to a CSS string
43
+ */
44
+ function toCssString(style) {
45
+ let result = "";
46
+ for (const key in style) {
47
+ if (!Object.hasOwn(style, key)) continue;
48
+ const value = style[key];
49
+ if (value !== void 0 && value !== null) {
50
+ const cssKey = camelToKebab(key);
51
+ result += `${cssKey}: ${value}; `;
52
+ }
53
+ }
54
+ return result.trim();
55
+ }
56
+ /** @internal */
57
+ function camelToKebab(str) {
58
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
59
+ }
60
+ //#endregion
61
+ exports.merge = merge;
62
+ exports.style = style;
63
+ exports.toCssString = toCssString;
64
+
65
+ //# sourceMappingURL=computed.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed.cjs","names":["memo","mergeStyles"],"sources":["../../src/style/computed.ts"],"sourcesContent":["/**\n * Computed style engine for @hedystia/view\n *\n * Provides reactive style computation and merging.\n */\n\nimport { memo } from \"../signal\";\nimport type { Accessor, StyleProps } from \"../types\";\nimport { mergeStyles } from \"../utils\";\n\n/**\n * Create a reusable computed style\n */\nexport function style<T extends StyleProps>(base: T | Accessor<T>): Accessor<T> {\n if (typeof base === \"function\") {\n return memo(() => {\n const result = base();\n return normalizeStyle(result) as T;\n });\n }\n const normalized = normalizeStyle(base);\n return () => normalized as T;\n}\n\n/**\n * Merge multiple style objects\n */\nexport function merge(...styles: (StyleProps | undefined | null)[]): StyleProps {\n let result: StyleProps = {};\n for (let i = 0; i < styles.length; i++) {\n const style = styles[i];\n if (style !== undefined && style !== null) {\n result = mergeStyles(result, style);\n }\n }\n return result;\n}\n\n/** @internal */\nfunction normalizeStyle(style: StyleProps): StyleProps {\n const result: StyleProps = {};\n for (const key in style) {\n if (!Object.hasOwn(style, key)) {\n continue;\n }\n const value = style[key];\n if (typeof value === \"function\") {\n result[key] = (value as () => string | number)();\n } else if (value !== undefined && value !== null) {\n result[key] = value as string | number;\n }\n }\n return result;\n}\n\n/**\n * Convert a style object to a CSS string\n */\nexport function toCssString(style: StyleProps): string {\n let result = \"\";\n for (const key in style) {\n if (!Object.hasOwn(style, key)) {\n continue;\n }\n const value = style[key];\n if (value !== undefined && value !== null) {\n const cssKey = camelToKebab(key);\n result += `${cssKey}: ${value}; `;\n }\n }\n return result.trim();\n}\n\n/** @internal */\nfunction camelToKebab(str: string): string {\n return str.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,MAA4B,MAAoC;AAC9E,KAAI,OAAO,SAAS,WAClB,QAAOA,eAAAA,WAAW;AAEhB,SAAO,eADQ,MAAM,CACQ;GAC7B;CAEJ,MAAM,aAAa,eAAe,KAAK;AACvC,cAAa;;;;;AAMf,SAAgB,MAAM,GAAG,QAAuD;CAC9E,IAAI,SAAqB,EAAE;AAC3B,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,OAAO;AACrB,MAAI,UAAU,KAAA,KAAa,UAAU,KACnC,UAASC,cAAAA,YAAY,QAAQ,MAAM;;AAGvC,QAAO;;;AAIT,SAAS,eAAe,OAA+B;CACrD,MAAM,SAAqB,EAAE;AAC7B,MAAK,MAAM,OAAO,OAAO;AACvB,MAAI,CAAC,OAAO,OAAO,OAAO,IAAI,CAC5B;EAEF,MAAM,QAAQ,MAAM;AACpB,MAAI,OAAO,UAAU,WACnB,QAAO,OAAQ,OAAiC;WACvC,UAAU,KAAA,KAAa,UAAU,KAC1C,QAAO,OAAO;;AAGlB,QAAO;;;;;AAMT,SAAgB,YAAY,OAA2B;CACrD,IAAI,SAAS;AACb,MAAK,MAAM,OAAO,OAAO;AACvB,MAAI,CAAC,OAAO,OAAO,OAAO,IAAI,CAC5B;EAEF,MAAM,QAAQ,MAAM;AACpB,MAAI,UAAU,KAAA,KAAa,UAAU,MAAM;GACzC,MAAM,SAAS,aAAa,IAAI;AAChC,aAAU,GAAG,OAAO,IAAI,MAAM;;;AAGlC,QAAO,OAAO,MAAM;;;AAItB,SAAS,aAAa,KAAqB;AACzC,QAAO,IAAI,QAAQ,mBAAmB,QAAQ,CAAC,aAAa"}
@@ -0,0 +1,18 @@
1
+ import { Accessor, StyleProps } from "../types.cjs";
2
+
3
+ //#region src/style/computed.d.ts
4
+ /**
5
+ * Create a reusable computed style
6
+ */
7
+ declare function style<T extends StyleProps>(base: T | Accessor<T>): Accessor<T>;
8
+ /**
9
+ * Merge multiple style objects
10
+ */
11
+ declare function merge(...styles: (StyleProps | undefined | null)[]): StyleProps;
12
+ /**
13
+ * Convert a style object to a CSS string
14
+ */
15
+ declare function toCssString(style: StyleProps): string;
16
+ //#endregion
17
+ export { merge, style, toCssString };
18
+ //# sourceMappingURL=computed.d.cts.map
@@ -0,0 +1,18 @@
1
+ import { Accessor, StyleProps } from "../types.mjs";
2
+
3
+ //#region src/style/computed.d.ts
4
+ /**
5
+ * Create a reusable computed style
6
+ */
7
+ declare function style<T extends StyleProps>(base: T | Accessor<T>): Accessor<T>;
8
+ /**
9
+ * Merge multiple style objects
10
+ */
11
+ declare function merge(...styles: (StyleProps | undefined | null)[]): StyleProps;
12
+ /**
13
+ * Convert a style object to a CSS string
14
+ */
15
+ declare function toCssString(style: StyleProps): string;
16
+ //#endregion
17
+ export { merge, style, toCssString };
18
+ //# sourceMappingURL=computed.d.mts.map
@@ -0,0 +1,63 @@
1
+ import { mergeStyles } from "../utils/index.mjs";
2
+ import { memo } from "../signal/signal.mjs";
3
+ //#region src/style/computed.ts
4
+ /**
5
+ * Computed style engine for @hedystia/view
6
+ *
7
+ * Provides reactive style computation and merging.
8
+ */
9
+ /**
10
+ * Create a reusable computed style
11
+ */
12
+ function style(base) {
13
+ if (typeof base === "function") return memo(() => {
14
+ return normalizeStyle(base());
15
+ });
16
+ const normalized = normalizeStyle(base);
17
+ return () => normalized;
18
+ }
19
+ /**
20
+ * Merge multiple style objects
21
+ */
22
+ function merge(...styles) {
23
+ let result = {};
24
+ for (let i = 0; i < styles.length; i++) {
25
+ const style = styles[i];
26
+ if (style !== void 0 && style !== null) result = mergeStyles(result, style);
27
+ }
28
+ return result;
29
+ }
30
+ /** @internal */
31
+ function normalizeStyle(style) {
32
+ const result = {};
33
+ for (const key in style) {
34
+ if (!Object.hasOwn(style, key)) continue;
35
+ const value = style[key];
36
+ if (typeof value === "function") result[key] = value();
37
+ else if (value !== void 0 && value !== null) result[key] = value;
38
+ }
39
+ return result;
40
+ }
41
+ /**
42
+ * Convert a style object to a CSS string
43
+ */
44
+ function toCssString(style) {
45
+ let result = "";
46
+ for (const key in style) {
47
+ if (!Object.hasOwn(style, key)) continue;
48
+ const value = style[key];
49
+ if (value !== void 0 && value !== null) {
50
+ const cssKey = camelToKebab(key);
51
+ result += `${cssKey}: ${value}; `;
52
+ }
53
+ }
54
+ return result.trim();
55
+ }
56
+ /** @internal */
57
+ function camelToKebab(str) {
58
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
59
+ }
60
+ //#endregion
61
+ export { merge, style, toCssString };
62
+
63
+ //# sourceMappingURL=computed.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed.mjs","names":[],"sources":["../../src/style/computed.ts"],"sourcesContent":["/**\n * Computed style engine for @hedystia/view\n *\n * Provides reactive style computation and merging.\n */\n\nimport { memo } from \"../signal\";\nimport type { Accessor, StyleProps } from \"../types\";\nimport { mergeStyles } from \"../utils\";\n\n/**\n * Create a reusable computed style\n */\nexport function style<T extends StyleProps>(base: T | Accessor<T>): Accessor<T> {\n if (typeof base === \"function\") {\n return memo(() => {\n const result = base();\n return normalizeStyle(result) as T;\n });\n }\n const normalized = normalizeStyle(base);\n return () => normalized as T;\n}\n\n/**\n * Merge multiple style objects\n */\nexport function merge(...styles: (StyleProps | undefined | null)[]): StyleProps {\n let result: StyleProps = {};\n for (let i = 0; i < styles.length; i++) {\n const style = styles[i];\n if (style !== undefined && style !== null) {\n result = mergeStyles(result, style);\n }\n }\n return result;\n}\n\n/** @internal */\nfunction normalizeStyle(style: StyleProps): StyleProps {\n const result: StyleProps = {};\n for (const key in style) {\n if (!Object.hasOwn(style, key)) {\n continue;\n }\n const value = style[key];\n if (typeof value === \"function\") {\n result[key] = (value as () => string | number)();\n } else if (value !== undefined && value !== null) {\n result[key] = value as string | number;\n }\n }\n return result;\n}\n\n/**\n * Convert a style object to a CSS string\n */\nexport function toCssString(style: StyleProps): string {\n let result = \"\";\n for (const key in style) {\n if (!Object.hasOwn(style, key)) {\n continue;\n }\n const value = style[key];\n if (value !== undefined && value !== null) {\n const cssKey = camelToKebab(key);\n result += `${cssKey}: ${value}; `;\n }\n }\n return result.trim();\n}\n\n/** @internal */\nfunction camelToKebab(str: string): string {\n return str.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,MAA4B,MAAoC;AAC9E,KAAI,OAAO,SAAS,WAClB,QAAO,WAAW;AAEhB,SAAO,eADQ,MAAM,CACQ;GAC7B;CAEJ,MAAM,aAAa,eAAe,KAAK;AACvC,cAAa;;;;;AAMf,SAAgB,MAAM,GAAG,QAAuD;CAC9E,IAAI,SAAqB,EAAE;AAC3B,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,OAAO;AACrB,MAAI,UAAU,KAAA,KAAa,UAAU,KACnC,UAAS,YAAY,QAAQ,MAAM;;AAGvC,QAAO;;;AAIT,SAAS,eAAe,OAA+B;CACrD,MAAM,SAAqB,EAAE;AAC7B,MAAK,MAAM,OAAO,OAAO;AACvB,MAAI,CAAC,OAAO,OAAO,OAAO,IAAI,CAC5B;EAEF,MAAM,QAAQ,MAAM;AACpB,MAAI,OAAO,UAAU,WACnB,QAAO,OAAQ,OAAiC;WACvC,UAAU,KAAA,KAAa,UAAU,KAC1C,QAAO,OAAO;;AAGlB,QAAO;;;;;AAMT,SAAgB,YAAY,OAA2B;CACrD,IAAI,SAAS;AACb,MAAK,MAAM,OAAO,OAAO;AACvB,MAAI,CAAC,OAAO,OAAO,OAAO,IAAI,CAC5B;EAEF,MAAM,QAAQ,MAAM;AACpB,MAAI,UAAU,KAAA,KAAa,UAAU,MAAM;GACzC,MAAM,SAAS,aAAa,IAAI;AAChC,aAAU,GAAG,OAAO,IAAI,MAAM;;;AAGlC,QAAO,OAAO,MAAM;;;AAItB,SAAS,aAAa,KAAqB;AACzC,QAAO,IAAI,QAAQ,mBAAmB,QAAQ,CAAC,aAAa"}
@@ -0,0 +1,74 @@
1
+ const require_signal = require("../signal/signal.cjs");
2
+ //#region src/text/text.ts
3
+ /**
4
+ * Provides prepare/layout pipeline for reactive text measurement.
5
+ */
6
+ /**
7
+ * Prepare text for layout measurement
8
+ */
9
+ function prepare(text, font) {
10
+ if (typeof window === "undefined") return {};
11
+ const ctx = document.createElement("canvas").getContext("2d");
12
+ if (!ctx) return {};
13
+ ctx.font = font;
14
+ const metrics = ctx.measureText(text);
15
+ return {
16
+ _text: text,
17
+ _font: font,
18
+ _width: metrics.width,
19
+ _height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent,
20
+ [Symbol.for("prepared")]: true
21
+ };
22
+ }
23
+ /**
24
+ * Layout prepared text at a given width
25
+ */
26
+ function layout(prepared, maxWidth, lineHeight) {
27
+ const internal = prepared;
28
+ if (!internal._text) return {
29
+ lineCount: 0,
30
+ height: 0
31
+ };
32
+ const text = internal._text;
33
+ const font = internal._font;
34
+ if (typeof window === "undefined") return {
35
+ lineCount: 1,
36
+ height: lineHeight
37
+ };
38
+ const ctx = document.createElement("canvas").getContext("2d");
39
+ if (!ctx) return {
40
+ lineCount: 1,
41
+ height: lineHeight
42
+ };
43
+ ctx.font = font;
44
+ const words = text.split(" ");
45
+ let lines = 0;
46
+ let currentLineWidth = 0;
47
+ for (let i = 0; i < words.length; i++) {
48
+ const word = words[i];
49
+ const wordWidth = ctx.measureText(word).width;
50
+ if (currentLineWidth + wordWidth > maxWidth) {
51
+ lines++;
52
+ currentLineWidth = wordWidth;
53
+ } else currentLineWidth += wordWidth + ctx.measureText(" ").width;
54
+ }
55
+ if (currentLineWidth > 0) lines++;
56
+ return {
57
+ lineCount: Math.max(1, lines),
58
+ height: Math.max(1, lines) * lineHeight
59
+ };
60
+ }
61
+ /**
62
+ * Create a reactive layout computation
63
+ */
64
+ function reactiveLayout(source, getPrepared, maxWidth, lineHeight) {
65
+ return require_signal.memo(() => {
66
+ return layout(getPrepared(source()), maxWidth, lineHeight);
67
+ });
68
+ }
69
+ //#endregion
70
+ exports.layout = layout;
71
+ exports.prepare = prepare;
72
+ exports.reactiveLayout = reactiveLayout;
73
+
74
+ //# sourceMappingURL=text.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.cjs","names":["memo"],"sources":["../../src/text/text.ts"],"sourcesContent":["/**\n * Provides prepare/layout pipeline for reactive text measurement.\n */\n\nimport { memo } from \"../signal\";\nimport type { Accessor } from \"../types\";\n\n/**\n * Prepared text handle\n */\nexport interface PreparedText {\n readonly [key: symbol]: true;\n}\n\n/**\n * Layout result\n */\nexport interface LayoutResult {\n lineCount: number;\n height: number;\n}\n\n/**\n * Prepare text for layout measurement\n */\nexport function prepare(text: string, font: string): PreparedText {\n if (typeof window === \"undefined\") {\n return {} as PreparedText;\n }\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n return {} as PreparedText;\n }\n\n ctx.font = font;\n const metrics = ctx.measureText(text);\n const width = metrics.width;\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n return {\n _text: text,\n _font: font,\n _width: width,\n _height: height,\n [Symbol.for(\"prepared\")]: true,\n } as PreparedText;\n}\n\n/**\n * Layout prepared text at a given width\n */\nexport function layout(prepared: PreparedText, maxWidth: number, lineHeight: number): LayoutResult {\n const internal = prepared as any;\n if (!internal._text) {\n return { lineCount: 0, height: 0 };\n }\n\n const text = internal._text as string;\n const font = internal._font as string;\n\n if (typeof window === \"undefined\") {\n return { lineCount: 1, height: lineHeight };\n }\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n return { lineCount: 1, height: lineHeight };\n }\n\n ctx.font = font;\n\n const words = text.split(\" \");\n let lines = 0;\n let currentLineWidth = 0;\n\n for (let i = 0; i < words.length; i++) {\n const word = words[i]!;\n const wordWidth = ctx.measureText(word).width;\n\n if (currentLineWidth + wordWidth > maxWidth) {\n lines++;\n currentLineWidth = wordWidth;\n } else {\n currentLineWidth += wordWidth + ctx.measureText(\" \").width;\n }\n }\n\n if (currentLineWidth > 0) {\n lines++;\n }\n\n return {\n lineCount: Math.max(1, lines),\n height: Math.max(1, lines) * lineHeight,\n };\n}\n\n/**\n * Create a reactive layout computation\n */\nexport function reactiveLayout<T extends object>(\n source: Accessor<T>,\n getPrepared: (item: T) => PreparedText,\n maxWidth: number,\n lineHeight: number,\n): Accessor<LayoutResult> {\n const computed = memo(() => {\n const item = source();\n const prepared = getPrepared(item);\n return layout(prepared, maxWidth, lineHeight);\n });\n return computed as unknown as Accessor<LayoutResult>;\n}\n"],"mappings":";;;;;;;;AAyBA,SAAgB,QAAQ,MAAc,MAA4B;AAChE,KAAI,OAAO,WAAW,YACpB,QAAO,EAAE;CAIX,MAAM,MADS,SAAS,cAAc,SAAS,CAC5B,WAAW,KAAK;AACnC,KAAI,CAAC,IACH,QAAO,EAAE;AAGX,KAAI,OAAO;CACX,MAAM,UAAU,IAAI,YAAY,KAAK;AAIrC,QAAO;EACL,OAAO;EACP,OAAO;EACP,QANY,QAAQ;EAOpB,SANa,QAAQ,0BAA0B,QAAQ;GAOtD,OAAO,IAAI,WAAW,GAAG;EAC3B;;;;;AAMH,SAAgB,OAAO,UAAwB,UAAkB,YAAkC;CACjG,MAAM,WAAW;AACjB,KAAI,CAAC,SAAS,MACZ,QAAO;EAAE,WAAW;EAAG,QAAQ;EAAG;CAGpC,MAAM,OAAO,SAAS;CACtB,MAAM,OAAO,SAAS;AAEtB,KAAI,OAAO,WAAW,YACpB,QAAO;EAAE,WAAW;EAAG,QAAQ;EAAY;CAI7C,MAAM,MADS,SAAS,cAAc,SAAS,CAC5B,WAAW,KAAK;AACnC,KAAI,CAAC,IACH,QAAO;EAAE,WAAW;EAAG,QAAQ;EAAY;AAG7C,KAAI,OAAO;CAEX,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,IAAI,QAAQ;CACZ,IAAI,mBAAmB;AAEvB,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,OAAO,MAAM;EACnB,MAAM,YAAY,IAAI,YAAY,KAAK,CAAC;AAExC,MAAI,mBAAmB,YAAY,UAAU;AAC3C;AACA,sBAAmB;QAEnB,qBAAoB,YAAY,IAAI,YAAY,IAAI,CAAC;;AAIzD,KAAI,mBAAmB,EACrB;AAGF,QAAO;EACL,WAAW,KAAK,IAAI,GAAG,MAAM;EAC7B,QAAQ,KAAK,IAAI,GAAG,MAAM,GAAG;EAC9B;;;;;AAMH,SAAgB,eACd,QACA,aACA,UACA,YACwB;AAMxB,QALiBA,eAAAA,WAAW;AAG1B,SAAO,OADU,YADJ,QAAQ,CACa,EACV,UAAU,WAAW;GAC7C"}
@@ -0,0 +1,31 @@
1
+ import { Accessor } from "../types.cjs";
2
+
3
+ //#region src/text/text.d.ts
4
+ /**
5
+ * Prepared text handle
6
+ */
7
+ interface PreparedText {
8
+ readonly [key: symbol]: true;
9
+ }
10
+ /**
11
+ * Layout result
12
+ */
13
+ interface LayoutResult {
14
+ lineCount: number;
15
+ height: number;
16
+ }
17
+ /**
18
+ * Prepare text for layout measurement
19
+ */
20
+ declare function prepare(text: string, font: string): PreparedText;
21
+ /**
22
+ * Layout prepared text at a given width
23
+ */
24
+ declare function layout(prepared: PreparedText, maxWidth: number, lineHeight: number): LayoutResult;
25
+ /**
26
+ * Create a reactive layout computation
27
+ */
28
+ declare function reactiveLayout<T extends object>(source: Accessor<T>, getPrepared: (item: T) => PreparedText, maxWidth: number, lineHeight: number): Accessor<LayoutResult>;
29
+ //#endregion
30
+ export { LayoutResult, PreparedText, layout, prepare, reactiveLayout };
31
+ //# sourceMappingURL=text.d.cts.map
@@ -0,0 +1,31 @@
1
+ import { Accessor } from "../types.mjs";
2
+
3
+ //#region src/text/text.d.ts
4
+ /**
5
+ * Prepared text handle
6
+ */
7
+ interface PreparedText {
8
+ readonly [key: symbol]: true;
9
+ }
10
+ /**
11
+ * Layout result
12
+ */
13
+ interface LayoutResult {
14
+ lineCount: number;
15
+ height: number;
16
+ }
17
+ /**
18
+ * Prepare text for layout measurement
19
+ */
20
+ declare function prepare(text: string, font: string): PreparedText;
21
+ /**
22
+ * Layout prepared text at a given width
23
+ */
24
+ declare function layout(prepared: PreparedText, maxWidth: number, lineHeight: number): LayoutResult;
25
+ /**
26
+ * Create a reactive layout computation
27
+ */
28
+ declare function reactiveLayout<T extends object>(source: Accessor<T>, getPrepared: (item: T) => PreparedText, maxWidth: number, lineHeight: number): Accessor<LayoutResult>;
29
+ //#endregion
30
+ export { LayoutResult, PreparedText, layout, prepare, reactiveLayout };
31
+ //# sourceMappingURL=text.d.mts.map
@@ -0,0 +1,72 @@
1
+ import { memo } from "../signal/signal.mjs";
2
+ //#region src/text/text.ts
3
+ /**
4
+ * Provides prepare/layout pipeline for reactive text measurement.
5
+ */
6
+ /**
7
+ * Prepare text for layout measurement
8
+ */
9
+ function prepare(text, font) {
10
+ if (typeof window === "undefined") return {};
11
+ const ctx = document.createElement("canvas").getContext("2d");
12
+ if (!ctx) return {};
13
+ ctx.font = font;
14
+ const metrics = ctx.measureText(text);
15
+ return {
16
+ _text: text,
17
+ _font: font,
18
+ _width: metrics.width,
19
+ _height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent,
20
+ [Symbol.for("prepared")]: true
21
+ };
22
+ }
23
+ /**
24
+ * Layout prepared text at a given width
25
+ */
26
+ function layout(prepared, maxWidth, lineHeight) {
27
+ const internal = prepared;
28
+ if (!internal._text) return {
29
+ lineCount: 0,
30
+ height: 0
31
+ };
32
+ const text = internal._text;
33
+ const font = internal._font;
34
+ if (typeof window === "undefined") return {
35
+ lineCount: 1,
36
+ height: lineHeight
37
+ };
38
+ const ctx = document.createElement("canvas").getContext("2d");
39
+ if (!ctx) return {
40
+ lineCount: 1,
41
+ height: lineHeight
42
+ };
43
+ ctx.font = font;
44
+ const words = text.split(" ");
45
+ let lines = 0;
46
+ let currentLineWidth = 0;
47
+ for (let i = 0; i < words.length; i++) {
48
+ const word = words[i];
49
+ const wordWidth = ctx.measureText(word).width;
50
+ if (currentLineWidth + wordWidth > maxWidth) {
51
+ lines++;
52
+ currentLineWidth = wordWidth;
53
+ } else currentLineWidth += wordWidth + ctx.measureText(" ").width;
54
+ }
55
+ if (currentLineWidth > 0) lines++;
56
+ return {
57
+ lineCount: Math.max(1, lines),
58
+ height: Math.max(1, lines) * lineHeight
59
+ };
60
+ }
61
+ /**
62
+ * Create a reactive layout computation
63
+ */
64
+ function reactiveLayout(source, getPrepared, maxWidth, lineHeight) {
65
+ return memo(() => {
66
+ return layout(getPrepared(source()), maxWidth, lineHeight);
67
+ });
68
+ }
69
+ //#endregion
70
+ export { layout, prepare, reactiveLayout };
71
+
72
+ //# sourceMappingURL=text.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.mjs","names":[],"sources":["../../src/text/text.ts"],"sourcesContent":["/**\n * Provides prepare/layout pipeline for reactive text measurement.\n */\n\nimport { memo } from \"../signal\";\nimport type { Accessor } from \"../types\";\n\n/**\n * Prepared text handle\n */\nexport interface PreparedText {\n readonly [key: symbol]: true;\n}\n\n/**\n * Layout result\n */\nexport interface LayoutResult {\n lineCount: number;\n height: number;\n}\n\n/**\n * Prepare text for layout measurement\n */\nexport function prepare(text: string, font: string): PreparedText {\n if (typeof window === \"undefined\") {\n return {} as PreparedText;\n }\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n return {} as PreparedText;\n }\n\n ctx.font = font;\n const metrics = ctx.measureText(text);\n const width = metrics.width;\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n return {\n _text: text,\n _font: font,\n _width: width,\n _height: height,\n [Symbol.for(\"prepared\")]: true,\n } as PreparedText;\n}\n\n/**\n * Layout prepared text at a given width\n */\nexport function layout(prepared: PreparedText, maxWidth: number, lineHeight: number): LayoutResult {\n const internal = prepared as any;\n if (!internal._text) {\n return { lineCount: 0, height: 0 };\n }\n\n const text = internal._text as string;\n const font = internal._font as string;\n\n if (typeof window === \"undefined\") {\n return { lineCount: 1, height: lineHeight };\n }\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n return { lineCount: 1, height: lineHeight };\n }\n\n ctx.font = font;\n\n const words = text.split(\" \");\n let lines = 0;\n let currentLineWidth = 0;\n\n for (let i = 0; i < words.length; i++) {\n const word = words[i]!;\n const wordWidth = ctx.measureText(word).width;\n\n if (currentLineWidth + wordWidth > maxWidth) {\n lines++;\n currentLineWidth = wordWidth;\n } else {\n currentLineWidth += wordWidth + ctx.measureText(\" \").width;\n }\n }\n\n if (currentLineWidth > 0) {\n lines++;\n }\n\n return {\n lineCount: Math.max(1, lines),\n height: Math.max(1, lines) * lineHeight,\n };\n}\n\n/**\n * Create a reactive layout computation\n */\nexport function reactiveLayout<T extends object>(\n source: Accessor<T>,\n getPrepared: (item: T) => PreparedText,\n maxWidth: number,\n lineHeight: number,\n): Accessor<LayoutResult> {\n const computed = memo(() => {\n const item = source();\n const prepared = getPrepared(item);\n return layout(prepared, maxWidth, lineHeight);\n });\n return computed as unknown as Accessor<LayoutResult>;\n}\n"],"mappings":";;;;;;;;AAyBA,SAAgB,QAAQ,MAAc,MAA4B;AAChE,KAAI,OAAO,WAAW,YACpB,QAAO,EAAE;CAIX,MAAM,MADS,SAAS,cAAc,SAAS,CAC5B,WAAW,KAAK;AACnC,KAAI,CAAC,IACH,QAAO,EAAE;AAGX,KAAI,OAAO;CACX,MAAM,UAAU,IAAI,YAAY,KAAK;AAIrC,QAAO;EACL,OAAO;EACP,OAAO;EACP,QANY,QAAQ;EAOpB,SANa,QAAQ,0BAA0B,QAAQ;GAOtD,OAAO,IAAI,WAAW,GAAG;EAC3B;;;;;AAMH,SAAgB,OAAO,UAAwB,UAAkB,YAAkC;CACjG,MAAM,WAAW;AACjB,KAAI,CAAC,SAAS,MACZ,QAAO;EAAE,WAAW;EAAG,QAAQ;EAAG;CAGpC,MAAM,OAAO,SAAS;CACtB,MAAM,OAAO,SAAS;AAEtB,KAAI,OAAO,WAAW,YACpB,QAAO;EAAE,WAAW;EAAG,QAAQ;EAAY;CAI7C,MAAM,MADS,SAAS,cAAc,SAAS,CAC5B,WAAW,KAAK;AACnC,KAAI,CAAC,IACH,QAAO;EAAE,WAAW;EAAG,QAAQ;EAAY;AAG7C,KAAI,OAAO;CAEX,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,IAAI,QAAQ;CACZ,IAAI,mBAAmB;AAEvB,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,OAAO,MAAM;EACnB,MAAM,YAAY,IAAI,YAAY,KAAK,CAAC;AAExC,MAAI,mBAAmB,YAAY,UAAU;AAC3C;AACA,sBAAmB;QAEnB,qBAAoB,YAAY,IAAI,YAAY,IAAI,CAAC;;AAIzD,KAAI,mBAAmB,EACrB;AAGF,QAAO;EACL,WAAW,KAAK,IAAI,GAAG,MAAM;EAC7B,QAAQ,KAAK,IAAI,GAAG,MAAM,GAAG;EAC9B;;;;;AAMH,SAAgB,eACd,QACA,aACA,UACA,YACwB;AAMxB,QALiB,WAAW;AAG1B,SAAO,OADU,YADJ,QAAQ,CACa,EACV,UAAU,WAAW;GAC7C"}
@@ -0,0 +1,185 @@
1
+ import { JSX } from "./jsx.cjs";
2
+
3
+ //#region src/types.d.ts
4
+ /**
5
+ * Function that returns a value of type T - used for reactive accessors
6
+ */
7
+ type Accessor<T> = () => T;
8
+ /**
9
+ * Mutable reactive signal holding a value of type T
10
+ */
11
+ interface Signal<T> {
12
+ /** @internal */
13
+ _value: T;
14
+ /** @internal */
15
+ _observers: Computation<any>[] | null;
16
+ /** @internal */
17
+ _observerSlots: number[] | null;
18
+ /** @internal */
19
+ _comparator?: (prev: T, next: T) => boolean;
20
+ }
21
+ /**
22
+ * Read-only derived reactive signal computed from other signals
23
+ */
24
+ interface Computed<T> {
25
+ /** @internal */
26
+ _value: T;
27
+ /** @internal */
28
+ _fn: () => T;
29
+ /** @internal */
30
+ _observers: Computation<any>[] | null;
31
+ /** @internal */
32
+ _observerSlots: number[] | null;
33
+ /** @internal */
34
+ _sources: Signal<any>[] | null;
35
+ /** @internal */
36
+ _sourceSlots: number[] | null;
37
+ /** @internal */
38
+ _comparator?: (prev: T, next: T) => boolean;
39
+ /** @internal */
40
+ _state: 0 | 1 | 2;
41
+ /** Call to get the current value */
42
+ (): T;
43
+ }
44
+ /**
45
+ * Union type for reading signal values
46
+ */
47
+ type ReadonlySignal<T> = Signal<T> | Computed<T>;
48
+ /**
49
+ * Internal computation node in the reactive graph
50
+ */
51
+ interface Computation<T> {
52
+ /** @internal */
53
+ _fn: EffectFunction<T>;
54
+ /** @internal */
55
+ _value: T | undefined;
56
+ /** @internal */
57
+ _sources: Signal<any>[] | null;
58
+ /** @internal */
59
+ _sourceSlots: number[] | null;
60
+ /** @internal */
61
+ _observers: Computation<any>[] | null;
62
+ /** @internal */
63
+ _observerSlots: number[] | null;
64
+ /** @internal */
65
+ _owner: Owner | null;
66
+ /** @internal */
67
+ _cleanups: (() => void)[] | null;
68
+ /** @internal */
69
+ _context: any | null;
70
+ /** @internal */
71
+ _suspense: SuspenseContextType | null;
72
+ /** @internal */
73
+ _user: boolean;
74
+ /** @internal */
75
+ _pure: boolean;
76
+ /** @internal */
77
+ _state: 0 | 1 | 2;
78
+ /** @internal */
79
+ _updatedAt: number | null;
80
+ }
81
+ /**
82
+ * Reactive owner/context node
83
+ */
84
+ interface Owner {
85
+ /** @internal */
86
+ _owned: Computation<any>[] | null;
87
+ /** @internal */
88
+ _cleanups: (() => void)[] | null;
89
+ /** @internal */
90
+ _owner: Owner | null;
91
+ /** @internal */
92
+ _context: any | null;
93
+ }
94
+ /**
95
+ * Effect function type for computations
96
+ */
97
+ type EffectFunction<T> = (prev?: T) => T;
98
+ /**
99
+ * Options for creating a signal
100
+ */
101
+ interface SignalOptions<T> {
102
+ equals?: false | ((prev: T, next: T) => boolean);
103
+ name?: string;
104
+ }
105
+ /**
106
+ * Component function type
107
+ */
108
+ type Component<P extends Record<string, any> = {}> = (props: P) => JSX.Element;
109
+ /**
110
+ * Component that accepts children
111
+ */
112
+ type ParentComponent<P extends Record<string, any> = {}> = Component<P & {
113
+ children?: JSX.Children;
114
+ }>;
115
+ /**
116
+ * Component that requires children
117
+ */
118
+ type FlowComponent<P extends Record<string, any> = {}, C = JSX.Children> = Component<P & {
119
+ children: C;
120
+ }>;
121
+ /**
122
+ * Context object for provider/consumer pattern
123
+ */
124
+ interface Context<T> {
125
+ _id: symbol;
126
+ _defaultValue: T | undefined;
127
+ Provider: Component<{
128
+ value: T;
129
+ children: JSX.Element;
130
+ }>;
131
+ }
132
+ /**
133
+ * Suspense context type for error boundaries and suspense
134
+ */
135
+ interface SuspenseContextType {
136
+ increment: () => void;
137
+ decrement: () => void;
138
+ resolved: boolean;
139
+ }
140
+ /**
141
+ * Resource object returned by load()
142
+ */
143
+ interface Resource<T> {
144
+ (): T | undefined;
145
+ readonly state: Signal<"unresolved" | "pending" | "ready" | "refreshing" | "errored">;
146
+ readonly loading: Signal<boolean>;
147
+ readonly error: Signal<Error | undefined>;
148
+ readonly data: Signal<T | undefined>;
149
+ readonly ready: boolean;
150
+ }
151
+ /**
152
+ * Action object for mutations
153
+ */
154
+ interface Action<T, A> {
155
+ (args: A): Promise<T>;
156
+ run: (args: A) => Promise<T>;
157
+ readonly loading: Signal<boolean>;
158
+ readonly error: Signal<Error | undefined>;
159
+ readonly data: Signal<T | undefined>;
160
+ }
161
+ /**
162
+ * Style properties type
163
+ */
164
+ type StyleProps = Record<string, string | number | Accessor<string | number> | undefined>;
165
+ /**
166
+ * Computed style object
167
+ */
168
+ type ComputedStyle<T extends StyleProps> = () => T;
169
+ /**
170
+ * Store value types
171
+ */
172
+ type StoreValue = string | number | boolean | null | undefined | object | StoreValue[];
173
+ /**
174
+ * Store node type for nested access
175
+ */
176
+ type StoreNode<T> = T extends object ? Record<keyof T, StoreNode<T[keyof T]>> : Signal<T>;
177
+ /**
178
+ * Store object
179
+ */
180
+ interface Store<T extends Record<string, StoreValue>> {
181
+ [key: string]: StoreNode<T[string]>;
182
+ }
183
+ //#endregion
184
+ export { Accessor, Action, Component, Computed, ComputedStyle, Context, FlowComponent, Owner, ParentComponent, ReadonlySignal, Resource, Signal, SignalOptions, Store, StoreNode, StoreValue, StyleProps };
185
+ //# sourceMappingURL=types.d.cts.map