camox 0.40.0 → 0.41.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 (97) hide show
  1. package/dist/components/PlatformLabel.js +62 -0
  2. package/dist/core/components/lexical/GradientNode.js +126 -0
  3. package/dist/core/components/lexical/InlineLexicalEditor.js +37 -56
  4. package/dist/core/components/lexical/InlineStylesPlugin.js +183 -0
  5. package/dist/core/components/lexical/SelectionBroadcaster.js +49 -46
  6. package/dist/core/components/lexical/SidebarLexicalEditor.js +197 -151
  7. package/dist/core/components/lexical/editorConfig.js +25 -7
  8. package/dist/core/components/lexical/selectTextLink.js +21 -0
  9. package/dist/core/createApp.d.ts +30 -17
  10. package/dist/core/createApp.js +14 -3
  11. package/dist/core/createBlock.d.ts +2 -2
  12. package/dist/core/createBlock.js +18 -15
  13. package/dist/core/createLayout.d.ts +48 -4
  14. package/dist/core/createLayout.js +51 -23
  15. package/dist/core/derivedRoutes.js +36 -0
  16. package/dist/core/editing/createEditableBlock.d.ts +9 -8
  17. package/dist/core/editing/createEditableBlock.js +167 -168
  18. package/dist/core/lib/lexicalReact.d.ts +1 -26
  19. package/dist/core/lib/lexicalReact.js +46 -60
  20. package/dist/core/lib/lexicalState.js +164 -81
  21. package/dist/core/lib/modifierFormats.js +4 -15
  22. package/dist/core/lib/textStyles.d.ts +27 -0
  23. package/dist/core/lib/textStyles.js +47 -0
  24. package/dist/features/navigation/navigation.d.ts +2 -0
  25. package/dist/features/navigation/navigation.js +51 -46
  26. package/dist/features/page/DerivedPageContent.js +61 -0
  27. package/dist/features/page/PublishedPageContent.js +52 -83
  28. package/dist/features/page/SharedLayoutContent.js +66 -0
  29. package/dist/features/preview/CamoxPreview.d.ts +16 -1
  30. package/dist/features/preview/CamoxPreview.js +242 -265
  31. package/dist/features/preview/DerivedPreview.js +137 -0
  32. package/dist/features/preview/EditablePageExperience.js +25 -8
  33. package/dist/features/preview/components/AddBlockSidebar.js +43 -33
  34. package/dist/features/preview/components/AssetLightbox.js +1 -1
  35. package/dist/features/preview/components/BlockThumbnail.js +192 -0
  36. package/dist/features/preview/components/CreatePageModal.js +123 -115
  37. package/dist/features/preview/components/DerivedLayoutDialog.js +100 -0
  38. package/dist/features/preview/components/DerivedLayoutSidebar.d.ts +5 -0
  39. package/dist/features/preview/components/DerivedLayoutSidebar.js +163 -0
  40. package/dist/features/preview/components/DerivedPageInfoSidebar.js +57 -0
  41. package/dist/features/preview/components/FieldToolbar.js +42 -20
  42. package/dist/features/preview/components/Frame.js +133 -140
  43. package/dist/features/preview/components/LeftSidebar.js +42 -38
  44. package/dist/features/preview/components/MobilePreviewDrawer.js +4 -4
  45. package/dist/features/preview/components/Overlays.js +57 -42
  46. package/dist/features/preview/components/PageInfoSidebar.js +63 -55
  47. package/dist/features/preview/components/PageNavigatorSidebar.js +34 -483
  48. package/dist/features/preview/components/PagePicker.js +205 -153
  49. package/dist/features/preview/components/PageTree.js +298 -206
  50. package/dist/features/preview/components/PreviewActivation.js +78 -0
  51. package/dist/features/preview/components/PreviewPanel.js +67 -35
  52. package/dist/features/preview/components/PreviewToolbar.js +218 -232
  53. package/dist/features/preview/components/PublicationRow.js +431 -0
  54. package/dist/features/preview/components/PublishDialog.js +180 -97
  55. package/dist/features/preview/components/RightSidebar.js +19 -34
  56. package/dist/features/preview/components/previewStyles.js +8 -0
  57. package/dist/features/preview/components/useUpdateBlockPosition.js +7 -13
  58. package/dist/features/preview/previewConstants.js +8 -0
  59. package/dist/features/preview/previewStore.js +0 -10
  60. package/dist/features/preview/publication.js +71 -0
  61. package/dist/features/provider/AuthenticatedCamoxProvider.js +2 -1
  62. package/dist/features/provider/CoreCamoxProvider.js +11 -2
  63. package/dist/features/provider/LocalhostPreviewProvider.js +6 -7
  64. package/dist/features/routes/pageRuntime.d.ts +10 -0
  65. package/dist/features/routes/pageRuntime.js +7 -9
  66. package/dist/features/runtime/PreviewDocumentContext.js +7 -0
  67. package/dist/features/runtime/RuntimeChrome.js +137 -0
  68. package/dist/features/runtime/SharedChromeContext.js +7 -0
  69. package/dist/features/runtime/navigationRequest.js +21 -0
  70. package/dist/features/runtime/navigationTarget.js +23 -0
  71. package/dist/features/runtime/pageApp.js +196 -121
  72. package/dist/features/runtime/pageNavigation.js +79 -130
  73. package/dist/features/runtime/runtime.d.ts +11 -0
  74. package/dist/features/runtime/runtime.js +183 -47
  75. package/dist/features/runtime/studioApp.d.ts +2 -11
  76. package/dist/features/runtime/studioApp.js +14 -177
  77. package/dist/features/studio/CamoxStudio.js +27 -13
  78. package/dist/features/studio/components/Navbar.js +80 -74
  79. package/dist/features/studio/studioTheme.js +25 -0
  80. package/dist/features/studio/useTheme.js +94 -109
  81. package/dist/features/vite/appGeneration.js +12 -3
  82. package/dist/features/vite/definitionsSync.js +4 -2
  83. package/dist/features/vite/layoutGeneration.js +38 -0
  84. package/dist/features/vite/runtimeDev.js +3 -1
  85. package/dist/lib/auth.js +15 -13
  86. package/dist/lib/normalized-data.js +4 -4
  87. package/dist/lib/platform.js +13 -0
  88. package/dist/lib/utils.js +90 -38
  89. package/dist/studio-overlays.css +5 -40
  90. package/dist/studio.css +1 -1
  91. package/package.json +8 -4
  92. package/skills/camox/SKILL.md +2 -0
  93. package/skills/camox/references/block-definitions.md +31 -12
  94. package/skills/camox/references/layout-definitions.md +2 -0
  95. package/dist/core/lib/modifiers.js +0 -24
  96. package/dist/features/preview/previewQueryFns.js +0 -23
  97. package/dist/features/runtime/studioNavigation.js +0 -120
