@guard-rail/core 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@ import {
9
9
  } from "../server/actions";
10
10
  import { useGRail } from "./Provider";
11
11
  import { CloseIcon } from "./Icons";
12
- import { S } from "./styles";
12
+ import { S, v } from "./styles";
13
13
  const ROLES = ["admin", "editor"];
14
14
  const ANIMATION_CSS = `
15
15
  @keyframes gr-fade-in { from { opacity: 0 } to { opacity: 1 } }
@@ -98,11 +98,11 @@ function TeamDrawer({ onClose }) {
98
98
  children: [
99
99
  /* @__PURE__ */ jsxs("header", { style: S.drawerHead, children: [
100
100
  /* @__PURE__ */ jsx("h2", { style: S.drawerTitle, children: "Team" }),
101
- /* @__PURE__ */ jsx("button", { style: { ...S.iconBtn, color: "#6b7280" }, onClick: requestClose, "aria-label": "Close", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
101
+ /* @__PURE__ */ jsx("button", { style: { ...S.iconBtn, color: v("muted") }, onClick: requestClose, "aria-label": "Close", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
102
102
  ] }),
103
103
  /* @__PURE__ */ jsxs("div", { style: S.drawerBody, children: [
104
104
  error && /* @__PURE__ */ jsx("div", { style: { ...S.error, marginBottom: 12 }, children: error }),
105
- loading ? /* @__PURE__ */ jsx("p", { style: { fontSize: 13, color: "#6b7280" }, children: "Loading\u2026" }) : members.map((m) => /* @__PURE__ */ jsxs("div", { "data-gr-row": true, style: S.memberRow, children: [
105
+ loading ? /* @__PURE__ */ jsx("p", { style: { fontSize: 13, color: v("muted") }, children: "Loading\u2026" }) : members.map((m) => /* @__PURE__ */ jsxs("div", { "data-gr-row": true, style: S.memberRow, children: [
106
106
  /* @__PURE__ */ jsxs("span", { style: S.memberEmail, title: m.email, children: [
107
107
  m.email,
108
108
  m.email === currentEmail && " (you)"
@@ -119,11 +119,11 @@ function TeamDrawer({ onClose }) {
119
119
  ),
120
120
  children: ROLES.map((r) => /* @__PURE__ */ jsx("option", { value: r, children: r }, r))
121
121
  }
122
- ) : /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#6b7280" }, children: m.role }),
122
+ ) : /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: v("muted") }, children: m.role }),
123
123
  isAdmin && /* @__PURE__ */ jsx(
124
124
  "button",
125
125
  {
126
- style: { ...S.iconBtn, color: "#9ca3af", width: 22, height: 22 },
126
+ style: { ...S.iconBtn, color: v("muted"), width: 22, height: 22 },
127
127
  disabled: pending,
128
128
  onClick: () => run(() => removeMember(m.email)),
129
129
  "aria-label": `Remove ${m.email}`,
@@ -172,7 +172,7 @@ function TeamDrawer({ onClose }) {
172
172
  ]
173
173
  }
174
174
  ),
175
- /* @__PURE__ */ jsxs("p", { style: { fontSize: 11, color: "#9ca3af", marginTop: 10 }, children: [
175
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: 11, color: v("subtle"), marginTop: 10 }, children: [
176
176
  "Guardrail records the invite. Sending the email is your app's job \u2014 wire the ",
177
177
  /* @__PURE__ */ jsx("code", { children: "onInvite" }),
178
178
  " handler."
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/Team.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useCallback, useEffect, useState, useTransition } from \"react\";\nimport {\n inviteMember,\n listTeam,\n removeMember,\n updateMemberRole,\n} from \"../server/actions\";\nimport { useGRail } from \"./Provider\";\nimport { CloseIcon } from \"./Icons\";\nimport { S } from \"./styles\";\nimport type { GRMember, GRRole } from \"../core/types\";\n\nconst ROLES: GRRole[] = [\"admin\", \"editor\"];\n\n/**\n * Keyframes cannot be expressed as inline styles, so the drawer ships the few\n * it needs. Scoped to [data-guardrail-team] to stay clear of app styles, and\n * disabled under prefers-reduced-motion.\n */\nconst ANIMATION_CSS = `\n@keyframes gr-fade-in { from { opacity: 0 } to { opacity: 1 } }\n@keyframes gr-slide-in {\n from { transform: translateX(100%) }\n to { transform: translateX(0) }\n}\n[data-guardrail-scrim] { animation: gr-fade-in 160ms ease-out both }\n[data-guardrail-team] { animation: gr-slide-in 220ms cubic-bezier(0.32, 0.72, 0, 1) both }\n[data-guardrail-team] [data-gr-row] { animation: gr-fade-in 240ms ease-out both }\n@keyframes gr-fade-out { from { opacity: 1 } to { opacity: 0 } }\n@keyframes gr-slide-out {\n from { transform: translateX(0) }\n to { transform: translateX(100%) }\n}\n[data-guardrail-scrim][data-closing] { animation: gr-fade-out 180ms ease-in both }\n[data-guardrail-team][data-closing] { animation: gr-slide-out 180ms cubic-bezier(0.4, 0, 1, 1) both }\n@media (prefers-reduced-motion: reduce) {\n [data-guardrail-scrim], [data-guardrail-team], [data-guardrail-team] [data-gr-row] {\n animation: none\n }\n}\n`;\n\nexport function TeamDrawer({ onClose }: { onClose: () => void }) {\n const { role, email: currentEmail } = useGRail();\n const isAdmin = role === \"admin\";\n\n const [members, setMembers] = useState<GRMember[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [inviteEmail, setInviteEmail] = useState(\"\");\n const [inviteRole, setInviteRole] = useState<GRRole>(\"editor\");\n const [pending, startTransition] = useTransition();\n\n const refresh = () =>\n listTeam().then((rows) => {\n setMembers(rows);\n setLoading(false);\n });\n\n useEffect(() => {\n void refresh();\n }, []);\n\n // Server actions re-check the role; this only decides what to render.\n // Always refresh: a failure can still have changed the roster (an invite\n // that saved but whose email failed, for instance).\n const run = (fn: () => Promise<{ success: boolean; error?: string }>) =>\n startTransition(async () => {\n setError(null);\n const res = await fn();\n if (!res.success) setError(res.error ?? \"Something went wrong.\");\n await refresh();\n });\n\n /**\n * Unmounting on close skips the exit animation entirely. Stay mounted, play\n * it, and let the parent unmount once it finishes.\n */\n const [closing, setClosing] = useState(false);\n const requestClose = useCallback(() => {\n const reduced =\n typeof window !== \"undefined\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n if (reduced) return onClose(); // No animation, so no animationend to wait for.\n setClosing(true);\n }, [onClose]);\n\n useEffect(() => {\n if (!closing) return;\n // Safety net if animationend never arrives (tab hidden, styles stripped).\n const t = window.setTimeout(onClose, 400);\n return () => window.clearTimeout(t);\n }, [closing, onClose]);\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && requestClose();\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [requestClose]);\n\n return (\n <>\n <style>{ANIMATION_CSS}</style>\n <div\n data-guardrail\n data-guardrail-scrim\n {...(closing ? { \"data-closing\": \"\" } : {})}\n style={S.scrim}\n onClick={requestClose}\n />\n <aside\n data-guardrail\n data-guardrail-team\n {...(closing ? { \"data-closing\": \"\" } : {})}\n onAnimationEnd={(e) => {\n // Row fade-ins bubble up here too; only the drawer's own exit counts.\n if (closing && e.target === e.currentTarget) onClose();\n }}\n style={S.drawer}\n role=\"dialog\"\n aria-label=\"Team\"\n >\n <header style={S.drawerHead}>\n <h2 style={S.drawerTitle}>Team</h2>\n <button style={{ ...S.iconBtn, color: \"#6b7280\" }} onClick={requestClose} aria-label=\"Close\">\n <CloseIcon />\n </button>\n </header>\n\n <div style={S.drawerBody}>\n {error && <div style={{ ...S.error, marginBottom: 12 }}>{error}</div>}\n\n {loading ? (\n <p style={{ fontSize: 13, color: \"#6b7280\" }}>Loading…</p>\n ) : (\n members.map((m) => (\n <div key={m.email} data-gr-row style={S.memberRow}>\n <span style={S.memberEmail} title={m.email}>\n {m.email}\n {m.email === currentEmail && \" (you)\"}\n </span>\n\n {m.status === \"pending\" && <span style={S.badge}>Invited</span>}\n\n {isAdmin ? (\n <select\n style={S.select}\n value={m.role}\n disabled={pending}\n onChange={(e) =>\n run(() =>\n updateMemberRole(m.email, e.target.value as GRRole),\n )\n }\n >\n {ROLES.map((r) => (\n <option key={r} value={r}>\n {r}\n </option>\n ))}\n </select>\n ) : (\n <span style={{ fontSize: 12, color: \"#6b7280\" }}>{m.role}</span>\n )}\n\n {isAdmin && (\n <button\n style={{ ...S.iconBtn, color: \"#9ca3af\", width: 22, height: 22 }}\n disabled={pending}\n onClick={() => run(() => removeMember(m.email))}\n aria-label={`Remove ${m.email}`}\n title=\"Remove\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n ))\n )}\n\n {isAdmin && (\n <>\n <p style={S.sectionLabel}>Invite someone</p>\n <form\n onSubmit={(e) => {\n e.preventDefault();\n run(async () => {\n const res = await inviteMember(inviteEmail, inviteRole);\n if (res.success) setInviteEmail(\"\");\n return res;\n });\n }}\n >\n <input\n style={S.field}\n type=\"email\"\n placeholder=\"name@company.com\"\n value={inviteEmail}\n onChange={(e) => setInviteEmail(e.target.value)}\n required\n />\n <div style={{ display: \"flex\", gap: 8 }}>\n <select\n style={{ ...S.select, flex: 1 }}\n value={inviteRole}\n onChange={(e) => setInviteRole(e.target.value as GRRole)}\n >\n {ROLES.map((r) => (\n <option key={r} value={r}>\n {r}\n </option>\n ))}\n </select>\n <button style={S.primaryBtn} type=\"submit\" disabled={pending}>\n {pending ? \"Working…\" : \"Invite\"}\n </button>\n </div>\n </form>\n <p style={{ fontSize: 11, color: \"#9ca3af\", marginTop: 10 }}>\n Guardrail records the invite. Sending the email is your app&apos;s\n job — wire the <code>onInvite</code> handler.\n </p>\n </>\n )}\n </div>\n </aside>\n </>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/react/Team.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useCallback, useEffect, useState, useTransition } from \"react\";\nimport {\n inviteMember,\n listTeam,\n removeMember,\n updateMemberRole,\n} from \"../server/actions\";\nimport { useGRail } from \"./Provider\";\nimport { CloseIcon } from \"./Icons\";\nimport { S, v } from \"./styles\";\nimport type { GRMember, GRRole } from \"../core/types\";\n\nconst ROLES: GRRole[] = [\"admin\", \"editor\"];\n\n/**\n * Keyframes cannot be expressed as inline styles, so the drawer ships the few\n * it needs. Scoped to [data-guardrail-team] to stay clear of app styles, and\n * disabled under prefers-reduced-motion.\n */\nconst ANIMATION_CSS = `\n@keyframes gr-fade-in { from { opacity: 0 } to { opacity: 1 } }\n@keyframes gr-slide-in {\n from { transform: translateX(100%) }\n to { transform: translateX(0) }\n}\n[data-guardrail-scrim] { animation: gr-fade-in 160ms ease-out both }\n[data-guardrail-team] { animation: gr-slide-in 220ms cubic-bezier(0.32, 0.72, 0, 1) both }\n[data-guardrail-team] [data-gr-row] { animation: gr-fade-in 240ms ease-out both }\n@keyframes gr-fade-out { from { opacity: 1 } to { opacity: 0 } }\n@keyframes gr-slide-out {\n from { transform: translateX(0) }\n to { transform: translateX(100%) }\n}\n[data-guardrail-scrim][data-closing] { animation: gr-fade-out 180ms ease-in both }\n[data-guardrail-team][data-closing] { animation: gr-slide-out 180ms cubic-bezier(0.4, 0, 1, 1) both }\n@media (prefers-reduced-motion: reduce) {\n [data-guardrail-scrim], [data-guardrail-team], [data-guardrail-team] [data-gr-row] {\n animation: none\n }\n}\n`;\n\nexport function TeamDrawer({ onClose }: { onClose: () => void }) {\n const { role, email: currentEmail } = useGRail();\n const isAdmin = role === \"admin\";\n\n const [members, setMembers] = useState<GRMember[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [inviteEmail, setInviteEmail] = useState(\"\");\n const [inviteRole, setInviteRole] = useState<GRRole>(\"editor\");\n const [pending, startTransition] = useTransition();\n\n const refresh = () =>\n listTeam().then((rows) => {\n setMembers(rows);\n setLoading(false);\n });\n\n useEffect(() => {\n void refresh();\n }, []);\n\n // Server actions re-check the role; this only decides what to render.\n // Always refresh: a failure can still have changed the roster (an invite\n // that saved but whose email failed, for instance).\n const run = (fn: () => Promise<{ success: boolean; error?: string }>) =>\n startTransition(async () => {\n setError(null);\n const res = await fn();\n if (!res.success) setError(res.error ?? \"Something went wrong.\");\n await refresh();\n });\n\n /**\n * Unmounting on close skips the exit animation entirely. Stay mounted, play\n * it, and let the parent unmount once it finishes.\n */\n const [closing, setClosing] = useState(false);\n const requestClose = useCallback(() => {\n const reduced =\n typeof window !== \"undefined\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n if (reduced) return onClose(); // No animation, so no animationend to wait for.\n setClosing(true);\n }, [onClose]);\n\n useEffect(() => {\n if (!closing) return;\n // Safety net if animationend never arrives (tab hidden, styles stripped).\n const t = window.setTimeout(onClose, 400);\n return () => window.clearTimeout(t);\n }, [closing, onClose]);\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && requestClose();\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [requestClose]);\n\n return (\n <>\n <style>{ANIMATION_CSS}</style>\n <div\n data-guardrail\n data-guardrail-scrim\n {...(closing ? { \"data-closing\": \"\" } : {})}\n style={S.scrim}\n onClick={requestClose}\n />\n <aside\n data-guardrail\n data-guardrail-team\n {...(closing ? { \"data-closing\": \"\" } : {})}\n onAnimationEnd={(e) => {\n // Row fade-ins bubble up here too; only the drawer's own exit counts.\n if (closing && e.target === e.currentTarget) onClose();\n }}\n style={S.drawer}\n role=\"dialog\"\n aria-label=\"Team\"\n >\n <header style={S.drawerHead}>\n <h2 style={S.drawerTitle}>Team</h2>\n <button style={{ ...S.iconBtn, color: v(\"muted\") }} onClick={requestClose} aria-label=\"Close\">\n <CloseIcon />\n </button>\n </header>\n\n <div style={S.drawerBody}>\n {error && <div style={{ ...S.error, marginBottom: 12 }}>{error}</div>}\n\n {loading ? (\n <p style={{ fontSize: 13, color: v(\"muted\") }}>Loading…</p>\n ) : (\n members.map((m) => (\n <div key={m.email} data-gr-row style={S.memberRow}>\n <span style={S.memberEmail} title={m.email}>\n {m.email}\n {m.email === currentEmail && \" (you)\"}\n </span>\n\n {m.status === \"pending\" && <span style={S.badge}>Invited</span>}\n\n {isAdmin ? (\n <select\n style={S.select}\n value={m.role}\n disabled={pending}\n onChange={(e) =>\n run(() =>\n updateMemberRole(m.email, e.target.value as GRRole),\n )\n }\n >\n {ROLES.map((r) => (\n <option key={r} value={r}>\n {r}\n </option>\n ))}\n </select>\n ) : (\n <span style={{ fontSize: 12, color: v(\"muted\") }}>{m.role}</span>\n )}\n\n {isAdmin && (\n <button\n style={{ ...S.iconBtn, color: v(\"muted\"), width: 22, height: 22 }}\n disabled={pending}\n onClick={() => run(() => removeMember(m.email))}\n aria-label={`Remove ${m.email}`}\n title=\"Remove\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n ))\n )}\n\n {isAdmin && (\n <>\n <p style={S.sectionLabel}>Invite someone</p>\n <form\n onSubmit={(e) => {\n e.preventDefault();\n run(async () => {\n const res = await inviteMember(inviteEmail, inviteRole);\n if (res.success) setInviteEmail(\"\");\n return res;\n });\n }}\n >\n <input\n style={S.field}\n type=\"email\"\n placeholder=\"name@company.com\"\n value={inviteEmail}\n onChange={(e) => setInviteEmail(e.target.value)}\n required\n />\n <div style={{ display: \"flex\", gap: 8 }}>\n <select\n style={{ ...S.select, flex: 1 }}\n value={inviteRole}\n onChange={(e) => setInviteRole(e.target.value as GRRole)}\n >\n {ROLES.map((r) => (\n <option key={r} value={r}>\n {r}\n </option>\n ))}\n </select>\n <button style={S.primaryBtn} type=\"submit\" disabled={pending}>\n {pending ? \"Working…\" : \"Invite\"}\n </button>\n </div>\n </form>\n <p style={{ fontSize: 11, color: v(\"subtle\"), marginTop: 10 }}>\n Guardrail records the invite. Sending the email is your app&apos;s\n job — wire the <code>onInvite</code> handler.\n </p>\n </>\n )}\n </div>\n </aside>\n </>\n );\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,44 @@
3
3
  * classes would make the package depend on the consumer having Tailwind *and*
4
4
  * adding node_modules/guardrail to their content globs — it would render
5
5
  * unstyled on a clean install. Developer-authored content is never touched.
6
+ *
7
+ * Colors are CSS variables so the chrome can follow the visitor's OS light/dark
8
+ * preference — inline styles can't express a media query, but they can read a
9
+ * variable that one defines. THEME_CSS (rendered once by <GRailAdmin>) sets the
10
+ * variables; every use below carries the light value as its fallback, so the
11
+ * chrome still renders correctly if that stylesheet is ever absent.
6
12
  */
13
+ declare const LIGHT: {
14
+ readonly bg: "#ffffff";
15
+ readonly "bg-glass": "rgba(255,255,255,0.97)";
16
+ readonly fg: "#111827";
17
+ readonly fg2: "#4b5563";
18
+ readonly muted: "#6b7280";
19
+ readonly subtle: "#9ca3af";
20
+ readonly border: "#e5e7eb";
21
+ readonly "border-strong": "#d1d5db";
22
+ readonly "border-soft": "#f3f4f6";
23
+ readonly "input-bg": "#ffffff";
24
+ readonly soft: "#f3f4f6";
25
+ readonly accent: "#2563eb";
26
+ readonly "accent-soft": "#eff6ff";
27
+ readonly "accent-text": "#1d4ed8";
28
+ readonly "primary-bg": "#111827";
29
+ readonly "primary-fg": "#ffffff";
30
+ readonly danger: "#dc2626";
31
+ readonly label: "#1e3a8a";
32
+ readonly shadow: "rgba(0,0,0,0.25)";
33
+ };
34
+ /** A themed color: reads the variable, falls back to the light value. */
35
+ declare const v: (name: keyof typeof LIGHT) => string;
36
+ /**
37
+ * Rendered once by <GRailAdmin>. Variables go on :root so portaled chrome
38
+ * inherits them. `color-scheme` is deliberately scoped to Guardrail's own
39
+ * elements, never :root — that would flip the host site's form controls and
40
+ * scrollbars too. It's what makes native controls inside the chrome (the
41
+ * team drawer's role <select>, its dropdown list) match the palette.
42
+ */
43
+ declare const THEME_CSS: string;
7
44
  declare const S: {
8
45
  banner: {
9
46
  position: "fixed";
@@ -11,7 +48,7 @@ declare const S: {
11
48
  left: number;
12
49
  width: string;
13
50
  background: string;
14
- color: "#000";
51
+ color: string;
15
52
  padding: string;
16
53
  zIndex: number;
17
54
  borderTop: string;
@@ -40,7 +77,7 @@ declare const S: {
40
77
  gap: number;
41
78
  };
42
79
  error: {
43
- color: "#dc2626";
80
+ color: string;
44
81
  fontSize: number;
45
82
  fontWeight: number;
46
83
  };
@@ -49,13 +86,13 @@ declare const S: {
49
86
  borderRadius: number;
50
87
  padding: string;
51
88
  fontSize: number;
52
- color: "#000";
89
+ color: string;
53
90
  background: string;
54
91
  outline: string;
55
92
  };
56
93
  primaryBtn: {
57
94
  background: string;
58
- color: "#fff";
95
+ color: string;
59
96
  padding: string;
60
97
  borderRadius: number;
61
98
  fontSize: number;
@@ -71,10 +108,10 @@ declare const S: {
71
108
  zIndex: number;
72
109
  background: string;
73
110
  backdropFilter: "blur(8px)";
74
- color: "#fff";
111
+ color: string;
75
112
  padding: string;
76
113
  borderRadius: number;
77
- boxShadow: "0 20px 40px rgba(0,0,0,0.35)";
114
+ boxShadow: `0 20px 40px ${string}`;
78
115
  display: "flex";
79
116
  alignItems: "center";
80
117
  gap: number;
@@ -93,7 +130,7 @@ declare const S: {
93
130
  fontWeight: number;
94
131
  textTransform: "uppercase";
95
132
  letterSpacing: string;
96
- color: "#dbeafe";
133
+ color: string;
97
134
  };
98
135
  divider: {
99
136
  width: number;
@@ -105,7 +142,7 @@ declare const S: {
105
142
  fontWeight: number;
106
143
  textTransform: "uppercase";
107
144
  letterSpacing: string;
108
- color: "#9ca3af";
145
+ color: string;
109
146
  background: string;
110
147
  border: string;
111
148
  cursor: "pointer";
@@ -117,9 +154,10 @@ declare const S: {
117
154
  transform: "translateX(-50%)";
118
155
  zIndex: number;
119
156
  background: string;
157
+ color: string;
120
158
  padding: number;
121
159
  borderRadius: number;
122
- boxShadow: "0 20px 40px rgba(0,0,0,0.25)";
160
+ boxShadow: `0 20px 40px ${string}`;
123
161
  border: string;
124
162
  minWidth: number;
125
163
  cursor: "default";
@@ -129,7 +167,7 @@ declare const S: {
129
167
  display: "block";
130
168
  fontSize: number;
131
169
  fontWeight: number;
132
- color: "#9ca3af";
170
+ color: string;
133
171
  marginBottom: number;
134
172
  textTransform: "uppercase";
135
173
  };
@@ -138,7 +176,7 @@ declare const S: {
138
176
  borderRadius: number;
139
177
  padding: string;
140
178
  fontSize: number;
141
- color: "#000";
179
+ color: string;
142
180
  background: string;
143
181
  width: string;
144
182
  marginBottom: number;
@@ -153,7 +191,7 @@ declare const S: {
153
191
  };
154
192
  cancelBtn: {
155
193
  background: string;
156
- color: "#4b5563";
194
+ color: string;
157
195
  padding: string;
158
196
  borderRadius: number;
159
197
  fontSize: number;
@@ -168,10 +206,11 @@ declare const S: {
168
206
  alignItems: "center";
169
207
  gap: number;
170
208
  background: string;
209
+ color: string;
171
210
  backdropFilter: "blur(8px)";
172
211
  padding: number;
173
212
  borderRadius: number;
174
- boxShadow: "0 8px 24px rgba(0,0,0,0.3)";
213
+ boxShadow: `0 8px 24px ${string}`;
175
214
  border: string;
176
215
  fontFamily: "system-ui, -apple-system, sans-serif";
177
216
  };
@@ -181,9 +220,10 @@ declare const S: {
181
220
  maxHeight: string;
182
221
  overflowY: "auto";
183
222
  background: string;
223
+ color: string;
184
224
  padding: number;
185
225
  borderRadius: number;
186
- boxShadow: "0 12px 32px rgba(0,0,0,0.25)";
226
+ boxShadow: `0 12px 32px ${string}`;
187
227
  border: string;
188
228
  minWidth: number;
189
229
  maxWidth: string;
@@ -199,7 +239,7 @@ declare const S: {
199
239
  borderRadius: number;
200
240
  border: string;
201
241
  background: string;
202
- color: "#e5e7eb";
242
+ color: string;
203
243
  cursor: "pointer";
204
244
  padding: number;
205
245
  };
@@ -229,9 +269,9 @@ declare const S: {
229
269
  height: string;
230
270
  width: string;
231
271
  background: string;
232
- color: "#111827";
272
+ color: string;
233
273
  zIndex: number;
234
- boxShadow: "-12px 0 32px rgba(0,0,0,0.2)";
274
+ boxShadow: `-12px 0 32px ${string}`;
235
275
  display: "flex";
236
276
  flexDirection: "column";
237
277
  fontFamily: "system-ui, -apple-system, sans-serif";
@@ -273,7 +313,7 @@ declare const S: {
273
313
  padding: string;
274
314
  fontSize: number;
275
315
  background: string;
276
- color: "#111827";
316
+ color: string;
277
317
  };
278
318
  badge: {
279
319
  fontSize: number;
@@ -290,7 +330,7 @@ declare const S: {
290
330
  fontWeight: number;
291
331
  textTransform: "uppercase";
292
332
  letterSpacing: string;
293
- color: "#9ca3af";
333
+ color: string;
294
334
  margin: string;
295
335
  };
296
336
  pickerScrim: {
@@ -307,10 +347,10 @@ declare const S: {
307
347
  width: string;
308
348
  maxHeight: string;
309
349
  background: string;
310
- color: "#111827";
350
+ color: string;
311
351
  borderRadius: number;
312
352
  zIndex: number;
313
- boxShadow: "0 24px 64px rgba(0,0,0,0.35)";
353
+ boxShadow: `0 24px 64px ${string}`;
314
354
  display: "flex";
315
355
  flexDirection: "column";
316
356
  overflow: "hidden";
@@ -332,7 +372,7 @@ declare const S: {
332
372
  padding: number;
333
373
  };
334
374
  pickerTileActive: {
335
- borderColor: "#2563eb";
375
+ borderColor: string;
336
376
  };
337
377
  pickerThumb: {
338
378
  width: string;
@@ -346,14 +386,14 @@ declare const S: {
346
386
  padding: number;
347
387
  textAlign: "center";
348
388
  fontSize: number;
349
- color: "#6b7280";
389
+ color: string;
350
390
  marginBottom: number;
351
391
  cursor: "pointer";
352
392
  };
353
393
  dropzoneActive: {
354
- borderColor: "#2563eb";
394
+ borderColor: string;
355
395
  background: string;
356
- color: "#1d4ed8";
396
+ color: string;
357
397
  };
358
398
  previewThumb: {
359
399
  width: string;
@@ -368,7 +408,7 @@ declare const S: {
368
408
  };
369
409
  secondaryBtn: {
370
410
  background: string;
371
- color: "#111827";
411
+ color: string;
372
412
  padding: string;
373
413
  borderRadius: number;
374
414
  fontSize: number;
@@ -378,6 +418,38 @@ declare const S: {
378
418
  width: string;
379
419
  marginBottom: number;
380
420
  };
421
+ /**
422
+ * Edit affordance for image fields, drawn as separate fixed elements instead
423
+ * of styling the <img> itself. Backgrounds (next/image `fill` behind
424
+ * overlaid content) can't take an in-place affordance: it either sits under
425
+ * the content and can't be clicked, or gets lifted over it and hides it.
426
+ * The outline ignores the pointer so overlaid content stays interactive;
427
+ * the handle is the one clickable piece.
428
+ */
429
+ markerOutline: {
430
+ position: "fixed";
431
+ zIndex: number;
432
+ pointerEvents: "none";
433
+ boxSizing: "border-box";
434
+ borderRadius: number;
435
+ };
436
+ markerHandle: {
437
+ position: "fixed";
438
+ zIndex: number;
439
+ display: "inline-flex";
440
+ alignItems: "center";
441
+ gap: number;
442
+ padding: string;
443
+ borderRadius: number;
444
+ border: string;
445
+ background: string;
446
+ color: "#fff";
447
+ fontSize: number;
448
+ fontWeight: number;
449
+ fontFamily: "system-ui, -apple-system, sans-serif";
450
+ cursor: "pointer";
451
+ boxShadow: `0 4px 12px ${string}`;
452
+ };
381
453
  repeaterItem: {
382
454
  position: "relative";
383
455
  outline: string;
@@ -391,10 +463,12 @@ declare const S: {
391
463
  display: "flex";
392
464
  gap: number;
393
465
  background: string;
466
+ color: string;
394
467
  backdropFilter: "blur(6px)";
395
468
  padding: number;
396
469
  borderRadius: number;
397
- boxShadow: "0 4px 12px rgba(0,0,0,0.25)";
470
+ boxShadow: `0 4px 12px ${string}`;
471
+ border: string;
398
472
  };
399
473
  repeaterAddRow: {
400
474
  display: "flex";
@@ -411,7 +485,7 @@ declare const S: {
411
485
  borderRadius: number;
412
486
  border: string;
413
487
  background: string;
414
- color: "#2563eb";
488
+ color: string;
415
489
  fontSize: number;
416
490
  fontWeight: number;
417
491
  cursor: "pointer";
@@ -421,10 +495,10 @@ declare const S: {
421
495
  borderRadius: number;
422
496
  padding: string;
423
497
  fontSize: number;
424
- color: "#000";
498
+ color: string;
425
499
  background: string;
426
500
  minWidth: number;
427
501
  };
428
502
  };
429
503
 
430
- export { S };
504
+ export { S, THEME_CSS, v };