@lolyjs/core 0.1.0-alpha.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 (53) hide show
  1. package/README.md +607 -0
  2. package/bin/loly.cjs +6 -0
  3. package/dist/bootstrap-BiCQmSkx.d.mts +50 -0
  4. package/dist/bootstrap-BiCQmSkx.d.ts +50 -0
  5. package/dist/cli.cjs +5186 -0
  6. package/dist/cli.cjs.map +1 -0
  7. package/dist/cli.d.mts +2 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.js +5181 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/index.cjs +5774 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.d.mts +445 -0
  14. package/dist/index.d.ts +445 -0
  15. package/dist/index.js +5731 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/react/cache.cjs +251 -0
  18. package/dist/react/cache.cjs.map +1 -0
  19. package/dist/react/cache.d.mts +59 -0
  20. package/dist/react/cache.d.ts +59 -0
  21. package/dist/react/cache.js +220 -0
  22. package/dist/react/cache.js.map +1 -0
  23. package/dist/react/components.cjs +218 -0
  24. package/dist/react/components.cjs.map +1 -0
  25. package/dist/react/components.d.mts +26 -0
  26. package/dist/react/components.d.ts +26 -0
  27. package/dist/react/components.js +190 -0
  28. package/dist/react/components.js.map +1 -0
  29. package/dist/react/hooks.cjs +86 -0
  30. package/dist/react/hooks.cjs.map +1 -0
  31. package/dist/react/hooks.d.mts +19 -0
  32. package/dist/react/hooks.d.ts +19 -0
  33. package/dist/react/hooks.js +58 -0
  34. package/dist/react/hooks.js.map +1 -0
  35. package/dist/react/sockets.cjs +43 -0
  36. package/dist/react/sockets.cjs.map +1 -0
  37. package/dist/react/sockets.d.mts +29 -0
  38. package/dist/react/sockets.d.ts +29 -0
  39. package/dist/react/sockets.js +18 -0
  40. package/dist/react/sockets.js.map +1 -0
  41. package/dist/react/themes.cjs +145 -0
  42. package/dist/react/themes.cjs.map +1 -0
  43. package/dist/react/themes.d.mts +13 -0
  44. package/dist/react/themes.d.ts +13 -0
  45. package/dist/react/themes.js +117 -0
  46. package/dist/react/themes.js.map +1 -0
  47. package/dist/runtime.cjs +626 -0
  48. package/dist/runtime.cjs.map +1 -0
  49. package/dist/runtime.d.mts +11 -0
  50. package/dist/runtime.d.ts +11 -0
  51. package/dist/runtime.js +599 -0
  52. package/dist/runtime.js.map +1 -0
  53. package/package.json +101 -0
