@vertz/ui 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.
@@ -0,0 +1,62 @@
1
+ import {
2
+ effect,
3
+ useContext
4
+ } from "./chunk-pgymxpn1.js";
5
+
6
+ // src/router/link.ts
7
+ function createLink(currentPath, navigate) {
8
+ return function Link(props) {
9
+ const el = document.createElement("a");
10
+ el.setAttribute("href", props.href);
11
+ el.textContent = props.children;
12
+ if (props.className) {
13
+ el.classList.add(props.className);
14
+ }
15
+ if (props.activeClass) {
16
+ const activeClass = props.activeClass;
17
+ effect(() => {
18
+ if (currentPath.value === props.href) {
19
+ el.classList.add(activeClass);
20
+ } else {
21
+ el.classList.remove(activeClass);
22
+ }
23
+ });
24
+ }
25
+ el.addEventListener("click", (event) => {
26
+ if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
27
+ return;
28
+ }
29
+ event.preventDefault();
30
+ navigate(props.href);
31
+ });
32
+ return el;
33
+ };
34
+ }
35
+
36
+ // src/router/outlet.ts
37
+ function createOutlet(outletCtx) {
38
+ return function Outlet() {
39
+ const ctx = useContext(outletCtx);
40
+ if (!ctx || !ctx.childComponent) {
41
+ return document.createComment("outlet:empty");
42
+ }
43
+ return ctx.childComponent();
44
+ };
45
+ }
46
+
47
+ // src/router/search-params.ts
48
+ function parseSearchParams(urlParams, schema) {
49
+ const raw = {};
50
+ for (const [key, value] of urlParams.entries()) {
51
+ raw[key] = value;
52
+ }
53
+ if (schema) {
54
+ return schema.parse(raw);
55
+ }
56
+ return raw;
57
+ }
58
+ function useSearchParams(searchSignal) {
59
+ return searchSignal.value;
60
+ }
61
+
62
+ export { createLink, createOutlet, parseSearchParams, useSearchParams };
@@ -0,0 +1,141 @@
1
+ // src/hydrate/component-registry.ts
2
+ async function resolveComponent(registry, componentId) {
3
+ const loader = registry[componentId];
4
+ if (!loader) {
5
+ throw new TypeError(`[hydrate] Component "${componentId}" not found in registry`);
6
+ }
7
+ const mod = await loader();
8
+ return mod.default;
9
+ }
10
+
11
+ // src/hydrate/props-deserializer.ts
12
+ function deserializeProps(container) {
13
+ const script = container.querySelector('script[type="application/json"]');
14
+ if (!script || !script.textContent) {
15
+ return {};
16
+ }
17
+ try {
18
+ return JSON.parse(script.textContent);
19
+ } catch {
20
+ return {};
21
+ }
22
+ }
23
+
24
+ // src/hydrate/strategies.ts
25
+ function eagerStrategy(el, hydrateFn) {
26
+ hydrateFn();
27
+ }
28
+ function lazyStrategy(el, hydrateFn) {
29
+ if (typeof IntersectionObserver === "undefined") {
30
+ hydrateFn();
31
+ return;
32
+ }
33
+ const observer = new IntersectionObserver((entries) => {
34
+ for (const entry of entries) {
35
+ if (entry.isIntersecting) {
36
+ observer.disconnect();
37
+ hydrateFn();
38
+ return;
39
+ }
40
+ }
41
+ }, { rootMargin: "200px" });
42
+ observer.observe(el);
43
+ }
44
+ function interactionStrategy(el, hydrateFn) {
45
+ const events = ["click", "focus", "pointerenter"];
46
+ function handler() {
47
+ for (const event of events) {
48
+ el.removeEventListener(event, handler);
49
+ }
50
+ hydrateFn();
51
+ }
52
+ for (const event of events) {
53
+ el.addEventListener(event, handler);
54
+ }
55
+ }
56
+ function idleStrategy(el, hydrateFn) {
57
+ if (typeof requestIdleCallback !== "undefined") {
58
+ requestIdleCallback(() => hydrateFn());
59
+ } else {
60
+ setTimeout(hydrateFn, 0);
61
+ }
62
+ }
63
+ function mediaStrategy(query) {
64
+ return (el, hydrateFn) => {
65
+ const mql = window.matchMedia(query);
66
+ if (mql.matches) {
67
+ hydrateFn();
68
+ return;
69
+ }
70
+ function onChange(event) {
71
+ if (event.matches) {
72
+ mql.removeEventListener("change", onChange);
73
+ hydrateFn();
74
+ }
75
+ }
76
+ mql.addEventListener("change", onChange);
77
+ };
78
+ }
79
+ function visibleStrategy(el, hydrateFn) {
80
+ if (typeof IntersectionObserver === "undefined") {
81
+ hydrateFn();
82
+ return;
83
+ }
84
+ const observer = new IntersectionObserver((entries) => {
85
+ for (const entry of entries) {
86
+ if (entry.isIntersecting) {
87
+ observer.disconnect();
88
+ hydrateFn();
89
+ return;
90
+ }
91
+ }
92
+ });
93
+ observer.observe(el);
94
+ }
95
+
96
+ // src/hydrate/hydrate.ts
97
+ function hydrate(registry) {
98
+ const elements = document.querySelectorAll("[data-v-id]");
99
+ for (const el of elements) {
100
+ if (el.hasAttribute("data-v-hydrated"))
101
+ continue;
102
+ const componentId = el.getAttribute("data-v-id");
103
+ if (!componentId)
104
+ continue;
105
+ const strategy = el.getAttribute("hydrate") ?? "lazy";
106
+ const props = deserializeProps(el);
107
+ const doHydrate = () => {
108
+ resolveComponent(registry, componentId).then((component) => {
109
+ component(props, el);
110
+ el.setAttribute("data-v-hydrated", "");
111
+ }).catch((error) => {
112
+ console.error(`[hydrate] Failed to hydrate component "${componentId}":`, error);
113
+ });
114
+ };
115
+ switch (strategy) {
116
+ case "eager":
117
+ eagerStrategy(el, doHydrate);
118
+ break;
119
+ case "lazy":
120
+ lazyStrategy(el, doHydrate);
121
+ break;
122
+ case "interaction":
123
+ interactionStrategy(el, doHydrate);
124
+ break;
125
+ case "idle":
126
+ idleStrategy(el, doHydrate);
127
+ break;
128
+ case "media": {
129
+ const query = el.getAttribute("hydrate-media") ?? "";
130
+ mediaStrategy(query)(el, doHydrate);
131
+ break;
132
+ }
133
+ case "visible":
134
+ visibleStrategy(el, doHydrate);
135
+ break;
136
+ default:
137
+ lazyStrategy(el, doHydrate);
138
+ }
139
+ }
140
+ }
141
+ export { resolveComponent, deserializeProps, eagerStrategy, lazyStrategy, interactionStrategy, idleStrategy, mediaStrategy, visibleStrategy, hydrate };