@vertebr/react 0.3.0 → 0.5.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 (126) hide show
  1. package/dist/components/admin/AdminContent.d.ts +36 -0
  2. package/dist/components/admin/AdminContent.d.ts.map +1 -0
  3. package/dist/components/admin/AdminContent.js +107 -0
  4. package/dist/components/admin/AdminHeader.d.ts +13 -0
  5. package/dist/components/admin/AdminHeader.d.ts.map +1 -0
  6. package/dist/components/admin/AdminHeader.js +32 -0
  7. package/dist/components/admin/AdminSidebar.d.ts +25 -0
  8. package/dist/components/admin/AdminSidebar.d.ts.map +1 -0
  9. package/dist/components/admin/AdminSidebar.js +31 -0
  10. package/dist/components/admin/VertebrAdmin.d.ts +3 -18
  11. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
  12. package/dist/components/admin/VertebrAdmin.js +130 -120
  13. package/dist/components/admin/sidebar.d.ts +3 -0
  14. package/dist/components/admin/sidebar.d.ts.map +1 -0
  15. package/dist/components/admin/sidebar.js +13 -0
  16. package/dist/components/admin/storage.d.ts +4 -0
  17. package/dist/components/admin/storage.d.ts.map +1 -0
  18. package/dist/components/admin/storage.js +24 -0
  19. package/dist/components/admin/types.d.ts +53 -0
  20. package/dist/components/admin/types.d.ts.map +1 -0
  21. package/dist/components/admin/types.js +1 -0
  22. package/dist/components/config/EnumInput.d.ts +10 -0
  23. package/dist/components/config/EnumInput.d.ts.map +1 -0
  24. package/dist/components/config/EnumInput.js +19 -0
  25. package/dist/components/config/EnumListInput.d.ts +10 -0
  26. package/dist/components/config/EnumListInput.d.ts.map +1 -0
  27. package/dist/components/config/EnumListInput.js +46 -0
  28. package/dist/components/config/VisibilityEye.d.ts +8 -0
  29. package/dist/components/config/VisibilityEye.d.ts.map +1 -0
  30. package/dist/components/config/VisibilityEye.js +18 -0
  31. package/dist/components/config/form/ConfigField.d.ts +2 -1
  32. package/dist/components/config/form/ConfigField.d.ts.map +1 -1
  33. package/dist/components/config/form/ConfigField.js +9 -4
  34. package/dist/components/config/form/ConfigForm.d.ts +1 -1
  35. package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
  36. package/dist/components/config/form/ConfigForm.js +18 -9
  37. package/dist/components/config/form/ConfigFormActions.d.ts +2 -1
  38. package/dist/components/config/form/ConfigFormActions.d.ts.map +1 -1
  39. package/dist/components/config/form/ConfigFormActions.js +2 -2
  40. package/dist/components/config/form/RecordConfigForm.d.ts +3 -1
  41. package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
  42. package/dist/components/config/form/RecordConfigForm.js +16 -8
  43. package/dist/components/config/form/SettingsConfigForm.d.ts +3 -1
  44. package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -1
  45. package/dist/components/config/form/SettingsConfigForm.js +2 -2
  46. package/dist/components/config/form/helpers/fields.d.ts +7 -0
  47. package/dist/components/config/form/helpers/fields.d.ts.map +1 -0
  48. package/dist/components/config/form/helpers/fields.js +31 -0
  49. package/dist/components/config/form/helpers/groups.d.ts +4 -0
  50. package/dist/components/config/form/helpers/groups.d.ts.map +1 -0
  51. package/dist/components/config/form/helpers/groups.js +107 -0
  52. package/dist/components/config/form/helpers/images.d.ts +4 -0
  53. package/dist/components/config/form/helpers/images.d.ts.map +1 -0
  54. package/dist/components/config/form/helpers/images.js +27 -0
  55. package/dist/components/config/form/helpers/index.d.ts +7 -0
  56. package/dist/components/config/form/helpers/index.d.ts.map +1 -0
  57. package/dist/components/config/form/helpers/index.js +6 -0
  58. package/dist/components/config/form/helpers/labels.d.ts +5 -0
  59. package/dist/components/config/form/helpers/labels.d.ts.map +1 -0
  60. package/dist/components/config/form/helpers/labels.js +28 -0
  61. package/dist/components/config/form/helpers/schema.d.ts +8 -0
  62. package/dist/components/config/form/helpers/schema.d.ts.map +1 -0
  63. package/dist/components/config/form/helpers/schema.js +30 -0
  64. package/dist/components/config/form/helpers/visibility.d.ts +13 -0
  65. package/dist/components/config/form/helpers/visibility.d.ts.map +1 -0
  66. package/dist/components/config/form/helpers/visibility.js +86 -0
  67. package/dist/components/config/form/types.d.ts +6 -0
  68. package/dist/components/config/form/types.d.ts.map +1 -1
  69. package/dist/components/emails/EmailRecipientSelect.d.ts +16 -0
  70. package/dist/components/emails/EmailRecipientSelect.d.ts.map +1 -0
  71. package/dist/components/emails/EmailRecipientSelect.js +10 -0
  72. package/dist/components/emails/EmailsActivityPanel.d.ts +11 -0
  73. package/dist/components/emails/EmailsActivityPanel.d.ts.map +1 -0
  74. package/dist/components/emails/EmailsActivityPanel.js +139 -0
  75. package/dist/components/emails/EmailsBoard.d.ts +47 -0
  76. package/dist/components/emails/EmailsBoard.d.ts.map +1 -0
  77. package/dist/components/emails/EmailsBoard.js +594 -0
  78. package/dist/components/emails/EmailsLibraryPanel.d.ts +25 -0
  79. package/dist/components/emails/EmailsLibraryPanel.d.ts.map +1 -0
  80. package/dist/components/emails/EmailsLibraryPanel.js +379 -0
  81. package/dist/components/emails/EmailsNavSelect.d.ts +18 -0
  82. package/dist/components/emails/EmailsNavSelect.d.ts.map +1 -0
  83. package/dist/components/emails/EmailsNavSelect.js +37 -0
  84. package/dist/components/emails/MultiCheckSelect.d.ts +18 -0
  85. package/dist/components/emails/MultiCheckSelect.d.ts.map +1 -0
  86. package/dist/components/emails/MultiCheckSelect.js +74 -0
  87. package/dist/components/metrics/MetricsBoard.d.ts +8 -2
  88. package/dist/components/metrics/MetricsBoard.d.ts.map +1 -1
  89. package/dist/components/metrics/MetricsBoard.js +55 -2
  90. package/dist/components/metrics/charts.d.ts +14 -0
  91. package/dist/components/metrics/charts.d.ts.map +1 -0
  92. package/dist/components/metrics/charts.js +212 -0
  93. package/dist/components/resources/ResourceActionModal.d.ts +14 -0
  94. package/dist/components/resources/ResourceActionModal.d.ts.map +1 -0
  95. package/dist/components/resources/ResourceActionModal.js +64 -0
  96. package/dist/components/resources/ResourceCell.d.ts.map +1 -1
  97. package/dist/components/resources/ResourceCell.js +25 -9
  98. package/dist/components/resources/ResourceCreateModal.d.ts +18 -0
  99. package/dist/components/resources/ResourceCreateModal.d.ts.map +1 -0
  100. package/dist/components/resources/ResourceCreateModal.js +22 -0
  101. package/dist/components/resources/ResourceMailModal.d.ts +12 -0
  102. package/dist/components/resources/ResourceMailModal.d.ts.map +1 -0
  103. package/dist/components/resources/ResourceMailModal.js +196 -0
  104. package/dist/components/resources/ResourceTable.d.ts +9 -3
  105. package/dist/components/resources/ResourceTable.d.ts.map +1 -1
  106. package/dist/components/resources/ResourceTable.js +241 -35
  107. package/dist/index.d.ts +11 -1
  108. package/dist/index.d.ts.map +1 -1
  109. package/dist/index.js +3 -0
  110. package/dist/lib/metricsRanges.d.ts +20 -0
  111. package/dist/lib/metricsRanges.d.ts.map +1 -0
  112. package/dist/lib/metricsRanges.js +14 -0
  113. package/dist/styles/cells.css +42 -0
  114. package/dist/styles/emails.css +632 -0
  115. package/dist/styles/form.css +145 -0
  116. package/dist/styles/index.css +3 -0
  117. package/dist/styles/mail.css +240 -0
  118. package/dist/styles/metrics.css +633 -0
  119. package/dist/styles/modal.css +18 -0
  120. package/dist/styles/nav.css +103 -1
  121. package/dist/styles/panel.css +8 -68
  122. package/dist/styles/table.css +26 -3
  123. package/package.json +2 -2
  124. package/dist/components/config/form/helpers.d.ts +0 -16
  125. package/dist/components/config/form/helpers.d.ts.map +0 -1
  126. package/dist/components/config/form/helpers.js +0 -186