@@ -0,0 +1,58 @@
1
+ // modules/react/hooks/useBroadcastChannel/index.tsx
2
+ import { useEffect, useState } from "react";
3
+ var useBroadcastChannel = (channelName) => {
4
+ const [message, setMessage] = useState(null);
5
+ const channel = new BroadcastChannel(channelName);
6
+ useEffect(() => {
7
+ const handleMessage = (event) => {
8
+ setMessage(event.data);
9
+ };
10
+ channel.onmessage = handleMessage;
11
+ return () => {
12
+ channel.close();
13
+ };
14
+ }, [channel]);
15
+ const sendMessage = (msg) => {
16
+ channel.postMessage(msg);
17
+ };
18
+ return { message, sendMessage };
19
+ };
20
+
21
+ // modules/react/hooks/usePageProps/index.ts
22
+ import { useEffect as useEffect2, useState as useState2 } from "react";
23
+ var usePageProps = () => {
24
+ const [props, setProps] = useState2(() => {
25
+ if (typeof window !== "undefined" && window?.__FW_DATA__) {
26
+ const data = window.__FW_DATA__;
27
+ return {
28
+ params: data.params || {},
29
+ props: data.props || {}
30
+ };
31
+ }
32
+ return {
33
+ params: {},
34
+ props: {}
35
+ };
36
+ });
37
+ useEffect2(() => {
38
+ const handleDataRefresh = () => {
39
+ if (window?.__FW_DATA__) {
40
+ const data = window.__FW_DATA__;
41
+ setProps({
42
+ params: data.params || {},
43
+ props: data.props || {}
44
+ });
45
+ }
46
+ };
47
+ window.addEventListener("fw-data-refresh", handleDataRefresh);
48
+ return () => {
49
+ window.removeEventListener("fw-data-refresh", handleDataRefresh);
50
+ };
51
+ }, []);
52
+ return props;
53
+ };
54
+ export {
55
+ useBroadcastChannel,
56
+ usePageProps
57
+ };
58
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../modules/react/hooks/useBroadcastChannel/index.tsx","../../modules/react/hooks/usePageProps/index.ts"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\r\n\r\nexport const useBroadcastChannel = (channelName: string) => {\r\n const [message, setMessage] = useState(null);\r\n const channel = new BroadcastChannel(channelName);\r\n\r\n useEffect(() => {\r\n const handleMessage = (event: MessageEvent) => {\r\n setMessage(event.data);\r\n };\r\n\r\n channel.onmessage = handleMessage;\r\n\r\n // Clean up the channel when the component unmounts\r\n return () => {\r\n channel.close();\r\n };\r\n }, [channel]);\r\n\r\n const sendMessage = (msg: unknown) => {\r\n channel.postMessage(msg);\r\n };\r\n\r\n return { message, sendMessage };\r\n};\r\n","import React, { useEffect, useState } from \"react\";\r\n\r\n/**\r\n * Hook to access page props and route parameters.\r\n *\r\n * Reads initial data from window.__FW_DATA__ set during SSR.\r\n * Automatically updates when `revalidate()` is called.\r\n *\r\n * @returns Object containing params and props\r\n */\r\nexport const usePageProps = () => {\r\n const [props, setProps] = useState(() => {\r\n // Initialize with current data if available\r\n if (typeof window !== \"undefined\" && (window as any)?.__FW_DATA__) {\r\n const data = (window as any).__FW_DATA__;\r\n return {\r\n params: data.params || {},\r\n props: data.props || {},\r\n };\r\n }\r\n return {\r\n params: {},\r\n props: {},\r\n };\r\n });\r\n\r\n useEffect(() => {\r\n // Listen for data refresh events (from revalidate() or navigation)\r\n const handleDataRefresh = () => {\r\n if ((window as any)?.__FW_DATA__) {\r\n const data = (window as any).__FW_DATA__;\r\n setProps({\r\n params: data.params || {},\r\n props: data.props || {},\r\n });\r\n }\r\n };\r\n\r\n window.addEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n\r\n return () => {\r\n window.removeEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n };\r\n }, []);\r\n\r\n return props;\r\n};\r\n"],"mappings":";AAAA,SAAgB,WAAW,gBAAgB;AAEpC,IAAM,sBAAsB,CAAC,gBAAwB;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,QAAM,UAAU,IAAI,iBAAiB,WAAW;AAEhD,YAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,UAAwB;AAC7C,iBAAW,MAAM,IAAI;AAAA,IACvB;AAEA,YAAQ,YAAY;AAGpB,WAAO,MAAM;AACX,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,cAAc,CAAC,QAAiB;AACpC,YAAQ,YAAY,GAAG;AAAA,EACzB;AAEA,SAAO,EAAE,SAAS,YAAY;AAChC;;;ACxBA,SAAgB,aAAAA,YAAW,YAAAC,iBAAgB;AAUpC,IAAM,eAAe,MAAM;AAChC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,MAAM;AAEvC,QAAI,OAAO,WAAW,eAAgB,QAAgB,aAAa;AACjE,YAAM,OAAQ,OAAe;AAC7B,aAAO;AAAA,QACL,QAAQ,KAAK,UAAU,CAAC;AAAA,QACxB,OAAO,KAAK,SAAS,CAAC;AAAA,MACxB;AAAA,IACF;AACA,WAAO;AAAA,MACL,QAAQ,CAAC;AAAA,MACT,OAAO,CAAC;AAAA,IACV;AAAA,EACF,CAAC;AAED,EAAAD,WAAU,MAAM;AAEd,UAAM,oBAAoB,MAAM;AAC9B,UAAK,QAAgB,aAAa;AAChC,cAAM,OAAQ,OAAe;AAC7B,iBAAS;AAAA,UACP,QAAQ,KAAK,UAAU,CAAC;AAAA,UACxB,OAAO,KAAK,SAAS,CAAC;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,iBAAiB,mBAAmB,iBAAiB;AAE5D,WAAO,MAAM;AACX,aAAO,oBAAoB,mBAAmB,iBAAiB;AAAA,IACjE;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;","names":["useEffect","useState"]}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // modules/react/sockets/index.ts
21
+ var sockets_exports = {};
22
+ __export(sockets_exports, {
23
+ lolySocket: () => lolySocket
24
+ });
25
+ module.exports = __toCommonJS(sockets_exports);
26
+ var import_socket = require("socket.io-client");
27
+ var lolySocket = (namespace, opts) => {
28
+ const baseUrl = process.env.PUBLIC_WS_BASE_URL || window.location.origin;
29
+ const normalizedNamespace = namespace.startsWith("/") ? namespace : `/${namespace}`;
30
+ const fullUrl = `${baseUrl}${normalizedNamespace}`;
31
+ const socket = (0, import_socket.io)(fullUrl, {
32
+ path: "/wss",
33
+ transports: ["websocket", "polling"],
34
+ autoConnect: true,
35
+ ...opts
36
+ });
37
+ return socket;
38
+ };
39
+ // Annotate the CommonJS export names for ESM import in node:
40
+ 0 && (module.exports = {
41
+ lolySocket
42
+ });
43
+ //# sourceMappingURL=sockets.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../modules/react/sockets/index.ts"],"sourcesContent":["import { io, ManagerOptions, Socket, SocketOptions } from \"socket.io-client\";\r\n\r\n/**\r\n * Creates a Socket.IO client connection to a specific namespace.\r\n * \r\n * This helper function simplifies Socket.IO client setup by handling:\r\n * - Namespace normalization (ensures leading slash)\r\n * - Base URL resolution (from environment or current origin)\r\n * - Default Socket.IO configuration (path: '/wss', transports: ['websocket', 'polling'])\r\n * \r\n * @param namespace - The namespace to connect to (e.g., '/chat' or 'chat').\r\n * The namespace will be normalized to always start with '/'.\r\n * Must match the namespace pattern defined in your server's WSS routes.\r\n * @param opts - Optional Socket.IO client options that will override the defaults.\r\n * \r\n * @returns A Socket.IO client instance connected to the specified namespace.\r\n * \r\n * @example\r\n * ```ts\r\n * const socket = lolySocket('/chat');\r\n * socket.on('message', (data) => {\r\n * console.log('Received:', data);\r\n * });\r\n * socket.emit('message', { text: 'Hello' });\r\n * ```\r\n */\r\nexport const lolySocket = (\r\n namespace: string,\r\n opts?: Partial<ManagerOptions & SocketOptions>\r\n): Socket => {\r\n const baseUrl = process.env.PUBLIC_WS_BASE_URL || window.location.origin;\r\n\r\n // Normalize namespace to always start with '/'\r\n const normalizedNamespace = namespace.startsWith(\"/\") ? namespace : `/${namespace}`;\r\n\r\n // In Socket.IO, when using a custom path, the namespace is specified in the URL:\r\n // baseUrl + namespace. The path '/wss' is the HTTP route where Socket.IO listens.\r\n const fullUrl = `${baseUrl}${normalizedNamespace}`;\r\n\r\n const socket = io(fullUrl, {\r\n path: \"/wss\",\r\n transports: [\"websocket\", \"polling\"],\r\n autoConnect: true,\r\n ...opts,\r\n });\r\n\r\n return socket;\r\n};\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA0D;AA0BnD,IAAM,aAAa,CACxB,WACA,SACW;AACX,QAAM,UAAU,QAAQ,IAAI,sBAAsB,OAAO,SAAS;AAGlE,QAAM,sBAAsB,UAAU,WAAW,GAAG,IAAI,YAAY,IAAI,SAAS;AAIjF,QAAM,UAAU,GAAG,OAAO,GAAG,mBAAmB;AAEhD,QAAM,aAAS,kBAAG,SAAS;AAAA,IACzB,MAAM;AAAA,IACN,YAAY,CAAC,aAAa,SAAS;AAAA,IACnC,aAAa;AAAA,IACb,GAAG;AAAA,EACL,CAAC;AAED,SAAO;AACT;","names":[]}
@@ -0,0 +1,29 @@
1
+ import { ManagerOptions, SocketOptions, Socket } from 'socket.io-client';
2
+
3
+ /**
4
+ * Creates a Socket.IO client connection to a specific namespace.
5
+ *
6
+ * This helper function simplifies Socket.IO client setup by handling:
7
+ * - Namespace normalization (ensures leading slash)
8
+ * - Base URL resolution (from environment or current origin)
9
+ * - Default Socket.IO configuration (path: '/wss', transports: ['websocket', 'polling'])
10
+ *
11
+ * @param namespace - The namespace to connect to (e.g., '/chat' or 'chat').
12
+ * The namespace will be normalized to always start with '/'.
13
+ * Must match the namespace pattern defined in your server's WSS routes.
14
+ * @param opts - Optional Socket.IO client options that will override the defaults.
15
+ *
16
+ * @returns A Socket.IO client instance connected to the specified namespace.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const socket = lolySocket('/chat');
21
+ * socket.on('message', (data) => {
22
+ * console.log('Received:', data);
23
+ * });
24
+ * socket.emit('message', { text: 'Hello' });
25
+ * ```
26
+ */
27
+ declare const lolySocket: (namespace: string, opts?: Partial<ManagerOptions & SocketOptions>) => Socket;
28
+
29
+ export { lolySocket };
@@ -0,0 +1,29 @@
1
+ import { ManagerOptions, SocketOptions, Socket } from 'socket.io-client';
2
+
3
+ /**
4
+ * Creates a Socket.IO client connection to a specific namespace.
5
+ *
6
+ * This helper function simplifies Socket.IO client setup by handling:
7
+ * - Namespace normalization (ensures leading slash)
8
+ * - Base URL resolution (from environment or current origin)
9
+ * - Default Socket.IO configuration (path: '/wss', transports: ['websocket', 'polling'])
10
+ *
11
+ * @param namespace - The namespace to connect to (e.g., '/chat' or 'chat').
12
+ * The namespace will be normalized to always start with '/'.
13
+ * Must match the namespace pattern defined in your server's WSS routes.
14
+ * @param opts - Optional Socket.IO client options that will override the defaults.
15
+ *
16
+ * @returns A Socket.IO client instance connected to the specified namespace.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const socket = lolySocket('/chat');
21
+ * socket.on('message', (data) => {
22
+ * console.log('Received:', data);
23
+ * });
24
+ * socket.emit('message', { text: 'Hello' });
25
+ * ```
26
+ */
27
+ declare const lolySocket: (namespace: string, opts?: Partial<ManagerOptions & SocketOptions>) => Socket;
28
+
29
+ export { lolySocket };
@@ -0,0 +1,18 @@
1
+ // modules/react/sockets/index.ts
2
+ import { io } from "socket.io-client";
3
+ var lolySocket = (namespace, opts) => {
4
+ const baseUrl = process.env.PUBLIC_WS_BASE_URL || window.location.origin;
5
+ const normalizedNamespace = namespace.startsWith("/") ? namespace : `/${namespace}`;
6
+ const fullUrl = `${baseUrl}${normalizedNamespace}`;
7
+ const socket = io(fullUrl, {
8
+ path: "/wss",
9
+ transports: ["websocket", "polling"],
10
+ autoConnect: true,
11
+ ...opts
12
+ });
13
+ return socket;
14
+ };
15
+ export {
16
+ lolySocket
17
+ };
18
+ //# sourceMappingURL=sockets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../modules/react/sockets/index.ts"],"sourcesContent":["import { io, ManagerOptions, Socket, SocketOptions } from \"socket.io-client\";\r\n\r\n/**\r\n * Creates a Socket.IO client connection to a specific namespace.\r\n * \r\n * This helper function simplifies Socket.IO client setup by handling:\r\n * - Namespace normalization (ensures leading slash)\r\n * - Base URL resolution (from environment or current origin)\r\n * - Default Socket.IO configuration (path: '/wss', transports: ['websocket', 'polling'])\r\n * \r\n * @param namespace - The namespace to connect to (e.g., '/chat' or 'chat').\r\n * The namespace will be normalized to always start with '/'.\r\n * Must match the namespace pattern defined in your server's WSS routes.\r\n * @param opts - Optional Socket.IO client options that will override the defaults.\r\n * \r\n * @returns A Socket.IO client instance connected to the specified namespace.\r\n * \r\n * @example\r\n * ```ts\r\n * const socket = lolySocket('/chat');\r\n * socket.on('message', (data) => {\r\n * console.log('Received:', data);\r\n * });\r\n * socket.emit('message', { text: 'Hello' });\r\n * ```\r\n */\r\nexport const lolySocket = (\r\n namespace: string,\r\n opts?: Partial<ManagerOptions & SocketOptions>\r\n): Socket => {\r\n const baseUrl = process.env.PUBLIC_WS_BASE_URL || window.location.origin;\r\n\r\n // Normalize namespace to always start with '/'\r\n const normalizedNamespace = namespace.startsWith(\"/\") ? namespace : `/${namespace}`;\r\n\r\n // In Socket.IO, when using a custom path, the namespace is specified in the URL:\r\n // baseUrl + namespace. The path '/wss' is the HTTP route where Socket.IO listens.\r\n const fullUrl = `${baseUrl}${normalizedNamespace}`;\r\n\r\n const socket = io(fullUrl, {\r\n path: \"/wss\",\r\n transports: [\"websocket\", \"polling\"],\r\n autoConnect: true,\r\n ...opts,\r\n });\r\n\r\n return socket;\r\n};\r\n"],"mappings":";AAAA,SAAS,UAAiD;AA0BnD,IAAM,aAAa,CACxB,WACA,SACW;AACX,QAAM,UAAU,QAAQ,IAAI,sBAAsB,OAAO,SAAS;AAGlE,QAAM,sBAAsB,UAAU,WAAW,GAAG,IAAI,YAAY,IAAI,SAAS;AAIjF,QAAM,UAAU,GAAG,OAAO,GAAG,mBAAmB;AAEhD,QAAM,SAAS,GAAG,SAAS;AAAA,IACzB,MAAM;AAAA,IACN,YAAY,CAAC,aAAa,SAAS;AAAA,IACnC,aAAa;AAAA,IACb,GAAG;AAAA,EACL,CAAC;AAED,SAAO;AACT;","names":[]}
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // modules/react/themes/index.ts
21
+ var themes_exports = {};
22
+ __export(themes_exports, {
23
+ ThemeProvider: () => ThemeProvider,
24
+ useTheme: () => useTheme
25
+ });
26
+ module.exports = __toCommonJS(themes_exports);
27
+
28
+ // modules/react/themes/theme-provider/index.tsx
29
+ var import_react2 = require("react");
30
+
31
+ // modules/react/hooks/useBroadcastChannel/index.tsx
32
+ var import_react = require("react");
33
+ var useBroadcastChannel = (channelName) => {
34
+ const [message, setMessage] = (0, import_react.useState)(null);
35
+ const channel = new BroadcastChannel(channelName);
36
+ (0, import_react.useEffect)(() => {
37
+ const handleMessage = (event) => {
38
+ setMessage(event.data);
39
+ };
40
+ channel.onmessage = handleMessage;
41
+ return () => {
42
+ channel.close();
43
+ };
44
+ }, [channel]);
45
+ const sendMessage = (msg) => {
46
+ channel.postMessage(msg);
47
+ };
48
+ return { message, sendMessage };
49
+ };
50
+
51
+ // modules/react/themes/theme-provider/index.tsx
52
+ var import_jsx_runtime = require("react/jsx-runtime");
53
+ var ThemeContext = (0, import_react2.createContext)({ theme: "light", handleThemeChange: () => {
54
+ } });
55
+ function getCookie(name) {
56
+ if (typeof document === "undefined") return null;
57
+ const value = `; ${document.cookie}`;
58
+ const parts = value.split(`; ${name}=`);
59
+ if (parts.length === 2) {
60
+ return parts.pop()?.split(";").shift() || null;
61
+ }
62
+ return null;
63
+ }
64
+ var ThemeProvider = ({
65
+ children,
66
+ initialTheme
67
+ }) => {
68
+ const { message: themeMessage, sendMessage } = useBroadcastChannel("theme_channel");
69
+ const [theme, setTheme] = (0, import_react2.useState)(() => {
70
+ if (initialTheme) return initialTheme;
71
+ if (typeof window !== "undefined") {
72
+ const windowData = window.__FW_DATA__;
73
+ if (windowData?.theme) return windowData.theme;
74
+ }
75
+ if (typeof window !== "undefined") {
76
+ const cookieTheme = getCookie("theme");
77
+ if (cookieTheme) return cookieTheme;
78
+ }
79
+ return "light";
80
+ });
81
+ (0, import_react2.useEffect)(() => {
82
+ if (!themeMessage) return;
83
+ if (themeMessage !== theme) {
84
+ setTheme(themeMessage);
85
+ }
86
+ }, [themeMessage, theme]);
87
+ (0, import_react2.useEffect)(() => {
88
+ const handleDataRefresh = () => {
89
+ if (typeof window !== "undefined") {
90
+ const windowData = window.__FW_DATA__;
91
+ if (windowData?.theme) {
92
+ setTheme((currentTheme) => {
93
+ if (windowData.theme !== currentTheme) {
94
+ return windowData.theme;
95
+ }
96
+ return currentTheme;
97
+ });
98
+ }
99
+ }
100
+ };
101
+ window.addEventListener("fw-data-refresh", handleDataRefresh);
102
+ return () => {
103
+ window.removeEventListener("fw-data-refresh", handleDataRefresh);
104
+ };
105
+ }, []);
106
+ (0, import_react2.useEffect)(() => {
107
+ if (initialTheme) {
108
+ setTheme(initialTheme);
109
+ }
110
+ }, [initialTheme]);
111
+ (0, import_react2.useEffect)(() => {
112
+ if (typeof document === "undefined") return;
113
+ const body = document.body;
114
+ const currentClasses = body.className.split(" ").filter(Boolean);
115
+ const themeClasses = ["light", "dark"];
116
+ const filteredClasses = currentClasses.filter(
117
+ (cls) => !themeClasses.includes(cls)
118
+ );
119
+ const newClassName = [...filteredClasses, theme].filter(Boolean).join(" ");
120
+ if (body.className !== newClassName) {
121
+ body.className = newClassName;
122
+ }
123
+ sendMessage(theme);
124
+ }, [theme, sendMessage]);
125
+ const handleThemeChange = (newTheme) => {
126
+ setTheme(newTheme);
127
+ document.cookie = `theme=${newTheme}; path=/; max-age=31536000`;
128
+ if (typeof window !== "undefined" && window.__FW_DATA__) {
129
+ window.__FW_DATA__ = {
130
+ ...window.__FW_DATA__,
131
+ theme: newTheme
132
+ };
133
+ }
134
+ };
135
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value: { theme, handleThemeChange }, children });
136
+ };
137
+ var useTheme = () => {
138
+ return (0, import_react2.useContext)(ThemeContext);
139
+ };
140
+ // Annotate the CommonJS export names for ESM import in node:
141
+ 0 && (module.exports = {
142
+ ThemeProvider,
143
+ useTheme
144
+ });
145
+ //# sourceMappingURL=themes.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../modules/react/themes/index.ts","../../modules/react/themes/theme-provider/index.tsx","../../modules/react/hooks/useBroadcastChannel/index.tsx"],"sourcesContent":["export {\r\n ThemeProvider,\r\n useTheme\r\n} from './theme-provider';","import React, { createContext, useContext, useState, useEffect } from \"react\";\r\nimport { useBroadcastChannel } from \"../../hooks/useBroadcastChannel\";\r\n\r\nconst ThemeContext = createContext<{\r\n theme: string;\r\n handleThemeChange: (theme: string) => void;\r\n}>({ theme: \"light\", handleThemeChange: () => {} });\r\n\r\n// Helper function to get cookie value\r\nfunction getCookie(name: string): string | null {\r\n if (typeof document === \"undefined\") return null;\r\n const value = `; ${document.cookie}`;\r\n const parts = value.split(`; ${name}=`);\r\n if (parts.length === 2) {\r\n return parts.pop()?.split(\";\").shift() || null;\r\n }\r\n return null;\r\n}\r\n\r\nexport const ThemeProvider = ({ \r\n children,\r\n initialTheme \r\n}: { \r\n children: React.ReactNode;\r\n initialTheme?: string;\r\n}) => {\r\n const { message: themeMessage, sendMessage } = useBroadcastChannel('theme_channel');\r\n\r\n // Initialize theme consistently between server and client\r\n // The server renders with initialTheme, and we must use the same value on client\r\n // to avoid hydration mismatch. Priority: initialTheme prop > window.__FW_DATA__ > cookie > default\r\n const [theme, setTheme] = useState<string>(() => {\r\n // 1. Use prop if provided (this should match what server rendered)\r\n if (initialTheme) return initialTheme;\r\n \r\n // 2. On client, use window.__FW_DATA__ from SSR (this is set before hydration)\r\n // This ensures consistency between server and client\r\n if (typeof window !== \"undefined\") {\r\n const windowData = (window as any).__FW_DATA__;\r\n if (windowData?.theme) return windowData.theme;\r\n }\r\n \r\n // 3. Fallback to cookie (only if window.__FW_DATA__ not available yet)\r\n if (typeof window !== \"undefined\") {\r\n const cookieTheme = getCookie(\"theme\");\r\n if (cookieTheme) return cookieTheme;\r\n }\r\n \r\n // Default fallback\r\n return \"light\";\r\n });\r\n\r\n // Listen for theme changes from broadcast channel (other tabs/windows)\r\n useEffect(() => {\r\n if (!themeMessage) return;\r\n if (themeMessage !== theme) {\r\n setTheme(themeMessage);\r\n }\r\n }, [themeMessage, theme]);\r\n\r\n // Listen for theme changes from window.__FW_DATA__ during SPA navigation\r\n useEffect(() => {\r\n const handleDataRefresh = () => {\r\n if (typeof window !== \"undefined\") {\r\n const windowData = (window as any).__FW_DATA__;\r\n if (windowData?.theme) {\r\n // Use functional update to avoid stale closure\r\n setTheme((currentTheme) => {\r\n if (windowData.theme !== currentTheme) {\r\n return windowData.theme;\r\n }\r\n return currentTheme;\r\n });\r\n }\r\n }\r\n };\r\n\r\n window.addEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n\r\n return () => {\r\n window.removeEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n };\r\n }, []);\r\n\r\n // Update theme when initialTheme prop changes (e.g., during SPA navigation)\r\n // This is the primary way theme updates during SPA navigation when layout re-renders\r\n useEffect(() => {\r\n if (initialTheme) {\r\n // Always update if initialTheme is provided, even if it's the same\r\n // This ensures theme syncs correctly during SPA navigation\r\n setTheme(initialTheme);\r\n }\r\n }, [initialTheme]);\r\n\r\n // Update body class when theme changes (skip during initial hydration to avoid mismatch)\r\n useEffect(() => {\r\n if (typeof document === \"undefined\") return;\r\n\r\n const body = document.body;\r\n const currentClasses = body.className.split(\" \").filter(Boolean);\r\n \r\n // Remove old theme classes (light, dark, etc.)\r\n const themeClasses = [\"light\", \"dark\"];\r\n const filteredClasses = currentClasses.filter(\r\n (cls) => !themeClasses.includes(cls)\r\n );\r\n \r\n // Add new theme class\r\n const newClassName = [...filteredClasses, theme].filter(Boolean).join(\" \");\r\n \r\n // Only update if different to avoid unnecessary DOM updates\r\n if (body.className !== newClassName) {\r\n body.className = newClassName;\r\n }\r\n\r\n sendMessage(theme);\r\n }, [theme, sendMessage]);\r\n\r\n const handleThemeChange = (newTheme: string) => {\r\n setTheme(newTheme);\r\n\r\n // Set theme cookie\r\n document.cookie = `theme=${newTheme}; path=/; max-age=31536000`; // 1 year expiry\r\n\r\n // Update window.__FW_DATA__.theme so getCurrentTheme() returns the correct value during navigation\r\n if (typeof window !== \"undefined\" && (window as any).__FW_DATA__) {\r\n (window as any).__FW_DATA__ = {\r\n ...(window as any).__FW_DATA__,\r\n theme: newTheme,\r\n };\r\n }\r\n };\r\n\r\n return (\r\n <ThemeContext.Provider value={{ theme, handleThemeChange }}>\r\n {children}\r\n </ThemeContext.Provider>\r\n );\r\n};\r\n\r\nexport const useTheme = () => {\r\n return useContext(ThemeContext);\r\n};\r\n","import React, { useEffect, useState } from \"react\";\r\n\r\nexport const useBroadcastChannel = (channelName: string) => {\r\n const [message, setMessage] = useState(null);\r\n const channel = new BroadcastChannel(channelName);\r\n\r\n useEffect(() => {\r\n const handleMessage = (event: MessageEvent) => {\r\n setMessage(event.data);\r\n };\r\n\r\n channel.onmessage = handleMessage;\r\n\r\n // Clean up the channel when the component unmounts\r\n return () => {\r\n channel.close();\r\n };\r\n }, [channel]);\r\n\r\n const sendMessage = (msg: unknown) => {\r\n channel.postMessage(msg);\r\n };\r\n\r\n return { message, sendMessage };\r\n};\r\n"],"mappings":"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","names":["import_react"]}
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ declare const ThemeProvider: ({ children, initialTheme }: {
5
+ children: React.ReactNode;
6
+ initialTheme?: string;
7
+ }) => react_jsx_runtime.JSX.Element;
8
+ declare const useTheme: () => {
9
+ theme: string;
10
+ handleThemeChange: (theme: string) => void;
11
+ };
12
+
13
+ export { ThemeProvider, useTheme };
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ declare const ThemeProvider: ({ children, initialTheme }: {
5
+ children: React.ReactNode;
6
+ initialTheme?: string;
7
+ }) => react_jsx_runtime.JSX.Element;
8
+ declare const useTheme: () => {
9
+ theme: string;
10
+ handleThemeChange: (theme: string) => void;
11
+ };
12
+
13
+ export { ThemeProvider, useTheme };
@@ -0,0 +1,117 @@
1
+ // modules/react/themes/theme-provider/index.tsx
2
+ import { createContext, useContext, useState as useState2, useEffect as useEffect2 } from "react";
3
+
4
+ // modules/react/hooks/useBroadcastChannel/index.tsx
5
+ import { useEffect, useState } from "react";
6
+ var useBroadcastChannel = (channelName) => {
7
+ const [message, setMessage] = useState(null);
8
+ const channel = new BroadcastChannel(channelName);
9
+ useEffect(() => {
10
+ const handleMessage = (event) => {
11
+ setMessage(event.data);
12
+ };
13
+ channel.onmessage = handleMessage;
14
+ return () => {
15
+ channel.close();
16
+ };
17
+ }, [channel]);
18
+ const sendMessage = (msg) => {
19
+ channel.postMessage(msg);
20
+ };
21
+ return { message, sendMessage };
22
+ };
23
+
24
+ // modules/react/themes/theme-provider/index.tsx
25
+ import { jsx } from "react/jsx-runtime";
26
+ var ThemeContext = createContext({ theme: "light", handleThemeChange: () => {
27
+ } });
28
+ function getCookie(name) {
29
+ if (typeof document === "undefined") return null;
30
+ const value = `; ${document.cookie}`;
31
+ const parts = value.split(`; ${name}=`);
32
+ if (parts.length === 2) {
33
+ return parts.pop()?.split(";").shift() || null;
34
+ }
35
+ return null;
36
+ }
37
+ var ThemeProvider = ({
38
+ children,
39
+ initialTheme
40
+ }) => {
41
+ const { message: themeMessage, sendMessage } = useBroadcastChannel("theme_channel");
42
+ const [theme, setTheme] = useState2(() => {
43
+ if (initialTheme) return initialTheme;
44
+ if (typeof window !== "undefined") {
45
+ const windowData = window.__FW_DATA__;
46
+ if (windowData?.theme) return windowData.theme;
47
+ }
48
+ if (typeof window !== "undefined") {
49
+ const cookieTheme = getCookie("theme");
50
+ if (cookieTheme) return cookieTheme;
51
+ }
52
+ return "light";
53
+ });
54
+ useEffect2(() => {
55
+ if (!themeMessage) return;
56
+ if (themeMessage !== theme) {
57
+ setTheme(themeMessage);
58
+ }
59
+ }, [themeMessage, theme]);
60
+ useEffect2(() => {
61
+ const handleDataRefresh = () => {
62
+ if (typeof window !== "undefined") {
63
+ const windowData = window.__FW_DATA__;
64
+ if (windowData?.theme) {
65
+ setTheme((currentTheme) => {
66
+ if (windowData.theme !== currentTheme) {
67
+ return windowData.theme;
68
+ }
69
+ return currentTheme;
70
+ });
71
+ }
72
+ }
73
+ };
74
+ window.addEventListener("fw-data-refresh", handleDataRefresh);
75
+ return () => {
76
+ window.removeEventListener("fw-data-refresh", handleDataRefresh);
77
+ };
78
+ }, []);
79
+ useEffect2(() => {
80
+ if (initialTheme) {
81
+ setTheme(initialTheme);
82
+ }
83
+ }, [initialTheme]);
84
+ useEffect2(() => {
85
+ if (typeof document === "undefined") return;
86
+ const body = document.body;
87
+ const currentClasses = body.className.split(" ").filter(Boolean);
88
+ const themeClasses = ["light", "dark"];
89
+ const filteredClasses = currentClasses.filter(
90
+ (cls) => !themeClasses.includes(cls)
91
+ );
92
+ const newClassName = [...filteredClasses, theme].filter(Boolean).join(" ");
93
+ if (body.className !== newClassName) {
94
+ body.className = newClassName;
95
+ }
96
+ sendMessage(theme);
97
+ }, [theme, sendMessage]);
98
+ const handleThemeChange = (newTheme) => {
99
+ setTheme(newTheme);
100
+ document.cookie = `theme=${newTheme}; path=/; max-age=31536000`;
101
+ if (typeof window !== "undefined" && window.__FW_DATA__) {
102
+ window.__FW_DATA__ = {
103
+ ...window.__FW_DATA__,
104
+ theme: newTheme
105
+ };
106
+ }
107
+ };
108
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme, handleThemeChange }, children });
109
+ };
110
+ var useTheme = () => {
111
+ return useContext(ThemeContext);
112
+ };
113
+ export {
114
+ ThemeProvider,
115
+ useTheme
116
+ };
117
+ //# sourceMappingURL=themes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../modules/react/themes/theme-provider/index.tsx","../../modules/react/hooks/useBroadcastChannel/index.tsx"],"sourcesContent":["import React, { createContext, useContext, useState, useEffect } from \"react\";\r\nimport { useBroadcastChannel } from \"../../hooks/useBroadcastChannel\";\r\n\r\nconst ThemeContext = createContext<{\r\n theme: string;\r\n handleThemeChange: (theme: string) => void;\r\n}>({ theme: \"light\", handleThemeChange: () => {} });\r\n\r\n// Helper function to get cookie value\r\nfunction getCookie(name: string): string | null {\r\n if (typeof document === \"undefined\") return null;\r\n const value = `; ${document.cookie}`;\r\n const parts = value.split(`; ${name}=`);\r\n if (parts.length === 2) {\r\n return parts.pop()?.split(\";\").shift() || null;\r\n }\r\n return null;\r\n}\r\n\r\nexport const ThemeProvider = ({ \r\n children,\r\n initialTheme \r\n}: { \r\n children: React.ReactNode;\r\n initialTheme?: string;\r\n}) => {\r\n const { message: themeMessage, sendMessage } = useBroadcastChannel('theme_channel');\r\n\r\n // Initialize theme consistently between server and client\r\n // The server renders with initialTheme, and we must use the same value on client\r\n // to avoid hydration mismatch. Priority: initialTheme prop > window.__FW_DATA__ > cookie > default\r\n const [theme, setTheme] = useState<string>(() => {\r\n // 1. Use prop if provided (this should match what server rendered)\r\n if (initialTheme) return initialTheme;\r\n \r\n // 2. On client, use window.__FW_DATA__ from SSR (this is set before hydration)\r\n // This ensures consistency between server and client\r\n if (typeof window !== \"undefined\") {\r\n const windowData = (window as any).__FW_DATA__;\r\n if (windowData?.theme) return windowData.theme;\r\n }\r\n \r\n // 3. Fallback to cookie (only if window.__FW_DATA__ not available yet)\r\n if (typeof window !== \"undefined\") {\r\n const cookieTheme = getCookie(\"theme\");\r\n if (cookieTheme) return cookieTheme;\r\n }\r\n \r\n // Default fallback\r\n return \"light\";\r\n });\r\n\r\n // Listen for theme changes from broadcast channel (other tabs/windows)\r\n useEffect(() => {\r\n if (!themeMessage) return;\r\n if (themeMessage !== theme) {\r\n setTheme(themeMessage);\r\n }\r\n }, [themeMessage, theme]);\r\n\r\n // Listen for theme changes from window.__FW_DATA__ during SPA navigation\r\n useEffect(() => {\r\n const handleDataRefresh = () => {\r\n if (typeof window !== \"undefined\") {\r\n const windowData = (window as any).__FW_DATA__;\r\n if (windowData?.theme) {\r\n // Use functional update to avoid stale closure\r\n setTheme((currentTheme) => {\r\n if (windowData.theme !== currentTheme) {\r\n return windowData.theme;\r\n }\r\n return currentTheme;\r\n });\r\n }\r\n }\r\n };\r\n\r\n window.addEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n\r\n return () => {\r\n window.removeEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n };\r\n }, []);\r\n\r\n // Update theme when initialTheme prop changes (e.g., during SPA navigation)\r\n // This is the primary way theme updates during SPA navigation when layout re-renders\r\n useEffect(() => {\r\n if (initialTheme) {\r\n // Always update if initialTheme is provided, even if it's the same\r\n // This ensures theme syncs correctly during SPA navigation\r\n setTheme(initialTheme);\r\n }\r\n }, [initialTheme]);\r\n\r\n // Update body class when theme changes (skip during initial hydration to avoid mismatch)\r\n useEffect(() => {\r\n if (typeof document === \"undefined\") return;\r\n\r\n const body = document.body;\r\n const currentClasses = body.className.split(\" \").filter(Boolean);\r\n \r\n // Remove old theme classes (light, dark, etc.)\r\n const themeClasses = [\"light\", \"dark\"];\r\n const filteredClasses = currentClasses.filter(\r\n (cls) => !themeClasses.includes(cls)\r\n );\r\n \r\n // Add new theme class\r\n const newClassName = [...filteredClasses, theme].filter(Boolean).join(\" \");\r\n \r\n // Only update if different to avoid unnecessary DOM updates\r\n if (body.className !== newClassName) {\r\n body.className = newClassName;\r\n }\r\n\r\n sendMessage(theme);\r\n }, [theme, sendMessage]);\r\n\r\n const handleThemeChange = (newTheme: string) => {\r\n setTheme(newTheme);\r\n\r\n // Set theme cookie\r\n document.cookie = `theme=${newTheme}; path=/; max-age=31536000`; // 1 year expiry\r\n\r\n // Update window.__FW_DATA__.theme so getCurrentTheme() returns the correct value during navigation\r\n if (typeof window !== \"undefined\" && (window as any).__FW_DATA__) {\r\n (window as any).__FW_DATA__ = {\r\n ...(window as any).__FW_DATA__,\r\n theme: newTheme,\r\n };\r\n }\r\n };\r\n\r\n return (\r\n <ThemeContext.Provider value={{ theme, handleThemeChange }}>\r\n {children}\r\n </ThemeContext.Provider>\r\n );\r\n};\r\n\r\nexport const useTheme = () => {\r\n return useContext(ThemeContext);\r\n};\r\n","import React, { useEffect, useState } from \"react\";\r\n\r\nexport const useBroadcastChannel = (channelName: string) => {\r\n const [message, setMessage] = useState(null);\r\n const channel = new BroadcastChannel(channelName);\r\n\r\n useEffect(() => {\r\n const handleMessage = (event: MessageEvent) => {\r\n setMessage(event.data);\r\n };\r\n\r\n channel.onmessage = handleMessage;\r\n\r\n // Clean up the channel when the component unmounts\r\n return () => {\r\n channel.close();\r\n };\r\n }, [channel]);\r\n\r\n const sendMessage = (msg: unknown) => {\r\n channel.postMessage(msg);\r\n };\r\n\r\n return { message, sendMessage };\r\n};\r\n"],"mappings":"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","names":["useState","useEffect","useState","useEffect"]}