@@ -1,127 +1,112 @@
1
1
  import { actionsStore } from "../provider/actionsStore.js";
2
+ import { STUDIO_THEME_STORAGE_KEY, bootstrapStudioTheme, readStudioTheme } from "./studioTheme.js";
2
3
  import { c } from "react/compiler-runtime";
3
4
  import * as React from "react";
4
5
 
5
6
  //#region src/features/studio/useTheme.ts
6
7
  let activeThemeOwnerCount = 0;
8
+ const listeners = /* @__PURE__ */ new Set();
9
+ let preference;
7
10
  function readStoredTheme() {
8
11
  if (typeof window === "undefined") return "system";
9
- return localStorage.getItem("theme") || "system";
12
+ return preference ?? readStudioTheme();
13
+ }
14
+ function subscribe(listener) {
15
+ listeners.add(listener);
16
+ return () => {
17
+ listeners.delete(listener);
18
+ };
19
+ }
20
+ function notify() {
21
+ listeners.forEach((listener) => listener());
22
+ }
23
+ function applyTheme(theme = readStoredTheme()) {
24
+ bootstrapStudioTheme(theme);
25
+ const resolved = document.documentElement.dataset.camoxStudioTheme;
26
+ document.body.classList.remove("light", "dark");
27
+ document.body.classList.add("camox-studio-theme", resolved);
28
+ document.body.dataset.camoxStudioTheme = resolved;
29
+ }
30
+ function setTheme(theme) {
31
+ preference = theme;
32
+ try {
33
+ localStorage.setItem(STUDIO_THEME_STORAGE_KEY, theme);
34
+ } catch {}
35
+ applyTheme(theme);
36
+ notify();
10
37
  }
11
- /**
12
- * Owns the studio theme: writes the active class onto `<html>` and persists
13
- * changes to localStorage. Should only be mounted from the studio chrome —
14
- * never from contexts that share `<html>` with the user's site.
15
- */
16
38
  function useApplyTheme() {
17
- const $ = c(10);
18
- if ($[0] !== "da3935c3f496f05138d1e012522f8d34be97b470fa5c8f37185df49127eab10f") {
19
- for (let $i = 0; $i < 10; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
20
- $[0] = "da3935c3f496f05138d1e012522f8d34be97b470fa5c8f37185df49127eab10f";
39
+ const $ = c(5);
40
+ if ($[0] !== "5860ae8e48f7dc27e488236def482df22f144de61ae2d86bfde82aeeea4f9874") {
41
+ for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
42
+ $[0] = "5860ae8e48f7dc27e488236def482df22f144de61ae2d86bfde82aeeea4f9874";
21
43
  }
22
- const [theme, setTheme] = React.useState(readStoredTheme);
23
- const [resolvedTheme, setResolvedTheme] = React.useState("light");
44
+ const theme = React.useSyncExternalStore(subscribe, readStoredTheme, _temp2);
45
+ const resolvedTheme = React.useSyncExternalStore(subscribe, _temp3, _temp4);
24
46
  let t0;
47
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
48
+ t0 = [];
49
+ $[1] = t0;
50
+ } else t0 = $[1];
51
+ React.useEffect(_temp7, t0);
25
52
  let t1;
26
- if ($[1] !== theme) {
27
- t0 = () => {
28
- const root = window.document.documentElement;
29
- const body = window.document.body;
30
- activeThemeOwnerCount = activeThemeOwnerCount + 1;
31
- const applyTheme = (themeToApply) => {
32
- setResolvedTheme(themeToApply);
33
- root.classList.remove("light", "dark");
34
- root.classList.add(themeToApply);
35
- root.dataset.camoxStudioTheme = themeToApply;
36
- body.classList.remove("light", "dark");
37
- body.classList.add("camox-studio-theme", themeToApply);
38
- body.dataset.camoxStudioTheme = themeToApply;
39
- };
40
- const resolveTheme = () => {
41
- if (theme !== "system") return theme;
42
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
43
- };
44
- applyTheme(resolveTheme());
45
- const observer = new MutationObserver(() => {
46
- const themeToApply_0 = resolveTheme();
47
- if (root.classList.contains(themeToApply_0) && body.classList.contains(themeToApply_0)) return;
48
- applyTheme(themeToApply_0);
49
- });
50
- observer.observe(root, {
51
- attributes: true,
52
- attributeFilter: ["class"]
53
- });
54
- observer.observe(body, {
55
- attributes: true,
56
- attributeFilter: ["class"]
57
- });
58
- if (theme === "system") {
59
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
60
- const updateSystemTheme = () => applyTheme(resolveTheme());
61
- mediaQuery.addEventListener("change", updateSystemTheme);
62
- return () => {
63
- mediaQuery.removeEventListener("change", updateSystemTheme);
64
- observer.disconnect();
65
- activeThemeOwnerCount = activeThemeOwnerCount - 1;
66
- if (activeThemeOwnerCount > 0) return;
67
- root.classList.remove("light", "dark");
68
- delete root.dataset.camoxStudioTheme;
69
- body.classList.remove("camox-studio-theme", "light", "dark");
70
- delete body.dataset.camoxStudioTheme;
71
- };
72
- }
73
- return () => {
74
- observer.disconnect();
75
- activeThemeOwnerCount = activeThemeOwnerCount - 1;
76
- if (activeThemeOwnerCount > 0) return;
77
- root.classList.remove("light", "dark");
78
- delete root.dataset.camoxStudioTheme;
79
- body.classList.remove("camox-studio-theme", "light", "dark");
80
- delete body.dataset.camoxStudioTheme;
81
- };
82
- };
83
- t1 = [theme];
84
- $[1] = theme;
85
- $[2] = t0;
86
- $[3] = t1;
87
- } else {
88
- t0 = $[2];
89
- t1 = $[3];
90
- }
91
- React.useEffect(t0, t1);
92
- let t2;
93
- let t3;
94
- if ($[4] !== theme) {
95
- t2 = () => {
96
- localStorage.setItem("theme", theme);
97
- };
98
- t3 = [theme];
99
- $[4] = theme;
100
- $[5] = t2;
101
- $[6] = t3;
102
- } else {
103
- t2 = $[5];
104
- t3 = $[6];
105
- }
106
- React.useEffect(t2, t3);
107
- let t4;
108
- if ($[7] !== resolvedTheme || $[8] !== theme) {
109
- t4 = {
53
+ if ($[2] !== resolvedTheme || $[3] !== theme) {
54
+ t1 = {
110
55
  theme,
111
56
  resolvedTheme,
112
57
  setTheme
113
58
  };
114
- $[7] = resolvedTheme;
115
- $[8] = theme;
116
- $[9] = t4;
117
- } else t4 = $[9];
118
- return t4;
59
+ $[2] = resolvedTheme;
60
+ $[3] = theme;
61
+ $[4] = t1;
62
+ } else t1 = $[4];
63
+ return t1;
64
+ }
65
+ function _temp7() {
66
+ const root = window.document.documentElement;
67
+ const body = window.document.body;
68
+ activeThemeOwnerCount = activeThemeOwnerCount + 1;
69
+ setTheme(readStoredTheme());
70
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
71
+ const updateSystemTheme = _temp5;
72
+ const onStorage = _temp6;
73
+ mediaQuery.addEventListener("change", updateSystemTheme);
74
+ window.addEventListener("storage", onStorage);
75
+ return () => {
76
+ mediaQuery.removeEventListener("change", updateSystemTheme);
77
+ window.removeEventListener("storage", onStorage);
78
+ activeThemeOwnerCount = activeThemeOwnerCount - 1;
79
+ if (activeThemeOwnerCount > 0) return;
80
+ root.classList.remove("light", "dark");
81
+ root.style.removeProperty("color-scheme");
82
+ delete root.dataset.camoxStudioTheme;
83
+ body.classList.remove("camox-studio-theme", "light", "dark");
84
+ delete body.dataset.camoxStudioTheme;
85
+ };
86
+ }
87
+ function _temp6(event) {
88
+ if (event.key !== "camox:studio:theme" && event.key !== null) return;
89
+ preference = void 0;
90
+ applyTheme();
91
+ notify();
92
+ }
93
+ function _temp5() {
94
+ if (readStoredTheme() === "system") setTheme("system");
95
+ }
96
+ function _temp4() {
97
+ return "light";
98
+ }
99
+ function _temp3() {
100
+ return document.documentElement.dataset.camoxStudioTheme === "dark" ? "dark" : "light";
101
+ }
102
+ function _temp2() {
103
+ return "system";
119
104
  }
120
105
  function useThemeActions() {
121
106
  const $ = c(5);
122
- if ($[0] !== "da3935c3f496f05138d1e012522f8d34be97b470fa5c8f37185df49127eab10f") {
107
+ if ($[0] !== "5860ae8e48f7dc27e488236def482df22f144de61ae2d86bfde82aeeea4f9874") {
123
108
  for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
124
- $[0] = "da3935c3f496f05138d1e012522f8d34be97b470fa5c8f37185df49127eab10f";
109
+ $[0] = "5860ae8e48f7dc27e488236def482df22f144de61ae2d86bfde82aeeea4f9874";
125
110
  }
126
111
  const { theme, setTheme } = useApplyTheme();
127
112
  let t0;
@@ -138,9 +123,9 @@ function useThemeActions() {
138
123
  "Color mode"
139
124
  ],
140
125
  groupLabel: "Studio",
141
- checkIfAvailable: _temp,
126
+ checkIfAvailable: _temp8,
142
127
  hasChildren: true,
143
- execute: _temp2
128
+ execute: _temp9
144
129
  },
145
130
  {
146
131
  id: "switch-to-light-theme",
@@ -177,7 +162,7 @@ function useThemeActions() {
177
162
  return () => {
178
163
  actionsStore.send({
179
164
  type: "unregisterManyActions",
180
- ids: actions.map(_temp3)
165
+ ids: actions.map(_temp0)
181
166
  });
182
167
  };
183
168
  };
@@ -192,11 +177,11 @@ function useThemeActions() {
192
177
  }
193
178
  React.useEffect(t0, t1);
194
179
  }
195
- function _temp3(a) {
180
+ function _temp0(a) {
196
181
  return a.id;
197
182
  }
198
- function _temp2() {}
199
- function _temp() {
183
+ function _temp9() {}
184
+ function _temp8() {
200
185
  return true;
201
186
  }
202
187
 
@@ -1,4 +1,5 @@
1
1
  import { writeIfChanged } from "./utils.js";
2
+ import { generateLayoutFiles } from "./layoutGeneration.js";
2
3
  import { readFileSync, writeFileSync } from "node:fs";
3
4
  import { relative, resolve } from "node:path";
4
5
 
@@ -28,16 +29,16 @@ const blocks = [...Object.values(blockModules), ...Object.values(legacyBlockModu
28
29
  );
29
30
 
30
31
  // Auto-import all layouts from the first-class layouts directory
31
- const layoutModules = import.meta.glob<{ layout: Layout }>(
32
+ const layoutModules = import.meta.glob<{ layout?: Layout; Layout?: Layout }>(
32
33
  '../layouts/*.{ts,tsx}',
33
34
  { eager: true },
34
35
  );
35
- const legacyLayoutModules = import.meta.glob<{ layout: Layout }>(
36
+ const legacyLayoutModules = import.meta.glob<{ layout?: Layout; Layout?: Layout }>(
36
37
  './layouts/*.{ts,tsx}',
37
38
  { eager: true },
38
39
  );
39
40
  const layouts = [...Object.values(layoutModules), ...Object.values(legacyLayoutModules)].map(
40
- (mod) => mod.layout,
41
+ (mod) => (mod.Layout ?? mod.layout)!,
41
42
  );
42
43
 
43
44
  export const camoxApp = createApp({
@@ -53,9 +54,17 @@ function getAppFileEntries(appRoot) {
53
54
  }];
54
55
  }
55
56
  function generateAppFile(appRoot) {
57
+ generateLayoutFiles(appRoot);
56
58
  for (const entry of getAppFileEntries(appRoot)) writeIfChanged(entry.path, entry.content);
57
59
  }
58
60
  function watchAppFile(server, appRoot) {
61
+ for (const event of [
62
+ "add",
63
+ "change",
64
+ "unlink"
65
+ ]) server.watcher.on(event, (path) => {
66
+ if (path.startsWith(resolve(appRoot, "src/layouts") + "/")) generateLayoutFiles(appRoot);
67
+ });
59
68
  const entries = getAppFileEntries(appRoot);
60
69
  const expectedByPath = new Map(entries.map((e) => [e.path, e.content]));
61
70
  server.watcher.on("change", (changedPath) => {
@@ -32,7 +32,8 @@ async function syncDefinitionsToApi(options) {
32
32
  settingsSchema: block._internal.settingsSchema,
33
33
  defaultContent: block._internal.getInitialContent(),
34
34
  defaultSettings: block._internal.getInitialSettings(),
35
- layoutOnly: block._internal.layoutOnly || void 0
35
+ layoutOnly: block._internal.layoutOnly || void 0,
36
+ synced: block._internal.synced
36
37
  }));
37
38
  let environmentCreated = false;
38
39
  let deletedDefinitionTypes = [];
@@ -186,7 +187,8 @@ async function syncDefinitions(server, options) {
186
187
  settingsSchema: block._internal.settingsSchema,
187
188
  defaultContent: block._internal.getInitialContent(),
188
189
  defaultSettings: block._internal.getInitialSettings(),
189
- layoutOnly: block._internal.layoutOnly || void 0
190
+ layoutOnly: block._internal.layoutOnly || void 0,
191
+ synced: block._internal.synced
190
192
  });
191
193
  } catch (error) {
192
194
  throwIfSyncAuthError(error);
@@ -0,0 +1,38 @@
1
+ import { writeIfChanged } from "./utils.js";
2
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { basename, resolve } from "node:path";
4
+
5
+ //#region src/features/vite/layoutGeneration.ts
6
+ /** Keep file identities stable across moves without executing application modules. */
7
+ function generateLayoutFiles(appRoot) {
8
+ const directory = resolve(appRoot, "src/layouts");
9
+ if (!existsSync(directory)) return;
10
+ const declarations = [];
11
+ for (const file of readdirSync(directory).sort()) {
12
+ if (!/\.(ts|tsx)$/.test(file) || file.endsWith(".d.ts")) continue;
13
+ const id = basename(file).replace(/\.(ts|tsx)$/, "");
14
+ const path = resolve(directory, file);
15
+ let source = readFileSync(path, "utf8");
16
+ if (!source.trim()) source = `import { createLayout } from "camox/createLayout";
17
+
18
+ export const Layout = createLayout(${JSON.stringify(id)})({
19
+ kind: "curated",
20
+ title: ${JSON.stringify(id)},
21
+ description: "",
22
+ blocks: { before: [], after: [] },
23
+ buildMetaTitle: ({ pageMetaTitle }) => pageMetaTitle,
24
+ component: ({ children }) => <main><Layout.BeforeBlocks />{children}<Layout.AfterBlocks /></main>,
25
+ });
26
+ `;
27
+ source = source.replace(/(createLayout\(\s*)["'][^"']+["'](\s*\)\s*\()/g, `$1${JSON.stringify(id)}$2`);
28
+ writeIfChanged(path, source);
29
+ const segments = id.split(".");
30
+ const route = "/" + segments.map((segment) => segment.startsWith("$") ? `:${segment.slice(1)}` : segment).join("/");
31
+ const params = segments.filter((segment) => segment.startsWith("$")).map((segment) => `${JSON.stringify(segment.slice(1))}: string`).join("; ");
32
+ declarations.push(`${JSON.stringify(id)}: { route: ${JSON.stringify(route)}; params: { ${params} } };`);
33
+ }
34
+ writeIfChanged(resolve(appRoot, "src/camox/layouts.gen.d.ts"), `// Generated by Camox.\nimport "camox/createLayout";\ndeclare module "camox/createLayout" {\n interface LayoutFileRoutes {\n ${declarations.join("\n ")}\n }\n}\n`);
35
+ }
36
+
37
+ //#endregion
38
+ export { generateLayoutFiles };
@@ -79,7 +79,7 @@ const blocks = [...Object.values(rootBlockModules), ...Object.values(legacyBlock
79
79
  .map((mod) => mod.block)
80
80
  .filter(Boolean);
81
81
  const layouts = [...Object.values(rootLayoutModules), ...Object.values(legacyLayoutModules)]
82
- .map((mod) => mod.layout)
82
+ .map((mod) => mod.Layout ?? mod.layout)
83
83
  .filter(Boolean);
84
84
 
85
85
  export const camoxApp = createApp({ blocks, layouts });
@@ -146,6 +146,7 @@ function generateVirtualCamoxServer(runtimeBasePath) {
146
146
  import { camoxApp } from "virtual:camox/app";
147
147
  import { camoxDocument } from "virtual:camox/document";
148
148
  import appStylesheetUrl from "virtual:camox/app-stylesheet-url";
149
+ import studioStylesheetUrl from "virtual:camox-studio-css";
149
150
  import pageClientEntryUrl from "virtual:camox/page-client-url";
150
151
  import studioClientEntryUrl from "virtual:camox/studio-client-url";
151
152
  import { renderPage } from "virtual:camox/page-server";
@@ -165,6 +166,7 @@ export async function handleCamoxRequest(request) {
165
166
  renderStudio,
166
167
  runtimeBasePath: ${JSON.stringify(runtimeBasePath)},
167
168
  stylesheetUrl: appStylesheetUrl,
169
+ studioStylesheetUrl,
168
170
  });
169
171
  }
170
172
  `;
package/dist/lib/auth.js CHANGED
@@ -217,9 +217,9 @@ function useProcessOtt(authClient) {
217
217
  const AuthContext = React.createContext(null);
218
218
  function useAuthContext() {
219
219
  const $ = c(1);
220
- if ($[0] !== "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93") {
220
+ if ($[0] !== "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b") {
221
221
  for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
222
- $[0] = "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93";
222
+ $[0] = "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b";
223
223
  }
224
224
  const ctx = React.useContext(AuthContext);
225
225
  if (!ctx) throw new Error("Missing CamoxProvider");
@@ -227,34 +227,36 @@ function useAuthContext() {
227
227
  }
228
228
  function useProjectSlug() {
229
229
  const $ = c(1);
230
- if ($[0] !== "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93") {
230
+ if ($[0] !== "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b") {
231
231
  for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
232
- $[0] = "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93";
232
+ $[0] = "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b";
233
233
  }
234
234
  return useAuthContext().projectSlug;
235
235
  }
236
+ const subscribeToHydration = () => () => {};
236
237
  function useAuthState() {
237
- const { authClient } = useAuthContext();
238
+ const { authClient, initialAuthenticated = false } = useAuthContext();
238
239
  const { data: session, isPending } = authClient.useSession();
240
+ const useInitial = !React.useSyncExternalStore(subscribeToHydration, () => true, () => false) || isPending;
239
241
  return {
240
- isAuthenticated: !!session,
241
- isLoading: isPending
242
+ isAuthenticated: useInitial ? initialAuthenticated : !!session,
243
+ isLoading: useInitial && !initialAuthenticated
242
244
  };
243
245
  }
244
246
  function useIsAuthenticated() {
245
247
  const $ = c(1);
246
- if ($[0] !== "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93") {
248
+ if ($[0] !== "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b") {
247
249
  for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
248
- $[0] = "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93";
250
+ $[0] = "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b";
249
251
  }
250
252
  const { isAuthenticated } = useAuthState();
251
253
  return isAuthenticated;
252
254
  }
253
255
  function useSignInRedirect(callbackHref) {
254
256
  const $ = c(4);
255
- if ($[0] !== "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93") {
257
+ if ($[0] !== "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b") {
256
258
  for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
257
- $[0] = "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93";
259
+ $[0] = "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b";
258
260
  }
259
261
  const { authenticationUrl } = useAuthContext();
260
262
  let t0;
@@ -276,9 +278,9 @@ function useSignInRedirect(callbackHref) {
276
278
  */
277
279
  function useAuthActions() {
278
280
  const $ = c(5);
279
- if ($[0] !== "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93") {
281
+ if ($[0] !== "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b") {
280
282
  for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
281
- $[0] = "96393d5626632a69960ca7e18d98e06ae87b8528faab082732a3cc7b48adfd93";
283
+ $[0] = "613abd4be0f81de0bf8df48c671a83e40c3e6ac86dab4c38ebcffe92268b614b";
282
284
  }
283
285
  const { authClient, authenticationUrl } = useAuthContext();
284
286
  let t0;
@@ -11,9 +11,9 @@ const NormalizedDataContext = React.createContext({
11
11
  });
12
12
  const NormalizedDataProvider = (t0) => {
13
13
  const $ = c(13);
14
- if ($[0] !== "9680f54d18eb424030716d5c43a9901462a27cc0d8227fb40b5d6abb9b464a89") {
14
+ if ($[0] !== "28aab7b25bd21e351d34503ab3d745344dc158d8c4a4ad7a8c63e2c8732703bb") {
15
15
  for (let $i = 0; $i < 13; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
16
- $[0] = "9680f54d18eb424030716d5c43a9901462a27cc0d8227fb40b5d6abb9b464a89";
16
+ $[0] = "28aab7b25bd21e351d34503ab3d745344dc158d8c4a4ad7a8c63e2c8732703bb";
17
17
  }
18
18
  const { files, repeatableItems, children } = t0;
19
19
  let t1;
@@ -74,9 +74,9 @@ function useStableArray(next) {
74
74
  }
75
75
  function usePageBlocks(pageStructure, t0) {
76
76
  const $ = c(37);
77
- if ($[0] !== "9680f54d18eb424030716d5c43a9901462a27cc0d8227fb40b5d6abb9b464a89") {
77
+ if ($[0] !== "28aab7b25bd21e351d34503ab3d745344dc158d8c4a4ad7a8c63e2c8732703bb") {
78
78
  for (let $i = 0; $i < 37; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
79
- $[0] = "9680f54d18eb424030716d5c43a9901462a27cc0d8227fb40b5d6abb9b464a89";
79
+ $[0] = "28aab7b25bd21e351d34503ab3d745344dc158d8c4a4ad7a8c63e2c8732703bb";
80
80
  }
81
81
  const source = t0 === void 0 ? "draft" : t0;
82
82
  const blockIds = pageStructure.page.blockIds;
@@ -0,0 +1,13 @@
1
+ //#region src/lib/platform.ts
2
+ function bootstrapPlatform() {
3
+ document.documentElement.dataset.camoxPlatform = /Mac|iPhone|iPad|iPod/i.test(navigator.userAgent) ? "mac" : "other";
4
+ }
5
+ const PLATFORM_SCRIPT = `(${bootstrapPlatform.toString()})();`;
6
+ const PLATFORM_LABEL_CSS = `
7
+ .camox-platform-mac{display:none}
8
+ :root[data-camox-platform="mac"] .camox-platform-mac{display:inline}
9
+ :root[data-camox-platform="mac"] .camox-platform-other{display:none}
10
+ `;
11
+
12
+ //#endregion
13
+ export { PLATFORM_LABEL_CSS, PLATFORM_SCRIPT, bootstrapPlatform };
package/dist/lib/utils.js CHANGED
@@ -1,4 +1,6 @@
1
- import { jsxs } from "react/jsx-runtime";
1
+ import { PlatformLabel } from "../components/PlatformLabel.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { jsx } from "react/jsx-runtime";
2
4
  import { Kbd } from "@camox/ui/kbd";
3
5
  import { INPUT_BASE_STYLES, INPUT_FOCUS_STYLES, cn } from "@camox/ui/utils";
4
6
 
@@ -21,44 +23,94 @@ function checkIfInputFocused(document = window.document) {
21
23
  */
22
24
  function formatShortcut(shortcut) {
23
25
  if (!shortcut) return null;
24
- const isMac = navigator.userAgent.toUpperCase().indexOf("MAC") >= 0;
25
- const modifiers = [];
26
- if (shortcut.withMeta) modifiers.push(isMac ? "⌘" : "Ctrl");
27
- if (shortcut.withAlt) modifiers.push(isMac ? "⌥" : "Alt");
28
- if (shortcut.withShift) modifiers.push(isMac ? "⇧" : "Shift");
29
- const formattedKey = (() => {
30
- if (shortcut.key === "Enter") return "↵";
31
- if (shortcut.key === "Escape") return "Esc";
32
- if (shortcut.key === "Backspace") return "⌫";
33
- if (shortcut.key === "ArrowUp") return "↑";
34
- if (shortcut.key === "ArrowDown") return "↓";
35
- if (shortcut.key === "ArrowLeft") return "←";
36
- if (shortcut.key === "ArrowRight") return "→";
37
- return shortcut.key.toUpperCase();
38
- })();
39
- return /* @__PURE__ */ jsxs(Kbd, { children: [
40
- modifiers.join(),
41
- " ",
42
- formattedKey
43
- ] });
26
+ return /* @__PURE__ */ jsx(Shortcut, { shortcut });
44
27
  }
45
- /**
46
- * Gets an action's shortcut component by action ID from the actions array.
47
- *
48
- * @param actions - Array of actions from actionsStore
49
- * @param actionId - The ID of the action to get the shortcut for
50
- * @returns React element displaying the keyboard shortcut, or null if not found
51
- *
52
- * @example
53
- * ```tsx
54
- * const actions = useSelector(actionsStore, (state) => state.context.actions);
55
- * getActionShortcut(actions, "cycle-viewport-mode") // Returns formatted shortcut component
56
- * ```
57
- */
58
- function getActionShortcut(actions, actionId) {
59
- const action = actions.find((a) => a.id === actionId);
60
- return action?.shortcut ? formatShortcut(action.shortcut) : null;
28
+ function Shortcut(t0) {
29
+ const $ = c(15);
30
+ if ($[0] !== "45dff80dbc1805709c694dadbd04b0216f01c3a1a826daf47b8bb5bac9e42d9a") {
31
+ for (let $i = 0; $i < 15; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
32
+ $[0] = "45dff80dbc1805709c694dadbd04b0216f01c3a1a826daf47b8bb5bac9e42d9a";
33
+ }
34
+ const { shortcut } = t0;
35
+ let t1;
36
+ bb0: {
37
+ if (shortcut.key === "Enter") {
38
+ t1 = "↵";
39
+ break bb0;
40
+ }
41
+ if (shortcut.key === "Escape") {
42
+ t1 = "Esc";
43
+ break bb0;
44
+ }
45
+ if (shortcut.key === "Backspace") {
46
+ t1 = "⌫";
47
+ break bb0;
48
+ }
49
+ if (shortcut.key === "ArrowUp") {
50
+ t1 = "↑";
51
+ break bb0;
52
+ }
53
+ if (shortcut.key === "ArrowDown") {
54
+ t1 = "↓";
55
+ break bb0;
56
+ }
57
+ if (shortcut.key === "ArrowLeft") {
58
+ t1 = "←";
59
+ break bb0;
60
+ }
61
+ if (shortcut.key === "ArrowRight") {
62
+ t1 = "→";
63
+ break bb0;
64
+ }
65
+ let t2;
66
+ if ($[1] !== shortcut.key) {
67
+ t2 = shortcut.key.toUpperCase();
68
+ $[1] = shortcut.key;
69
+ $[2] = t2;
70
+ } else t2 = $[2];
71
+ t1 = t2;
72
+ }
73
+ const formattedKey = t1;
74
+ let t2;
75
+ if ($[3] !== formattedKey || $[4] !== shortcut.withAlt || $[5] !== shortcut.withMeta || $[6] !== shortcut.withShift) {
76
+ t2 = (mac) => {
77
+ const modifiers = [];
78
+ if (shortcut.withMeta) modifiers.push(mac ? "⌘" : "Ctrl");
79
+ if (shortcut.withAlt) modifiers.push(mac ? "⌥" : "Alt");
80
+ if (shortcut.withShift) modifiers.push(mac ? "⇧" : "Shift");
81
+ return `${modifiers.join()} ${formattedKey}`.trim();
82
+ };
83
+ $[3] = formattedKey;
84
+ $[4] = shortcut.withAlt;
85
+ $[5] = shortcut.withMeta;
86
+ $[6] = shortcut.withShift;
87
+ $[7] = t2;
88
+ } else t2 = $[7];
89
+ const label = t2;
90
+ let t3;
91
+ if ($[8] !== label) {
92
+ t3 = label(true);
93
+ $[8] = label;
94
+ $[9] = t3;
95
+ } else t3 = $[9];
96
+ let t4;
97
+ if ($[10] !== label) {
98
+ t4 = label(false);
99
+ $[10] = label;
100
+ $[11] = t4;
101
+ } else t4 = $[11];
102
+ let t5;
103
+ if ($[12] !== t3 || $[13] !== t4) {
104
+ t5 = /* @__PURE__ */ jsx(Kbd, { children: /* @__PURE__ */ jsx(PlatformLabel, {
105
+ mac: t3,
106
+ other: t4
107
+ }) });
108
+ $[12] = t3;
109
+ $[13] = t4;
110
+ $[14] = t5;
111
+ } else t5 = $[14];
112
+ return t5;
61
113
  }
62
114
 
63
115
  //#endregion
64
- export { INPUT_BASE_STYLES, INPUT_FOCUS_STYLES, checkIfInputFocused, cn, formatShortcut, getActionShortcut };
116
+ export { INPUT_BASE_STYLES, INPUT_FOCUS_STYLES, checkIfInputFocused, cn, formatShortcut };