@@ -1,38 +1,14 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useState } from "react";
3
3
  import { createVertebrClient, } from "@vertebr/client";
4
- import { ConfigForm } from "../config/ConfigForm";
5
- import { EnvSelect } from "../env/EnvSelect";
6
- import { GalleryBoard } from "../gallery/GalleryBoard";
7
- import { MetricsBoard } from "../metrics/MetricsBoard";
8
- import { ResourcePanel } from "../resources/ResourceTable";
9
- import { ThemeToggle } from "../theme/ThemeToggle";
10
4
  import { useVertebrTheme } from "../../hooks/useVertebrTheme";
11
- function readStored(key) {
12
- try {
13
- return localStorage.getItem(key);
14
- }
15
- catch {
16
- return null;
17
- }
18
- }
19
- function writeStored(key, value) {
20
- try {
21
- localStorage.setItem(key, value);
22
- }
23
- catch {
24
- // ignore
25
- }
26
- }
27
- function clearStored(key) {
28
- try {
29
- localStorage.removeItem(key);
30
- }
31
- catch {
32
- // ignore
33
- }
34
- }
35
- export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane", envStorageKey = "vertebr:env", tokenStorageKey = "vertebr:token", themeStorageKey = "vertebr:theme", getAccessToken, authUserLabel, onSignOut, }) {
5
+ import { parseMetricsRangeId, } from "../../lib/metricsRanges";
6
+ import { AdminContent } from "./AdminContent";
7
+ import { AdminHeader } from "./AdminHeader";
8
+ import { AdminSidebar } from "./AdminSidebar";
9
+ import { sidebarGroups } from "./sidebar";
10
+ import { clearStored, readStored, writeStored } from "./storage";
11
+ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane", envStorageKey = "vertebr:env", tokenStorageKey = "vertebr:token", themeStorageKey = "vertebr:theme", metricsRangeStorageKey = "vertebr:metrics-range", getAccessToken, authUserLabel, onSignOut, }) {
36
12
  const { theme, setTheme } = useVertebrTheme(themeStorageKey);
37
13
  const [environment, setEnvironment] = useState(() => readStored(envStorageKey) ?? "");
38
14
  const [token, setToken] = useState(() => readStored(tokenStorageKey) ?? "");
@@ -50,8 +26,11 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
50
26
  const [configData, setConfigData] = useState(null);
51
27
  const [metricsData, setMetricsData] = useState(null);
52
28
  const [metricsLoading, setMetricsLoading] = useState(false);
29
+ const [metricsRange, setMetricsRange] = useState(() => parseMetricsRangeId(readStored(metricsRangeStorageKey)));
53
30
  const [galleryData, setGalleryData] = useState(null);
54
31
  const [galleryLoading, setGalleryLoading] = useState(false);
32
+ const [emailsData, setEmailsData] = useState(null);
33
+ const [emailsLoading, setEmailsLoading] = useState(false);
55
34
  const [error, setError] = useState(null);
56
35
  const [loading, setLoading] = useState(true);
57
36
  useEffect(() => {
@@ -97,6 +76,8 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
97
76
  return current;
98
77
  if (current?.kind === "gallery" && next.gallery)
99
78
  return current;
79
+ if (current?.kind === "emails" && next.emails)
80
+ return current;
100
81
  if (current?.kind === "resource") {
101
82
  if (next.resources.some((r) => r.id === current.id))
102
83
  return current;
@@ -112,6 +93,8 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
112
93
  return { kind: "resource", id: firstResource.id };
113
94
  if (next.gallery)
114
95
  return { kind: "gallery" };
96
+ if (next.emails)
97
+ return { kind: "emails", tab: "compose" };
115
98
  const firstConfig = next.configs[0];
116
99
  if (firstConfig)
117
100
  return { kind: "config", id: firstConfig.id };
@@ -142,12 +125,13 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
142
125
  setError(null);
143
126
  if (selection.kind === "overview") {
144
127
  setMetricsLoading(true);
145
- const data = await client.getMetrics();
128
+ const data = await client.getMetrics({ range: metricsRange });
146
129
  if (!cancelled) {
147
130
  setMetricsData(data);
148
131
  setResourceData(null);
149
132
  setConfigData(null);
150
133
  setGalleryData(null);
134
+ setEmailsData(null);
151
135
  }
152
136
  }
153
137
  else if (selection.kind === "gallery") {
@@ -158,6 +142,18 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
158
142
  setResourceData(null);
159
143
  setConfigData(null);
160
144
  setMetricsData(null);
145
+ setEmailsData(null);
146
+ }
147
+ }
148
+ else if (selection.kind === "emails") {
149
+ setEmailsLoading(true);
150
+ const data = await client.getEmails();
151
+ if (!cancelled) {
152
+ setEmailsData(data);
153
+ setResourceData(null);
154
+ setConfigData(null);
155
+ setMetricsData(null);
156
+ setGalleryData(null);
161
157
  }
162
158
  }
163
159
  else if (selection.kind === "resource") {
@@ -167,6 +163,7 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
167
163
  setConfigData(null);
168
164
  setMetricsData(null);
169
165
  setGalleryData(null);
166
+ setEmailsData(null);
170
167
  }
171
168
  }
172
169
  else {
@@ -176,6 +173,7 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
176
173
  setResourceData(null);
177
174
  setMetricsData(null);
178
175
  setGalleryData(null);
176
+ setEmailsData(null);
179
177
  }
180
178
  }
181
179
  }
@@ -188,13 +186,14 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
188
186
  if (!cancelled) {
189
187
  setMetricsLoading(false);
190
188
  setGalleryLoading(false);
189
+ setEmailsLoading(false);
191
190
  }
192
191
  }
193
192
  })();
194
193
  return () => {
195
194
  cancelled = true;
196
195
  };
197
- }, [client, selection, catalog, environment]);
196
+ }, [client, selection, catalog, environment, metricsRange]);
198
197
  const refreshResource = useCallback(async () => {
199
198
  if (selection?.kind !== "resource")
200
199
  return;
@@ -204,13 +203,17 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
204
203
  const refreshMetrics = useCallback(async () => {
205
204
  setMetricsLoading(true);
206
205
  try {
207
- const data = await client.getMetrics();
206
+ const data = await client.getMetrics({ range: metricsRange, fresh: true });
208
207
  setMetricsData(data);
209
208
  }
210
209
  finally {
211
210
  setMetricsLoading(false);
212
211
  }
213
- }, [client]);
212
+ }, [client, metricsRange]);
213
+ const changeMetricsRange = useCallback((next) => {
214
+ setMetricsRange(next);
215
+ writeStored(metricsRangeStorageKey, next);
216
+ }, [metricsRangeStorageKey]);
214
217
  const refreshGallery = useCallback(async () => {
215
218
  setGalleryLoading(true);
216
219
  try {
@@ -221,6 +224,16 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
221
224
  setGalleryLoading(false);
222
225
  }
223
226
  }, [client]);
227
+ const refreshEmails = useCallback(async () => {
228
+ setEmailsLoading(true);
229
+ try {
230
+ const data = await client.getEmails({ fresh: true });
231
+ setEmailsData(data);
232
+ }
233
+ finally {
234
+ setEmailsLoading(false);
235
+ }
236
+ }, [client]);
224
237
  const listGallery = useCallback(async () => {
225
238
  const data = await client.getGallery();
226
239
  return data.items;
@@ -278,6 +291,79 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
278
291
  setTokenDraft("");
279
292
  clearStored(tokenStorageKey);
280
293
  };
294
+ const navGroups = useMemo(() => {
295
+ if (!catalog)
296
+ return [];
297
+ const entries = [];
298
+ if (catalog.metrics) {
299
+ entries.push({
300
+ key: "overview",
301
+ group: catalog.metrics.group ?? "Analytics",
302
+ label: catalog.metrics.label,
303
+ active: selection?.kind === "overview",
304
+ onSelect: () => setSelection({ kind: "overview" }),
305
+ });
306
+ }
307
+ for (const resource of catalog.resources) {
308
+ entries.push({
309
+ key: `resource:${resource.id}`,
310
+ group: resource.group ?? "Resources",
311
+ label: resource.label,
312
+ active: selection?.kind === "resource" && selection.id === resource.id,
313
+ onSelect: () => setSelection({ kind: "resource", id: resource.id }),
314
+ });
315
+ }
316
+ if (catalog.gallery) {
317
+ entries.push({
318
+ key: "gallery",
319
+ group: catalog.gallery.group ?? "Resources",
320
+ label: catalog.gallery.label,
321
+ active: selection?.kind === "gallery",
322
+ onSelect: () => setSelection({ kind: "gallery" }),
323
+ });
324
+ }
325
+ if (catalog.emails) {
326
+ const emailsTab = selection?.kind === "emails" ? (selection.tab ?? "compose") : null;
327
+ entries.push({
328
+ key: "emails",
329
+ group: catalog.emails.group ?? "Growth",
330
+ label: catalog.emails.label,
331
+ active: selection?.kind === "emails",
332
+ onSelect: () => setSelection({ kind: "emails", tab: "compose" }),
333
+ children: [
334
+ {
335
+ key: "emails:compose",
336
+ label: "Compose",
337
+ active: emailsTab === "compose",
338
+ onSelect: () => setSelection({ kind: "emails", tab: "compose" }),
339
+ },
340
+ {
341
+ key: "emails:templates",
342
+ label: "Templates",
343
+ active: emailsTab === "templates",
344
+ onSelect: () => setSelection({ kind: "emails", tab: "templates" }),
345
+ },
346
+ {
347
+ key: "emails:activity",
348
+ label: "Activity",
349
+ active: emailsTab === "activity",
350
+ onSelect: () => setSelection({ kind: "emails", tab: "activity" }),
351
+ },
352
+ ],
353
+ });
354
+ }
355
+ for (const config of catalog.configs) {
356
+ const fallback = config.section === "page" ? "Pages" : "Config";
357
+ entries.push({
358
+ key: `config:${config.id}`,
359
+ group: config.group ?? fallback,
360
+ label: config.label,
361
+ active: selection?.kind === "config" && selection.id === config.id,
362
+ onSelect: () => setSelection({ kind: "config", id: config.id }),
363
+ });
364
+ }
365
+ return sidebarGroups(entries);
366
+ }, [catalog, selection]);
281
367
  if (!bootstrap && loading) {
282
368
  return _jsx("div", { className: "vertebr-loading", children: "Loading Vertebr\u2026" });
283
369
  }
@@ -288,88 +374,12 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
288
374
  ? (catalog?.metrics?.label ?? "Overview")
289
375
  : selection?.kind === "gallery"
290
376
  ? (catalog?.gallery?.label ?? "Gallery")
291
- : selection?.kind === "resource"
292
- ? catalog?.resources.find((r) => r.id === selection.id)?.label
293
- : selection?.kind === "config"
294
- ? catalog?.configs.find((c) => c.id === selection.id)?.label
295
- : null;
296
- return (_jsxs("div", { className: "vertebr-root", "data-env": environment, children: [_jsxs("aside", { className: "vertebr-sidebar", children: [_jsxs("div", { className: "vertebr-sidebar-top", children: [_jsxs("div", { className: "vertebr-brand", children: [_jsx("strong", { children: bootstrap?.brand ?? catalog?.brand ?? "Vertebr" }), _jsx("span", { children: title })] }), envList.length > 0 ? (_jsxs("div", { className: "vertebr-env", children: [_jsx("div", { className: "vertebr-nav-label", children: "Environment" }), _jsx(EnvSelect, { environments: envList, value: environment, onChange: switchEnvironment })] })) : null, _jsxs("nav", { className: "vertebr-nav", children: [catalog?.metrics ? (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: "Analytics" }), _jsx("button", { type: "button", "data-active": selection?.kind === "overview", onClick: () => setSelection({ kind: "overview" }), children: catalog.metrics.label })] })) : null, catalog &&
297
- (catalog.resources.length > 0 || catalog.gallery) ? (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: "Resources" }), catalog.resources.map((resource) => (_jsx("button", { type: "button", "data-active": selection?.kind === "resource" &&
298
- selection.id === resource.id, onClick: () => setSelection({ kind: "resource", id: resource.id }), children: resource.label }, resource.id))), catalog.gallery ? (_jsx("button", { type: "button", "data-active": selection?.kind === "gallery", onClick: () => setSelection({ kind: "gallery" }), children: catalog.gallery.label })) : null] })) : null, catalog &&
299
- catalog.configs.some((c) => (c.section ?? "config") !== "page") ? (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: "Config" }), catalog.configs
300
- .filter((c) => (c.section ?? "config") !== "page")
301
- .map((config) => (_jsx("button", { type: "button", "data-active": selection?.kind === "config" &&
302
- selection.id === config.id, onClick: () => setSelection({ kind: "config", id: config.id }), children: config.label }, config.id)))] })) : null, catalog &&
303
- catalog.configs.some((c) => c.section === "page") ? (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: "Pages" }), catalog.configs
304
- .filter((c) => c.section === "page")
305
- .map((config) => (_jsx("button", { type: "button", "data-active": selection?.kind === "config" &&
306
- selection.id === config.id, onClick: () => setSelection({ kind: "config", id: config.id }), children: config.label }, config.id)))] })) : null] })] }), _jsxs("div", { className: "vertebr-sidebar-bottom", children: [getAccessToken && authUserLabel ? (_jsxs("div", { className: "vertebr-auth", children: [_jsx("div", { className: "vertebr-nav-label", children: "Signed in" }), _jsx("p", { className: "vertebr-auth-hint", children: authUserLabel }), onSignOut ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: () => void onSignOut(), children: "Sign out" })) : null] })) : null, !getAccessToken && (authRequired || token) ? (_jsxs("div", { className: "vertebr-auth", children: [_jsx("div", { className: "vertebr-nav-label", children: "Access" }), _jsx("p", { className: "vertebr-auth-hint", children: authRequired
307
- ? `This environment requires auth${activeEnv?.auth?.claimKey
308
- ? ` (${activeEnv.auth.claimKey})`
309
- : ""}.`
310
- : "Optional access token for protected environments." }), _jsx("input", { className: "vertebr-auth-input", type: "password", placeholder: "Bearer token", value: tokenDraft, onChange: (event) => setTokenDraft(event.target.value), autoComplete: "off" }), _jsxs("div", { className: "vertebr-auth-actions", children: [_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", onClick: saveToken, children: "Use token" }), token ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: clearToken, children: "Clear" })) : null] })] })) : null, _jsx(ThemeToggle, { theme: theme, onChange: setTheme })] })] }), _jsxs("main", { className: "vertebr-main", children: [_jsxs("header", { className: "vertebr-header", children: [_jsxs("div", { children: [_jsxs("div", { className: "vertebr-heading-row", children: [_jsx("h1", { children: activeLabel ?? (catalog ? "Dashboard" : "Sign in") }), activeEnv ? (_jsx("span", { className: "vertebr-env-badge", "data-tone": activeEnv.tone ?? "neutral", children: activeEnv.label })) : null] }), _jsx("p", { children: !catalog && authRequired
311
- ? "Provide an access token to load this environment."
312
- : selection?.kind === "overview"
313
- ? "Live metrics for the selected environment."
314
- : selection?.kind === "gallery"
315
- ? "Browse and upload shared media assets."
316
- : selection?.kind === "resource"
317
- ? "Manage records scoped to the selected environment."
318
- : selection?.kind === "config"
319
- ? isPageSelection
320
- ? "Edit content for this page."
321
- : "Owner-managed config for this environment."
322
- : "Select a panel." })] }), error ? (_jsx("span", { className: "vertebr-status", "data-tone": "danger", children: error })) : null] }), _jsx("div", { className: "vertebr-content", children: catalog ? (_jsxs("section", { className: "vertebr-panel", children: [selection?.kind === "overview" ? (_jsx(MetricsBoard, { label: metricsData?.label ?? catalog.metrics?.label, metrics: metricsData?.metrics ?? [], loading: metricsLoading, onRefresh: () => void refreshMetrics() })) : null, selection?.kind === "gallery" && galleryData ? (_jsx(GalleryBoard, { label: galleryData.label, items: galleryData.items, accept: galleryData.accept, maxBytes: galleryData.maxBytes, canDelete: galleryData.canDelete, loading: galleryLoading, onRefresh: () => void refreshGallery(), onUpload: async (files) => {
323
- if (files.length === 1 && files[0]) {
324
- await client.uploadGalleryFile(files[0]);
325
- }
326
- else {
327
- await client.uploadGalleryFiles(files);
328
- }
329
- await refreshGallery();
330
- }, onDelete: galleryData.canDelete
331
- ? async (id) => {
332
- await client.deleteGalleryItem(id);
333
- await refreshGallery();
334
- }
335
- : undefined })) : null, selection?.kind === "resource" && resourceData ? (_jsx(ResourcePanel, { schema: resourceData.schema, items: resourceData.items, permissions: resourceData.permissions, actions: resourceData.actions, uploads: resourceData.uploads, storageKey: resourceData.id, onUpdate: resourceData.permissions.update
336
- ? async (rowId, value) => {
337
- await client.updateResource(resourceData.id, rowId, value);
338
- await refreshResource();
339
- }
340
- : undefined, onCreate: resourceData.permissions.create
341
- ? async (value) => {
342
- await client.createResource(resourceData.id, value);
343
- await refreshResource();
344
- }
345
- : undefined, onDelete: resourceData.permissions.delete
346
- ? async (rowId) => {
347
- await client.deleteResource(resourceData.id, rowId);
348
- await refreshResource();
349
- }
350
- : undefined, onAction: async (rowId, actionId) => {
351
- await client.runResourceAction(resourceData.id, rowId, actionId);
352
- await refreshResource();
353
- }, onUpload: resourceData.uploads
354
- ? async (field, files) => {
355
- if (files.length === 1 && files[0]) {
356
- const result = await client.uploadResourceFile(resourceData.id, field, files[0]);
357
- return [
358
- { url: result.url, name: result.name },
359
- ];
360
- }
361
- const result = await client.uploadResourceFiles(resourceData.id, field, files);
362
- return result.files;
363
- }
364
- : undefined, ...galleryPicker })) : null, selection?.kind === "config" && configData ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "vertebr-panel-head", children: [_jsx("h2", { children: isPageSelection ? "Page content" : "Settings" }), _jsxs("span", { className: "vertebr-count", children: [Object.keys(configData.schema).length, " fields"] })] }), _jsx(ConfigForm, { schema: configData.schema, value: configData.value, onSave: async (next) => {
365
- const saved = await client.setConfig(configData.id, next);
366
- setConfigData({
367
- ...configData,
368
- value: saved.value,
369
- });
370
- }, ...galleryPicker })] })) : null] })) : (_jsx("section", { className: "vertebr-panel", children: _jsx("div", { className: "vertebr-empty", children: authRequired
371
- ? "Authenticated access required for this environment."
372
- : loading
373
- ? "Loading…"
374
- : "Unable to load catalog." }) })) })] })] }));
377
+ : selection?.kind === "emails"
378
+ ? (catalog?.emails?.label ?? "Emails")
379
+ : selection?.kind === "resource"
380
+ ? catalog?.resources.find((r) => r.id === selection.id)?.label
381
+ : selection?.kind === "config"
382
+ ? catalog?.configs.find((c) => c.id === selection.id)?.label
383
+ : null;
384
+ return (_jsxs("div", { className: "vertebr-root", "data-env": environment, children: [_jsx(AdminSidebar, { brand: bootstrap?.brand ?? catalog?.brand ?? "Vertebr", title: title, envList: envList, environment: environment, onEnvironmentChange: switchEnvironment, navGroups: navGroups, getAccessToken: getAccessToken, authUserLabel: authUserLabel, onSignOut: onSignOut, authRequired: authRequired, activeEnv: activeEnv, token: token, tokenDraft: tokenDraft, onTokenDraftChange: setTokenDraft, onSaveToken: saveToken, onClearToken: clearToken, theme: theme, onThemeChange: setTheme }), _jsxs("main", { className: "vertebr-main", children: [_jsx(AdminHeader, { activeLabel: activeLabel ?? (catalog ? "Dashboard" : "Sign in"), activeEnv: activeEnv, catalogLoaded: Boolean(catalog), authRequired: authRequired, selection: selection, isPageSelection: isPageSelection, error: error }), _jsx(AdminContent, { client: client, catalog: catalog, selection: selection, authRequired: authRequired, loading: loading, isPageSelection: isPageSelection, metricsData: metricsData, metricsLoading: metricsLoading, metricsRange: metricsRange, onMetricsRangeChange: changeMetricsRange, onRefreshMetrics: refreshMetrics, galleryData: galleryData, galleryLoading: galleryLoading, onRefreshGallery: refreshGallery, emailsData: emailsData, emailsLoading: emailsLoading, onRefreshEmails: refreshEmails, resourceData: resourceData, onRefreshResource: refreshResource, configData: configData, onConfigSaved: setConfigData, galleryPicker: galleryPicker })] })] }));
375
385
  }
@@ -0,0 +1,3 @@
1
+ import type { SidebarEntry, SidebarNavGroup } from "./types";
2
+ export declare function sidebarGroups(entries: SidebarEntry[]): SidebarNavGroup[];
3
+ //# sourceMappingURL=sidebar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/admin/sidebar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE7D,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,eAAe,EAAE,CAYxE"}
@@ -0,0 +1,13 @@
1
+ export function sidebarGroups(entries) {
2
+ const order = [];
3
+ const map = new Map();
4
+ for (const entry of entries) {
5
+ const group = entry.group.trim() || "Resources";
6
+ if (!map.has(group)) {
7
+ map.set(group, []);
8
+ order.push(group);
9
+ }
10
+ map.get(group).push(entry);
11
+ }
12
+ return order.map((label) => ({ label, items: map.get(label) }));
13
+ }
@@ -0,0 +1,4 @@
1
+ export declare function readStored(key: string): string | null;
2
+ export declare function writeStored(key: string, value: string): void;
3
+ export declare function clearStored(key: string): void;
4
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/components/admin/storage.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMrD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAM5D;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAM7C"}
@@ -0,0 +1,24 @@
1
+ export function readStored(key) {
2
+ try {
3
+ return localStorage.getItem(key);
4
+ }
5
+ catch {
6
+ return null;
7
+ }
8
+ }
9
+ export function writeStored(key, value) {
10
+ try {
11
+ localStorage.setItem(key, value);
12
+ }
13
+ catch {
14
+ // ignore
15
+ }
16
+ }
17
+ export function clearStored(key) {
18
+ try {
19
+ localStorage.removeItem(key);
20
+ }
21
+ catch {
22
+ // ignore
23
+ }
24
+ }
@@ -0,0 +1,53 @@
1
+ export type VertebrAdminProps = {
2
+ /** Base URL for Vertebr API, e.g. `/admin/api` */
3
+ apiBase?: string;
4
+ title?: string;
5
+ /** localStorage key for remembering the selected environment */
6
+ envStorageKey?: string;
7
+ /** localStorage key for the access token */
8
+ tokenStorageKey?: string;
9
+ /** localStorage key for light/dark theme preference */
10
+ themeStorageKey?: string;
11
+ /** localStorage key for the overview metrics range */
12
+ metricsRangeStorageKey?: string;
13
+ /** Optional host-provided token getter (Firebase ID token, etc.) */
14
+ getAccessToken?: () => string | null | undefined | Promise<string | null | undefined>;
15
+ /** Signed-in identity shown in the dashboard. */
16
+ authUserLabel?: string;
17
+ /** Host-provided sign-out action. */
18
+ onSignOut?: () => void | Promise<void>;
19
+ };
20
+ export type EmailsTab = "compose" | "templates" | "activity";
21
+ export type Selection = {
22
+ kind: "overview";
23
+ } | {
24
+ kind: "resource";
25
+ id: string;
26
+ } | {
27
+ kind: "gallery";
28
+ } | {
29
+ kind: "emails";
30
+ tab?: EmailsTab;
31
+ } | {
32
+ kind: "config";
33
+ id: string;
34
+ } | null;
35
+ export type SidebarEntry = {
36
+ key: string;
37
+ group: string;
38
+ label: string;
39
+ active: boolean;
40
+ onSelect: () => void;
41
+ /** Nested items shown under this entry (e.g. Emails sections). */
42
+ children?: Array<{
43
+ key: string;
44
+ label: string;
45
+ active: boolean;
46
+ onSelect: () => void;
47
+ }>;
48
+ };
49
+ export type SidebarNavGroup = {
50
+ label: string;
51
+ items: SidebarEntry[];
52
+ };
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/admin/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,oEAAoE;IACpE,cAAc,CAAC,EAAE,MACb,MAAM,GACN,IAAI,GACJ,SAAS,GACT,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACvC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAE7D,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,CAAC,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B,IAAI,CAAC;AAET,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC,CAAC;CACJ,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { FieldSchema } from "@vertebr/client";
2
+ export type EnumInputProps = {
3
+ id: string;
4
+ value: unknown;
5
+ field: FieldSchema;
6
+ readOnly?: boolean;
7
+ onChange: (value: string) => void;
8
+ };
9
+ export declare function EnumInput({ id, value, field, readOnly, onChange, }: EnumInputProps): import("react").JSX.Element;
10
+ //# sourceMappingURL=EnumInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnumInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/EnumInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,+BAmDhB"}
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as Select from "@radix-ui/react-select";
3
+ import { optionLabel } from "./form/helpers/labels";
4
+ export function EnumInput({ id, value, field, readOnly, onChange, }) {
5
+ const options = field.options?.filter(Boolean) ?? [];
6
+ const current = typeof value === "string" && options.includes(value)
7
+ ? value
8
+ : (options[0] ?? "");
9
+ if (options.length === 0) {
10
+ return (_jsx("input", { id: id, type: "text", readOnly: readOnly, value: current, disabled: true }));
11
+ }
12
+ return (_jsxs(Select.Root, { value: current, onValueChange: onChange, disabled: readOnly, children: [_jsxs(Select.Trigger, { id: id, className: "vertebr-select-trigger", children: [_jsx("span", { className: "vertebr-select-value", children: _jsx(Select.Value, { children: optionLabel(current, field) }) }), _jsx(Select.Icon, { className: "vertebr-select-icon", children: _jsx(ChevronIcon, {}) })] }), _jsx(Select.Portal, { children: _jsx(Select.Content, { className: "vertebr-select-content", position: "popper", sideOffset: 6, children: _jsx(Select.Viewport, { className: "vertebr-select-viewport", children: options.map((option) => (_jsxs(Select.Item, { value: option, className: "vertebr-select-item", children: [_jsx(Select.ItemText, { children: optionLabel(option, field) }), _jsx(Select.ItemIndicator, { className: "vertebr-select-check", children: _jsx(CheckIcon, {}) })] }, option))) }) }) })] }));
13
+ }
14
+ function ChevronIcon() {
15
+ return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", "aria-hidden": "true", children: _jsx("path", { d: "M2.5 4.5 6 8l3.5-3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }) }));
16
+ }
17
+ function CheckIcon() {
18
+ return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", "aria-hidden": "true", children: _jsx("path", { d: "M2.5 6.2 5 8.7 9.5 3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }) }));
19
+ }
@@ -0,0 +1,10 @@
1
+ import type { FieldSchema } from "@vertebr/client";
2
+ export type EnumListInputProps = {
3
+ id: string;
4
+ value: unknown;
5
+ field: FieldSchema;
6
+ readOnly?: boolean;
7
+ onChange: (value: string[]) => void;
8
+ };
9
+ export declare function EnumListInput({ id, value, field, readOnly, onChange, }: EnumListInputProps): import("react").JSX.Element;
10
+ //# sourceMappingURL=EnumListInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnumListInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/EnumListInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACrC,CAAC;AAiBF,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,+BAiEpB"}
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { optionLabel } from "./form/helpers/labels";
3
+ function asStringList(value) {
4
+ if (!Array.isArray(value))
5
+ return [];
6
+ return value.map((item) => String(item).trim()).filter(Boolean);
7
+ }
8
+ function orderedRows(options, selected) {
9
+ const known = new Set(options);
10
+ const picked = selected.filter((id) => known.has(id));
11
+ const rest = options.filter((id) => !picked.includes(id));
12
+ return [
13
+ ...picked.map((id) => ({ id, on: true })),
14
+ ...rest.map((id) => ({ id, on: false })),
15
+ ];
16
+ }
17
+ export function EnumListInput({ id, value, field, readOnly, onChange, }) {
18
+ const options = field.options?.filter(Boolean) ?? [];
19
+ const selected = asStringList(value);
20
+ const rows = orderedRows(options, selected);
21
+ const commit = (nextRows) => {
22
+ onChange(nextRows.filter((row) => row.on).map((row) => row.id));
23
+ };
24
+ return (_jsx("ul", { id: id, className: "vertebr-enum-list", children: rows.map((row, index) => (_jsxs("li", { className: "vertebr-enum-list-row", "data-on": row.on, children: [_jsxs("label", { className: "vertebr-enum-list-label", children: [_jsx("input", { type: "checkbox", checked: row.on, disabled: readOnly, onChange: (event) => {
25
+ const next = rows.map((item) => item.id === row.id
26
+ ? { ...item, on: event.target.checked }
27
+ : item);
28
+ commit(next);
29
+ } }), _jsx("span", { children: optionLabel(row.id, field) })] }), _jsxs("div", { className: "vertebr-enum-list-move", children: [_jsx("button", { type: "button", "aria-label": `Move ${optionLabel(row.id, field)} up`, disabled: readOnly || index === 0, onClick: () => {
30
+ if (index === 0)
31
+ return;
32
+ const next = [...rows];
33
+ const current = next[index];
34
+ next[index] = next[index - 1];
35
+ next[index - 1] = current;
36
+ commit(next);
37
+ }, children: "\u2191" }), _jsx("button", { type: "button", "aria-label": `Move ${optionLabel(row.id, field)} down`, disabled: readOnly || index === rows.length - 1, onClick: () => {
38
+ if (index >= rows.length - 1)
39
+ return;
40
+ const next = [...rows];
41
+ const current = next[index];
42
+ next[index] = next[index + 1];
43
+ next[index + 1] = current;
44
+ commit(next);
45
+ }, children: "\u2193" })] })] }, row.id))) }));
46
+ }
@@ -0,0 +1,8 @@
1
+ import type { UseFormReturn } from "react-hook-form";
2
+ export type VisibilityEyeButtonProps = {
3
+ name: string;
4
+ label: string;
5
+ form: UseFormReturn<Record<string, unknown>>;
6
+ };
7
+ export declare function VisibilityEyeButton({ name, label, form, }: VisibilityEyeButtonProps): import("react").JSX.Element;
8
+ //# sourceMappingURL=VisibilityEye.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisibilityEye.d.ts","sourceRoot":"","sources":["../../../src/components/config/VisibilityEye.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC9C,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,KAAK,EACL,IAAI,GACL,EAAE,wBAAwB,+BA0B1B"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ export function VisibilityEyeButton({ name, label, form, }) {
4
+ const visible = form.watch(name) !== false;
5
+ useEffect(() => {
6
+ form.register(name);
7
+ }, [form, name]);
8
+ return (_jsx("button", { type: "button", className: "vertebr-visibility-btn", "aria-pressed": visible, "aria-label": visible ? `Hide ${label} on storefront` : `Show ${label} on storefront`, title: visible ? "Visible on storefront" : "Hidden on storefront", onClick: () => form.setValue(name, !visible, {
9
+ shouldDirty: true,
10
+ shouldTouch: true,
11
+ }), children: visible ? _jsx(EyeIcon, {}) : _jsx(EyeOffIcon, {}) }));
12
+ }
13
+ function EyeIcon() {
14
+ return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }), _jsx("circle", { cx: "12", cy: "12", r: "3" })] }));
15
+ }
16
+ function EyeOffIcon() {
17
+ return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }), _jsx("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }), _jsx("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }), _jsx("path", { d: "m2 2 20 20" })] }));
18
+ }
@@ -16,6 +16,7 @@ export type ConfigFieldProps = GalleryHandlers & {
16
16
  }>>;
17
17
  hideImagePreview?: boolean;
18
18
  hideUpload?: boolean;
19
+ visibilityGroup?: string;
19
20
  };
20
- export declare function ConfigField({ fieldKey, field, groupLabel, variant, schema, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, hideImagePreview, hideUpload, }: ConfigFieldProps): import("react").JSX.Element;
21
+ export declare function ConfigField({ fieldKey, field, groupLabel, variant, schema, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, hideImagePreview, hideUpload, visibilityGroup, }: ConfigFieldProps): import("react").JSX.Element;
21
22
  //# sourceMappingURL=ConfigField.d.ts.map