@teamvelix/velix 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,97 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * Velix v5 Islands Architecture
5
+ *
6
+ * Islands allow partial hydration — only interactive components are hydrated
7
+ * on the client, while static content remains as HTML.
8
+ *
9
+ * Usage: Add 'use island' at the top of a component file.
10
+ */
11
+
12
+ /**
13
+ * Island wrapper component for server-side rendering
14
+ */
15
+ declare function Island({ component: Component, props, name, clientPath }: {
16
+ component: React.ComponentType<any>;
17
+ props?: any;
18
+ name: string;
19
+ clientPath: string;
20
+ }): React.ReactElement<{
21
+ 'data-island': string;
22
+ 'data-island-name': string;
23
+ 'data-island-props': string;
24
+ }, string | React.JSXElementConstructor<any>>;
25
+ /**
26
+ * Gets all registered islands and clears the registry
27
+ */
28
+ declare function getRegisteredIslands(): any[];
29
+ /**
30
+ * Creates an island component wrapper
31
+ */
32
+ declare function createIsland(Component: React.ComponentType<any>, options?: {
33
+ name?: string;
34
+ clientPath?: string;
35
+ }): {
36
+ (props: any): React.ReactElement<{
37
+ 'data-island': string;
38
+ 'data-island-name': string;
39
+ 'data-island-props': string;
40
+ }, string | React.JSXElementConstructor<any>>;
41
+ displayName: string;
42
+ isIsland: boolean;
43
+ originalComponent: React.ComponentType<any>;
44
+ };
45
+ /**
46
+ * Island loading strategies
47
+ */
48
+ declare const LoadStrategy: {
49
+ readonly IMMEDIATE: "immediate";
50
+ readonly VISIBLE: "visible";
51
+ readonly IDLE: "idle";
52
+ readonly MEDIA: "media";
53
+ };
54
+ /**
55
+ * Creates a lazy island that hydrates based on strategy
56
+ */
57
+ declare function createLazyIsland(Component: React.ComponentType<any>, options?: {
58
+ name?: string;
59
+ clientPath?: string;
60
+ strategy?: string;
61
+ media?: string | null;
62
+ }): {
63
+ (props: any): React.ReactElement<{
64
+ 'data-island': string;
65
+ 'data-island-name': any;
66
+ 'data-island-strategy': string;
67
+ 'data-island-media': string | null;
68
+ 'data-island-props': string;
69
+ }, string | React.JSXElementConstructor<any>>;
70
+ displayName: string;
71
+ isIsland: boolean;
72
+ isLazy: boolean;
73
+ };
74
+ /**
75
+ * Generates the client-side hydration script for islands
76
+ */
77
+ declare function generateHydrationScript(islands: any[]): string;
78
+ /**
79
+ * Generates advanced hydration script with loading strategies
80
+ */
81
+ declare function generateAdvancedHydrationScript(islands: any[]): string;
82
+ declare const _default: {
83
+ Island: typeof Island;
84
+ createIsland: typeof createIsland;
85
+ createLazyIsland: typeof createLazyIsland;
86
+ getRegisteredIslands: typeof getRegisteredIslands;
87
+ generateHydrationScript: typeof generateHydrationScript;
88
+ generateAdvancedHydrationScript: typeof generateAdvancedHydrationScript;
89
+ LoadStrategy: {
90
+ readonly IMMEDIATE: "immediate";
91
+ readonly VISIBLE: "visible";
92
+ readonly IDLE: "idle";
93
+ readonly MEDIA: "media";
94
+ };
95
+ };
96
+
97
+ export { Island, LoadStrategy, createIsland, createLazyIsland, _default as default, generateAdvancedHydrationScript, generateHydrationScript, getRegisteredIslands };
@@ -0,0 +1,182 @@
1
+ // islands/index.ts
2
+ import React from "react";
3
+ import crypto from "crypto";
4
+ var islandRegistry = /* @__PURE__ */ new Map();
5
+ function generateIslandId(componentName) {
6
+ const hash = crypto.randomBytes(4).toString("hex");
7
+ return `island-${componentName}-${hash}`;
8
+ }
9
+ function Island({ component: Component, props = {}, name, clientPath }) {
10
+ const islandId = generateIslandId(name);
11
+ islandRegistry.set(islandId, { id: islandId, name, clientPath, props });
12
+ return React.createElement("div", {
13
+ "data-island": islandId,
14
+ "data-island-name": name,
15
+ "data-island-props": JSON.stringify(props)
16
+ }, React.createElement(Component, props));
17
+ }
18
+ function getRegisteredIslands() {
19
+ const islands = Array.from(islandRegistry.values());
20
+ islandRegistry.clear();
21
+ return islands;
22
+ }
23
+ function createIsland(Component, options = {}) {
24
+ const { name = Component.name || "Island", clientPath } = options;
25
+ function IslandWrapper(props) {
26
+ return Island({
27
+ component: Component,
28
+ props,
29
+ name,
30
+ clientPath: clientPath || `/__velix/islands/${name}.js`
31
+ });
32
+ }
33
+ IslandWrapper.displayName = `Island(${name})`;
34
+ IslandWrapper.isIsland = true;
35
+ IslandWrapper.originalComponent = Component;
36
+ return IslandWrapper;
37
+ }
38
+ var LoadStrategy = {
39
+ IMMEDIATE: "immediate",
40
+ VISIBLE: "visible",
41
+ IDLE: "idle",
42
+ MEDIA: "media"
43
+ };
44
+ function createLazyIsland(Component, options = {}) {
45
+ const {
46
+ name = Component.name || "LazyIsland",
47
+ clientPath,
48
+ strategy = LoadStrategy.VISIBLE,
49
+ media = null
50
+ } = options;
51
+ function LazyIslandWrapper(props) {
52
+ const islandId = generateIslandId(name);
53
+ islandRegistry.set(islandId, {
54
+ id: islandId,
55
+ name,
56
+ clientPath: clientPath || `/__velix/islands/${name}.js`,
57
+ props,
58
+ strategy,
59
+ media
60
+ });
61
+ return React.createElement("div", {
62
+ "data-island": islandId,
63
+ "data-island-name": name,
64
+ "data-island-strategy": strategy,
65
+ "data-island-media": media,
66
+ "data-island-props": JSON.stringify(props)
67
+ });
68
+ }
69
+ LazyIslandWrapper.displayName = `LazyIsland(${name})`;
70
+ LazyIslandWrapper.isIsland = true;
71
+ LazyIslandWrapper.isLazy = true;
72
+ return LazyIslandWrapper;
73
+ }
74
+ function generateHydrationScript(islands) {
75
+ if (!islands.length) return "";
76
+ const islandData = islands.map((island) => ({
77
+ id: island.id,
78
+ name: island.name,
79
+ path: island.clientPath,
80
+ props: island.props
81
+ }));
82
+ return `
83
+ <script type="module">
84
+ const islands = ${JSON.stringify(islandData)};
85
+
86
+ async function hydrateIslands() {
87
+ const { hydrateRoot } = await import('/__velix/react-dom-client.js');
88
+ const React = await import('/__velix/react.js');
89
+
90
+ for (const island of islands) {
91
+ try {
92
+ const el = document.querySelector(\`[data-island="\${island.id}"]\`);
93
+ if (!el) continue;
94
+ const mod = await import(island.path);
95
+ hydrateRoot(el, React.createElement(mod.default, island.props));
96
+ el.setAttribute('data-hydrated', 'true');
97
+ } catch (error) {
98
+ console.error(\`Failed to hydrate island \${island.name}:\`, error);
99
+ }
100
+ }
101
+ }
102
+
103
+ if (document.readyState === 'loading') {
104
+ document.addEventListener('DOMContentLoaded', hydrateIslands);
105
+ } else {
106
+ hydrateIslands();
107
+ }
108
+ </script>`;
109
+ }
110
+ function generateAdvancedHydrationScript(islands) {
111
+ if (!islands.length) return "";
112
+ const islandData = islands.map((island) => ({
113
+ id: island.id,
114
+ name: island.name,
115
+ path: island.clientPath,
116
+ props: island.props,
117
+ strategy: island.strategy || LoadStrategy.IMMEDIATE,
118
+ media: island.media
119
+ }));
120
+ return `
121
+ <script type="module">
122
+ const islands = ${JSON.stringify(islandData)};
123
+
124
+ async function hydrateIsland(island) {
125
+ const el = document.querySelector(\`[data-island="\${island.id}"]\`);
126
+ if (!el || el.hasAttribute('data-hydrated')) return;
127
+
128
+ try {
129
+ const { hydrateRoot } = await import('/__velix/react-dom-client.js');
130
+ const React = await import('/__velix/react.js');
131
+ const mod = await import(island.path);
132
+ hydrateRoot(el, React.createElement(mod.default, island.props));
133
+ el.setAttribute('data-hydrated', 'true');
134
+ } catch (error) {
135
+ console.error(\`Failed to hydrate island \${island.name}:\`, error);
136
+ }
137
+ }
138
+
139
+ const visibleObserver = new IntersectionObserver((entries) => {
140
+ entries.forEach(entry => {
141
+ if (entry.isIntersecting) {
142
+ const id = entry.target.getAttribute('data-island');
143
+ const island = islands.find(i => i.id === id);
144
+ if (island) { hydrateIsland(island); visibleObserver.unobserve(entry.target); }
145
+ }
146
+ });
147
+ }, { rootMargin: '50px' });
148
+
149
+ function processIslands() {
150
+ for (const island of islands) {
151
+ const el = document.querySelector(\`[data-island="\${island.id}"]\`);
152
+ if (!el) continue;
153
+ switch (island.strategy) {
154
+ case 'immediate': hydrateIsland(island); break;
155
+ case 'visible': visibleObserver.observe(el); break;
156
+ case 'idle': requestIdleCallback(() => hydrateIsland(island)); break;
157
+ case 'media':
158
+ if (island.media && window.matchMedia(island.media).matches) hydrateIsland(island);
159
+ break;
160
+ }
161
+ }
162
+ }
163
+
164
+ if (document.readyState === 'loading') {
165
+ document.addEventListener('DOMContentLoaded', processIslands);
166
+ } else {
167
+ processIslands();
168
+ }
169
+ </script>`;
170
+ }
171
+ var islands_default = { Island, createIsland, createLazyIsland, getRegisteredIslands, generateHydrationScript, generateAdvancedHydrationScript, LoadStrategy };
172
+ export {
173
+ Island,
174
+ LoadStrategy,
175
+ createIsland,
176
+ createLazyIsland,
177
+ islands_default as default,
178
+ generateAdvancedHydrationScript,
179
+ generateHydrationScript,
180
+ getRegisteredIslands
181
+ };
182
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../islands/index.ts"],"sourcesContent":["/**\n * Velix v5 Islands Architecture\n *\n * Islands allow partial hydration — only interactive components are hydrated\n * on the client, while static content remains as HTML.\n *\n * Usage: Add 'use island' at the top of a component file.\n */\n\nimport React from 'react';\nimport crypto from 'crypto';\n\n// Island registry for tracking all islands in a render\nconst islandRegistry = new Map();\n\nfunction generateIslandId(componentName: string): string {\n const hash = crypto.randomBytes(4).toString('hex');\n return `island-${componentName}-${hash}`;\n}\n\n/**\n * Island wrapper component for server-side rendering\n */\nexport function Island({ component: Component, props = {}, name, clientPath }: {\n component: React.ComponentType<any>;\n props?: any;\n name: string;\n clientPath: string;\n}) {\n const islandId = generateIslandId(name);\n\n islandRegistry.set(islandId, { id: islandId, name, clientPath, props });\n\n return React.createElement('div', {\n 'data-island': islandId,\n 'data-island-name': name,\n 'data-island-props': JSON.stringify(props),\n }, React.createElement(Component, props));\n}\n\n/**\n * Gets all registered islands and clears the registry\n */\nexport function getRegisteredIslands() {\n const islands = Array.from(islandRegistry.values());\n islandRegistry.clear();\n return islands;\n}\n\n/**\n * Creates an island component wrapper\n */\nexport function createIsland(Component: React.ComponentType<any>, options: { name?: string; clientPath?: string } = {}) {\n const { name = (Component as any).name || 'Island', clientPath } = options;\n\n function IslandWrapper(props: any) {\n return Island({\n component: Component, props, name,\n clientPath: clientPath || `/__velix/islands/${name}.js`\n });\n }\n\n IslandWrapper.displayName = `Island(${name})`;\n IslandWrapper.isIsland = true;\n IslandWrapper.originalComponent = Component;\n return IslandWrapper;\n}\n\n/**\n * Island loading strategies\n */\nexport const LoadStrategy = {\n IMMEDIATE: 'immediate',\n VISIBLE: 'visible',\n IDLE: 'idle',\n MEDIA: 'media'\n} as const;\n\n/**\n * Creates a lazy island that hydrates based on strategy\n */\nexport function createLazyIsland(Component: React.ComponentType<any>, options: {\n name?: string; clientPath?: string; strategy?: string; media?: string | null;\n} = {}) {\n const {\n name = (Component as any).name || 'LazyIsland',\n clientPath,\n strategy = LoadStrategy.VISIBLE,\n media = null\n } = options;\n\n function LazyIslandWrapper(props: any) {\n const islandId = generateIslandId(name);\n\n islandRegistry.set(islandId, {\n id: islandId, name,\n clientPath: clientPath || `/__velix/islands/${name}.js`,\n props, strategy, media\n });\n\n return React.createElement('div', {\n 'data-island': islandId,\n 'data-island-name': name,\n 'data-island-strategy': strategy,\n 'data-island-media': media,\n 'data-island-props': JSON.stringify(props),\n });\n }\n\n LazyIslandWrapper.displayName = `LazyIsland(${name})`;\n LazyIslandWrapper.isIsland = true;\n LazyIslandWrapper.isLazy = true;\n return LazyIslandWrapper;\n}\n\n/**\n * Generates the client-side hydration script for islands\n */\nexport function generateHydrationScript(islands: any[]): string {\n if (!islands.length) return '';\n\n const islandData = islands.map((island: any) => ({\n id: island.id, name: island.name,\n path: island.clientPath, props: island.props\n }));\n\n return `\n<script type=\"module\">\n const islands = ${JSON.stringify(islandData)};\n\n async function hydrateIslands() {\n const { hydrateRoot } = await import('/__velix/react-dom-client.js');\n const React = await import('/__velix/react.js');\n\n for (const island of islands) {\n try {\n const el = document.querySelector(\\`[data-island=\"\\${island.id}\"]\\`);\n if (!el) continue;\n const mod = await import(island.path);\n hydrateRoot(el, React.createElement(mod.default, island.props));\n el.setAttribute('data-hydrated', 'true');\n } catch (error) {\n console.error(\\`Failed to hydrate island \\${island.name}:\\`, error);\n }\n }\n }\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', hydrateIslands);\n } else {\n hydrateIslands();\n }\n</script>`;\n}\n\n/**\n * Generates advanced hydration script with loading strategies\n */\nexport function generateAdvancedHydrationScript(islands: any[]): string {\n if (!islands.length) return '';\n\n const islandData = islands.map((island: any) => ({\n id: island.id, name: island.name, path: island.clientPath,\n props: island.props, strategy: island.strategy || LoadStrategy.IMMEDIATE,\n media: island.media\n }));\n\n return `\n<script type=\"module\">\n const islands = ${JSON.stringify(islandData)};\n\n async function hydrateIsland(island) {\n const el = document.querySelector(\\`[data-island=\"\\${island.id}\"]\\`);\n if (!el || el.hasAttribute('data-hydrated')) return;\n\n try {\n const { hydrateRoot } = await import('/__velix/react-dom-client.js');\n const React = await import('/__velix/react.js');\n const mod = await import(island.path);\n hydrateRoot(el, React.createElement(mod.default, island.props));\n el.setAttribute('data-hydrated', 'true');\n } catch (error) {\n console.error(\\`Failed to hydrate island \\${island.name}:\\`, error);\n }\n }\n\n const visibleObserver = new IntersectionObserver((entries) => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const id = entry.target.getAttribute('data-island');\n const island = islands.find(i => i.id === id);\n if (island) { hydrateIsland(island); visibleObserver.unobserve(entry.target); }\n }\n });\n }, { rootMargin: '50px' });\n\n function processIslands() {\n for (const island of islands) {\n const el = document.querySelector(\\`[data-island=\"\\${island.id}\"]\\`);\n if (!el) continue;\n switch (island.strategy) {\n case 'immediate': hydrateIsland(island); break;\n case 'visible': visibleObserver.observe(el); break;\n case 'idle': requestIdleCallback(() => hydrateIsland(island)); break;\n case 'media':\n if (island.media && window.matchMedia(island.media).matches) hydrateIsland(island);\n break;\n }\n }\n }\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', processIslands);\n } else {\n processIslands();\n }\n</script>`;\n}\n\nexport default { Island, createIsland, createLazyIsland, getRegisteredIslands, generateHydrationScript, generateAdvancedHydrationScript, LoadStrategy };\n"],"mappings":"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","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }