@driftime/sanity-plugin-handbook 0.2.0 → 0.3.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 (69) hide show
  1. package/README.md +133 -80
  2. package/dist/index.d.ts +203 -110
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +2790 -2064
  5. package/dist/index.js.map +1 -1
  6. package/package.json +36 -37
  7. package/dist/index.cjs +0 -2094
  8. package/dist/index.cjs.map +0 -1
  9. package/dist/index.d.cts +0 -143
  10. package/src/blocks/callout/block.tsx +0 -56
  11. package/src/blocks/callout/content.tsx +0 -41
  12. package/src/blocks/callout/preview.tsx +0 -15
  13. package/src/blocks/code/block.tsx +0 -18
  14. package/src/blocks/code/content.tsx +0 -18
  15. package/src/blocks/code/preview.tsx +0 -17
  16. package/src/blocks/horizontal-rule/block.tsx +0 -5
  17. package/src/blocks/horizontal-rule/content.tsx +0 -8
  18. package/src/blocks/horizontal-rule/preview.tsx +0 -5
  19. package/src/blocks/image/block.tsx +0 -23
  20. package/src/blocks/image/content.tsx +0 -31
  21. package/src/blocks/image/preview.tsx +0 -23
  22. package/src/blocks/video/block.tsx +0 -21
  23. package/src/blocks/video/content.tsx +0 -37
  24. package/src/blocks/video/preview.tsx +0 -21
  25. package/src/components/content-panel.tsx +0 -58
  26. package/src/components/decorators.tsx +0 -53
  27. package/src/components/document-types.tsx +0 -49
  28. package/src/components/field.tsx +0 -530
  29. package/src/components/guide-content.tsx +0 -117
  30. package/src/components/guides.tsx +0 -36
  31. package/src/components/pane-header.tsx +0 -26
  32. package/src/components/sidebar-group.tsx +0 -30
  33. package/src/components/sidebar-tab.tsx +0 -78
  34. package/src/contexts/handbook-context.tsx +0 -84
  35. package/src/getting-started/document-types.tsx +0 -104
  36. package/src/getting-started/how-to-use.tsx +0 -95
  37. package/src/getting-started/overview.tsx +0 -65
  38. package/src/hooks/use-container-width.ts +0 -41
  39. package/src/hooks/use-handbook-configuration.ts +0 -74
  40. package/src/hooks/use-is-handbook-editor.ts +0 -18
  41. package/src/icons/book-open-text.tsx +0 -22
  42. package/src/icons/book-text.tsx +0 -19
  43. package/src/icons/code.tsx +0 -18
  44. package/src/icons/image.tsx +0 -19
  45. package/src/icons/info.tsx +0 -19
  46. package/src/icons/layout-grid.tsx +0 -20
  47. package/src/icons/lightbulb.tsx +0 -19
  48. package/src/icons/list-plus.tsx +0 -21
  49. package/src/icons/message-circle-question-mark.tsx +0 -19
  50. package/src/icons/minus.tsx +0 -17
  51. package/src/icons/triangle-alert.tsx +0 -19
  52. package/src/icons/video.tsx +0 -18
  53. package/src/index.ts +0 -145
  54. package/src/layouts/content.tsx +0 -13
  55. package/src/layouts/sidebar.tsx +0 -15
  56. package/src/layouts/tool.tsx +0 -205
  57. package/src/lib/handbook-structure.ts +0 -47
  58. package/src/lib/icons.ts +0 -16
  59. package/src/lib/utils.ts +0 -69
  60. package/src/schemas/annotations/link.ts +0 -19
  61. package/src/schemas/blocks/callout.ts +0 -69
  62. package/src/schemas/blocks/code.ts +0 -46
  63. package/src/schemas/blocks/horizontal-rule.ts +0 -31
  64. package/src/schemas/blocks/image.ts +0 -40
  65. package/src/schemas/blocks/video.ts +0 -34
  66. package/src/schemas/guide-content.ts +0 -58
  67. package/src/schemas/types/guide.ts +0 -48
  68. package/src/schemas/types/handbook.ts +0 -86
  69. package/src/types.ts +0 -101
package/dist/index.js CHANGED
@@ -1,2097 +1,2823 @@
1
- import { useClient, useSchema, defineArrayMember, defineField, defineType, useCurrentUser, definePlugin } from "sanity";
2
- import { jsxs, jsx, Fragment } from "react/jsx-runtime";
3
- import { forwardRef, useState, useEffect, createContext, useContext, useRef, createElement, useCallback, useMemo } from "react";
4
- import { Card, Flex, Text, Box, Stack, Heading, useClickOutsideEvent, Popover, Code, Button } from "@sanity/ui";
5
- function BookTextIcon(props) {
6
- return /* @__PURE__ */ jsxs(
7
- "svg",
8
- {
9
- xmlns: "http://www.w3.org/2000/svg",
10
- viewBox: "0 0 24 24",
11
- fill: "none",
12
- stroke: "currentColor",
13
- strokeLinecap: "round",
14
- strokeLinejoin: "round",
15
- ...props,
16
- children: [
17
- /* @__PURE__ */ jsx("path", { d: "M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20" }),
18
- /* @__PURE__ */ jsx("path", { d: "M8 11h8" }),
19
- /* @__PURE__ */ jsx("path", { d: "M8 7h6" })
20
- ]
21
- }
22
- );
23
- }
24
- const ArrowLeftIcon = /* @__PURE__ */ forwardRef(function(props, ref) {
25
- return /* @__PURE__ */ jsxs(
26
- "svg",
27
- {
28
- "data-sanity-icon": "arrow-left",
29
- width: "1em",
30
- height: "1em",
31
- viewBox: "0 0 25 25",
32
- fill: "none",
33
- xmlns: "http://www.w3.org/2000/svg",
34
- ...props,
35
- ref,
36
- children: [
37
- /* @__PURE__ */ jsx("path", { d: "M5.5 12.5H20", stroke: "currentColor", strokeWidth: 1.2, strokeLinejoin: "round" }),
38
- /* @__PURE__ */ jsx(
39
- "path",
40
- {
41
- d: "M11 18L5.5 12.5L11 7",
42
- stroke: "currentColor",
43
- strokeWidth: 1.2,
44
- strokeLinejoin: "round"
45
- }
46
- )
47
- ]
48
- }
49
- );
50
- }), ChevronDownIcon = /* @__PURE__ */ forwardRef(function(props, ref) {
51
- return /* @__PURE__ */ jsx(
52
- "svg",
53
- {
54
- "data-sanity-icon": "chevron-down",
55
- width: "1em",
56
- height: "1em",
57
- viewBox: "0 0 25 25",
58
- fill: "none",
59
- xmlns: "http://www.w3.org/2000/svg",
60
- ...props,
61
- ref,
62
- children: /* @__PURE__ */ jsx(
63
- "path",
64
- {
65
- d: "M17 10L12.5 14.5L8 10",
66
- stroke: "currentColor",
67
- strokeWidth: 1.2,
68
- strokeLinejoin: "round"
69
- }
70
- )
71
- }
72
- );
73
- }), ChevronRightIcon = /* @__PURE__ */ forwardRef(function(props, ref) {
74
- return /* @__PURE__ */ jsx(
75
- "svg",
76
- {
77
- "data-sanity-icon": "chevron-right",
78
- width: "1em",
79
- height: "1em",
80
- viewBox: "0 0 25 25",
81
- fill: "none",
82
- xmlns: "http://www.w3.org/2000/svg",
83
- ...props,
84
- ref,
85
- children: /* @__PURE__ */ jsx(
86
- "path",
87
- {
88
- d: "M10 8L14.5 12.5L10 17",
89
- stroke: "currentColor",
90
- strokeWidth: 1.2,
91
- strokeLinejoin: "round"
92
- }
93
- )
94
- }
95
- );
96
- });
97
- function PaneHeader({ title }) {
98
- return /* @__PURE__ */ jsx("div", { style: { position: "sticky", top: 0, zIndex: 1, lineHeight: 0 }, children: /* @__PURE__ */ jsx(Card, { tone: "inherit", children: /* @__PURE__ */ jsx(Flex, { direction: "column", padding: 3, style: { boxSizing: "border-box" }, children: /* @__PURE__ */ jsx(Flex, { align: "flex-start", children: /* @__PURE__ */ jsx(Card, { flex: 1, paddingLeft: 2, padding: 2, children: /* @__PURE__ */ jsx(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, textOverflow: "ellipsis", weight: "semibold", style: { cursor: "default", outline: "none" }, children: title }) }) }) }) }) }) });
99
- }
100
- const query = `*[_type == "handbook.handbook"][0]{
101
- groups[]{
102
- _key,
103
- title,
104
- guides[]{
105
- _key,
106
- ...@->{
107
- _id,
108
- _type,
109
- title,
110
- description,
111
- content[]{
112
- ...,
113
- _type == "handbook.image" => {
114
- ...,
115
- "asset": { "url": asset.asset->url }
116
- },
117
- _type == "handbook.video" => {
118
- ...,
119
- "asset": { "url": asset.asset->url }
120
- }
121
- }
122
- }
123
- }
124
- }
125
- }`, listenQuery = '*[_type == "handbook.handbook" || _type == "handbook.guide"]';
126
- function useHandbookConfiguration() {
127
- const client = useClient({ apiVersion: "2026-01-01" }), [configuration, setConfiguration] = useState(null), [loading, setLoading] = useState(!0);
128
- return useEffect(() => {
129
- async function fetchConfiguration() {
130
- const result = await client.fetch(query);
131
- setConfiguration(result), setLoading(!1);
132
- }
133
- fetchConfiguration();
134
- const subscription = client.listen(listenQuery).subscribe(() => {
135
- fetchConfiguration();
136
- });
137
- return () => {
138
- subscription.unsubscribe();
139
- };
140
- }, [client]), { configuration, loading };
1
+ import { CommandList, PreviewCard, SanityDefaultPreview, defineArrayMember, defineField, definePlugin, defineType, useClient, useCurrentUser, useSchema } from "sanity";
2
+ import { c } from "react/compiler-runtime";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { createContext, createElement, useContext, useEffect, useRef, useState } from "react";
5
+ import { Box, Button, Card, Flex, Heading, Layer, LayerProvider, Stack, Text, useClickOutsideEvent, useElementSize, useTheme_v2 } from "@sanity/ui";
6
+ import { Code } from "@sanity/ui/code";
7
+ import { Pane, PaneContent, PaneLayout } from "sanity/structure";
8
+ import { PaneContext, PaneLayoutContext } from "sanity/_singletons";
9
+ import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
10
+ import { ChevronDownIcon } from "@sanity/icons/ChevronDown";
11
+ import { ChevronRightIcon } from "@sanity/icons/ChevronRight";
12
+ import { Popover } from "@sanity/ui/popover";
13
+ import { PortableText } from "@portabletext/react";
14
+ /** Properties every icon the plugin draws is rendered with. */
15
+ const defaultIconProps = {
16
+ width: "1em",
17
+ height: "1em",
18
+ strokeWidth: 1.5
19
+ };
20
+ function BookOpenTextIcon(props) {
21
+ let $ = c(8), t0, t1, t2, t3, t4, t5;
22
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "M12 7v14" }), t1 = /* @__PURE__ */ jsx("path", { d: "M16 12h2" }), t2 = /* @__PURE__ */ jsx("path", { d: "M16 8h2" }), t3 = /* @__PURE__ */ jsx("path", { d: "M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z" }), t4 = /* @__PURE__ */ jsx("path", { d: "M6 12h2" }), t5 = /* @__PURE__ */ jsx("path", { d: "M6 8h2" }), $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3, $[4] = t4, $[5] = t5) : (t0 = $[0], t1 = $[1], t2 = $[2], t3 = $[3], t4 = $[4], t5 = $[5]);
23
+ let t6;
24
+ return $[6] === props ? t6 = $[7] : (t6 = /* @__PURE__ */ jsxs("svg", {
25
+ xmlns: "http://www.w3.org/2000/svg",
26
+ width: 24,
27
+ height: 24,
28
+ viewBox: "0 0 24 24",
29
+ fill: "none",
30
+ stroke: "currentColor",
31
+ strokeWidth: 2,
32
+ strokeLinecap: "round",
33
+ strokeLinejoin: "round",
34
+ ...props,
35
+ children: [
36
+ t0,
37
+ t1,
38
+ t2,
39
+ t3,
40
+ t4,
41
+ t5
42
+ ]
43
+ }), $[6] = props, $[7] = t6), t6;
44
+ }
45
+ /**
46
+ * Creates a Sanity Studio icon component from an SVG icon.
47
+ *
48
+ * @param icon - The icon component to wrap.
49
+ * @param props - Additional props merged over the default properties a Studio icon is drawn with.
50
+ * @returns A Studio icon component.
51
+ */
52
+ function createSanityIcon(icon, props) {
53
+ let Icon = icon;
54
+ function SanityIcon() {
55
+ return createElement(Icon, {
56
+ ...defaultIconProps,
57
+ ...props
58
+ });
59
+ }
60
+ return SanityIcon;
61
+ }
62
+ function PortableCode(t0) {
63
+ let $ = c(8), props, style;
64
+ $[0] === t0 ? (props = $[1], style = $[2]) : ({style, ...props} = t0, $[0] = t0, $[1] = props, $[2] = style);
65
+ let t1;
66
+ $[3] === style ? t1 = $[4] : (t1 = {
67
+ paddingBlock: 2,
68
+ paddingInline: 4,
69
+ fontSize: "0.875em",
70
+ backgroundColor: "var(--card-code-bg-color)",
71
+ borderRadius: 2,
72
+ ...style
73
+ }, $[3] = style, $[4] = t1);
74
+ let t2;
75
+ return $[5] !== props || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx("code", {
76
+ style: t1,
77
+ ...props
78
+ }), $[5] = props, $[6] = t1, $[7] = t2) : t2 = $[7], t2;
79
+ }
80
+ function CodeDecorator(t0) {
81
+ let $ = c(2), { children } = t0, t1;
82
+ return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(PortableCode, { children }), $[0] = children, $[1] = t1), t1;
83
+ }
84
+ function ListItemStyle(t0) {
85
+ let $ = c(3), { children } = t0, t1;
86
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = { marginTop: "0.375em" }, $[0] = t1) : t1 = $[0];
87
+ let t2;
88
+ return $[1] === children ? t2 = $[2] : (t2 = /* @__PURE__ */ jsx(Text, {
89
+ size: 1,
90
+ style: t1,
91
+ children
92
+ }), $[1] = children, $[2] = t2), t2;
93
+ }
94
+ function PortableBlockquote(t0) {
95
+ let $ = c(15), children, muted, props, style;
96
+ $[0] === t0 ? (children = $[1], muted = $[2], props = $[3], style = $[4]) : ({muted, children, style, ...props} = t0, $[0] = t0, $[1] = children, $[2] = muted, $[3] = props, $[4] = style);
97
+ let t1;
98
+ $[5] === style ? t1 = $[6] : (t1 = {
99
+ borderLeft: "2px solid var(--card-border-color)",
100
+ ...style
101
+ }, $[5] = style, $[6] = t1);
102
+ let t2;
103
+ $[7] === Symbol.for("react.memo_cache_sentinel") ? (t2 = { fontStyle: "italic" }, $[7] = t2) : t2 = $[7];
104
+ let t3;
105
+ $[8] !== children || $[9] !== muted ? (t3 = /* @__PURE__ */ jsx(Text, {
106
+ size: 1,
107
+ muted,
108
+ style: t2,
109
+ children
110
+ }), $[8] = children, $[9] = muted, $[10] = t3) : t3 = $[10];
111
+ let t4;
112
+ return $[11] !== props || $[12] !== t1 || $[13] !== t3 ? (t4 = /* @__PURE__ */ jsx(Box, {
113
+ paddingY: 1,
114
+ paddingLeft: 3,
115
+ style: t1,
116
+ ...props,
117
+ children: t3
118
+ }), $[11] = props, $[12] = t1, $[13] = t3, $[14] = t4) : t4 = $[14], t4;
119
+ }
120
+ function PortableHeading(props) {
121
+ let $ = c(2), t0;
122
+ return $[0] === props ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Text, {
123
+ as: "h2",
124
+ size: 1,
125
+ weight: "medium",
126
+ ...props
127
+ }), $[0] = props, $[1] = t0), t0;
128
+ }
129
+ function PortableParagraph(props) {
130
+ let $ = c(2), t0;
131
+ return $[0] === props ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Text, {
132
+ size: 1,
133
+ ...props
134
+ }), $[0] = props, $[1] = t0), t0;
135
+ }
136
+ function ParagraphStyle(t0) {
137
+ let $ = c(2), { children } = t0, t1;
138
+ return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(PortableParagraph, { children }), $[0] = children, $[1] = t1), t1;
139
+ }
140
+ function HeadingStyle(t0) {
141
+ let $ = c(2), { children } = t0, t1;
142
+ return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(PortableHeading, { children }), $[0] = children, $[1] = t1), t1;
143
+ }
144
+ function BlockquoteStyle(t0) {
145
+ let $ = c(2), { children } = t0, t1;
146
+ return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(PortableBlockquote, { children }), $[0] = children, $[1] = t1), t1;
141
147
  }
142
- function isDefined(value) {
143
- return value == null || value === !1 ? !1 : typeof value == "string" ? value.trim() !== "" : Array.isArray(value) ? value.some((element) => isDefined(element)) : typeof value == "object" ? Object.keys(value).length > 0 : !0;
148
+ const linkAnnotation = defineArrayMember({
149
+ name: "link",
150
+ type: "object",
151
+ description: "Link applied to the selected text.",
152
+ preview: {
153
+ select: { href: "href" },
154
+ prepare(selection) {
155
+ let { href } = selection;
156
+ return { title: href ?? "Link" };
157
+ }
158
+ },
159
+ fields: [defineField({
160
+ name: "href",
161
+ title: "URL",
162
+ type: "url",
163
+ description: "Web address destination for this link. Supports http, https, mailto, and tel schemes.",
164
+ validation: (rule) => rule.uri({ scheme: [
165
+ "http",
166
+ "https",
167
+ "mailto",
168
+ "tel"
169
+ ] })
170
+ })]
171
+ });
172
+ function InfoIcon(props) {
173
+ let $ = c(5), t0, t1, t2;
174
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("circle", {
175
+ cx: "12",
176
+ cy: "12",
177
+ r: "10"
178
+ }), t1 = /* @__PURE__ */ jsx("path", { d: "M12 16v-4" }), t2 = /* @__PURE__ */ jsx("path", { d: "M12 8h.01" }), $[0] = t0, $[1] = t1, $[2] = t2) : (t0 = $[0], t1 = $[1], t2 = $[2]);
179
+ let t3;
180
+ return $[3] === props ? t3 = $[4] : (t3 = /* @__PURE__ */ jsxs("svg", {
181
+ xmlns: "http://www.w3.org/2000/svg",
182
+ width: 24,
183
+ height: 24,
184
+ viewBox: "0 0 24 24",
185
+ fill: "none",
186
+ stroke: "currentColor",
187
+ strokeWidth: 2,
188
+ strokeLinecap: "round",
189
+ strokeLinejoin: "round",
190
+ ...props,
191
+ children: [
192
+ t0,
193
+ t1,
194
+ t2
195
+ ]
196
+ }), $[3] = props, $[4] = t3), t3;
144
197
  }
145
- function isPermittedEditor(editors, email) {
146
- return isDefined(editors) ? isDefined(email) ? editors.includes(email) : !1 : !0;
198
+ function LightbulbIcon(props) {
199
+ let $ = c(5), t0, t1, t2;
200
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5" }), t1 = /* @__PURE__ */ jsx("path", { d: "M9 18h6" }), t2 = /* @__PURE__ */ jsx("path", { d: "M10 22h4" }), $[0] = t0, $[1] = t1, $[2] = t2) : (t0 = $[0], t1 = $[1], t2 = $[2]);
201
+ let t3;
202
+ return $[3] === props ? t3 = $[4] : (t3 = /* @__PURE__ */ jsxs("svg", {
203
+ xmlns: "http://www.w3.org/2000/svg",
204
+ width: 24,
205
+ height: 24,
206
+ viewBox: "0 0 24 24",
207
+ fill: "none",
208
+ stroke: "currentColor",
209
+ strokeWidth: 2,
210
+ strokeLinecap: "round",
211
+ strokeLinejoin: "round",
212
+ ...props,
213
+ children: [
214
+ t0,
215
+ t1,
216
+ t2
217
+ ]
218
+ }), $[3] = props, $[4] = t3), t3;
147
219
  }
220
+ function TriangleAlertIcon(props) {
221
+ let $ = c(5), t0, t1, t2;
222
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }), t1 = /* @__PURE__ */ jsx("path", { d: "M12 9v4" }), t2 = /* @__PURE__ */ jsx("path", { d: "M12 17h.01" }), $[0] = t0, $[1] = t1, $[2] = t2) : (t0 = $[0], t1 = $[1], t2 = $[2]);
223
+ let t3;
224
+ return $[3] === props ? t3 = $[4] : (t3 = /* @__PURE__ */ jsxs("svg", {
225
+ xmlns: "http://www.w3.org/2000/svg",
226
+ width: 24,
227
+ height: 24,
228
+ viewBox: "0 0 24 24",
229
+ fill: "none",
230
+ stroke: "currentColor",
231
+ strokeWidth: 2,
232
+ strokeLinecap: "round",
233
+ strokeLinejoin: "round",
234
+ ...props,
235
+ children: [
236
+ t0,
237
+ t1,
238
+ t2
239
+ ]
240
+ }), $[3] = props, $[4] = t3), t3;
241
+ }
242
+ /** Presentation for each callout variant. */
243
+ const presentation = {
244
+ tip: {
245
+ icon: LightbulbIcon,
246
+ tone: "positive"
247
+ },
248
+ info: {
249
+ icon: InfoIcon,
250
+ tone: "primary"
251
+ },
252
+ warning: {
253
+ icon: TriangleAlertIcon,
254
+ tone: "caution"
255
+ }
256
+ };
257
+ function CalloutContent(t0) {
258
+ let $ = c(17), children, props, variant;
259
+ $[0] === t0 ? (children = $[1], props = $[2], variant = $[3]) : ({variant, children, ...props} = t0, $[0] = t0, $[1] = children, $[2] = props, $[3] = variant);
260
+ let { icon: Icon, tone } = presentation[variant], t1;
261
+ $[4] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
262
+ flexShrink: 0,
263
+ marginTop: "-2px",
264
+ fontSize: "16px",
265
+ color: "var(--card-icon-color)"
266
+ }, $[4] = t1) : t1 = $[4];
267
+ let t2;
268
+ $[5] === Icon ? t2 = $[6] : (t2 = /* @__PURE__ */ jsx("div", {
269
+ style: t1,
270
+ children: /* @__PURE__ */ jsx(Icon, { ...defaultIconProps })
271
+ }), $[5] = Icon, $[6] = t2);
272
+ let t3;
273
+ $[7] === Symbol.for("react.memo_cache_sentinel") ? (t3 = { color: "var(--card-icon-color)" }, $[7] = t3) : t3 = $[7];
274
+ let t4;
275
+ $[8] === children ? t4 = $[9] : (t4 = /* @__PURE__ */ jsx(Text, {
276
+ size: 1,
277
+ style: t3,
278
+ children
279
+ }), $[8] = children, $[9] = t4);
280
+ let t5;
281
+ $[10] !== t2 || $[11] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Flex, {
282
+ align: "flex-start",
283
+ gap: 3,
284
+ children: [t2, t4]
285
+ }), $[10] = t2, $[11] = t4, $[12] = t5) : t5 = $[12];
286
+ let t6;
287
+ return $[13] !== props || $[14] !== t5 || $[15] !== tone ? (t6 = /* @__PURE__ */ jsx(Card, {
288
+ padding: 4,
289
+ radius: 2,
290
+ tone,
291
+ ...props,
292
+ children: t5
293
+ }), $[13] = props, $[14] = t5, $[15] = tone, $[16] = t6) : t6 = $[16], t6;
294
+ }
295
+ function CalloutPreview(t0) {
296
+ let $ = c(8), { variant, body } = t0, t1 = variant ?? "tip", t2;
297
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t2 = {
298
+ display: "flex",
299
+ flexDirection: "column",
300
+ gap: 12
301
+ }, $[0] = t2) : t2 = $[0];
302
+ let t3;
303
+ $[1] === body ? t3 = $[2] : (t3 = body?.map(_temp2$1), $[1] = body, $[2] = t3);
304
+ let t4;
305
+ $[3] === t3 ? t4 = $[4] : (t4 = /* @__PURE__ */ jsx("div", {
306
+ style: t2,
307
+ children: t3
308
+ }), $[3] = t3, $[4] = t4);
309
+ let t5;
310
+ return $[5] !== t1 || $[6] !== t4 ? (t5 = /* @__PURE__ */ jsx(CalloutContent, {
311
+ variant: t1,
312
+ children: t4
313
+ }), $[5] = t1, $[6] = t4, $[7] = t5) : t5 = $[7], t5;
314
+ }
315
+ function _temp2$1(t0) {
316
+ let { _key, children } = t0;
317
+ return /* @__PURE__ */ jsx("div", {
318
+ style: { whiteSpace: "pre-wrap" },
319
+ children: children.map(_temp$3).join("")
320
+ }, _key);
321
+ }
322
+ function _temp$3(child) {
323
+ return child.text;
324
+ }
325
+ function MessageCircleIcon(props) {
326
+ let $ = c(3), t0;
327
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719" }), $[0] = t0) : t0 = $[0];
328
+ let t1;
329
+ return $[1] === props ? t1 = $[2] : (t1 = /* @__PURE__ */ jsx("svg", {
330
+ xmlns: "http://www.w3.org/2000/svg",
331
+ width: 24,
332
+ height: 24,
333
+ viewBox: "0 0 24 24",
334
+ fill: "none",
335
+ stroke: "currentColor",
336
+ strokeWidth: 2,
337
+ strokeLinecap: "round",
338
+ strokeLinejoin: "round",
339
+ ...props,
340
+ children: t0
341
+ }), $[1] = props, $[2] = t1), t1;
342
+ }
343
+ /** Type name of the callout block. */
344
+ const calloutTypeName = "handbook.callout", calloutType = defineType({
345
+ name: calloutTypeName,
346
+ type: "object",
347
+ title: "Callout",
348
+ icon: createSanityIcon(MessageCircleIcon),
349
+ description: "Highlighted message block drawing attention to tips, supplementary information, or warnings.",
350
+ components: { preview: CalloutPreview },
351
+ preview: {
352
+ select: {
353
+ variant: "variant",
354
+ body: "body"
355
+ },
356
+ prepare(selection) {
357
+ let { variant, body } = selection;
358
+ return {
359
+ title: "Callout",
360
+ variant,
361
+ body
362
+ };
363
+ }
364
+ },
365
+ fields: [defineField({
366
+ name: "variant",
367
+ type: "string",
368
+ description: "Visual style and intent of the callout.",
369
+ initialValue: "tip",
370
+ validation: (rule) => rule.required(),
371
+ options: {
372
+ list: [
373
+ {
374
+ title: "Tip",
375
+ value: "tip"
376
+ },
377
+ {
378
+ title: "Information",
379
+ value: "info"
380
+ },
381
+ {
382
+ title: "Warning",
383
+ value: "warning"
384
+ }
385
+ ],
386
+ layout: "radio",
387
+ direction: "horizontal"
388
+ }
389
+ }), defineField({
390
+ name: "body",
391
+ type: "array",
392
+ description: "Content displayed inside the callout. Supports inline formatting and links.",
393
+ of: [defineArrayMember({
394
+ name: "block",
395
+ type: "block",
396
+ styles: [{
397
+ title: "Normal",
398
+ value: "normal",
399
+ component: ParagraphStyle
400
+ }],
401
+ lists: [],
402
+ marks: {
403
+ decorators: [
404
+ {
405
+ title: "Bold",
406
+ value: "strong"
407
+ },
408
+ {
409
+ title: "Italic",
410
+ value: "em"
411
+ },
412
+ {
413
+ title: "Strikethrough",
414
+ value: "strike-through"
415
+ },
416
+ {
417
+ title: "Code",
418
+ value: "code",
419
+ component: CodeDecorator
420
+ }
421
+ ],
422
+ annotations: [linkAnnotation]
423
+ }
424
+ })]
425
+ })]
426
+ });
427
+ function CodeContent(t0) {
428
+ let $ = c(14), code, language, props, style;
429
+ $[0] === t0 ? (code = $[1], language = $[2], props = $[3], style = $[4]) : ({code, language, style, ...props} = t0, $[0] = t0, $[1] = code, $[2] = language, $[3] = props, $[4] = style);
430
+ let t1;
431
+ $[5] === style ? t1 = $[6] : (t1 = {
432
+ overflowX: "auto",
433
+ ...style
434
+ }, $[5] = style, $[6] = t1);
435
+ let t2;
436
+ $[7] !== code || $[8] !== language ? (t2 = /* @__PURE__ */ jsx(Code, {
437
+ size: 1,
438
+ language,
439
+ children: code
440
+ }), $[7] = code, $[8] = language, $[9] = t2) : t2 = $[9];
441
+ let t3;
442
+ return $[10] !== props || $[11] !== t1 || $[12] !== t2 ? (t3 = /* @__PURE__ */ jsx(Card, {
443
+ padding: 4,
444
+ radius: 2,
445
+ tone: "transparent",
446
+ style: t1,
447
+ ...props,
448
+ children: t2
449
+ }), $[10] = props, $[11] = t1, $[12] = t2, $[13] = t3) : t3 = $[13], t3;
450
+ }
451
+ /**
452
+ * Checks whether a value is defined and non-empty, treating `false`, empty strings, and objects with
453
+ * no keys as absent. An array is absent unless one of its elements is itself present, while anything
454
+ * built from a class counts as present on existence alone. Not intended for boolean flags.
455
+ *
456
+ * @param value - The value to check.
457
+ * @returns True if the value is defined and not empty.
458
+ */
459
+ function isDefined(value) {
460
+ if (value == null || value === !1) return !1;
461
+ if (typeof value == "string") return value.trim() !== "";
462
+ if (Array.isArray(value)) return value.some((element) => isDefined(element));
463
+ if (typeof value == "object") {
464
+ let prototype = Reflect.getPrototypeOf(value);
465
+ return prototype !== Object.prototype && prototype !== null || Object.keys(value).length > 0;
466
+ }
467
+ return !0;
468
+ }
469
+ /**
470
+ * Converts a string between different casing formats.
471
+ *
472
+ * @param value - The string to convert.
473
+ * @param format - The target casing format.
474
+ * @returns The converted string.
475
+ */
148
476
  function convertCase(value, format) {
149
- const words = value.replaceAll(/([a-z0-9])([A-Z])/g, "$1 $2").replaceAll(/[-_\s]+/g, " ").trim().toLowerCase();
150
- switch (format) {
151
- case "kebab":
152
- return words.replaceAll(/\s+/g, "-");
153
- case "snake":
154
- return words.replaceAll(/\s+/g, "_");
155
- case "camel":
156
- return words.replaceAll(/\s+(.)/g, (_match, character) => character.toUpperCase());
157
- case "pascal":
158
- return words.replaceAll(/(?:^|\s+)(.)/g, (_match, character) => character.toUpperCase());
159
- case "title":
160
- return words.replaceAll(/\b\w/g, (character) => character.toUpperCase());
161
- case "sentence":
162
- return words.replaceAll(/^(.)/g, (character) => character.toUpperCase());
163
- default:
164
- return value;
165
- }
166
- }
167
- const HandbookContext = createContext(void 0);
168
- function HandbookProvider({
169
- sidebarTitle,
170
- groups,
171
- blocks,
172
- undocumentedFieldMessage,
173
- children
174
- }) {
175
- const [activeTab, setActiveTab] = useState(null), [sidebarExpanded, setSidebarExpanded] = useState(!0), { configuration, loading } = useHandbookConfiguration();
176
- return /* @__PURE__ */ jsx(
177
- HandbookContext,
178
- {
179
- value: {
180
- sidebarTitle,
181
- activeTab,
182
- sidebarExpanded,
183
- loading,
184
- groups,
185
- configuration,
186
- blocks,
187
- undocumentedFieldMessage,
188
- setActiveTab,
189
- setSidebarExpanded
190
- },
191
- children
192
- }
193
- );
477
+ let words = value.replaceAll(/(?<lower>[a-z0-9])(?<upper>[A-Z])/gu, "$<lower> $<upper>").replaceAll(/[-_\s]+/gu, " ").trim().toLowerCase();
478
+ switch (format) {
479
+ case "kebab": return words.replaceAll(/\s+/gu, "-");
480
+ case "snake": return words.replaceAll(/\s+/gu, "_");
481
+ case "camel": return words.replaceAll(/\s+(?<character>.)/gu, (_match, character) => character.toUpperCase());
482
+ case "pascal": return words.replaceAll(/(?:^|\s+)(?<character>.)/gu, (_match, character) => character.toUpperCase());
483
+ case "title": return words.replaceAll(/\b\w/gu, (character) => character.toUpperCase());
484
+ case "sentence": return words.replaceAll(/^(?<character>.)/gu, (character) => character.toUpperCase());
485
+ default: return value;
486
+ }
487
+ }
488
+ function CodePreview(t0) {
489
+ let $ = c(3), { code, language } = t0;
490
+ if (!isDefined(code)) return null;
491
+ let t1;
492
+ return $[0] !== code || $[1] !== language ? (t1 = /* @__PURE__ */ jsx(CodeContent, {
493
+ code,
494
+ language
495
+ }), $[0] = code, $[1] = language, $[2] = t1) : t1 = $[2], t1;
194
496
  }
195
- function useHandbookContext() {
196
- const handbookContext = useContext(HandbookContext);
197
- if (!isDefined(handbookContext)) throw new Error("useHandbookContext can only be used within <HandbookProvider>");
198
- return handbookContext;
199
- }
200
- function useContainerWidth() {
201
- const reference = useRef(null), [width, setWidth] = useState(void 0);
202
- return useEffect(() => {
203
- const element = reference.current;
204
- if (!isDefined(element)) return;
205
- const observer = new ResizeObserver((entries2) => {
206
- for (const entry of entries2)
207
- setWidth(entry.contentRect.width);
208
- });
209
- return observer.observe(element), () => {
210
- observer.disconnect();
211
- };
212
- }, []), { reference, width };
213
- }
214
- function ContentPanel({ id, title, description, children }) {
215
- const { activeTab } = useHandbookContext();
216
- return activeTab !== id ? null : /* @__PURE__ */ jsxs(
217
- "div",
218
- {
219
- id: `panel-${id}`,
220
- "aria-labelledby": id,
221
- role: "tabpanel",
222
- style: { display: "flex", flexDirection: "column", height: "100%" },
223
- children: [
224
- /* @__PURE__ */ jsx(PaneHeader, { title }),
225
- /* @__PURE__ */ jsx("div", { style: { flex: 1, overflowY: "auto" }, children: /* @__PURE__ */ jsxs(
226
- Box,
227
- {
228
- style: {
229
- maxWidth: "640px",
230
- boxSizing: "border-box",
231
- marginInline: "auto",
232
- paddingInline: "20px",
233
- paddingBlockStart: "32px",
234
- paddingBlockEnd: "220px"
235
- },
236
- children: [
237
- /* @__PURE__ */ jsxs(Stack, { marginBottom: 6, space: 5, children: [
238
- /* @__PURE__ */ jsx(Heading, { as: "h2", size: 4, children: title }),
239
- isDefined(description) && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: description })
240
- ] }),
241
- children
242
- ]
243
- }
244
- ) })
245
- ]
246
- }
247
- );
497
+ function CodeIcon(props) {
498
+ let $ = c(4), t0, t1;
499
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "m16 18 6-6-6-6" }), t1 = /* @__PURE__ */ jsx("path", { d: "m8 6-6 6 6 6" }), $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]);
500
+ let t2;
501
+ return $[2] === props ? t2 = $[3] : (t2 = /* @__PURE__ */ jsxs("svg", {
502
+ xmlns: "http://www.w3.org/2000/svg",
503
+ width: 24,
504
+ height: 24,
505
+ viewBox: "0 0 24 24",
506
+ fill: "none",
507
+ stroke: "currentColor",
508
+ strokeWidth: 2,
509
+ strokeLinecap: "round",
510
+ strokeLinejoin: "round",
511
+ ...props,
512
+ children: [t0, t1]
513
+ }), $[2] = props, $[3] = t2), t2;
514
+ }
515
+ /** Type name of the code block. */
516
+ const codeTypeName = "handbook.code", codeType = defineType({
517
+ name: codeTypeName,
518
+ type: "object",
519
+ title: "Code",
520
+ icon: createSanityIcon(CodeIcon),
521
+ description: "Syntax-highlighted code block with language selection.",
522
+ components: { preview: CodePreview },
523
+ preview: { select: {
524
+ code: "code",
525
+ language: "language"
526
+ } },
527
+ fields: [defineField({
528
+ name: "code",
529
+ type: "text",
530
+ description: "The source code to display."
531
+ }), defineField({
532
+ name: "language",
533
+ type: "string",
534
+ description: "Programming language used for syntax highlighting.",
535
+ options: { list: [
536
+ {
537
+ title: "CSS",
538
+ value: "css"
539
+ },
540
+ {
541
+ title: "GROQ",
542
+ value: "groq"
543
+ },
544
+ {
545
+ title: "HTML",
546
+ value: "html"
547
+ },
548
+ {
549
+ title: "JavaScript",
550
+ value: "javascript"
551
+ },
552
+ {
553
+ title: "JSON",
554
+ value: "json"
555
+ },
556
+ {
557
+ title: "Plain Text",
558
+ value: "text"
559
+ },
560
+ {
561
+ title: "React",
562
+ value: "tsx"
563
+ },
564
+ {
565
+ title: "Shell",
566
+ value: "shell"
567
+ },
568
+ {
569
+ title: "TypeScript",
570
+ value: "typescript"
571
+ }
572
+ ] }
573
+ })]
574
+ });
575
+ function HorizontalRuleContent(t0) {
576
+ let $ = c(8), props, style;
577
+ $[0] === t0 ? (props = $[1], style = $[2]) : ({style, ...props} = t0, $[0] = t0, $[1] = props, $[2] = style);
578
+ let t1;
579
+ $[3] === style ? t1 = $[4] : (t1 = {
580
+ border: "none",
581
+ borderTop: "1px solid var(--card-border-color)",
582
+ ...style
583
+ }, $[3] = style, $[4] = t1);
584
+ let t2;
585
+ return $[5] !== props || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx("hr", {
586
+ style: t1,
587
+ ...props
588
+ }), $[5] = props, $[6] = t1, $[7] = t2) : t2 = $[7], t2;
589
+ }
590
+ function HorizontalRulePreview(_props) {
591
+ let $ = c(1), t0;
592
+ return $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx(HorizontalRuleContent, { style: { marginBlock: 8 } }), $[0] = t0) : t0 = $[0], t0;
593
+ }
594
+ function SeparatorHorizontalIcon(props) {
595
+ let $ = c(5), t0, t1, t2;
596
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "m16 16-4 4-4-4" }), t1 = /* @__PURE__ */ jsx("path", { d: "M3 12h18" }), t2 = /* @__PURE__ */ jsx("path", { d: "m8 8 4-4 4 4" }), $[0] = t0, $[1] = t1, $[2] = t2) : (t0 = $[0], t1 = $[1], t2 = $[2]);
597
+ let t3;
598
+ return $[3] === props ? t3 = $[4] : (t3 = /* @__PURE__ */ jsxs("svg", {
599
+ xmlns: "http://www.w3.org/2000/svg",
600
+ width: 24,
601
+ height: 24,
602
+ viewBox: "0 0 24 24",
603
+ fill: "none",
604
+ stroke: "currentColor",
605
+ strokeWidth: 2,
606
+ strokeLinecap: "round",
607
+ strokeLinejoin: "round",
608
+ ...props,
609
+ children: [
610
+ t0,
611
+ t1,
612
+ t2
613
+ ]
614
+ }), $[3] = props, $[4] = t3), t3;
615
+ }
616
+ /** Type name of the horizontal rule block. */
617
+ const horizontalRuleTypeName = "handbook.horizontalRule", horizontalRuleType = defineType({
618
+ name: horizontalRuleTypeName,
619
+ type: "object",
620
+ title: "Horizontal Rule",
621
+ icon: createSanityIcon(SeparatorHorizontalIcon),
622
+ description: "Visual divider between sections of content.",
623
+ components: { preview: HorizontalRulePreview },
624
+ preview: { prepare() {
625
+ return { title: "Horizontal Rule" };
626
+ } },
627
+ fields: [defineField({
628
+ name: "style",
629
+ type: "string",
630
+ description: "Reserved. A horizontal rule carries no authored content.",
631
+ hidden: !0
632
+ })]
633
+ });
634
+ function Caption(t0) {
635
+ let $ = c(13), children, props, style;
636
+ $[0] === t0 ? (children = $[1], props = $[2], style = $[3]) : ({children, style, ...props} = t0, $[0] = t0, $[1] = children, $[2] = props, $[3] = style);
637
+ let t1;
638
+ $[4] === style ? t1 = $[5] : (t1 = {
639
+ marginBlockStart: 12,
640
+ ...style
641
+ }, $[4] = style, $[5] = t1);
642
+ let t2;
643
+ $[6] === Symbol.for("react.memo_cache_sentinel") ? (t2 = { fontStyle: "italic" }, $[6] = t2) : t2 = $[6];
644
+ let t3;
645
+ $[7] === children ? t3 = $[8] : (t3 = /* @__PURE__ */ jsx(Text, {
646
+ size: 1,
647
+ muted: !0,
648
+ style: t2,
649
+ children
650
+ }), $[7] = children, $[8] = t3);
651
+ let t4;
652
+ return $[9] !== props || $[10] !== t1 || $[11] !== t3 ? (t4 = /* @__PURE__ */ jsx("div", {
653
+ style: t1,
654
+ ...props,
655
+ children: t3
656
+ }), $[9] = props, $[10] = t1, $[11] = t3, $[12] = t4) : t4 = $[12], t4;
657
+ }
658
+ function ImageContent(t0) {
659
+ let $ = c(15), alt, caption, props, url;
660
+ $[0] === t0 ? (alt = $[1], caption = $[2], props = $[3], url = $[4]) : ({url, alt, caption, ...props} = t0, $[0] = t0, $[1] = alt, $[2] = caption, $[3] = props, $[4] = url);
661
+ let t1 = alt ?? "", t2;
662
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t2 = {
663
+ display: "block",
664
+ maxWidth: "100%",
665
+ borderRadius: 4
666
+ }, $[5] = t2) : t2 = $[5];
667
+ let t3;
668
+ $[6] !== t1 || $[7] !== url ? (t3 = /* @__PURE__ */ jsx("img", {
669
+ src: url,
670
+ alt: t1,
671
+ style: t2
672
+ }), $[6] = t1, $[7] = url, $[8] = t3) : t3 = $[8];
673
+ let t4;
674
+ $[9] === caption ? t4 = $[10] : (t4 = isDefined(caption) && /* @__PURE__ */ jsx(Caption, { children: caption }), $[9] = caption, $[10] = t4);
675
+ let t5;
676
+ return $[11] !== props || $[12] !== t3 || $[13] !== t4 ? (t5 = /* @__PURE__ */ jsxs("div", {
677
+ ...props,
678
+ children: [t3, t4]
679
+ }), $[11] = props, $[12] = t3, $[13] = t4, $[14] = t5) : t5 = $[14], t5;
680
+ }
681
+ function ImagePreview(t0) {
682
+ let $ = c(5), { url, alt, caption } = t0;
683
+ if (!isDefined(url)) return null;
684
+ let t1;
685
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = { padding: 8 }, $[0] = t1) : t1 = $[0];
686
+ let t2;
687
+ return $[1] !== alt || $[2] !== caption || $[3] !== url ? (t2 = /* @__PURE__ */ jsx(ImageContent, {
688
+ url,
689
+ alt,
690
+ caption,
691
+ style: t1
692
+ }), $[1] = alt, $[2] = caption, $[3] = url, $[4] = t2) : t2 = $[4], t2;
248
693
  }
249
- function InfoIcon(props) {
250
- return /* @__PURE__ */ jsxs(
251
- "svg",
252
- {
253
- xmlns: "http://www.w3.org/2000/svg",
254
- viewBox: "0 0 24 24",
255
- fill: "none",
256
- stroke: "currentColor",
257
- strokeLinecap: "round",
258
- strokeLinejoin: "round",
259
- ...props,
260
- children: [
261
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
262
- /* @__PURE__ */ jsx("path", { d: "M12 16v-4" }),
263
- /* @__PURE__ */ jsx("path", { d: "M12 8h.01" })
264
- ]
265
- }
266
- );
694
+ function ImageIcon(props) {
695
+ let $ = c(5), t0, t1, t2;
696
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("rect", {
697
+ width: "18",
698
+ height: "18",
699
+ x: "3",
700
+ y: "3",
701
+ rx: "2",
702
+ ry: "2"
703
+ }), t1 = /* @__PURE__ */ jsx("circle", {
704
+ cx: "9",
705
+ cy: "9",
706
+ r: "2"
707
+ }), t2 = /* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" }), $[0] = t0, $[1] = t1, $[2] = t2) : (t0 = $[0], t1 = $[1], t2 = $[2]);
708
+ let t3;
709
+ return $[3] === props ? t3 = $[4] : (t3 = /* @__PURE__ */ jsxs("svg", {
710
+ xmlns: "http://www.w3.org/2000/svg",
711
+ width: 24,
712
+ height: 24,
713
+ viewBox: "0 0 24 24",
714
+ fill: "none",
715
+ stroke: "currentColor",
716
+ strokeWidth: 2,
717
+ strokeLinecap: "round",
718
+ strokeLinejoin: "round",
719
+ ...props,
720
+ children: [
721
+ t0,
722
+ t1,
723
+ t2
724
+ ]
725
+ }), $[3] = props, $[4] = t3), t3;
726
+ }
727
+ /** Type name of the image block. */
728
+ const imageTypeName = "handbook.image", imageType = defineType({
729
+ name: imageTypeName,
730
+ type: "object",
731
+ title: "Image",
732
+ icon: createSanityIcon(ImageIcon),
733
+ description: "Image with an optional caption and alternative text.",
734
+ components: { preview: ImagePreview },
735
+ preview: { select: {
736
+ caption: "caption",
737
+ alt: "alt",
738
+ url: "asset.asset.url"
739
+ } },
740
+ fields: [
741
+ defineField({
742
+ name: "asset",
743
+ title: "Image",
744
+ type: "image",
745
+ description: "Upload or select an image from the media library.",
746
+ options: { hotspot: !0 }
747
+ }),
748
+ defineField({
749
+ name: "caption",
750
+ type: "string",
751
+ description: "Caption text displayed below the image, such as a credit or a note."
752
+ }),
753
+ defineField({
754
+ name: "alt",
755
+ title: "Alternative Text",
756
+ type: "string",
757
+ description: "Describes what the image shows for people who cannot see it. Don't repeat the caption here."
758
+ })
759
+ ]
760
+ });
761
+ function VideoContent(t0) {
762
+ let $ = c(16), caption, props, url;
763
+ $[0] === t0 ? (caption = $[1], props = $[2], url = $[3]) : ({url, caption, ...props} = t0, $[0] = t0, $[1] = caption, $[2] = props, $[3] = url);
764
+ let t1;
765
+ $[4] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
766
+ display: "block",
767
+ maxWidth: "100%",
768
+ borderRadius: 4,
769
+ WebkitTransform: "translateZ(0)"
770
+ }, $[4] = t1) : t1 = $[4];
771
+ let t2 = caption ?? "Video", t3;
772
+ $[5] === t2 ? t3 = $[6] : (t3 = /* @__PURE__ */ jsx("track", {
773
+ kind: "captions",
774
+ label: t2
775
+ }), $[5] = t2, $[6] = t3);
776
+ let t4;
777
+ $[7] !== t3 || $[8] !== url ? (t4 = /* @__PURE__ */ jsx("video", {
778
+ src: url,
779
+ controls: !0,
780
+ style: t1,
781
+ children: t3
782
+ }), $[7] = t3, $[8] = url, $[9] = t4) : t4 = $[9];
783
+ let t5;
784
+ $[10] === caption ? t5 = $[11] : (t5 = isDefined(caption) && /* @__PURE__ */ jsx(Caption, { children: caption }), $[10] = caption, $[11] = t5);
785
+ let t6;
786
+ return $[12] !== props || $[13] !== t4 || $[14] !== t5 ? (t6 = /* @__PURE__ */ jsxs("div", {
787
+ ...props,
788
+ children: [t4, t5]
789
+ }), $[12] = props, $[13] = t4, $[14] = t5, $[15] = t6) : t6 = $[15], t6;
790
+ }
791
+ function VideoPreview(t0) {
792
+ let $ = c(4), { url, caption } = t0;
793
+ if (!isDefined(url)) return null;
794
+ let t1;
795
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = { padding: 8 }, $[0] = t1) : t1 = $[0];
796
+ let t2;
797
+ return $[1] !== caption || $[2] !== url ? (t2 = /* @__PURE__ */ jsx(VideoContent, {
798
+ url,
799
+ caption,
800
+ style: t1
801
+ }), $[1] = caption, $[2] = url, $[3] = t2) : t2 = $[3], t2;
802
+ }
803
+ function FilmIcon(props) {
804
+ let $ = c(10), t0, t1, t2, t3, t4, t5, t6, t7;
805
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("rect", {
806
+ x: "3",
807
+ y: "3",
808
+ width: "18",
809
+ height: "18",
810
+ rx: "2"
811
+ }), t1 = /* @__PURE__ */ jsx("path", { d: "M7 3v18" }), t2 = /* @__PURE__ */ jsx("path", { d: "M3 7.5h4" }), t3 = /* @__PURE__ */ jsx("path", { d: "M3 12h18" }), t4 = /* @__PURE__ */ jsx("path", { d: "M3 16.5h4" }), t5 = /* @__PURE__ */ jsx("path", { d: "M17 3v18" }), t6 = /* @__PURE__ */ jsx("path", { d: "M17 7.5h4" }), t7 = /* @__PURE__ */ jsx("path", { d: "M17 16.5h4" }), $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3, $[4] = t4, $[5] = t5, $[6] = t6, $[7] = t7) : (t0 = $[0], t1 = $[1], t2 = $[2], t3 = $[3], t4 = $[4], t5 = $[5], t6 = $[6], t7 = $[7]);
812
+ let t8;
813
+ return $[8] === props ? t8 = $[9] : (t8 = /* @__PURE__ */ jsxs("svg", {
814
+ xmlns: "http://www.w3.org/2000/svg",
815
+ width: 24,
816
+ height: 24,
817
+ viewBox: "0 0 24 24",
818
+ fill: "none",
819
+ stroke: "currentColor",
820
+ strokeWidth: 2,
821
+ strokeLinecap: "round",
822
+ strokeLinejoin: "round",
823
+ ...props,
824
+ children: [
825
+ t0,
826
+ t1,
827
+ t2,
828
+ t3,
829
+ t4,
830
+ t5,
831
+ t6,
832
+ t7
833
+ ]
834
+ }), $[8] = props, $[9] = t8), t8;
835
+ }
836
+ /** Type name of the video block. */
837
+ const videoTypeName = "handbook.video", videoType = defineType({
838
+ name: videoTypeName,
839
+ type: "object",
840
+ title: "Video",
841
+ icon: createSanityIcon(FilmIcon),
842
+ description: "Video with an optional caption.",
843
+ components: { preview: VideoPreview },
844
+ preview: { select: {
845
+ caption: "caption",
846
+ url: "asset.asset.url"
847
+ } },
848
+ fields: [defineField({
849
+ name: "asset",
850
+ title: "Video",
851
+ type: "file",
852
+ description: "Upload or select a video from the media library.",
853
+ options: { accept: "video/*" }
854
+ }), defineField({
855
+ name: "caption",
856
+ type: "string",
857
+ description: "Caption text displayed below the video, such as a credit or a note."
858
+ })]
859
+ });
860
+ /**
861
+ * Creates the Portable Text content field for Handbook guides, offering the built-in blocks alongside
862
+ * any a consumer registered.
863
+ *
864
+ * @param customBlocks - Custom block definitions registered by the consumer.
865
+ * @returns A field definition for the guide content array.
866
+ */
867
+ function createGuideContentField(customBlocks = []) {
868
+ return defineField({
869
+ name: "content",
870
+ type: "array",
871
+ description: "Rich text with formatting, headings, lists, images, code blocks, and custom blocks.",
872
+ of: [
873
+ defineArrayMember({
874
+ name: "block",
875
+ type: "block",
876
+ styles: [
877
+ {
878
+ title: "Paragraph",
879
+ value: "normal",
880
+ component: ParagraphStyle
881
+ },
882
+ {
883
+ title: "Heading",
884
+ value: "h2",
885
+ component: HeadingStyle
886
+ },
887
+ {
888
+ title: "Blockquote",
889
+ value: "blockquote",
890
+ component: BlockquoteStyle
891
+ }
892
+ ],
893
+ lists: [{
894
+ title: "Bullet",
895
+ value: "bullet",
896
+ component: ListItemStyle
897
+ }, {
898
+ title: "Number",
899
+ value: "number",
900
+ component: ListItemStyle
901
+ }],
902
+ marks: {
903
+ decorators: [
904
+ {
905
+ title: "Bold",
906
+ value: "strong"
907
+ },
908
+ {
909
+ title: "Italic",
910
+ value: "em"
911
+ },
912
+ {
913
+ title: "Strikethrough",
914
+ value: "strike-through"
915
+ },
916
+ {
917
+ title: "Code",
918
+ value: "code",
919
+ component: CodeDecorator
920
+ }
921
+ ],
922
+ annotations: [linkAnnotation]
923
+ }
924
+ }),
925
+ defineArrayMember({
926
+ name: imageTypeName,
927
+ type: imageTypeName
928
+ }),
929
+ defineArrayMember({
930
+ name: videoTypeName,
931
+ type: videoTypeName
932
+ }),
933
+ defineArrayMember({
934
+ name: codeTypeName,
935
+ type: codeTypeName
936
+ }),
937
+ defineArrayMember({
938
+ name: calloutTypeName,
939
+ type: calloutTypeName
940
+ }),
941
+ defineArrayMember({
942
+ name: horizontalRuleTypeName,
943
+ type: horizontalRuleTypeName
944
+ }),
945
+ ...customBlocks.map((block) => defineArrayMember({
946
+ name: block.schema.name,
947
+ type: block.schema.name
948
+ }))
949
+ ]
950
+ });
951
+ }
952
+ /** Document type name of an individual guide. */
953
+ const guideTypeName = "handbook.guide";
954
+ /**
955
+ * Creates the document type a single guide is authored as, with its content field offering the
956
+ * built-in blocks alongside any a consumer registered.
957
+ *
958
+ * @param customBlocks - Custom block definitions registered by the consumer.
959
+ * @returns A document type definition for Handbook guides.
960
+ */
961
+ function createGuideType(customBlocks = []) {
962
+ return defineType({
963
+ name: guideTypeName,
964
+ type: "document",
965
+ title: "Handbook Guide",
966
+ icon: createSanityIcon(BookOpenTextIcon),
967
+ description: "Handbook page authored with rich text, images, and custom blocks.",
968
+ preview: {
969
+ select: {
970
+ title: "title",
971
+ description: "description"
972
+ },
973
+ prepare(selection) {
974
+ let { title, description } = selection;
975
+ return {
976
+ title: title ?? "Untitled",
977
+ subtitle: description
978
+ };
979
+ }
980
+ },
981
+ fields: [
982
+ defineField({
983
+ name: "title",
984
+ type: "string",
985
+ description: "Appears in the Handbook sidebar and as the guide heading.",
986
+ validation: (rule) => rule.required()
987
+ }),
988
+ defineField({
989
+ name: "description",
990
+ type: "string",
991
+ description: "Short introduction text displayed below the guide heading."
992
+ }),
993
+ createGuideContentField(customBlocks)
994
+ ]
995
+ });
267
996
  }
268
- function LightbulbIcon(props) {
269
- return /* @__PURE__ */ jsxs(
270
- "svg",
271
- {
272
- xmlns: "http://www.w3.org/2000/svg",
273
- viewBox: "0 0 24 24",
274
- fill: "none",
275
- stroke: "currentColor",
276
- strokeLinecap: "round",
277
- strokeLinejoin: "round",
278
- ...props,
279
- children: [
280
- /* @__PURE__ */ jsx("path", { d: "M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5" }),
281
- /* @__PURE__ */ jsx("path", { d: "M9 18h6" }),
282
- /* @__PURE__ */ jsx("path", { d: "M10 22h4" })
283
- ]
284
- }
285
- );
997
+ function BookTextIcon(props) {
998
+ let $ = c(5), t0, t1, t2;
999
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20" }), t1 = /* @__PURE__ */ jsx("path", { d: "M8 11h8" }), t2 = /* @__PURE__ */ jsx("path", { d: "M8 7h6" }), $[0] = t0, $[1] = t1, $[2] = t2) : (t0 = $[0], t1 = $[1], t2 = $[2]);
1000
+ let t3;
1001
+ return $[3] === props ? t3 = $[4] : (t3 = /* @__PURE__ */ jsxs("svg", {
1002
+ xmlns: "http://www.w3.org/2000/svg",
1003
+ width: 24,
1004
+ height: 24,
1005
+ viewBox: "0 0 24 24",
1006
+ fill: "none",
1007
+ stroke: "currentColor",
1008
+ strokeWidth: 2,
1009
+ strokeLinecap: "round",
1010
+ strokeLinejoin: "round",
1011
+ ...props,
1012
+ children: [
1013
+ t0,
1014
+ t1,
1015
+ t2
1016
+ ]
1017
+ }), $[3] = props, $[4] = t3), t3;
286
1018
  }
287
- function TriangleAlertIcon(props) {
288
- return /* @__PURE__ */ jsxs(
289
- "svg",
290
- {
291
- xmlns: "http://www.w3.org/2000/svg",
292
- viewBox: "0 0 24 24",
293
- fill: "none",
294
- stroke: "currentColor",
295
- strokeLinecap: "round",
296
- strokeLinejoin: "round",
297
- ...props,
298
- children: [
299
- /* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
300
- /* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
301
- /* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
302
- ]
1019
+ function ListPlusIcon(props) {
1020
+ let $ = c(7), t0, t1, t2, t3, t4;
1021
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "M16 5H3" }), t1 = /* @__PURE__ */ jsx("path", { d: "M11 12H3" }), t2 = /* @__PURE__ */ jsx("path", { d: "M16 19H3" }), t3 = /* @__PURE__ */ jsx("path", { d: "M18 9v6" }), t4 = /* @__PURE__ */ jsx("path", { d: "M21 12h-6" }), $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3, $[4] = t4) : (t0 = $[0], t1 = $[1], t2 = $[2], t3 = $[3], t4 = $[4]);
1022
+ let t5;
1023
+ return $[5] === props ? t5 = $[6] : (t5 = /* @__PURE__ */ jsxs("svg", {
1024
+ xmlns: "http://www.w3.org/2000/svg",
1025
+ width: 24,
1026
+ height: 24,
1027
+ viewBox: "0 0 24 24",
1028
+ fill: "none",
1029
+ stroke: "currentColor",
1030
+ strokeWidth: 2,
1031
+ strokeLinecap: "round",
1032
+ strokeLinejoin: "round",
1033
+ ...props,
1034
+ children: [
1035
+ t0,
1036
+ t1,
1037
+ t2,
1038
+ t3,
1039
+ t4
1040
+ ]
1041
+ }), $[5] = props, $[6] = t5), t5;
1042
+ }
1043
+ /** Document type name of the Handbook singleton. */
1044
+ const handbookTypeName = "handbook.handbook", handbookType = defineType({
1045
+ name: handbookTypeName,
1046
+ type: "document",
1047
+ title: "Handbook",
1048
+ icon: createSanityIcon(BookTextIcon),
1049
+ description: "Defines the groups of guides shown in the Handbook sidebar, and the order they appear in.",
1050
+ preview: { prepare() {
1051
+ return { title: "Handbook" };
1052
+ } },
1053
+ fields: [defineField({
1054
+ name: "groups",
1055
+ type: "array",
1056
+ description: "Ordered list of groups displayed in the Handbook sidebar. Each group contains a title and an ordered list of guide references.",
1057
+ of: [defineArrayMember({
1058
+ name: "group",
1059
+ type: "object",
1060
+ icon: createSanityIcon(ListPlusIcon),
1061
+ description: "Named section of the Handbook sidebar holding an ordered list of guides.",
1062
+ fields: [defineField({
1063
+ name: "title",
1064
+ type: "string",
1065
+ description: "Heading displayed above this group of guides in the sidebar.",
1066
+ validation: (rule) => rule.required()
1067
+ }), defineField({
1068
+ name: "guides",
1069
+ type: "array",
1070
+ description: "Ordered list of guides within this group. Drag to reorder.",
1071
+ of: [defineArrayMember({
1072
+ name: "guide",
1073
+ type: "reference",
1074
+ to: [{ type: guideTypeName }]
1075
+ })]
1076
+ })],
1077
+ preview: {
1078
+ select: {
1079
+ title: "title",
1080
+ guide0: "guides.0.title",
1081
+ guide1: "guides.1.title",
1082
+ guide2: "guides.2.title"
1083
+ },
1084
+ prepare(selection) {
1085
+ let { title, guide0, guide1, guide2 } = selection, shown = [
1086
+ guide0,
1087
+ guide1,
1088
+ guide2
1089
+ ].filter((guide) => isDefined(guide)).slice(0, 2), hasMore = isDefined(guide2);
1090
+ function formatSubtitle() {
1091
+ return isDefined(shown) ? hasMore ? `${shown.join(", ")}, and others` : shown.join(" and ") : "No guides selected";
1092
+ }
1093
+ return {
1094
+ title: title ?? "Group",
1095
+ subtitle: formatSubtitle()
1096
+ };
1097
+ }
1098
+ }
1099
+ })]
1100
+ })]
1101
+ }), singletonTypes = /* @__PURE__ */ new Set([handbookTypeName]), documentTypes = /* @__PURE__ */ new Set([handbookTypeName, guideTypeName]), contentSpacing = {
1102
+ section: 48,
1103
+ paragraph: 16,
1104
+ heading: 48,
1105
+ media: 24,
1106
+ callout: 32,
1107
+ blockquote: 32,
1108
+ list: 32,
1109
+ nestedList: 12,
1110
+ rule: 40
1111
+ }, assetUrlFragment = "\"asset\": { \"url\": asset.asset->url }", guideFragment = `...@-> {
1112
+ ...,
1113
+ content[] { ..., ${`
1114
+ _type == "${imageTypeName}" => { ..., ${assetUrlFragment} },
1115
+ _type == "${videoTypeName}" => { ..., ${assetUrlFragment} }
1116
+ `} }
1117
+ }`;
1118
+ /**
1119
+ * Brands a GROQ query with the shape of the data it returns, so a fetch can infer its result type
1120
+ * instead of being told it at every call site.
1121
+ *
1122
+ * @param query - The GROQ query string.
1123
+ * @returns The query, typed to the given result shape.
1124
+ */
1125
+ function defineTypedQuery(query) {
1126
+ return query;
1127
+ }
1128
+ /**
1129
+ * Runs a branded query against the dataset, resolving a missing document to undefined.
1130
+ *
1131
+ * @param client - The Sanity client to query with.
1132
+ * @param query - The branded query to run.
1133
+ * @returns The result, or undefined when the query matched nothing.
1134
+ */
1135
+ async function fetchQuery(client, query) {
1136
+ return await client.fetch(query) ?? void 0;
1137
+ }
1138
+ /** Fetches the Handbook singleton with expanded guide references. */
1139
+ const handbookQuery = defineTypedQuery(`
1140
+ *[_type == "${handbookTypeName}"][0] {
1141
+ ...,
1142
+ groups[] {
1143
+ ...,
1144
+ guides[] {
1145
+ ...,
1146
+ ${guideFragment}
1147
+ }
303
1148
  }
304
- );
305
- }
306
- const defaultIconProps = { width: "1em", height: "1em", strokeWidth: 1.5 };
307
- function createSanityIcon(icon, props) {
308
- return () => createElement(icon, { ...defaultIconProps, ...props });
1149
+ }
1150
+ `), handbookDocumentsQuery = defineTypedQuery(`*[_type == "${handbookTypeName}" || _type == "${guideTypeName}"]`);
1151
+ /**
1152
+ * Fetches the Handbook singleton from the dataset with its guide references expanded, refetching
1153
+ * whenever one of the documents it draws on changes.
1154
+ *
1155
+ * @returns The Handbook and a flag for whether it is still loading.
1156
+ */
1157
+ function useHandbookDocument() {
1158
+ let $ = c(7), t0;
1159
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = { apiVersion: "2026-01-01" }, $[0] = t0) : t0 = $[0];
1160
+ let client = useClient(t0), [handbook, setHandbook] = useState(void 0), [loading, setLoading] = useState(!0), t1, t2;
1161
+ $[1] === client ? (t1 = $[2], t2 = $[3]) : (t1 = () => {
1162
+ let fetchHandbook = async function fetchHandbook() {
1163
+ setHandbook(await fetchQuery(client, handbookQuery)), setLoading(!1);
1164
+ };
1165
+ fetchHandbook();
1166
+ let subscription = client.listen(handbookDocumentsQuery).subscribe(() => {
1167
+ fetchHandbook();
1168
+ });
1169
+ return () => {
1170
+ subscription.unsubscribe();
1171
+ };
1172
+ }, t2 = [client], $[1] = client, $[2] = t1, $[3] = t2), useEffect(t1, t2);
1173
+ let t3;
1174
+ return $[4] !== handbook || $[5] !== loading ? (t3 = {
1175
+ handbook,
1176
+ loading
1177
+ }, $[4] = handbook, $[5] = loading, $[6] = t3) : t3 = $[6], t3;
309
1178
  }
1179
+ const HandbookContext = createContext(void 0);
1180
+ /**
1181
+ * Accesses the Handbook context for tab state and plugin configuration.
1182
+ *
1183
+ * @returns The resolved plugin configuration alongside the state the panes share.
1184
+ * @throws {Error} If used outside the provider.
1185
+ */
1186
+ function useHandbookContext() {
1187
+ let handbookContext = useContext(HandbookContext);
1188
+ if (!isDefined(handbookContext)) throw Error("useHandbookContext can only be used within <HandbookProvider>");
1189
+ return handbookContext;
1190
+ }
1191
+ /**
1192
+ * Provides the tab state the sidebar and content panes share, alongside the plugin configuration and
1193
+ * the handbook singleton fetched from the dataset.
1194
+ *
1195
+ * @param props - Configuration from the plugin, and the tool to provide it to.
1196
+ * @returns The provider wrapping its children.
1197
+ */
1198
+ function HandbookProvider(t0) {
1199
+ let $ = c(12), { sidebarTitle, roles, blocks, undocumentedFieldMessage, children } = t0, [activeTab, setActiveTab] = useState(void 0), [sidebarExpanded, setSidebarExpanded] = useState(!0), { handbook, loading } = useHandbookDocument(), t1;
1200
+ $[0] !== activeTab || $[1] !== blocks || $[2] !== handbook || $[3] !== loading || $[4] !== roles || $[5] !== sidebarExpanded || $[6] !== sidebarTitle || $[7] !== undocumentedFieldMessage ? (t1 = {
1201
+ sidebarTitle,
1202
+ roles,
1203
+ blocks,
1204
+ undocumentedFieldMessage,
1205
+ activeTab,
1206
+ sidebarExpanded,
1207
+ loading,
1208
+ handbook,
1209
+ setActiveTab,
1210
+ setSidebarExpanded
1211
+ }, $[0] = activeTab, $[1] = blocks, $[2] = handbook, $[3] = loading, $[4] = roles, $[5] = sidebarExpanded, $[6] = sidebarTitle, $[7] = undocumentedFieldMessage, $[8] = t1) : t1 = $[8];
1212
+ let t2;
1213
+ return $[9] !== children || $[10] !== t1 ? (t2 = /* @__PURE__ */ jsx(HandbookContext, {
1214
+ value: t1,
1215
+ children
1216
+ }), $[9] = children, $[10] = t1, $[11] = t2) : t2 = $[11], t2;
1217
+ }
1218
+ function PaneHeader(t0) {
1219
+ let $ = c(46), backButton, props, style, title;
1220
+ $[0] === t0 ? (backButton = $[1], props = $[2], style = $[3], title = $[4]) : ({title, backButton, style, ...props} = t0, $[0] = t0, $[1] = backButton, $[2] = props, $[3] = style, $[4] = title);
1221
+ let { color } = useTheme_v2(), pane = useContext(PaneContext), paneSize = useElementSize(pane?.rootElement ?? null), collapsed = pane?.collapsed ?? !1, isLast = pane?.isLast ?? !1, paneHeight = paneSize?.border.height ?? 0, collapsedWidth = paneHeight > 0 ? paneHeight : window.innerHeight, { bg, fg } = color.selectable.default.enabled, t1;
1222
+ $[5] !== collapsed || $[6] !== pane ? (t1 = function handleTitleClick() {
1223
+ collapsed || pane?.collapse();
1224
+ }, $[5] = collapsed, $[6] = pane, $[7] = t1) : t1 = $[7];
1225
+ let handleTitleClick = t1, t2;
1226
+ $[8] !== collapsed || $[9] !== pane ? (t2 = function handleLayoutClick() {
1227
+ collapsed && pane?.expand();
1228
+ }, $[8] = collapsed, $[9] = pane, $[10] = t2) : t2 = $[10];
1229
+ let handleLayoutClick = t2, t3 = collapsed ? "" : void 0, t4;
1230
+ $[11] === style ? t4 = $[12] : (t4 = {
1231
+ lineHeight: 0,
1232
+ position: "sticky",
1233
+ top: 0,
1234
+ ...style
1235
+ }, $[11] = style, $[12] = t4);
1236
+ let t5 = collapsed ? "" : void 0, t6 = collapsed ? collapsedWidth : void 0, t7 = collapsed ? "rotate(90deg)" : void 0, t8;
1237
+ $[13] !== t6 || $[14] !== t7 ? (t8 = {
1238
+ width: t6,
1239
+ transform: t7,
1240
+ transformOrigin: "calc(51px / 2)"
1241
+ }, $[13] = t6, $[14] = t7, $[15] = t8) : t8 = $[15];
1242
+ let t9;
1243
+ $[16] === backButton ? t9 = $[17] : (t9 = isDefined(backButton) && /* @__PURE__ */ jsx(Box, {
1244
+ flex: "none",
1245
+ children: backButton
1246
+ }), $[16] = backButton, $[17] = t9);
1247
+ let t10 = isDefined(backButton) ? 1 : 2, t11 = isLast && !collapsed ? -1 : 0, t12;
1248
+ $[18] === bg ? t12 = $[19] : (t12 = {
1249
+ backgroundColor: bg,
1250
+ minWidth: 0
1251
+ }, $[18] = bg, $[19] = t12);
1252
+ let t13;
1253
+ $[20] === fg ? t13 = $[21] : (t13 = {
1254
+ color: fg,
1255
+ cursor: "default",
1256
+ minWidth: 0,
1257
+ outline: "none"
1258
+ }, $[20] = fg, $[21] = t13);
1259
+ let t14;
1260
+ $[22] !== t13 || $[23] !== title ? (t14 = /* @__PURE__ */ jsx(Flex, {
1261
+ align: "center",
1262
+ gap: 1,
1263
+ children: /* @__PURE__ */ jsx(Text, {
1264
+ size: 1,
1265
+ textOverflow: "ellipsis",
1266
+ weight: "semibold",
1267
+ style: t13,
1268
+ children: title
1269
+ })
1270
+ }), $[22] = t13, $[23] = title, $[24] = t14) : t14 = $[24];
1271
+ let t15;
1272
+ $[25] !== handleTitleClick || $[26] !== t10 || $[27] !== t11 || $[28] !== t12 || $[29] !== t14 ? (t15 = /* @__PURE__ */ jsx(Card, {
1273
+ flex: 1,
1274
+ onClick: handleTitleClick,
1275
+ padding: 2,
1276
+ paddingLeft: t10,
1277
+ tabIndex: t11,
1278
+ style: t12,
1279
+ __unstable_focusRing: !0,
1280
+ children: t14
1281
+ }), $[25] = handleTitleClick, $[26] = t10, $[27] = t11, $[28] = t12, $[29] = t14, $[30] = t15) : t15 = $[30];
1282
+ let t16;
1283
+ $[31] !== t15 || $[32] !== t9 ? (t16 = /* @__PURE__ */ jsxs(Flex, {
1284
+ align: "flex-start",
1285
+ gap: 3,
1286
+ children: [t9, t15]
1287
+ }), $[31] = t15, $[32] = t9, $[33] = t16) : t16 = $[33];
1288
+ let t17;
1289
+ $[34] !== handleLayoutClick || $[35] !== t16 || $[36] !== t8 ? (t17 = /* @__PURE__ */ jsx(Flex, {
1290
+ direction: "column",
1291
+ gap: 3,
1292
+ onClick: handleLayoutClick,
1293
+ padding: 3,
1294
+ sizing: "border",
1295
+ style: t8,
1296
+ children: t16
1297
+ }), $[34] = handleLayoutClick, $[35] = t16, $[36] = t8, $[37] = t17) : t17 = $[37];
1298
+ let t18;
1299
+ $[38] !== t17 || $[39] !== t5 ? (t18 = /* @__PURE__ */ jsx(Card, {
1300
+ tone: "inherit",
1301
+ "data-collapsed": t5,
1302
+ children: t17
1303
+ }), $[38] = t17, $[39] = t5, $[40] = t18) : t18 = $[40];
1304
+ let t19;
1305
+ return $[41] !== props || $[42] !== t18 || $[43] !== t3 || $[44] !== t4 ? (t19 = /* @__PURE__ */ jsx(LayerProvider, {
1306
+ zOffset: 100,
1307
+ children: /* @__PURE__ */ jsx(Layer, {
1308
+ "data-collapsed": t3,
1309
+ style: t4,
1310
+ ...props,
1311
+ children: t18
1312
+ })
1313
+ }), $[41] = props, $[42] = t18, $[43] = t3, $[44] = t4, $[45] = t19) : t19 = $[45], t19;
1314
+ }
1315
+ function ContentPanel(t0) {
1316
+ let $ = c(31), children, description, id, props, title;
1317
+ $[0] === t0 ? (children = $[1], description = $[2], id = $[3], props = $[4], title = $[5]) : ({id, title, description, children, ...props} = t0, $[0] = t0, $[1] = children, $[2] = description, $[3] = id, $[4] = props, $[5] = title);
1318
+ let { setSidebarExpanded } = useHandbookContext(), paneLayout = useContext(PaneLayoutContext), t1;
1319
+ $[6] !== paneLayout?.collapsed || $[7] !== setSidebarExpanded ? (t1 = paneLayout?.collapsed === !0 && /* @__PURE__ */ jsx(Button, {
1320
+ "aria-label": "Back",
1321
+ icon: ArrowLeftIcon,
1322
+ mode: "bleed",
1323
+ onClick: () => {
1324
+ setSidebarExpanded(!0);
1325
+ }
1326
+ }), $[6] = paneLayout?.collapsed, $[7] = setSidebarExpanded, $[8] = t1) : t1 = $[8];
1327
+ let t2;
1328
+ $[9] !== t1 || $[10] !== title ? (t2 = /* @__PURE__ */ jsx(PaneHeader, {
1329
+ title,
1330
+ backButton: t1
1331
+ }), $[9] = t1, $[10] = title, $[11] = t2) : t2 = $[11];
1332
+ let t3 = `panel-${id}`, t4;
1333
+ $[12] === Symbol.for("react.memo_cache_sentinel") ? (t4 = {
1334
+ maxWidth: 640,
1335
+ boxSizing: "border-box",
1336
+ marginInline: "auto",
1337
+ paddingInline: 20,
1338
+ paddingBlockStart: 32,
1339
+ paddingBlockEnd: 220
1340
+ }, $[12] = t4) : t4 = $[12];
1341
+ let t5;
1342
+ $[13] === title ? t5 = $[14] : (t5 = /* @__PURE__ */ jsx(Heading, {
1343
+ as: "h2",
1344
+ size: 4,
1345
+ children: title
1346
+ }), $[13] = title, $[14] = t5);
1347
+ let t6;
1348
+ $[15] === description ? t6 = $[16] : (t6 = isDefined(description) && /* @__PURE__ */ jsx(Text, {
1349
+ size: 1,
1350
+ muted: !0,
1351
+ children: description
1352
+ }), $[15] = description, $[16] = t6);
1353
+ let t7;
1354
+ $[17] !== t5 || $[18] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Stack, {
1355
+ marginBottom: 6,
1356
+ gap: 5,
1357
+ children: [t5, t6]
1358
+ }), $[17] = t5, $[18] = t6, $[19] = t7) : t7 = $[19];
1359
+ let t8;
1360
+ $[20] !== children || $[21] !== t7 ? (t8 = /* @__PURE__ */ jsxs(Box, {
1361
+ style: t4,
1362
+ children: [t7, children]
1363
+ }), $[20] = children, $[21] = t7, $[22] = t8) : t8 = $[22];
1364
+ let t9;
1365
+ $[23] !== id || $[24] !== props || $[25] !== t3 || $[26] !== t8 ? (t9 = /* @__PURE__ */ jsx(PaneContent, {
1366
+ id: t3,
1367
+ "aria-labelledby": id,
1368
+ overflow: "auto",
1369
+ ...props,
1370
+ children: t8
1371
+ }), $[23] = id, $[24] = props, $[25] = t3, $[26] = t8, $[27] = t9) : t9 = $[27];
1372
+ let t10;
1373
+ return $[28] !== t2 || $[29] !== t9 ? (t10 = /* @__PURE__ */ jsxs(Fragment, { children: [t2, t9] }), $[28] = t2, $[29] = t9, $[30] = t10) : t10 = $[30], t10;
1374
+ }
1375
+ function FieldHint(t0) {
1376
+ let $ = c(33), children, icon, label, onClose, onOpen, open, props;
1377
+ $[0] === t0 ? (children = $[1], icon = $[2], label = $[3], onClose = $[4], onOpen = $[5], open = $[6], props = $[7]) : ({label, icon, open, children, onOpen, onClose, ...props} = t0, $[0] = t0, $[1] = children, $[2] = icon, $[3] = label, $[4] = onClose, $[5] = onOpen, $[6] = open, $[7] = props);
1378
+ let buttonReference = useRef(null), popoverReference = useRef(null), t1;
1379
+ $[8] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => [buttonReference.current, popoverReference.current], $[8] = t1) : t1 = $[8], useClickOutsideEvent(open ? onClose : void 0, t1);
1380
+ let t2;
1381
+ $[9] === Symbol.for("react.memo_cache_sentinel") ? (t2 = { maxWidth: 280 }, $[9] = t2) : t2 = $[9];
1382
+ let t3;
1383
+ $[10] === label ? t3 = $[11] : (t3 = /* @__PURE__ */ jsx(Text, {
1384
+ size: 1,
1385
+ weight: "semibold",
1386
+ children: label
1387
+ }), $[10] = label, $[11] = t3);
1388
+ let t4;
1389
+ $[12] === children ? t4 = $[13] : (t4 = /* @__PURE__ */ jsx(Text, {
1390
+ size: 1,
1391
+ muted: !0,
1392
+ children
1393
+ }), $[12] = children, $[13] = t4);
1394
+ let t5;
1395
+ $[14] !== t3 || $[15] !== t4 ? (t5 = /* @__PURE__ */ jsx("div", {
1396
+ ref: popoverReference,
1397
+ children: /* @__PURE__ */ jsx(Box, {
1398
+ padding: 3,
1399
+ style: t2,
1400
+ children: /* @__PURE__ */ jsxs(Stack, {
1401
+ gap: 3,
1402
+ children: [t3, t4]
1403
+ })
1404
+ })
1405
+ }), $[14] = t3, $[15] = t4, $[16] = t5) : t5 = $[16];
1406
+ let t6 = open ? onClose : onOpen, t7;
1407
+ $[17] === onOpen ? t7 = $[18] : (t7 = (event) => {
1408
+ event.pointerType === "mouse" && onOpen();
1409
+ }, $[17] = onOpen, $[18] = t7);
1410
+ let t8;
1411
+ $[19] === onClose ? t8 = $[20] : (t8 = (event_0) => {
1412
+ event_0.pointerType === "mouse" && onClose();
1413
+ }, $[19] = onClose, $[20] = t8);
1414
+ let t9;
1415
+ $[21] === Symbol.for("react.memo_cache_sentinel") ? (t9 = {
1416
+ display: "flex",
1417
+ alignItems: "center",
1418
+ padding: 2,
1419
+ fontSize: 16,
1420
+ color: "var(--card-icon-color)",
1421
+ background: "none",
1422
+ border: "none",
1423
+ cursor: "pointer"
1424
+ }, $[21] = t9) : t9 = $[21];
1425
+ let t10;
1426
+ $[22] !== icon || $[23] !== label || $[24] !== t6 || $[25] !== t7 || $[26] !== t8 ? (t10 = /* @__PURE__ */ jsx("button", {
1427
+ ref: buttonReference,
1428
+ "aria-label": label,
1429
+ type: "button",
1430
+ onClick: t6,
1431
+ onPointerEnter: t7,
1432
+ onPointerLeave: t8,
1433
+ style: t9,
1434
+ children: icon
1435
+ }), $[22] = icon, $[23] = label, $[24] = t6, $[25] = t7, $[26] = t8, $[27] = t10) : t10 = $[27];
1436
+ let t11;
1437
+ return $[28] !== open || $[29] !== props || $[30] !== t10 || $[31] !== t5 ? (t11 = /* @__PURE__ */ jsx(Popover, {
1438
+ open,
1439
+ placement: "top",
1440
+ portal: !0,
1441
+ radius: 2,
1442
+ shadow: 2,
1443
+ content: t5,
1444
+ ...props,
1445
+ children: t10
1446
+ }), $[28] = open, $[29] = props, $[30] = t10, $[31] = t5, $[32] = t11) : t11 = $[32], t11;
1447
+ }
1448
+ /** Hint kinds a field can carry, in the order they are displayed. */
1449
+ const hintKinds = [
1450
+ {
1451
+ name: "tip",
1452
+ label: "Tip",
1453
+ icon: LightbulbIcon
1454
+ },
1455
+ {
1456
+ name: "info",
1457
+ label: "Information",
1458
+ icon: InfoIcon
1459
+ },
1460
+ {
1461
+ name: "caution",
1462
+ label: "Caution",
1463
+ icon: TriangleAlertIcon
1464
+ }
1465
+ ];
1466
+ function FieldHints(t0) {
1467
+ let $ = c(22), caution, info, props, tip;
1468
+ $[0] === t0 ? (caution = $[1], info = $[2], props = $[3], tip = $[4]) : ({tip, info, caution, ...props} = t0, $[0] = t0, $[1] = caution, $[2] = info, $[3] = props, $[4] = tip);
1469
+ let [openHint, setOpenHint] = useState(void 0), T0, t1, t2, t3, t4;
1470
+ if ($[5] !== caution || $[6] !== info || $[7] !== openHint || $[8] !== props || $[9] !== tip) {
1471
+ let hints = {
1472
+ tip,
1473
+ info,
1474
+ caution
1475
+ }, t5;
1476
+ $[15] === Symbol.for("react.memo_cache_sentinel") ? (t5 = function closeHint() {
1477
+ setOpenHint(void 0);
1478
+ }, $[15] = t5) : t5 = $[15];
1479
+ let closeHint = t5;
1480
+ T0 = Flex, t1 = "center", t2 = 2, t3 = props, t4 = hintKinds.flatMap((t6) => {
1481
+ let { name, label, icon: Icon } = t6, hint = hints[name];
1482
+ return isDefined(hint) ? /* @__PURE__ */ jsx(FieldHint, {
1483
+ label,
1484
+ icon: /* @__PURE__ */ jsx(Icon, { ...defaultIconProps }),
1485
+ open: openHint === name,
1486
+ onOpen: () => {
1487
+ setOpenHint(name);
1488
+ },
1489
+ onClose: closeHint,
1490
+ children: hint
1491
+ }, name) : [];
1492
+ }), $[5] = caution, $[6] = info, $[7] = openHint, $[8] = props, $[9] = tip, $[10] = T0, $[11] = t1, $[12] = t2, $[13] = t3, $[14] = t4;
1493
+ } else T0 = $[10], t1 = $[11], t2 = $[12], t3 = $[13], t4 = $[14];
1494
+ let t5;
1495
+ return $[16] !== T0 || $[17] !== t1 || $[18] !== t2 || $[19] !== t3 || $[20] !== t4 ? (t5 = /* @__PURE__ */ jsx(T0, {
1496
+ align: t1,
1497
+ gap: t2,
1498
+ ...t3,
1499
+ children: t4
1500
+ }), $[16] = T0, $[17] = t1, $[18] = t2, $[19] = t3, $[20] = t4, $[21] = t5) : t5 = $[21], t5;
1501
+ }
1502
+ /**
1503
+ * Resolves the label shown for a schema type, preferring Handbook metadata over the schema's own
1504
+ * title and falling back to a title-cased name.
1505
+ *
1506
+ * @param type - The schema type or field to resolve a label for.
1507
+ * @returns The label.
1508
+ */
1509
+ function resolveTitle(type) {
1510
+ let { name, title, handbook } = type;
1511
+ return handbook?.title ?? title ?? convertCase(name, "title");
1512
+ }
1513
+ /**
1514
+ * Resolves the description shown for a schema type, preferring Handbook metadata and ignoring the
1515
+ * non-string descriptions a schema may carry.
1516
+ *
1517
+ * @param type - The schema type or field to resolve a description for.
1518
+ * @returns The description, or undefined when neither source provides one.
1519
+ */
1520
+ function resolveDescription(type) {
1521
+ let { description, handbook } = type;
1522
+ return handbook?.description ?? (typeof description == "string" ? description : void 0);
1523
+ }
1524
+ /**
1525
+ * Narrows a schema type's icon to a renderable component, discarding the string form a schema may
1526
+ * carry instead. A consumer's icon is redrawn at the plugin's own weight, so it sits beside the
1527
+ * built-in ones rather than at its own library's default size.
1528
+ *
1529
+ * @param type - The schema type to read an icon from.
1530
+ * @returns The icon component, or undefined when none is set.
1531
+ */
1532
+ function resolveIcon(type) {
1533
+ return typeof type.icon == "function" ? createSanityIcon(type.icon) : void 0;
1534
+ }
1535
+ /** Schema type names treated as leaf types whose subfields are not displayed. */
310
1536
  const opaqueTypes = /* @__PURE__ */ new Set([
311
- "block",
312
- "boolean",
313
- "crossDatasetReference",
314
- "date",
315
- "datetime",
316
- "file",
317
- "geopoint",
318
- "image",
319
- "number",
320
- "reference",
321
- "slug",
322
- "string",
323
- "text",
324
- "url"
1537
+ "block",
1538
+ "boolean",
1539
+ "crossDatasetReference",
1540
+ "date",
1541
+ "datetime",
1542
+ "file",
1543
+ "geopoint",
1544
+ "image",
1545
+ "number",
1546
+ "reference",
1547
+ "slug",
1548
+ "string",
1549
+ "text",
1550
+ "url"
325
1551
  ]), inheritedFieldNames = {
326
- block: /* @__PURE__ */ new Set(["children", "level", "listItem", "markDefs", "style"]),
327
- file: /* @__PURE__ */ new Set(["asset", "media"]),
328
- geopoint: /* @__PURE__ */ new Set(["alt", "lat", "lng"]),
329
- image: /* @__PURE__ */ new Set(["asset", "crop", "hotspot", "media"]),
330
- slug: /* @__PURE__ */ new Set(["current", "source"])
1552
+ block: /* @__PURE__ */ new Set([
1553
+ "children",
1554
+ "level",
1555
+ "listItem",
1556
+ "markDefs",
1557
+ "style"
1558
+ ]),
1559
+ file: /* @__PURE__ */ new Set(["asset", "media"]),
1560
+ geopoint: /* @__PURE__ */ new Set([
1561
+ "alt",
1562
+ "lat",
1563
+ "lng"
1564
+ ]),
1565
+ image: /* @__PURE__ */ new Set([
1566
+ "asset",
1567
+ "crop",
1568
+ "hotspot",
1569
+ "media"
1570
+ ]),
1571
+ slug: /* @__PURE__ */ new Set(["current", "source"])
331
1572
  };
1573
+ /**
1574
+ * Checks whether a value is a compiled schema field with a nested type object.
1575
+ *
1576
+ * @param value - The value to check.
1577
+ * @returns True if the value is a compiled field.
1578
+ */
332
1579
  function isCompiledField(value) {
333
- return typeof value != "object" || value === null || !("name" in value) || !("type" in value) ? !1 : typeof value.type == "object" && value.type !== null;
334
- }
1580
+ return typeof value != "object" || !value || !("name" in value) || !("type" in value) ? !1 : typeof value.type == "object" && value.type !== null;
1581
+ }
1582
+ /**
1583
+ * Checks whether a value has a `fields` array property.
1584
+ *
1585
+ * @param value - The value to check.
1586
+ * @returns True if the value contains a `fields` array.
1587
+ */
335
1588
  function hasFieldsArray(value) {
336
- return typeof value != "object" || value === null || !("fields" in value) ? !1 : Array.isArray(value.fields);
337
- }
1589
+ return typeof value != "object" || !value || !("fields" in value) ? !1 : Array.isArray(value.fields);
1590
+ }
1591
+ /**
1592
+ * Checks whether a value has an `of` array property.
1593
+ *
1594
+ * @param value - The value to check.
1595
+ * @returns True if the value contains an `of` array.
1596
+ */
338
1597
  function hasOfArray(value) {
339
- return typeof value != "object" || value === null || !("of" in value) ? !1 : Array.isArray(value.of);
340
- }
1598
+ return typeof value != "object" || !value || !("of" in value) ? !1 : Array.isArray(value.of);
1599
+ }
1600
+ /**
1601
+ * Extracts the type name a value declares, where it names one at all.
1602
+ *
1603
+ * @param value - The value to inspect.
1604
+ * @returns The type name, or undefined when the value declares none.
1605
+ */
341
1606
  function getTypeName(value) {
342
- if (!(typeof value != "object" || value === null || !("type" in value)))
343
- return typeof value.type == "string" ? value.type : void 0;
344
- }
345
- function isOpaqueType(typeName) {
346
- return opaqueTypes.has(typeName);
347
- }
1607
+ if (!(typeof value != "object" || !value || !("type" in value))) return typeof value.type == "string" ? value.type : void 0;
1608
+ }
1609
+ /**
1610
+ * Extracts the parent type name from a compiled schema type, if present.
1611
+ *
1612
+ * @param resolvedType - The compiled schema type to inspect.
1613
+ * @returns The parent type name, or undefined when the type extends none.
1614
+ */
348
1615
  function getParentTypeName(resolvedType) {
349
- if (!(typeof resolvedType != "object" || resolvedType === null || !("type" in resolvedType)) && !(typeof resolvedType.type != "object" || resolvedType.type === null || !("name" in resolvedType.type)))
350
- return String(resolvedType.type.name);
351
- }
1616
+ if (!(typeof resolvedType != "object" || !resolvedType || !("type" in resolvedType)) && !(typeof resolvedType.type != "object" || resolvedType.type === null || !("name" in resolvedType.type))) return String(resolvedType.type.name);
1617
+ }
1618
+ /**
1619
+ * Normalises a compiled schema field into the shape the Handbook renders. Type names already seen are
1620
+ * tracked so a type that refers back to itself does not recurse forever.
1621
+ *
1622
+ * @param field - A compiled schema field or plain field definition.
1623
+ * @param visited - Type names already seen in this normalisation chain.
1624
+ * @returns The normalised field.
1625
+ */
352
1626
  function normaliseField(field, visited = /* @__PURE__ */ new Set()) {
353
- if (isCompiledField(field)) {
354
- const typeName = field.type.name, result = {
355
- name: field.name,
356
- type: typeName,
357
- title: field.title ?? field.type.title,
358
- description: field.description ?? field.type.description,
359
- handbook: field.handbook
360
- };
361
- if (!visited.has(typeName)) {
362
- const next = !opaqueTypes.has(typeName) && typeName !== "object" && typeName !== "array" ? /* @__PURE__ */ new Set([...visited, typeName]) : visited, fieldSource = hasFieldsArray(field) ? field : field.type, ofSource = hasOfArray(field) ? field : field.type;
363
- hasFieldsArray(fieldSource) && (result.fields = fieldSource.fields.map((subfield) => normaliseField(subfield, next))), hasOfArray(ofSource) && (result.of = ofSource.of.map((member) => normaliseField(member, next)));
364
- }
365
- return result;
366
- }
367
- return field;
368
- }
1627
+ if (isCompiledField(field)) {
1628
+ let typeName = field.type.name, result = {
1629
+ name: field.name,
1630
+ type: typeName,
1631
+ title: field.title ?? field.type.title,
1632
+ description: field.description ?? field.type.description,
1633
+ handbook: field.handbook
1634
+ };
1635
+ if (!visited.has(typeName)) {
1636
+ let next = !opaqueTypes.has(typeName) && typeName !== "object" && typeName !== "array" ? /* @__PURE__ */ new Set([...visited, typeName]) : visited, fieldSource = hasFieldsArray(field) ? field : field.type, ofSource = hasOfArray(field) ? field : field.type;
1637
+ hasFieldsArray(fieldSource) && (result.fields = fieldSource.fields.map((subfield) => normaliseField(subfield, next))), hasOfArray(ofSource) && (result.of = ofSource.of.map((member) => normaliseField(member, next)));
1638
+ }
1639
+ return result;
1640
+ }
1641
+ return field;
1642
+ }
1643
+ /**
1644
+ * Resolves only the fields a custom type adds on top of an opaque base type, leaving out the ones the
1645
+ * base type contributes of its own accord.
1646
+ *
1647
+ * @param resolvedType - The compiled or normalised schema type.
1648
+ * @param parentName - The opaque base type name.
1649
+ * @returns The custom fields, or undefined when the type adds none.
1650
+ */
369
1651
  function resolveCustomFields(resolvedType, parentName) {
370
- if (!hasFieldsArray(resolvedType)) return;
371
- const inherited = inheritedFieldNames[parentName], customFields = resolvedType.fields.map((field) => normaliseField(field)).filter((field) => inherited === void 0 || !inherited.has(field.name));
372
- return isDefined(customFields) ? customFields : void 0;
373
- }
1652
+ if (!hasFieldsArray(resolvedType)) return;
1653
+ let inherited = inheritedFieldNames[parentName], customFields = resolvedType.fields.map((field) => normaliseField(field)).filter((field) => !isDefined(inherited) || !inherited.has(field.name));
1654
+ return isDefined(customFields) ? customFields : void 0;
1655
+ }
1656
+ /**
1657
+ * Normalises a list of raw field values into the shape the Handbook renders.
1658
+ *
1659
+ * @param items - Raw field values to normalise.
1660
+ * @returns The normalised fields, or undefined when the list holds none.
1661
+ */
374
1662
  function resolveNormalisedFields(items) {
375
- const normalised = items.map((item) => normaliseField(item));
376
- return isDefined(normalised) ? normalised : void 0;
377
- }
1663
+ let normalised = items.map((item) => normaliseField(item));
1664
+ return isDefined(normalised) ? normalised : void 0;
1665
+ }
1666
+ /**
1667
+ * Normalises array members and filters out opaque types that have no meaningful subfields.
1668
+ *
1669
+ * @param members - Raw array member values to normalise.
1670
+ * @returns The normalised non-opaque members, or undefined when none remain.
1671
+ */
378
1672
  function resolveNormalisedMembers(members) {
379
- const normalised = members.map((member) => normaliseField(member)).filter((member) => !isOpaqueType(member.type));
380
- return isDefined(normalised) ? normalised : void 0;
381
- }
1673
+ let normalised = members.map((member) => normaliseField(member)).filter((member) => !opaqueTypes.has(member.type));
1674
+ return isDefined(normalised) ? normalised : void 0;
1675
+ }
1676
+ /**
1677
+ * Resolves the name of the type a value extends, reaching into the schema registry when the value
1678
+ * carries nothing but a type name of its own.
1679
+ *
1680
+ * @param value - The value to inspect.
1681
+ * @param schema - The Sanity schema registry.
1682
+ * @returns The parent type name, or undefined when the value extends none.
1683
+ */
382
1684
  function resolveParentName(value, schema) {
383
- const direct = getParentTypeName(value);
384
- if (isDefined(direct)) return direct;
385
- const typeName = getTypeName(value);
386
- if (!isDefined(typeName)) return;
387
- const resolvedType = schema.get(typeName);
388
- return isDefined(resolvedType) ? getParentTypeName(resolvedType) : void 0;
389
- }
1685
+ let direct = getParentTypeName(value);
1686
+ if (isDefined(direct)) return direct;
1687
+ let typeName = getTypeName(value);
1688
+ if (!isDefined(typeName)) return;
1689
+ let resolvedType = schema.get(typeName);
1690
+ return isDefined(resolvedType) ? getParentTypeName(resolvedType) : void 0;
1691
+ }
1692
+ /**
1693
+ * Extracts the fields a value displays, whether it carries them directly, carries array members that
1694
+ * do, or names a type that does.
1695
+ *
1696
+ * @param value - The value to extract fields from.
1697
+ * @param schema - The Sanity schema registry.
1698
+ * @returns The resolved fields, or undefined when the value has none.
1699
+ */
390
1700
  function resolveFields(value, schema) {
391
- if (hasFieldsArray(value)) {
392
- const parentName = resolveParentName(value, schema);
393
- return isDefined(parentName) && isOpaqueType(parentName) ? resolveCustomFields(value, parentName) : resolveNormalisedFields(value.fields);
394
- }
395
- if (hasOfArray(value)) {
396
- const members = value.of;
397
- if (members.length === 1) {
398
- const [member] = members, normalised = normaliseField(member);
399
- if (isOpaqueType(normalised.type)) return;
400
- if (hasFieldsArray(normalised)) {
401
- const parentName = resolveParentName(normalised, schema);
402
- return isDefined(parentName) && isOpaqueType(parentName) ? resolveCustomFields(normalised, parentName) : resolveNormalisedFields(normalised.fields);
403
- }
404
- const memberType = schema.get(normalised.type);
405
- if (isDefined(memberType)) return resolveFields(memberType, schema);
406
- }
407
- return resolveNormalisedMembers(members);
408
- }
409
- }
1701
+ if (hasFieldsArray(value)) {
1702
+ let parentName = resolveParentName(value, schema);
1703
+ return isDefined(parentName) && opaqueTypes.has(parentName) ? resolveCustomFields(value, parentName) : resolveNormalisedFields(value.fields);
1704
+ }
1705
+ if (hasOfArray(value)) {
1706
+ let members = value.of;
1707
+ if (members.length === 1) {
1708
+ let [member] = members, normalised = normaliseField(member);
1709
+ if (opaqueTypes.has(normalised.type)) return;
1710
+ if (hasFieldsArray(normalised)) {
1711
+ let parentName = resolveParentName(normalised, schema);
1712
+ return isDefined(parentName) && opaqueTypes.has(parentName) ? resolveCustomFields(normalised, parentName) : resolveNormalisedFields(normalised.fields);
1713
+ }
1714
+ let memberType = schema.get(normalised.type);
1715
+ if (isDefined(memberType)) return resolveFields(memberType, schema);
1716
+ }
1717
+ return resolveNormalisedMembers(members);
1718
+ }
1719
+ }
1720
+ /**
1721
+ * Resolves the displayable subfields of a field definition by traversing the schema.
1722
+ *
1723
+ * @param field - The parent field definition.
1724
+ * @param schema - The Sanity schema registry.
1725
+ * @returns The non-opaque subfields, or undefined when the field has none.
1726
+ */
410
1727
  function getSubfields(field, schema) {
411
- if (isOpaqueType(field.type)) return;
412
- const directFields = resolveFields(field, schema);
413
- if (directFields !== void 0) return directFields;
414
- const resolvedType = schema.get(field.type);
415
- if (!isDefined(resolvedType)) return;
416
- const parentName = getParentTypeName(resolvedType);
417
- return isDefined(parentName) && isOpaqueType(parentName) ? resolveCustomFields(resolvedType, parentName) : resolveFields(resolvedType, schema);
418
- }
419
- function FieldHint({ label, icon, color, open, children, onToggle, onClose }) {
420
- const buttonReference = useRef(null), popoverReference = useRef(null);
421
- return useClickOutsideEvent(open ? onClose : void 0, () => [buttonReference.current, popoverReference.current]), /* @__PURE__ */ jsx(
422
- Popover,
423
- {
424
- open,
425
- placement: "top",
426
- portal: !0,
427
- radius: 2,
428
- shadow: 2,
429
- content: /* @__PURE__ */ jsx("div", { ref: popoverReference, children: /* @__PURE__ */ jsx(Box, { padding: 3, style: { maxWidth: "280px" }, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
430
- /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: label }),
431
- /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children })
432
- ] }) }) }),
433
- children: /* @__PURE__ */ jsx(
434
- "button",
435
- {
436
- ref: buttonReference,
437
- "aria-label": label,
438
- type: "button",
439
- onClick: onToggle,
440
- onMouseEnter: onToggle,
441
- onMouseLeave: onClose,
442
- style: {
443
- display: "flex",
444
- alignItems: "center",
445
- padding: "2px",
446
- fontSize: "16px",
447
- color,
448
- background: "none",
449
- border: "none",
450
- cursor: "pointer"
451
- },
452
- children: icon
453
- }
454
- )
455
- }
456
- );
457
- }
458
- function FieldHints({ tip, info, caution }) {
459
- const [openHint, setOpenHint] = useState(null), closeHint = useCallback(() => {
460
- setOpenHint(null);
461
- }, []);
462
- return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
463
- isDefined(tip) && /* @__PURE__ */ jsx(
464
- FieldHint,
465
- {
466
- label: "Tip",
467
- icon: /* @__PURE__ */ jsx(LightbulbIcon, { ...defaultIconProps }),
468
- color: "var(--card-icon-color)",
469
- open: openHint === "tip",
470
- onToggle: () => {
471
- setOpenHint(openHint === "tip" ? null : "tip");
472
- },
473
- onClose: closeHint,
474
- children: tip
475
- }
476
- ),
477
- isDefined(info) && /* @__PURE__ */ jsx(
478
- FieldHint,
479
- {
480
- label: "Information",
481
- icon: /* @__PURE__ */ jsx(InfoIcon, { ...defaultIconProps }),
482
- color: "var(--card-icon-color)",
483
- open: openHint === "info",
484
- onToggle: () => {
485
- setOpenHint(openHint === "info" ? null : "info");
486
- },
487
- onClose: closeHint,
488
- children: info
489
- }
490
- ),
491
- isDefined(caution) && /* @__PURE__ */ jsx(
492
- FieldHint,
493
- {
494
- label: "Caution",
495
- icon: /* @__PURE__ */ jsx(TriangleAlertIcon, { ...defaultIconProps }),
496
- color: "var(--card-icon-color)",
497
- open: openHint === "caution",
498
- onToggle: () => {
499
- setOpenHint(openHint === "caution" ? null : "caution");
500
- },
501
- onClose: closeHint,
502
- children: caution
503
- }
504
- )
505
- ] });
506
- }
507
- function Field({ field, depth = 0, ancestors = /* @__PURE__ */ new Set() }) {
508
- const schema = useSchema(), { undocumentedFieldMessage } = useHandbookContext(), [expanded, setExpanded] = useState(!1), effectiveTitle = field.handbook?.title ?? field.title ?? (field.name && convertCase(field.name, "title")), effectiveDescription = field.handbook?.description ?? field.description ?? undocumentedFieldMessage, { example, tip, info, caution } = field.handbook ?? {}, hasHints = isDefined([tip, info, caution]), isCycle = ancestors.has(field.type), subfields = isCycle ? void 0 : getSubfields(field, schema), hasSubfields = isDefined(subfields);
509
- return /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
510
- /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
511
- /* @__PURE__ */ jsxs(Flex, { align: "center", paddingY: 1, gap: 2, children: [
512
- /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
513
- /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: effectiveTitle }),
514
- /* @__PURE__ */ jsx(Text, { size: 0, muted: !0, style: { marginTop: "2px" }, children: field.type })
515
- ] }) }),
516
- hasHints && /* @__PURE__ */ jsx(FieldHints, { tip, info, caution })
517
- ] }),
518
- isDefined(effectiveDescription) && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: effectiveDescription }),
519
- isDefined(example) && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children: [
520
- "e.g. ",
521
- example
522
- ] }) })
523
- ] }),
524
- isCycle && /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children: [
525
- "See ",
526
- convertCase(field.type, "title"),
527
- " above."
528
- ] }) }),
529
- hasSubfields && /* @__PURE__ */ jsxs(Fragment, { children: [
530
- /* @__PURE__ */ jsx(
531
- Card,
532
- {
533
- as: "button",
534
- padding: 3,
535
- radius: 2,
536
- tone: "transparent",
537
- onClick: () => {
538
- setExpanded(!expanded);
539
- },
540
- style: { width: "100%", marginTop: "1rem", textAlign: "left", border: "none", cursor: "pointer" },
541
- children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
542
- /* @__PURE__ */ jsx(Text, { size: 0, children: expanded ? /* @__PURE__ */ jsx(ChevronDownIcon, {}) : /* @__PURE__ */ jsx(ChevronRightIcon, {}) }),
543
- /* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, weight: "medium", children: [
544
- subfields.length,
545
- " subfield",
546
- subfields.length === 1 ? "" : "s"
547
- ] })
548
- ] })
549
- }
550
- ),
551
- expanded && /* @__PURE__ */ jsx(
552
- "div",
553
- {
554
- style: {
555
- marginTop: "16px",
556
- marginBottom: "8px",
557
- paddingLeft: "16px",
558
- borderLeft: "1px solid var(--card-border-color)"
559
- },
560
- children: /* @__PURE__ */ jsx(Stack, { space: 5, children: subfields.map((subfield) => /* @__PURE__ */ jsx(
561
- Field,
562
- {
563
- field: subfield,
564
- depth: depth + 1,
565
- ancestors: /* @__PURE__ */ new Set([...ancestors, field.type])
566
- },
567
- subfield.name
568
- )) })
569
- }
570
- )
571
- ] })
572
- ] });
573
- }
574
- function SidebarGroup({ heading, children }) {
575
- return /* @__PURE__ */ jsxs("div", { children: [
576
- /* @__PURE__ */ jsx(Box, { paddingY: 2, children: /* @__PURE__ */ jsx(Card, { paddingLeft: 2, padding: 2, children: /* @__PURE__ */ jsx(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsx(
577
- Text,
578
- {
579
- size: 1,
580
- muted: !0,
581
- textOverflow: "ellipsis",
582
- weight: "semibold",
583
- style: { cursor: "default", outline: "none" },
584
- children: heading
585
- }
586
- ) }) }) }),
587
- children
588
- ] });
589
- }
590
- function SidebarTab({ id, label, icon: Icon }) {
591
- const { activeTab, setActiveTab, setSidebarExpanded } = useHandbookContext(), selected = activeTab === id;
592
- return /* @__PURE__ */ jsx(
593
- Card,
594
- {
595
- id,
596
- "aria-controls": `panel-${id}`,
597
- "aria-selected": selected,
598
- role: "option",
599
- as: "button",
600
- selected,
601
- marginBottom: 1,
602
- radius: 2,
603
- sizing: "border",
604
- tabIndex: -1,
605
- tone: "inherit",
606
- onClick: () => {
607
- setActiveTab(id), setSidebarExpanded(!1);
608
- },
609
- style: { width: "100%", textAlign: "left", border: "none", cursor: "pointer" },
610
- children: /* @__PURE__ */ jsx(
611
- Flex,
612
- {
613
- align: "center",
614
- paddingLeft: isDefined(Icon) ? 1 : 2,
615
- paddingRight: 2,
616
- paddingY: 1,
617
- style: { height: "1.5625rem", boxSizing: "content-box" },
618
- children: /* @__PURE__ */ jsxs(Flex, { align: "center", flex: 1, gap: 2, children: [
619
- isDefined(Icon) && /* @__PURE__ */ jsx(
620
- "div",
621
- {
622
- style: {
623
- display: "flex",
624
- alignItems: "center",
625
- justifyContent: "center",
626
- width: "25px",
627
- height: "25px",
628
- color: "var(--card-icon-color)"
629
- },
630
- children: /* @__PURE__ */ jsx(Icon, {})
631
- }
632
- ),
633
- /* @__PURE__ */ jsx(Stack, { flex: 1, space: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, textOverflow: "ellipsis", weight: "medium", style: { color: "inherit" }, children: label }) }),
634
- /* @__PURE__ */ jsx(Box, { paddingLeft: 4, paddingRight: 1, children: /* @__PURE__ */ jsx(Box, { style: { opacity: 0.5 }, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) }) }) })
635
- ] })
636
- }
637
- )
638
- }
639
- );
640
- }
641
- function DocumentTypesTabs() {
642
- const { groups } = useHandbookContext();
643
- return groups.map((group) => {
644
- const { title, documents } = group;
645
- return /* @__PURE__ */ jsx(SidebarGroup, { heading: title, children: documents.map((document) => {
646
- const effectiveTitle = document.handbook?.title ?? document.title ?? convertCase(document.name, "title"), icon = typeof document.icon == "function" ? document.icon : void 0;
647
- return /* @__PURE__ */ jsx(SidebarTab, { id: document.name, label: effectiveTitle, icon }, document.name);
648
- }) }, title);
649
- });
650
- }
651
- function DocumentTypesPanels() {
652
- const { groups } = useHandbookContext();
653
- return groups.map((group) => {
654
- const { documents } = group;
655
- return documents.map((document) => {
656
- const effectiveTitle = document.handbook?.title ?? document.title ?? convertCase(document.name, "title"), effectiveDescription = document.handbook?.description ?? (typeof document.description == "string" ? document.description : void 0);
657
- return /* @__PURE__ */ jsx(ContentPanel, { id: document.name, title: effectiveTitle, description: effectiveDescription, children: /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "3.25rem" }, children: document.fields.map((field) => /* @__PURE__ */ jsx(Field, { field }, field.name)) }) }, document.name);
658
- });
659
- });
660
- }
661
- function BookOpenTextIcon(props) {
662
- return /* @__PURE__ */ jsxs(
663
- "svg",
664
- {
665
- xmlns: "http://www.w3.org/2000/svg",
666
- viewBox: "0 0 24 24",
667
- fill: "none",
668
- stroke: "currentColor",
669
- strokeLinecap: "round",
670
- strokeLinejoin: "round",
671
- ...props,
672
- children: [
673
- /* @__PURE__ */ jsx("path", { d: "M12 7v14" }),
674
- /* @__PURE__ */ jsx("path", { d: "M16 12h2" }),
675
- /* @__PURE__ */ jsx("path", { d: "M16 8h2" }),
676
- /* @__PURE__ */ jsx("path", { d: "M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z" }),
677
- /* @__PURE__ */ jsx("path", { d: "M6 12h2" }),
678
- /* @__PURE__ */ jsx("path", { d: "M6 8h2" })
679
- ]
680
- }
681
- );
682
- }
683
- function isPortableTextSpan(node) {
684
- return node._type === "span" && "text" in node && typeof node.text == "string" && (node.marks === void 0 || Array.isArray(node.marks) && node.marks.every((mark) => typeof mark == "string"));
685
- }
686
- function isPortableTextBlock(node) {
687
- return typeof node._type == "string" && node._type[0] !== "@" && (!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && node.markDefs.every((def) => typeof def._key == "string")) && "children" in node && Array.isArray(node.children) && node.children.every((child) => typeof child == "object" && "_type" in child);
688
- }
689
- function isPortableTextListItemBlock(block) {
690
- return isPortableTextBlock(block) && "listItem" in block && typeof block.listItem == "string" && (block.level === void 0 || typeof block.level == "number");
691
- }
692
- function isPortableTextToolkitList(block) {
693
- return block._type === "@list";
694
- }
695
- function isPortableTextToolkitSpan(span) {
696
- return span._type === "@span";
697
- }
698
- function isPortableTextToolkitTextNode(node) {
699
- return node._type === "@text";
700
- }
701
- const knownDecorators = [
702
- "strong",
703
- "em",
704
- "code",
705
- "underline",
706
- "strike-through"
707
- ];
708
- function sortMarksByOccurences(span, index, blockChildren) {
709
- if (!isPortableTextSpan(span) || !span.marks || !span.marks.length) return [];
710
- let marks = span.marks.slice(), occurences = {};
711
- return marks.forEach((mark) => {
712
- occurences[mark] = 1;
713
- for (let siblingIndex = index + 1; siblingIndex < blockChildren.length; siblingIndex++) {
714
- let sibling = blockChildren[siblingIndex];
715
- if (sibling && isPortableTextSpan(sibling) && Array.isArray(sibling.marks) && sibling.marks.indexOf(mark) !== -1) occurences[mark]++;
716
- else break;
717
- }
718
- }), marks.sort((markA, markB) => sortMarks(occurences, markA, markB));
719
- }
720
- function sortMarks(occurences, markA, markB) {
721
- let aOccurences = occurences[markA], bOccurences = occurences[markB];
722
- if (aOccurences !== bOccurences) return bOccurences - aOccurences;
723
- let aKnownPos = knownDecorators.indexOf(markA), bKnownPos = knownDecorators.indexOf(markB);
724
- return aKnownPos === bKnownPos ? markA.localeCompare(markB) : aKnownPos - bKnownPos;
725
- }
726
- function buildMarksTree(block) {
727
- let { children } = block, markDefs = block.markDefs ?? [];
728
- if (!children || !children.length) return [];
729
- let sortedMarks = children.map(sortMarksByOccurences), rootNode = {
730
- _type: "@span",
731
- children: [],
732
- markType: "<unknown>"
733
- }, nodeStack = [rootNode];
734
- for (let i = 0; i < children.length; i++) {
735
- let span = children[i];
736
- if (!span) continue;
737
- let marksNeeded = sortedMarks[i] || [], pos = 1;
738
- if (nodeStack.length > 1) for (; pos < nodeStack.length; pos++) {
739
- let mark = nodeStack[pos]?.markKey || "", index = marksNeeded.indexOf(mark);
740
- if (index === -1) break;
741
- marksNeeded.splice(index, 1);
742
- }
743
- nodeStack = nodeStack.slice(0, pos);
744
- let currentNode = nodeStack[nodeStack.length - 1];
745
- if (currentNode) {
746
- for (let markKey of marksNeeded) {
747
- let markDef = markDefs?.find((def) => def._key === markKey), node = {
748
- _type: "@span",
749
- _key: span._key,
750
- children: [],
751
- markDef,
752
- markType: markDef ? markDef._type : markKey,
753
- markKey
754
- };
755
- currentNode.children.push(node), nodeStack.push(node), currentNode = node;
756
- }
757
- if (isPortableTextSpan(span)) {
758
- let lines = span.text.split(`
759
- `);
760
- for (let line = lines.length; line-- > 1; ) lines.splice(line, 0, `
761
- `);
762
- currentNode.children = currentNode.children.concat(lines.map((text) => ({
763
- _type: "@text",
764
- text
765
- })));
766
- } else currentNode.children = currentNode.children.concat(span);
767
- }
768
- }
769
- return rootNode.children;
770
- }
771
- function nestLists(blocks, mode) {
772
- let tree = [], currentList;
773
- for (let i = 0; i < blocks.length; i++) {
774
- let block = blocks[i];
775
- if (block) {
776
- if (!isPortableTextListItemBlock(block)) {
777
- tree.push(block), currentList = void 0;
778
- continue;
779
- }
780
- if (!currentList) {
781
- currentList = listFromBlock(block, i, mode), tree.push(currentList);
782
- continue;
783
- }
784
- if (blockMatchesList(block, currentList)) {
785
- currentList.children.push(block);
786
- continue;
787
- }
788
- if ((block.level || 1) > currentList.level) {
789
- let newList = listFromBlock(block, i, mode);
790
- if (mode === "html") {
791
- let lastListItem = currentList.children[currentList.children.length - 1], newLastChild = {
792
- ...lastListItem,
793
- children: [...lastListItem.children, newList]
794
- };
795
- currentList.children[currentList.children.length - 1] = newLastChild;
796
- } else currentList.children.push(newList);
797
- currentList = newList;
798
- continue;
799
- }
800
- if ((block.level || 1) < currentList.level) {
801
- let matchingBranch = tree[tree.length - 1], match = matchingBranch && findListMatching(matchingBranch, block);
802
- if (match) {
803
- currentList = match, currentList.children.push(block);
804
- continue;
805
- }
806
- currentList = listFromBlock(block, i, mode), tree.push(currentList);
807
- continue;
808
- }
809
- if (block.listItem !== currentList.listItem) {
810
- let matchingBranch = tree[tree.length - 1], match = matchingBranch && findListMatching(matchingBranch, { level: block.level || 1 });
811
- if (match && match.listItem === block.listItem) {
812
- currentList = match, currentList.children.push(block);
813
- continue;
814
- } else {
815
- currentList = listFromBlock(block, i, mode), tree.push(currentList);
816
- continue;
817
- }
818
- }
819
- console.warn("Unknown state encountered for block", block), tree.push(block);
820
- }
821
- }
822
- return tree;
823
- }
824
- function blockMatchesList(block, list) {
825
- return (block.level || 1) === list.level && block.listItem === list.listItem;
826
- }
827
- function listFromBlock(block, index, mode) {
828
- return {
829
- _type: "@list",
830
- _key: `${block._key || `${index}`}-parent`,
831
- mode,
832
- level: block.level || 1,
833
- listItem: block.listItem,
834
- children: [block]
835
- };
836
- }
837
- function findListMatching(rootNode, matching) {
838
- let level = matching.level || 1, style = matching.listItem || "normal", filterOnType = typeof matching.listItem == "string";
839
- if (isPortableTextToolkitList(rootNode) && (rootNode.level || 1) === level && filterOnType && (rootNode.listItem || "normal") === style) return rootNode;
840
- if (!("children" in rootNode)) return;
841
- let node = rootNode.children[rootNode.children.length - 1];
842
- return node && !isPortableTextSpan(node) ? findListMatching(node, matching) : void 0;
843
- }
844
- function spanToPlainText(span) {
845
- let text = "";
846
- return span.children.forEach((current) => {
847
- isPortableTextToolkitTextNode(current) ? text += current.text : isPortableTextToolkitSpan(current) && (text += spanToPlainText(current));
848
- }), text;
849
- }
850
- const LIST_NEST_MODE_HTML = "html", defaultLists = {
851
- number: ({ children }) => /* @__PURE__ */ jsx("ol", { children }),
852
- bullet: ({ children }) => /* @__PURE__ */ jsx("ul", { children })
853
- }, DefaultListItem = ({ children }) => /* @__PURE__ */ jsx("li", { children }), link = ({ children, value }) => /* @__PURE__ */ jsx("a", {
854
- href: value?.href,
855
- children
856
- }), underlineStyle = { textDecoration: "underline" }, defaultMarks = {
857
- em: ({ children }) => /* @__PURE__ */ jsx("em", { children }),
858
- strong: ({ children }) => /* @__PURE__ */ jsx("strong", { children }),
859
- code: ({ children }) => /* @__PURE__ */ jsx("code", { children }),
860
- underline: ({ children }) => /* @__PURE__ */ jsx("span", {
861
- style: underlineStyle,
862
- children
863
- }),
864
- "strike-through": ({ children }) => /* @__PURE__ */ jsx("del", { children }),
865
- link
866
- }, getTemplate = (type, prop) => `[@portabletext/react] Unknown ${type}, specify a component for it in the \`components.${prop}\` prop`, unknownTypeWarning = (typeName) => getTemplate(`block type "${typeName}"`, "types"), unknownMarkWarning = (markType) => getTemplate(`mark type "${markType}"`, "marks"), unknownBlockStyleWarning = (blockStyle) => getTemplate(`block style "${blockStyle}"`, "block"), unknownListStyleWarning = (listStyle) => getTemplate(`list style "${listStyle}"`, "list"), unknownListItemStyleWarning = (listStyle) => getTemplate(`list item style "${listStyle}"`, "listItem");
867
- function printWarning(message) {
868
- console.warn(message);
869
- }
870
- const hidden = { display: "none" }, defaultComponents = {
871
- types: {},
872
- block: {
873
- normal: ({ children }) => /* @__PURE__ */ jsx("p", { children }),
874
- blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { children }),
875
- h1: ({ children }) => /* @__PURE__ */ jsx("h1", { children }),
876
- h2: ({ children }) => /* @__PURE__ */ jsx("h2", { children }),
877
- h3: ({ children }) => /* @__PURE__ */ jsx("h3", { children }),
878
- h4: ({ children }) => /* @__PURE__ */ jsx("h4", { children }),
879
- h5: ({ children }) => /* @__PURE__ */ jsx("h5", { children }),
880
- h6: ({ children }) => /* @__PURE__ */ jsx("h6", { children })
881
- },
882
- marks: defaultMarks,
883
- list: defaultLists,
884
- listItem: DefaultListItem,
885
- hardBreak: () => /* @__PURE__ */ jsx("br", {}),
886
- unknownType: ({ value, isInline }) => {
887
- let warning = unknownTypeWarning(value._type);
888
- return jsx(isInline ? "span" : "div", {
889
- style: hidden,
890
- children: warning
891
- });
892
- },
893
- unknownMark: ({ markType, children }) => /* @__PURE__ */ jsx("span", {
894
- className: `unknown__pt__mark__${markType}`,
895
- children
896
- }),
897
- unknownList: ({ children }) => /* @__PURE__ */ jsx("ul", { children }),
898
- unknownListItem: ({ children }) => /* @__PURE__ */ jsx("li", { children }),
899
- unknownBlockStyle: ({ children }) => /* @__PURE__ */ jsx("p", { children })
900
- };
901
- function mergeComponents(parent, overrides) {
902
- let { block: _block, list: _list, listItem: _listItem, marks: _marks, types: _types, ...rest } = overrides;
903
- return {
904
- ...parent,
905
- block: mergeDeeply(parent, overrides, "block"),
906
- list: mergeDeeply(parent, overrides, "list"),
907
- listItem: mergeDeeply(parent, overrides, "listItem"),
908
- marks: mergeDeeply(parent, overrides, "marks"),
909
- types: mergeDeeply(parent, overrides, "types"),
910
- ...rest
911
- };
912
- }
913
- function mergeDeeply(parent, overrides, key) {
914
- let override = overrides[key], parentVal = parent[key];
915
- return typeof override == "function" || override && typeof parentVal == "function" ? override : override ? {
916
- ...parentVal,
917
- ...override
918
- } : parentVal;
919
- }
920
- function PortableText({ value: input, components: componentOverrides, listNestingMode, onMissingComponent: missingComponentHandler = printWarning }) {
921
- let handleMissingComponent = missingComponentHandler || noop, nested = nestLists(Array.isArray(input) ? input : [input], listNestingMode || LIST_NEST_MODE_HTML), components = useMemo(() => componentOverrides ? mergeComponents(defaultComponents, componentOverrides) : defaultComponents, [componentOverrides]), renderNode = useMemo(() => getNodeRenderer(components, handleMissingComponent), [components, handleMissingComponent]);
922
- return /* @__PURE__ */ jsx(Fragment, { children: nested.map((node, index) => renderNode({
923
- node,
924
- index,
925
- isInline: !1,
926
- renderNode
927
- })) });
928
- }
929
- const getNodeRenderer = (components, handleMissingComponent) => {
930
- function renderNode(options) {
931
- let { node, index, isInline } = options, key = node._key || `node-${index}`;
932
- return isPortableTextToolkitList(node) ? renderList(node, index, key) : isPortableTextListItemBlock(node) ? renderListItem(node, index, key) : isPortableTextToolkitSpan(node) ? renderSpan(node, index, key) : hasCustomComponentForNode(node) ? renderCustomBlock(node, index, key, isInline) : isPortableTextBlock(node) ? renderBlock(node, index, key, isInline) : isPortableTextToolkitTextNode(node) ? renderText(node, key) : renderUnknownType(node, index, key, isInline);
933
- }
934
- function hasCustomComponentForNode(node) {
935
- return node._type in components.types;
936
- }
937
- function renderListItem(node, index, key) {
938
- let tree = serializeBlock({
939
- node,
940
- index,
941
- isInline: !1,
942
- renderNode
943
- }), renderer = components.listItem, Li = (typeof renderer == "function" ? renderer : renderer[node.listItem]) || components.unknownListItem;
944
- if (Li === components.unknownListItem) {
945
- let style = node.listItem || "bullet";
946
- handleMissingComponent(unknownListItemStyleWarning(style), {
947
- type: style,
948
- nodeType: "listItemStyle"
949
- });
950
- }
951
- let children = tree.children;
952
- if (node.style && node.style !== "normal") {
953
- let { listItem: _listItem, ...blockNode } = node;
954
- children = renderNode({
955
- node: blockNode,
956
- index,
957
- isInline: !1
958
- });
959
- }
960
- return /* @__PURE__ */ jsx(Li, {
961
- value: node,
962
- index,
963
- isInline: !1,
964
- renderNode,
965
- children
966
- }, key);
967
- }
968
- function renderList(node, index, key) {
969
- let children = node.children.map((child, childIndex) => renderNode({
970
- node: child._key ? child : {
971
- ...child,
972
- _key: `li-${index}-${childIndex}`
973
- },
974
- index: childIndex,
975
- isInline: !1
976
- })), component = components.list, List = (typeof component == "function" ? component : component[node.listItem]) || components.unknownList;
977
- if (List === components.unknownList) {
978
- let style = node.listItem || "bullet";
979
- handleMissingComponent(unknownListStyleWarning(style), {
980
- nodeType: "listStyle",
981
- type: style
982
- });
983
- }
984
- return /* @__PURE__ */ jsx(List, {
985
- value: node,
986
- index,
987
- isInline: !1,
988
- renderNode,
989
- children
990
- }, key);
991
- }
992
- function renderSpan(node, _index, key) {
993
- let { markDef, markType, markKey } = node, Span = components.marks[markType] || components.unknownMark, children = node.children.map((child, childIndex) => renderNode({
994
- node: child,
995
- index: childIndex,
996
- isInline: !0
997
- }));
998
- return Span === components.unknownMark && handleMissingComponent(unknownMarkWarning(markType), {
999
- nodeType: "mark",
1000
- type: markType
1001
- }), /* @__PURE__ */ jsx(Span, {
1002
- text: spanToPlainText(node),
1003
- value: markDef,
1004
- markType,
1005
- markKey,
1006
- renderNode,
1007
- children
1008
- }, key);
1009
- }
1010
- function renderBlock(node, index, key, isInline) {
1011
- let { _key, ...props } = serializeBlock({
1012
- node,
1013
- index,
1014
- isInline,
1015
- renderNode
1016
- }), style = props.node.style || "normal", Block = (typeof components.block == "function" ? components.block : components.block[style]) || components.unknownBlockStyle;
1017
- return Block === components.unknownBlockStyle && handleMissingComponent(unknownBlockStyleWarning(style), {
1018
- nodeType: "blockStyle",
1019
- type: style
1020
- }), /* @__PURE__ */ jsx(Block, {
1021
- ...props,
1022
- value: props.node,
1023
- renderNode
1024
- }, key);
1025
- }
1026
- function renderText(node, key) {
1027
- if (node.text === `
1028
- `) {
1029
- let HardBreak = components.hardBreak;
1030
- return HardBreak ? /* @__PURE__ */ jsx(HardBreak, {}, key) : `
1031
- `;
1032
- }
1033
- return node.text;
1034
- }
1035
- function renderUnknownType(node, index, key, isInline) {
1036
- let nodeOptions = {
1037
- value: node,
1038
- isInline,
1039
- index,
1040
- renderNode
1041
- };
1042
- handleMissingComponent(unknownTypeWarning(node._type), {
1043
- nodeType: "block",
1044
- type: node._type
1045
- });
1046
- let UnknownType = components.unknownType;
1047
- return /* @__PURE__ */ jsx(UnknownType, { ...nodeOptions }, key);
1048
- }
1049
- function renderCustomBlock(node, index, key, isInline) {
1050
- let nodeOptions = {
1051
- value: node,
1052
- isInline,
1053
- index,
1054
- renderNode
1055
- }, Node = components.types[node._type];
1056
- return Node ? /* @__PURE__ */ jsx(Node, { ...nodeOptions }, key) : null;
1057
- }
1058
- return renderNode;
1059
- };
1060
- function serializeBlock(options) {
1061
- let { node, index, isInline, renderNode } = options, children = buildMarksTree(node).map((child, i) => renderNode({
1062
- node: child,
1063
- isInline: !0,
1064
- index: i,
1065
- renderNode
1066
- }));
1067
- return {
1068
- _key: node._key || `block-${index}`,
1069
- children,
1070
- index,
1071
- isInline,
1072
- node
1073
- };
1074
- }
1075
- function noop() {
1076
- }
1077
- const variantConfig = {
1078
- tip: { icon: LightbulbIcon, tone: "positive" },
1079
- info: { icon: InfoIcon, tone: "primary" },
1080
- warning: { icon: TriangleAlertIcon, tone: "caution" }
1081
- };
1082
- function CalloutContent({ variant, children }) {
1083
- const config = variantConfig[variant], Icon = config.icon;
1084
- return /* @__PURE__ */ jsx(Card, { padding: 4, radius: 2, tone: config.tone, children: /* @__PURE__ */ jsxs(Flex, { align: "flex-start", gap: 3, children: [
1085
- /* @__PURE__ */ jsx("div", { style: { flexShrink: 0, marginTop: "-2px", fontSize: "16px", color: "var(--card-icon-color)" }, children: /* @__PURE__ */ jsx(Icon, { ...defaultIconProps }) }),
1086
- /* @__PURE__ */ jsx(Text, { size: 1, style: { color: "var(--card-icon-color)" }, children })
1087
- ] }) });
1088
- }
1089
- function CalloutBlock({ value }) {
1090
- return /* @__PURE__ */ jsx("div", { style: { marginBlock: "2rem" }, children: /* @__PURE__ */ jsx(CalloutContent, { variant: value.variant, children: /* @__PURE__ */ jsx(
1091
- PortableText,
1092
- {
1093
- value: value.body,
1094
- components: {
1095
- block: { normal: ({ children }) => /* @__PURE__ */ jsx(Fragment, { children }) },
1096
- marks: {
1097
- strong: ({ children }) => /* @__PURE__ */ jsx("strong", { children }),
1098
- em: ({ children }) => /* @__PURE__ */ jsx("em", { children }),
1099
- code: ({ children }) => /* @__PURE__ */ jsx(
1100
- "code",
1101
- {
1102
- style: {
1103
- padding: "0.125rem 0.25rem",
1104
- fontSize: "0.875em",
1105
- backgroundColor: "var(--card-code-bg-color)",
1106
- borderRadius: "0.125rem"
1107
- },
1108
- children
1109
- }
1110
- ),
1111
- link: ({ children, value: mark }) => /* @__PURE__ */ jsx(
1112
- "a",
1113
- {
1114
- href: mark?.href,
1115
- target: "_blank",
1116
- rel: "noopener noreferrer",
1117
- style: { color: "var(--card-fg-color)" },
1118
- children
1119
- }
1120
- )
1121
- }
1122
- }
1123
- }
1124
- ) }) });
1125
- }
1126
- function CodeContent({ code, language }) {
1127
- return /* @__PURE__ */ jsx(Card, { padding: 4, radius: 2, tone: "transparent", style: { overflowX: "auto" }, children: /* @__PURE__ */ jsx(Code, { size: 1, language, children: code }) });
1128
- }
1129
- function CodeBlock({ value }) {
1130
- return /* @__PURE__ */ jsx("div", { style: { marginBlock: "1.5rem" }, children: /* @__PURE__ */ jsx(CodeContent, { code: value.code, language: value.language }) });
1131
- }
1132
- function HorizontalRuleContent({ marginBlock = "0" }) {
1133
- return /* @__PURE__ */ jsx("hr", { style: { marginBlock, border: "none", borderTop: "1px solid var(--card-border-color)" } });
1134
- }
1135
- function HorizontalRuleBlock() {
1136
- return /* @__PURE__ */ jsx(HorizontalRuleContent, { marginBlock: "2.5rem" });
1137
- }
1138
- function ImageContent({ url, alt, caption }) {
1139
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1140
- /* @__PURE__ */ jsx(
1141
- "img",
1142
- {
1143
- src: url,
1144
- alt: alt ?? "",
1145
- style: { display: "block", maxWidth: "100%", borderRadius: "0.25rem", overflow: "hidden" }
1146
- }
1147
- ),
1148
- isDefined(caption) && /* @__PURE__ */ jsx("div", { style: { marginBlockStart: "0.75rem" }, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children: caption }) })
1149
- ] });
1150
- }
1151
- function ImageBlock({ value }) {
1152
- return isDefined(value.asset?.url) ? /* @__PURE__ */ jsx("div", { style: { marginBlock: "1.5rem" }, children: /* @__PURE__ */ jsx(ImageContent, { url: value.asset.url, alt: value.alt, caption: value.caption }) }) : null;
1153
- }
1154
- function VideoContent({ url, caption }) {
1155
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1156
- /* @__PURE__ */ jsx(
1157
- "video",
1158
- {
1159
- src: url,
1160
- controls: !0,
1161
- style: {
1162
- display: "block",
1163
- maxWidth: "100%",
1164
- borderRadius: "0.25rem",
1165
- overflow: "hidden",
1166
- WebkitTransform: "translateZ(0)"
1167
- },
1168
- children: /* @__PURE__ */ jsx("track", { kind: "captions", label: caption ?? "Video" })
1169
- }
1170
- ),
1171
- isDefined(caption) && /* @__PURE__ */ jsx("div", { style: { marginBlockStart: "0.75rem" }, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children: caption }) })
1172
- ] });
1173
- }
1174
- function VideoBlock({ value }) {
1175
- return isDefined(value.asset?.url) ? /* @__PURE__ */ jsx("div", { style: { marginBlock: "1.5rem" }, children: /* @__PURE__ */ jsx(VideoContent, { url: value.asset.url, caption: value.caption }) }) : null;
1176
- }
1177
- const portableTextComponents = {
1178
- block: {
1179
- h2: ({ children }) => /* @__PURE__ */ jsx("div", { style: { marginBlockStart: "3rem", marginBlockEnd: "0.25rem" }, children: /* @__PURE__ */ jsx(Text, { as: "h2", size: 1, weight: "medium", children }) }),
1180
- normal: ({ children }) => /* @__PURE__ */ jsx("div", { style: { marginBlock: "1rem" }, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children }) }),
1181
- blockquote: ({ children }) => /* @__PURE__ */ jsx("div", { style: { marginBlock: "2rem" }, children: /* @__PURE__ */ jsx(Box, { paddingLeft: 3, paddingY: 1, style: { borderLeft: "2px solid var(--card-border-color)" }, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children }) }) })
1182
- },
1183
- list: {
1184
- bullet: ({ children, value }) => /* @__PURE__ */ jsx("div", { style: { marginBlock: value.level > 1 ? "0.75rem" : "2rem" }, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: /* @__PURE__ */ jsx("ul", { style: { display: "flex", flexDirection: "column", gap: "0.375rem", margin: 0, paddingLeft: "1.25em" }, children }) }) }),
1185
- number: ({ children, value }) => /* @__PURE__ */ jsx("div", { style: { marginBlock: value.level > 1 ? "0.75rem" : "2rem" }, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: /* @__PURE__ */ jsx("ol", { style: { display: "flex", flexDirection: "column", gap: "0.375rem", margin: 0, paddingLeft: "1.25em" }, children }) }) })
1186
- },
1187
- listItem: {
1188
- bullet: ({ children }) => /* @__PURE__ */ jsx("li", { children }),
1189
- number: ({ children }) => /* @__PURE__ */ jsx("li", { children })
1190
- },
1191
- marks: {
1192
- strong: ({ children }) => /* @__PURE__ */ jsx("strong", { children }),
1193
- em: ({ children }) => /* @__PURE__ */ jsx("em", { children }),
1194
- code: ({ children }) => /* @__PURE__ */ jsx(
1195
- "code",
1196
- {
1197
- style: {
1198
- padding: "0.125rem 0.25rem",
1199
- fontSize: "0.875em",
1200
- backgroundColor: "var(--card-code-bg-color)",
1201
- borderRadius: "0.125rem"
1202
- },
1203
- children
1204
- }
1205
- ),
1206
- link: ({ children, value }) => /* @__PURE__ */ jsx("a", { href: value?.href, target: "_blank", rel: "noopener noreferrer", style: { color: "var(--card-link-fg-color)" }, children }),
1207
- "strike-through": ({ children }) => /* @__PURE__ */ jsx("del", { children })
1208
- }
1209
- };
1210
- function GuideContent({ content }) {
1211
- const { blocks: customBlocks } = useHandbookContext(), components = useMemo(() => {
1212
- const customTypes = {};
1213
- for (const block of customBlocks)
1214
- customTypes[block.schema.name] = block.component;
1215
- return {
1216
- ...portableTextComponents,
1217
- types: {
1218
- "handbook.image": ImageBlock,
1219
- "handbook.video": VideoBlock,
1220
- "handbook.code": CodeBlock,
1221
- "handbook.callout": CalloutBlock,
1222
- "handbook.horizontalRule": HorizontalRuleBlock,
1223
- ...customTypes
1224
- }
1225
- };
1226
- }, [customBlocks]);
1227
- return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(PortableText, { value: content, components }) });
1228
- }
1229
- function GuidesTabs() {
1230
- const { configuration, loading } = useHandbookContext();
1231
- return loading || !isDefined(configuration) ? null : configuration.groups.map((group) => /* @__PURE__ */ jsx(SidebarGroup, { heading: group.title, children: group.guides.map((guide) => /* @__PURE__ */ jsx(SidebarTab, { id: guide._key, label: guide.title, icon: createSanityIcon(BookOpenTextIcon) }, guide._key)) }, group._key));
1232
- }
1233
- function GuidesPanels() {
1234
- const { configuration, loading } = useHandbookContext();
1235
- return loading || !isDefined(configuration) ? null : configuration.groups.flatMap(
1236
- (group) => group.guides.map((guide) => /* @__PURE__ */ jsx(ContentPanel, { id: guide._key, title: guide.title, description: guide.description, children: /* @__PURE__ */ jsx(GuideContent, { content: guide.content }) }, guide._key))
1237
- );
1728
+ if (opaqueTypes.has(field.type)) return;
1729
+ let directFields = resolveFields(field, schema);
1730
+ if (isDefined(directFields)) return directFields;
1731
+ let resolvedType = schema.get(field.type);
1732
+ if (!isDefined(resolvedType)) return;
1733
+ let parentName = getParentTypeName(resolvedType);
1734
+ return isDefined(parentName) && opaqueTypes.has(parentName) ? resolveCustomFields(resolvedType, parentName) : resolveFields(resolvedType, schema);
1735
+ }
1736
+ /** Shared empty ancestor set, so the default prop keeps a stable reference across renders. */
1737
+ const noAncestors = /* @__PURE__ */ new Set();
1738
+ function Field(t0) {
1739
+ let $ = c(59), field, props, t1;
1740
+ $[0] === t0 ? (field = $[1], props = $[2], t1 = $[3]) : ({field, ancestors: t1, ...props} = t0, $[0] = t0, $[1] = field, $[2] = props, $[3] = t1);
1741
+ let ancestors = t1 === void 0 ? noAncestors : t1, schema = useSchema(), { undocumentedFieldMessage } = useHandbookContext(), [expanded, setExpanded] = useState(!1), t2;
1742
+ $[4] === field ? t2 = $[5] : (t2 = resolveTitle(field), $[4] = field, $[5] = t2);
1743
+ let effectiveTitle = t2, t3;
1744
+ $[6] !== field || $[7] !== undocumentedFieldMessage ? (t3 = resolveDescription(field) ?? undocumentedFieldMessage, $[6] = field, $[7] = undocumentedFieldMessage, $[8] = t3) : t3 = $[8];
1745
+ let effectiveDescription = t3, caution, example, info, t4, tip;
1746
+ $[9] === field.handbook ? (caution = $[10], example = $[11], info = $[12], t4 = $[13], tip = $[14]) : ({example, tip, info, caution} = field.handbook ?? {}, t4 = isDefined([
1747
+ tip,
1748
+ info,
1749
+ caution
1750
+ ]), $[9] = field.handbook, $[10] = caution, $[11] = example, $[12] = info, $[13] = t4, $[14] = tip);
1751
+ let hasHints = t4, t5;
1752
+ $[15] !== ancestors || $[16] !== field.type ? (t5 = ancestors.has(field.type), $[15] = ancestors, $[16] = field.type, $[17] = t5) : t5 = $[17];
1753
+ let isCycle = t5, t6;
1754
+ if ($[18] !== ancestors || $[19] !== caution || $[20] !== effectiveDescription || $[21] !== effectiveTitle || $[22] !== example || $[23] !== expanded || $[24] !== field || $[25] !== hasHints || $[26] !== info || $[27] !== isCycle || $[28] !== props || $[29] !== schema || $[30] !== tip) {
1755
+ let subfields = isCycle ? void 0 : getSubfields(field, schema), hasSubfields = isDefined(subfields), t7;
1756
+ $[32] === effectiveTitle ? t7 = $[33] : (t7 = /* @__PURE__ */ jsx(Text, {
1757
+ size: 1,
1758
+ weight: "medium",
1759
+ children: effectiveTitle
1760
+ }), $[32] = effectiveTitle, $[33] = t7);
1761
+ let t8;
1762
+ $[34] === Symbol.for("react.memo_cache_sentinel") ? (t8 = { marginTop: 2 }, $[34] = t8) : t8 = $[34];
1763
+ let t9;
1764
+ $[35] === field.type ? t9 = $[36] : (t9 = /* @__PURE__ */ jsx(Text, {
1765
+ size: 0,
1766
+ muted: !0,
1767
+ style: t8,
1768
+ children: field.type
1769
+ }), $[35] = field.type, $[36] = t9);
1770
+ let t10;
1771
+ $[37] !== t7 || $[38] !== t9 ? (t10 = /* @__PURE__ */ jsx(Box, {
1772
+ flex: 1,
1773
+ children: /* @__PURE__ */ jsxs(Flex, {
1774
+ align: "center",
1775
+ gap: 2,
1776
+ children: [t7, t9]
1777
+ })
1778
+ }), $[37] = t7, $[38] = t9, $[39] = t10) : t10 = $[39];
1779
+ let t11;
1780
+ $[40] !== caution || $[41] !== hasHints || $[42] !== info || $[43] !== tip ? (t11 = hasHints && /* @__PURE__ */ jsx(FieldHints, {
1781
+ tip,
1782
+ info,
1783
+ caution
1784
+ }), $[40] = caution, $[41] = hasHints, $[42] = info, $[43] = tip, $[44] = t11) : t11 = $[44];
1785
+ let t12;
1786
+ $[45] !== t10 || $[46] !== t11 ? (t12 = /* @__PURE__ */ jsxs(Flex, {
1787
+ align: "center",
1788
+ paddingY: 1,
1789
+ gap: 2,
1790
+ children: [t10, t11]
1791
+ }), $[45] = t10, $[46] = t11, $[47] = t12) : t12 = $[47];
1792
+ let t13;
1793
+ $[48] === effectiveDescription ? t13 = $[49] : (t13 = isDefined(effectiveDescription) && /* @__PURE__ */ jsx(Text, {
1794
+ size: 1,
1795
+ muted: !0,
1796
+ children: effectiveDescription
1797
+ }), $[48] = effectiveDescription, $[49] = t13);
1798
+ let t14;
1799
+ $[50] === example ? t14 = $[51] : (t14 = isDefined(example) && /* @__PURE__ */ jsx(Box, {
1800
+ marginTop: 1,
1801
+ children: /* @__PURE__ */ jsxs(Text, {
1802
+ size: 1,
1803
+ muted: !0,
1804
+ style: { fontStyle: "italic" },
1805
+ children: ["e.g. ", example]
1806
+ })
1807
+ }), $[50] = example, $[51] = t14);
1808
+ let t15;
1809
+ $[52] !== t12 || $[53] !== t13 || $[54] !== t14 ? (t15 = /* @__PURE__ */ jsxs(Stack, {
1810
+ gap: 3,
1811
+ children: [
1812
+ t12,
1813
+ t13,
1814
+ t14
1815
+ ]
1816
+ }), $[52] = t12, $[53] = t13, $[54] = t14, $[55] = t15) : t15 = $[55];
1817
+ let t16;
1818
+ $[56] !== field.type || $[57] !== isCycle ? (t16 = isCycle && /* @__PURE__ */ jsx(Box, {
1819
+ marginTop: 2,
1820
+ children: /* @__PURE__ */ jsxs(Text, {
1821
+ size: 1,
1822
+ muted: !0,
1823
+ style: { fontStyle: "italic" },
1824
+ children: [
1825
+ "See ",
1826
+ convertCase(field.type, "title"),
1827
+ " above."
1828
+ ]
1829
+ })
1830
+ }), $[56] = field.type, $[57] = isCycle, $[58] = t16) : t16 = $[58], t6 = /* @__PURE__ */ jsxs(Stack, {
1831
+ gap: 2,
1832
+ ...props,
1833
+ children: [
1834
+ t15,
1835
+ t16,
1836
+ hasSubfields && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Card, {
1837
+ as: "button",
1838
+ padding: 3,
1839
+ radius: 2,
1840
+ sizing: "border",
1841
+ tone: "transparent",
1842
+ onClick: () => {
1843
+ setExpanded(!expanded);
1844
+ },
1845
+ style: {
1846
+ marginTop: 16,
1847
+ textAlign: "left",
1848
+ border: "none",
1849
+ cursor: "pointer"
1850
+ },
1851
+ children: /* @__PURE__ */ jsxs(Flex, {
1852
+ align: "center",
1853
+ gap: 2,
1854
+ children: [/* @__PURE__ */ jsx(Text, {
1855
+ size: 0,
1856
+ children: jsx(expanded ? ChevronDownIcon : ChevronRightIcon, {})
1857
+ }), /* @__PURE__ */ jsxs(Text, {
1858
+ size: 1,
1859
+ muted: !0,
1860
+ weight: "medium",
1861
+ children: [
1862
+ subfields.length,
1863
+ " subfield",
1864
+ subfields.length === 1 ? "" : "s"
1865
+ ]
1866
+ })]
1867
+ })
1868
+ }), expanded && /* @__PURE__ */ jsx("div", {
1869
+ style: {
1870
+ marginTop: 16,
1871
+ marginBottom: 8,
1872
+ paddingLeft: 16,
1873
+ borderLeft: "1px solid var(--card-border-color)"
1874
+ },
1875
+ children: /* @__PURE__ */ jsx(Stack, {
1876
+ gap: 5,
1877
+ children: subfields.map((subfield) => /* @__PURE__ */ jsx(Field, {
1878
+ field: subfield,
1879
+ ancestors: /* @__PURE__ */ new Set([...ancestors, field.type])
1880
+ }, subfield.name))
1881
+ })
1882
+ })] })
1883
+ ]
1884
+ }), $[18] = ancestors, $[19] = caution, $[20] = effectiveDescription, $[21] = effectiveTitle, $[22] = example, $[23] = expanded, $[24] = field, $[25] = hasHints, $[26] = info, $[27] = isCycle, $[28] = props, $[29] = schema, $[30] = tip, $[31] = t6;
1885
+ } else t6 = $[31];
1886
+ return t6;
1887
+ }
1888
+ /**
1889
+ * Builds a section for each configured document role.
1890
+ *
1891
+ * @param roles - Document roles from the plugin configuration.
1892
+ * @returns One section per role, holding an entry per document type.
1893
+ */
1894
+ function documentTypesSections(roles) {
1895
+ return roles.map(({ title, documents }) => ({
1896
+ title,
1897
+ entries: documents.map((document) => ({
1898
+ id: document.name,
1899
+ title: resolveTitle(document),
1900
+ description: resolveDescription(document),
1901
+ icon: resolveIcon(document),
1902
+ render: () => /* @__PURE__ */ jsx("div", {
1903
+ style: {
1904
+ display: "flex",
1905
+ flexDirection: "column",
1906
+ gap: contentSpacing.section
1907
+ },
1908
+ children: document.fields.map((field) => /* @__PURE__ */ jsx(Field, { field }, field.name))
1909
+ })
1910
+ }))
1911
+ }));
1238
1912
  }
1239
1913
  function LayoutGridIcon(props) {
1240
- return /* @__PURE__ */ jsxs(
1241
- "svg",
1242
- {
1243
- xmlns: "http://www.w3.org/2000/svg",
1244
- viewBox: "0 0 24 24",
1245
- fill: "none",
1246
- stroke: "currentColor",
1247
- strokeLinecap: "round",
1248
- strokeLinejoin: "round",
1249
- ...props,
1250
- children: [
1251
- /* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "3", y: "3", rx: "1" }),
1252
- /* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "14", y: "3", rx: "1" }),
1253
- /* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "14", y: "14", rx: "1" }),
1254
- /* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "3", y: "14", rx: "1" })
1255
- ]
1256
- }
1257
- );
1914
+ let $ = c(6), t0, t1, t2, t3;
1915
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("rect", {
1916
+ width: "7",
1917
+ height: "7",
1918
+ x: "3",
1919
+ y: "3",
1920
+ rx: "1"
1921
+ }), t1 = /* @__PURE__ */ jsx("rect", {
1922
+ width: "7",
1923
+ height: "7",
1924
+ x: "14",
1925
+ y: "3",
1926
+ rx: "1"
1927
+ }), t2 = /* @__PURE__ */ jsx("rect", {
1928
+ width: "7",
1929
+ height: "7",
1930
+ x: "14",
1931
+ y: "14",
1932
+ rx: "1"
1933
+ }), t3 = /* @__PURE__ */ jsx("rect", {
1934
+ width: "7",
1935
+ height: "7",
1936
+ x: "3",
1937
+ y: "14",
1938
+ rx: "1"
1939
+ }), $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3) : (t0 = $[0], t1 = $[1], t2 = $[2], t3 = $[3]);
1940
+ let t4;
1941
+ return $[4] === props ? t4 = $[5] : (t4 = /* @__PURE__ */ jsxs("svg", {
1942
+ xmlns: "http://www.w3.org/2000/svg",
1943
+ width: 24,
1944
+ height: 24,
1945
+ viewBox: "0 0 24 24",
1946
+ fill: "none",
1947
+ stroke: "currentColor",
1948
+ strokeWidth: 2,
1949
+ strokeLinecap: "round",
1950
+ strokeLinejoin: "round",
1951
+ ...props,
1952
+ children: [
1953
+ t0,
1954
+ t1,
1955
+ t2,
1956
+ t3
1957
+ ]
1958
+ }), $[4] = props, $[5] = t4), t4;
1258
1959
  }
1259
1960
  function DocumentTypesOverview() {
1260
- const { groups, setActiveTab, setSidebarExpanded } = useHandbookContext();
1261
- return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "2.5rem" }, children: groups.map((group) => {
1262
- const { title, description, documents } = group;
1263
- return /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
1264
- /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1265
- /* @__PURE__ */ jsx(Flex, { align: "center", paddingY: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: title }) }),
1266
- isDefined(description) && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: description })
1267
- ] }),
1268
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Stack, { space: 2, children: documents.map((document) => {
1269
- const Icon = typeof document.icon == "function" ? document.icon : void 0, documentDescription = document.handbook?.description ?? (typeof document.description == "string" ? document.description : void 0);
1270
- return /* @__PURE__ */ jsx(
1271
- Card,
1272
- {
1273
- as: "button",
1274
- padding: 3,
1275
- radius: 2,
1276
- sizing: "border",
1277
- tone: "inherit",
1278
- onClick: () => {
1279
- setActiveTab(document.name), setSidebarExpanded(!1);
1280
- },
1281
- style: {
1282
- width: "calc(100% + 24px)",
1283
- marginLeft: "-12px",
1284
- textAlign: "left",
1285
- border: "none",
1286
- cursor: "pointer"
1287
- },
1288
- children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
1289
- /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1290
- /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, style: { marginLeft: "-4px" }, children: [
1291
- isDefined(Icon) && /* @__PURE__ */ jsx(
1292
- "div",
1293
- {
1294
- style: {
1295
- display: "flex",
1296
- alignItems: "center",
1297
- justifyContent: "center",
1298
- width: "25px",
1299
- height: "25px",
1300
- color: "var(--card-icon-color)"
1301
- },
1302
- children: /* @__PURE__ */ jsx(Icon, {})
1303
- }
1304
- ),
1305
- /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: document.title ?? document.name })
1306
- ] }),
1307
- isDefined(documentDescription) && /* @__PURE__ */ jsx(Box, { paddingBottom: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: documentDescription }) })
1308
- ] }) }),
1309
- /* @__PURE__ */ jsx(Box, { flex: "none", style: { opacity: 0.5 }, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) }) })
1310
- ] })
1311
- },
1312
- document.name
1313
- );
1314
- }) }) })
1315
- ] }, title);
1316
- }) });
1317
- }
1318
- function HintRow({ icon, children }) {
1319
- return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
1320
- /* @__PURE__ */ jsx(
1321
- "div",
1322
- {
1323
- style: {
1324
- display: "flex",
1325
- alignItems: "center",
1326
- flexShrink: 0,
1327
- fontSize: "16px",
1328
- color: "var(--card-icon-color)"
1329
- },
1330
- children: icon
1331
- }
1332
- ),
1333
- /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children })
1334
- ] });
1335
- }
1961
+ let $ = c(10), { roles, setActiveTab, setSidebarExpanded } = useHandbookContext(), t0;
1962
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
1963
+ display: "flex",
1964
+ flexDirection: "column",
1965
+ gap: contentSpacing.section
1966
+ }, $[0] = t0) : t0 = $[0];
1967
+ let t1;
1968
+ if ($[1] !== roles || $[2] !== setActiveTab || $[3] !== setSidebarExpanded) {
1969
+ let t2;
1970
+ $[5] !== setActiveTab || $[6] !== setSidebarExpanded ? (t2 = (role) => {
1971
+ let { title, description, documents } = role;
1972
+ return /* @__PURE__ */ jsxs(Stack, {
1973
+ gap: 2,
1974
+ children: [/* @__PURE__ */ jsxs(Stack, {
1975
+ gap: 3,
1976
+ children: [/* @__PURE__ */ jsx(Flex, {
1977
+ align: "center",
1978
+ paddingY: 1,
1979
+ children: /* @__PURE__ */ jsx(Text, {
1980
+ size: 1,
1981
+ weight: "medium",
1982
+ children: title
1983
+ })
1984
+ }), isDefined(description) && /* @__PURE__ */ jsx(Text, {
1985
+ size: 1,
1986
+ muted: !0,
1987
+ children: description
1988
+ })]
1989
+ }), /* @__PURE__ */ jsx(Box, {
1990
+ marginTop: 1,
1991
+ children: /* @__PURE__ */ jsx(Stack, {
1992
+ gap: 2,
1993
+ children: documents.map((document) => {
1994
+ let Icon = resolveIcon(document), documentDescription = resolveDescription(document);
1995
+ return /* @__PURE__ */ jsx(Card, {
1996
+ as: "button",
1997
+ padding: 3,
1998
+ radius: 2,
1999
+ sizing: "border",
2000
+ tone: "inherit",
2001
+ onClick: () => {
2002
+ setActiveTab(document.name), setSidebarExpanded(!1);
2003
+ },
2004
+ style: {
2005
+ width: "calc(100% + 24px)",
2006
+ marginLeft: "-12px",
2007
+ textAlign: "left",
2008
+ border: "none",
2009
+ cursor: "pointer"
2010
+ },
2011
+ children: /* @__PURE__ */ jsxs(Flex, {
2012
+ align: "center",
2013
+ gap: 3,
2014
+ children: [/* @__PURE__ */ jsx(Box, {
2015
+ flex: 1,
2016
+ children: /* @__PURE__ */ jsxs(Stack, {
2017
+ gap: 3,
2018
+ children: [/* @__PURE__ */ jsxs(Flex, {
2019
+ align: "center",
2020
+ gap: 2,
2021
+ style: { marginLeft: "-4px" },
2022
+ children: [isDefined(Icon) && /* @__PURE__ */ jsx("div", {
2023
+ style: {
2024
+ display: "flex",
2025
+ alignItems: "center",
2026
+ justifyContent: "center",
2027
+ width: 25,
2028
+ height: 25,
2029
+ color: "var(--card-icon-color)"
2030
+ },
2031
+ children: /* @__PURE__ */ jsx(Icon, {})
2032
+ }), /* @__PURE__ */ jsx(Text, {
2033
+ size: 1,
2034
+ weight: "medium",
2035
+ children: resolveTitle(document)
2036
+ })]
2037
+ }), isDefined(documentDescription) && /* @__PURE__ */ jsx(Box, {
2038
+ paddingBottom: 1,
2039
+ children: /* @__PURE__ */ jsx(Text, {
2040
+ size: 1,
2041
+ muted: !0,
2042
+ children: documentDescription
2043
+ })
2044
+ })]
2045
+ })
2046
+ }), /* @__PURE__ */ jsx(Box, {
2047
+ flex: "none",
2048
+ style: { opacity: .5 },
2049
+ children: /* @__PURE__ */ jsx(Text, {
2050
+ muted: !0,
2051
+ size: 1,
2052
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
2053
+ })
2054
+ })]
2055
+ })
2056
+ }, document.name);
2057
+ })
2058
+ })
2059
+ })]
2060
+ }, title);
2061
+ }, $[5] = setActiveTab, $[6] = setSidebarExpanded, $[7] = t2) : t2 = $[7], t1 = roles.map(t2), $[1] = roles, $[2] = setActiveTab, $[3] = setSidebarExpanded, $[4] = t1;
2062
+ } else t1 = $[4];
2063
+ let t2;
2064
+ return $[8] === t1 ? t2 = $[9] : (t2 = /* @__PURE__ */ jsx("div", {
2065
+ style: t0,
2066
+ children: t1
2067
+ }), $[8] = t1, $[9] = t2), t2;
2068
+ }
2069
+ /** What each hint kind signals to an editor, shown as a legend alongside its icon. */
2070
+ const hintDescriptions = {
2071
+ tip: "Helpful tips and best practices for content editors.",
2072
+ info: "Additional context about how the field is used.",
2073
+ caution: "Important warnings about constraints or potential issues."
2074
+ };
1336
2075
  function HowToUse() {
1337
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "3rem" }, children: [
1338
- /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1339
- /* @__PURE__ */ jsx(Flex, { align: "center", paddingY: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: "Navigating the Handbook" }) }),
1340
- /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Use the sidebar to browse document types and guides. Each entry opens a detailed view in the main panel showing field descriptions, examples, and tips." })
1341
- ] }),
1342
- /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1343
- /* @__PURE__ */ jsx(Flex, { align: "center", paddingY: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: "Understanding Fields" }) }),
1344
- /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Each document type lists its fields with a name and type label. Below the name you will find a description explaining what the field is for and how to use it. Some fields include an example value shown in italics." }),
1345
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children: "e.g. Acme Inc." }) })
1346
- ] }),
1347
- /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1348
- /* @__PURE__ */ jsx(Flex, { align: "center", paddingY: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: "Hints and Warnings" }) }),
1349
- /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Look for these icons next to field names. Hover or click them to reveal additional guidance." }),
1350
- /* @__PURE__ */ jsxs(Stack, { space: 3, marginTop: 2, children: [
1351
- /* @__PURE__ */ jsx(HintRow, { icon: /* @__PURE__ */ jsx(LightbulbIcon, { ...defaultIconProps }), children: "Helpful tips and best practices for content editors." }),
1352
- /* @__PURE__ */ jsx(HintRow, { icon: /* @__PURE__ */ jsx(InfoIcon, { ...defaultIconProps }), children: "Additional context about how the field is used." }),
1353
- /* @__PURE__ */ jsx(HintRow, { icon: /* @__PURE__ */ jsx(TriangleAlertIcon, { ...defaultIconProps }), children: "Important warnings about constraints or potential issues." })
1354
- ] })
1355
- ] }),
1356
- /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1357
- /* @__PURE__ */ jsx(Flex, { align: "center", paddingY: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: "Nested Fields" }) }),
1358
- /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Some fields contain subfields \u2014 for example, a content block might include a heading and body text. These are shown as collapsible sections you can expand to explore the full structure." })
1359
- ] })
1360
- ] });
1361
- }
1362
- const entries = [
1363
- {
1364
- name: "how-to-use-this-handbook",
1365
- title: "How to Use This Handbook",
1366
- icon: createSanityIcon(BookTextIcon),
1367
- description: "A quick guide to navigating the Handbook, understanding the information presented for each field, and making the most of tips, hints, and warnings.",
1368
- component: HowToUse
1369
- },
1370
- {
1371
- name: "document-types",
1372
- title: "Document Types",
1373
- icon: createSanityIcon(LayoutGridIcon),
1374
- description: "An overview of all document types, organised by group. Select a document type to view its fields, descriptions, and examples.",
1375
- component: DocumentTypesOverview
1376
- }
1377
- ];
1378
- function GettingStartedTabs() {
1379
- return /* @__PURE__ */ jsx(SidebarGroup, { heading: "Getting Started", children: entries.map((entry) => /* @__PURE__ */ jsx(SidebarTab, { id: entry.name, label: entry.title, icon: entry.icon }, entry.name)) });
1380
- }
1381
- function GettingStartedPanels() {
1382
- return entries.map((entry) => {
1383
- const { name, title, description, component: Component } = entry;
1384
- return /* @__PURE__ */ jsx(ContentPanel, { id: name, title, description, children: /* @__PURE__ */ jsx(Component, {}) }, name);
1385
- });
1386
- }
1387
- function Content() {
1388
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1389
- /* @__PURE__ */ jsx(GettingStartedPanels, {}),
1390
- /* @__PURE__ */ jsx(DocumentTypesPanels, {}),
1391
- /* @__PURE__ */ jsx(GuidesPanels, {})
1392
- ] });
1393
- }
1394
- function Sidebar() {
1395
- return /* @__PURE__ */ jsxs(Box, { paddingX: 3, paddingBottom: 1, children: [
1396
- /* @__PURE__ */ jsx(GettingStartedTabs, {}),
1397
- /* @__PURE__ */ jsx(DocumentTypesTabs, {}),
1398
- /* @__PURE__ */ jsx(GuidesTabs, {})
1399
- ] });
1400
- }
1401
- const defaultUndocumentedFieldMessage = "This field has not been documented yet. Contact your development team for guidance.", wideBreakpoint = 920, narrowBreakpoint = 480, sidebarWidth = 320, collapsedSidebarWidth = 51;
1402
- function CollapsedSidebar() {
1403
- const { sidebarTitle, setSidebarExpanded } = useHandbookContext();
1404
- return /* @__PURE__ */ jsx(
1405
- "div",
1406
- {
1407
- style: {
1408
- width: `${collapsedSidebarWidth}px`,
1409
- minWidth: `${collapsedSidebarWidth}px`,
1410
- overflow: "hidden",
1411
- borderRight: "1px solid var(--card-border-color)"
1412
- },
1413
- children: /* @__PURE__ */ jsx(Card, { tone: "inherit", "data-collapsed": "", children: /* @__PURE__ */ jsx(
1414
- Flex,
1415
- {
1416
- direction: "column",
1417
- padding: 3,
1418
- onClick: () => {
1419
- setSidebarExpanded(!0);
1420
- },
1421
- style: {
1422
- width: "100vh",
1423
- boxSizing: "border-box",
1424
- transform: "rotate(90deg)",
1425
- transformOrigin: `calc(${collapsedSidebarWidth}px / 2)`,
1426
- cursor: "pointer"
1427
- },
1428
- children: /* @__PURE__ */ jsx(Flex, { align: "flex-start", children: /* @__PURE__ */ jsx(Card, { flex: 1, paddingLeft: 2, padding: 2, children: /* @__PURE__ */ jsx(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, textOverflow: "ellipsis", weight: "semibold", style: { cursor: "default", outline: "none" }, children: sidebarTitle }) }) }) })
1429
- }
1430
- ) })
1431
- }
1432
- );
1433
- }
1434
- function NarrowContentHeader() {
1435
- const { sidebarTitle, setSidebarExpanded } = useHandbookContext();
1436
- return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: 3, children: [
1437
- /* @__PURE__ */ jsx(
1438
- Button,
1439
- {
1440
- icon: ArrowLeftIcon,
1441
- mode: "bleed",
1442
- onClick: () => {
1443
- setSidebarExpanded(!0);
1444
- }
1445
- }
1446
- ),
1447
- /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: sidebarTitle })
1448
- ] });
1449
- }
1450
- function ExpandedSidebar() {
1451
- const { sidebarTitle } = useHandbookContext();
1452
- return /* @__PURE__ */ jsxs(
1453
- Card,
1454
- {
1455
- borderRight: !0,
1456
- style: { display: "flex", flexDirection: "column", width: `${sidebarWidth}px`, minWidth: `${sidebarWidth}px` },
1457
- children: [
1458
- /* @__PURE__ */ jsx(PaneHeader, { title: sidebarTitle }),
1459
- /* @__PURE__ */ jsx("div", { style: { flex: 1, paddingBottom: "4px", overflowY: "auto" }, children: /* @__PURE__ */ jsx(Sidebar, {}) })
1460
- ]
1461
- }
1462
- );
1463
- }
1464
- function NarrowLayout() {
1465
- const { sidebarTitle, sidebarExpanded } = useHandbookContext();
1466
- return sidebarExpanded ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", flex: 1 }, children: [
1467
- /* @__PURE__ */ jsx(PaneHeader, { title: sidebarTitle }),
1468
- /* @__PURE__ */ jsx("div", { style: { flex: 1, paddingBottom: "4px", overflowY: "auto" }, children: /* @__PURE__ */ jsx(Sidebar, {}) })
1469
- ] }) : /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", flex: 1 }, children: [
1470
- /* @__PURE__ */ jsx(NarrowContentHeader, {}),
1471
- /* @__PURE__ */ jsx(Content, {})
1472
- ] });
1473
- }
1474
- function MediumLayout() {
1475
- const { sidebarExpanded, setSidebarExpanded } = useHandbookContext();
1476
- return sidebarExpanded ? /* @__PURE__ */ jsxs(Flex, { style: { flex: 1 }, children: [
1477
- /* @__PURE__ */ jsx(ExpandedSidebar, {}),
1478
- /* @__PURE__ */ jsx(
1479
- Card,
1480
- {
1481
- flex: 1,
1482
- padding: 3,
1483
- onClick: () => {
1484
- setSidebarExpanded(!1);
1485
- },
1486
- style: { opacity: 0.4, overflowY: "auto", cursor: "pointer" }
1487
- }
1488
- )
1489
- ] }) : /* @__PURE__ */ jsxs(Flex, { style: { flex: 1 }, children: [
1490
- /* @__PURE__ */ jsx(CollapsedSidebar, {}),
1491
- /* @__PURE__ */ jsx(Card, { flex: 1, style: { display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsx(Content, {}) })
1492
- ] });
1493
- }
1494
- function WideLayout() {
1495
- return /* @__PURE__ */ jsxs(Flex, { style: { flex: 1 }, children: [
1496
- /* @__PURE__ */ jsx(ExpandedSidebar, {}),
1497
- /* @__PURE__ */ jsx(Card, { flex: 1, style: { display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsx(Content, {}) })
1498
- ] });
1499
- }
1500
- function HandbookLayout() {
1501
- const { reference: containerReference, width: containerWidth } = useContainerWidth(), isNarrow = isDefined(containerWidth) && containerWidth < narrowBreakpoint, isMedium = isDefined(containerWidth) && containerWidth >= narrowBreakpoint && containerWidth < wideBreakpoint;
1502
- function renderLayout() {
1503
- return isNarrow ? /* @__PURE__ */ jsx(NarrowLayout, {}) : isMedium ? /* @__PURE__ */ jsx(MediumLayout, {}) : /* @__PURE__ */ jsx(WideLayout, {});
1504
- }
1505
- return /* @__PURE__ */ jsx("div", { ref: containerReference, style: { display: "flex", flexDirection: "column", height: "100%" }, children: renderLayout() });
1506
- }
1507
- function createHandbookTool(config) {
1508
- return function() {
1509
- return /* @__PURE__ */ jsx(
1510
- HandbookProvider,
1511
- {
1512
- sidebarTitle: config.sidebarTitle ?? "Handbook",
1513
- groups: config.groups ?? [],
1514
- blocks: config.blocks ?? [],
1515
- undocumentedFieldMessage: config.undocumentedFieldMessage ?? defaultUndocumentedFieldMessage,
1516
- children: /* @__PURE__ */ jsx(HandbookLayout, {})
1517
- }
1518
- );
1519
- };
1520
- }
1521
- let registeredEditors;
1522
- function setHandbookEditors(editors) {
1523
- registeredEditors = editors;
1524
- }
1525
- function handbookStructure(structureBuilder, context) {
1526
- if (!isPermittedEditor(registeredEditors, context.currentUser?.email)) return [];
1527
- const { listItem, document, documentTypeList } = structureBuilder;
1528
- return [
1529
- listItem().title("Handbook").icon(createSanityIcon(BookTextIcon)).child(document().id("handbook.handbook").schemaType("handbook.handbook").title("Handbook")),
1530
- listItem().title("Handbook Guides").icon(createSanityIcon(BookOpenTextIcon)).child(documentTypeList("handbook.guide").title("Handbook Guides"))
1531
- ];
1532
- }
1533
- function CalloutPreview({ variant, text }) {
1534
- return /* @__PURE__ */ jsx(CalloutContent, { variant: variant ?? "tip", children: text });
1535
- }
1536
- function ParagraphDecorator({ children }) {
1537
- return /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8125rem" }, children });
1538
- }
1539
- function HeadingDecorator({ children }) {
1540
- return /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8125rem", fontWeight: "500" }, children });
1541
- }
1542
- function BlockquoteDecorator({ children }) {
1543
- return /* @__PURE__ */ jsx(
1544
- "div",
1545
- {
1546
- style: {
1547
- paddingLeft: "0.75em",
1548
- fontSize: "0.8125rem",
1549
- fontStyle: "italic",
1550
- borderLeft: "2px solid var(--card-border-color)"
1551
- },
1552
- children
1553
- }
1554
- );
1555
- }
1556
- function BulletListDecorator({ children }) {
1557
- return /* @__PURE__ */ jsx("div", { style: { marginTop: "-0.25em", fontSize: "0.8125rem" }, children });
1558
- }
1559
- function NumberListDecorator({ children }) {
1560
- return /* @__PURE__ */ jsx("div", { style: { marginTop: "-0.25em", fontSize: "0.8125rem" }, children });
1561
- }
1562
- function InlineCodeDecorator({ children }) {
1563
- return /* @__PURE__ */ jsx(
1564
- "code",
1565
- {
1566
- style: {
1567
- padding: "0.125rem 0.25rem",
1568
- fontSize: "0.8125rem",
1569
- color: "var(--card-muted-fg-color)",
1570
- backgroundColor: "var(--card-code-bg-color)",
1571
- borderRadius: "0.125rem"
1572
- },
1573
- children
1574
- }
1575
- );
1576
- }
1577
- function MessageCircleQuestionMarkIcon(props) {
1578
- return /* @__PURE__ */ jsxs(
1579
- "svg",
1580
- {
1581
- xmlns: "http://www.w3.org/2000/svg",
1582
- viewBox: "0 0 24 24",
1583
- fill: "none",
1584
- stroke: "currentColor",
1585
- strokeLinecap: "round",
1586
- strokeLinejoin: "round",
1587
- ...props,
1588
- children: [
1589
- /* @__PURE__ */ jsx("path", { d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719" }),
1590
- /* @__PURE__ */ jsx("path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" }),
1591
- /* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
1592
- ]
1593
- }
1594
- );
1595
- }
1596
- const linkAnnotation = defineArrayMember({
1597
- name: "link",
1598
- type: "object",
1599
- fields: [
1600
- defineField({
1601
- name: "href",
1602
- title: "URL",
1603
- type: "url",
1604
- description: "Web address for this link. Supports http, https, mailto, and tel schemes.",
1605
- validation: (rule) => rule.uri({ scheme: ["http", "https", "mailto", "tel"] })
1606
- })
1607
- ]
1608
- }), handbookCalloutType = defineType({
1609
- name: "handbook.callout",
1610
- title: "Callout",
1611
- type: "object",
1612
- icon: createSanityIcon(MessageCircleQuestionMarkIcon),
1613
- description: "A highlighted message block used to draw attention to tips, supplementary information, or warnings.",
1614
- preview: {
1615
- select: { variant: "variant", body: "body" },
1616
- prepare({ variant, body }) {
1617
- const text = Array.isArray(body) ? body.flatMap((block) => (block.children ?? []).map((child) => child.text ?? "")).join("") : "";
1618
- return { variant, text };
1619
- }
1620
- },
1621
- components: {
1622
- preview: CalloutPreview
1623
- },
1624
- fields: [
1625
- defineField({
1626
- name: "variant",
1627
- title: "Variant",
1628
- type: "string",
1629
- description: "Visual style and intent of the callout.",
1630
- initialValue: "tip",
1631
- validation: (rule) => rule.required(),
1632
- options: {
1633
- list: [
1634
- { title: "Tip", value: "tip" },
1635
- { title: "Information", value: "info" },
1636
- { title: "Warning", value: "warning" }
1637
- ],
1638
- layout: "radio",
1639
- direction: "horizontal"
1640
- }
1641
- }),
1642
- defineField({
1643
- name: "body",
1644
- title: "Body",
1645
- type: "array",
1646
- description: "Content displayed inside the callout. Supports inline formatting and links.",
1647
- of: [
1648
- defineArrayMember({
1649
- type: "block",
1650
- styles: [{ title: "Normal", value: "normal", component: ParagraphDecorator }],
1651
- marks: {
1652
- decorators: [
1653
- { title: "Bold", value: "strong" },
1654
- { title: "Italic", value: "em" },
1655
- { title: "Strikethrough", value: "strike-through" },
1656
- { title: "Code", value: "code", component: InlineCodeDecorator }
1657
- ],
1658
- annotations: [linkAnnotation]
1659
- },
1660
- lists: []
1661
- })
1662
- ]
1663
- })
1664
- ]
1665
- });
1666
- function CodePreview({ code, language }) {
1667
- return isDefined(code) ? /* @__PURE__ */ jsx(CodeContent, { code, language }) : null;
1668
- }
1669
- function CodeIcon(props) {
1670
- return /* @__PURE__ */ jsxs(
1671
- "svg",
1672
- {
1673
- xmlns: "http://www.w3.org/2000/svg",
1674
- viewBox: "0 0 24 24",
1675
- fill: "none",
1676
- stroke: "currentColor",
1677
- strokeLinecap: "round",
1678
- strokeLinejoin: "round",
1679
- ...props,
1680
- children: [
1681
- /* @__PURE__ */ jsx("path", { d: "m16 18 6-6-6-6" }),
1682
- /* @__PURE__ */ jsx("path", { d: "m8 6-6 6 6 6" })
1683
- ]
1684
- }
1685
- );
1686
- }
1687
- const handbookCodeType = defineType({
1688
- name: "handbook.code",
1689
- title: "Code",
1690
- type: "object",
1691
- icon: createSanityIcon(CodeIcon),
1692
- description: "A syntax-highlighted code block with language selection.",
1693
- preview: {
1694
- select: { code: "code", language: "language" }
1695
- },
1696
- components: {
1697
- preview: CodePreview
1698
- },
1699
- fields: [
1700
- defineField({
1701
- name: "code",
1702
- title: "Code",
1703
- type: "text",
1704
- description: "The source code to display."
1705
- }),
1706
- defineField({
1707
- name: "language",
1708
- title: "Language",
1709
- type: "string",
1710
- description: "Programming language used for syntax highlighting.",
1711
- options: {
1712
- list: [
1713
- { title: "CSS", value: "css" },
1714
- { title: "GROQ", value: "groq" },
1715
- { title: "HTML", value: "html" },
1716
- { title: "JavaScript", value: "javascript" },
1717
- { title: "JSON", value: "json" },
1718
- { title: "Plain Text", value: "text" },
1719
- { title: "React", value: "tsx" },
1720
- { title: "Shell", value: "shell" },
1721
- { title: "TypeScript", value: "typescript" }
1722
- ]
1723
- }
1724
- })
1725
- ]
1726
- });
1727
- function HorizontalRulePreview() {
1728
- return /* @__PURE__ */ jsx(HorizontalRuleContent, { marginBlock: "0.5rem" });
1729
- }
1730
- function MinusIcon(props) {
1731
- return /* @__PURE__ */ jsx(
1732
- "svg",
1733
- {
1734
- xmlns: "http://www.w3.org/2000/svg",
1735
- viewBox: "0 0 24 24",
1736
- fill: "none",
1737
- stroke: "currentColor",
1738
- strokeLinecap: "round",
1739
- strokeLinejoin: "round",
1740
- ...props,
1741
- children: /* @__PURE__ */ jsx("path", { d: "M5 12h14" })
1742
- }
1743
- );
1744
- }
1745
- const handbookHorizontalRuleType = defineType({
1746
- name: "handbook.horizontalRule",
1747
- title: "Horizontal Rule",
1748
- type: "object",
1749
- icon: createSanityIcon(MinusIcon),
1750
- description: "A visual divider between sections of content.",
1751
- preview: {
1752
- prepare() {
1753
- return { title: "Horizontal Rule" };
1754
- }
1755
- },
1756
- components: {
1757
- preview: HorizontalRulePreview
1758
- },
1759
- fields: [
1760
- defineField({
1761
- name: "style",
1762
- title: "Style",
1763
- type: "string",
1764
- description: "Presentation style for the divider.",
1765
- hidden: !0,
1766
- initialValue: "default"
1767
- })
1768
- ]
1769
- });
1770
- function ImagePreview({ url, alt, caption }) {
1771
- return isDefined(url) ? /* @__PURE__ */ jsx("div", { style: { padding: "0.5rem" }, children: /* @__PURE__ */ jsx(ImageContent, { url, alt, caption }) }) : null;
1772
- }
1773
- function ImageIcon(props) {
1774
- return /* @__PURE__ */ jsxs(
1775
- "svg",
1776
- {
1777
- xmlns: "http://www.w3.org/2000/svg",
1778
- viewBox: "0 0 24 24",
1779
- fill: "none",
1780
- stroke: "currentColor",
1781
- strokeLinecap: "round",
1782
- strokeLinejoin: "round",
1783
- ...props,
1784
- children: [
1785
- /* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
1786
- /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
1787
- /* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
1788
- ]
1789
- }
1790
- );
1791
- }
1792
- const handbookImageType = defineType({
1793
- name: "handbook.image",
1794
- title: "Image",
1795
- type: "object",
1796
- icon: createSanityIcon(ImageIcon),
1797
- description: "An image with optional caption and alternative text for accessibility.",
1798
- preview: {
1799
- select: { caption: "caption", alt: "alt", url: "asset.asset.url" }
1800
- },
1801
- components: {
1802
- preview: ImagePreview
1803
- },
1804
- fields: [
1805
- defineField({
1806
- name: "asset",
1807
- title: "Image",
1808
- type: "image",
1809
- description: "Upload or select an image from the media library.",
1810
- options: { hotspot: !0 }
1811
- }),
1812
- defineField({
1813
- name: "caption",
1814
- title: "Caption",
1815
- type: "string",
1816
- description: "Text displayed beneath the image in the handbook."
1817
- }),
1818
- defineField({
1819
- name: "alt",
1820
- title: "Alternative Text",
1821
- type: "string",
1822
- description: "Describes the image for screen readers and accessibility tools."
1823
- })
1824
- ]
1825
- });
1826
- function VideoPreview({ url, caption }) {
1827
- return isDefined(url) ? /* @__PURE__ */ jsx("div", { style: { padding: "0.5rem" }, children: /* @__PURE__ */ jsx(VideoContent, { url, caption }) }) : null;
1828
- }
1829
- function VideoIcon(props) {
1830
- return /* @__PURE__ */ jsxs(
1831
- "svg",
1832
- {
1833
- xmlns: "http://www.w3.org/2000/svg",
1834
- viewBox: "0 0 24 24",
1835
- fill: "none",
1836
- stroke: "currentColor",
1837
- strokeLinecap: "round",
1838
- strokeLinejoin: "round",
1839
- ...props,
1840
- children: [
1841
- /* @__PURE__ */ jsx("path", { d: "m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5" }),
1842
- /* @__PURE__ */ jsx("rect", { x: "2", y: "6", width: "14", height: "12", rx: "2" })
1843
- ]
1844
- }
1845
- );
1846
- }
1847
- const handbookVideoType = defineType({
1848
- name: "handbook.video",
1849
- title: "Video",
1850
- type: "object",
1851
- icon: createSanityIcon(VideoIcon),
1852
- description: "An uploaded video with optional caption.",
1853
- preview: {
1854
- select: { caption: "caption", url: "asset.asset.url" }
1855
- },
1856
- components: {
1857
- preview: VideoPreview
1858
- },
1859
- fields: [
1860
- defineField({
1861
- name: "asset",
1862
- title: "Video",
1863
- type: "file",
1864
- description: "Upload or select a video from the media library.",
1865
- options: { accept: "video/*" }
1866
- }),
1867
- defineField({
1868
- name: "caption",
1869
- title: "Caption",
1870
- type: "string",
1871
- description: "Text displayed beneath the video in the handbook."
1872
- })
1873
- ]
1874
- });
1875
- function createGuideContentField(customBlocks = []) {
1876
- return defineField({
1877
- name: "content",
1878
- title: "Content",
1879
- type: "array",
1880
- description: "Rich text content for this guide. Supports headings, lists, images, code blocks, and custom blocks.",
1881
- of: [
1882
- defineArrayMember({
1883
- name: "block",
1884
- type: "block",
1885
- styles: [
1886
- { title: "Paragraph", value: "normal", component: ParagraphDecorator },
1887
- { title: "Heading", value: "h2", component: HeadingDecorator },
1888
- { title: "Blockquote", value: "blockquote", component: BlockquoteDecorator }
1889
- ],
1890
- marks: {
1891
- decorators: [
1892
- { title: "Bold", value: "strong" },
1893
- { title: "Italic", value: "em" },
1894
- { title: "Strikethrough", value: "strike-through" },
1895
- { title: "Code", value: "code", component: InlineCodeDecorator }
1896
- ],
1897
- annotations: [linkAnnotation]
1898
- },
1899
- lists: [
1900
- { title: "Bullet", value: "bullet", component: BulletListDecorator },
1901
- { title: "Number", value: "number", component: NumberListDecorator }
1902
- ]
1903
- }),
1904
- defineArrayMember({ type: "handbook.image" }),
1905
- defineArrayMember({ type: "handbook.video" }),
1906
- defineArrayMember({ type: "handbook.code" }),
1907
- defineArrayMember({ type: "handbook.callout" }),
1908
- defineArrayMember({ type: "handbook.horizontalRule" }),
1909
- ...customBlocks.map((block) => defineArrayMember({ type: block.schema.name }))
1910
- ]
1911
- });
1912
- }
1913
- function createHandbookGuideType(customBlocks = []) {
1914
- return defineType({
1915
- name: "handbook.guide",
1916
- title: "Handbook Guide",
1917
- type: "document",
1918
- icon: createSanityIcon(BookOpenTextIcon),
1919
- description: "A handbook page authored with rich text, images, and custom blocks.",
1920
- preview: {
1921
- select: { title: "title", description: "description" },
1922
- prepare({ title, description }) {
1923
- return {
1924
- title: title ?? "Untitled Guide",
1925
- subtitle: description
1926
- };
1927
- }
1928
- },
1929
- fields: [
1930
- defineField({
1931
- name: "title",
1932
- title: "Title",
1933
- type: "string",
1934
- description: "Display title shown in the handbook sidebar and as the page heading.",
1935
- validation: (rule) => rule.required()
1936
- }),
1937
- defineField({
1938
- name: "description",
1939
- title: "Description",
1940
- type: "string",
1941
- description: "Brief summary displayed beneath the guide heading."
1942
- }),
1943
- createGuideContentField(customBlocks)
1944
- ]
1945
- });
1946
- }
1947
- function ListPlusIcon(props) {
1948
- return /* @__PURE__ */ jsxs(
1949
- "svg",
1950
- {
1951
- xmlns: "http://www.w3.org/2000/svg",
1952
- viewBox: "0 0 24 24",
1953
- fill: "none",
1954
- stroke: "currentColor",
1955
- strokeLinecap: "round",
1956
- strokeLinejoin: "round",
1957
- ...props,
1958
- children: [
1959
- /* @__PURE__ */ jsx("path", { d: "M16 5H3" }),
1960
- /* @__PURE__ */ jsx("path", { d: "M11 12H3" }),
1961
- /* @__PURE__ */ jsx("path", { d: "M16 19H3" }),
1962
- /* @__PURE__ */ jsx("path", { d: "M18 9v6" }),
1963
- /* @__PURE__ */ jsx("path", { d: "M21 12h-6" })
1964
- ]
1965
- }
1966
- );
1967
- }
1968
- const handbookType = defineType({
1969
- name: "handbook.handbook",
1970
- title: "Handbook",
1971
- type: "document",
1972
- icon: createSanityIcon(BookTextIcon),
1973
- description: "Defines the structure and ordering of the handbook, including groups and their guides.",
1974
- preview: {
1975
- prepare() {
1976
- return { title: "Handbook" };
1977
- }
1978
- },
1979
- fields: [
1980
- defineField({
1981
- name: "groups",
1982
- title: "Groups",
1983
- type: "array",
1984
- description: "Ordered list of groups displayed in the handbook sidebar. Each group contains a title and an ordered list of guide references.",
1985
- of: [
1986
- defineArrayMember({
1987
- name: "group",
1988
- type: "object",
1989
- icon: createSanityIcon(ListPlusIcon),
1990
- fields: [
1991
- defineField({
1992
- name: "title",
1993
- title: "Title",
1994
- type: "string",
1995
- description: "Heading displayed above this group of guides in the sidebar.",
1996
- validation: (rule) => rule.required()
1997
- }),
1998
- defineField({
1999
- name: "guides",
2000
- title: "Guides",
2001
- type: "array",
2002
- description: "Ordered list of guides within this group. Drag to reorder.",
2003
- of: [
2004
- defineArrayMember({
2005
- type: "reference",
2006
- to: [{ type: "handbook.guide" }]
2007
- })
2008
- ]
2009
- })
2010
- ],
2011
- preview: {
2012
- select: { title: "title", guide0: "guides.0.title", guide1: "guides.1.title", guide2: "guides.2.title" },
2013
- prepare({
2014
- title,
2015
- guide0,
2016
- guide1,
2017
- guide2
2018
- }) {
2019
- const shown = [guide0, guide1, guide2].filter((guide) => isDefined(guide)).slice(0, 2), hasMore = isDefined(guide2);
2020
- function formatSubtitle() {
2021
- return isDefined(shown) ? hasMore ? `${shown.join(", ")}, and others` : shown.join(" and ") : "No guides selected";
2022
- }
2023
- return {
2024
- title: title ?? "Untitled Group",
2025
- subtitle: formatSubtitle()
2026
- };
2027
- }
2028
- }
2029
- })
2030
- ]
2031
- })
2032
- ]
2076
+ let $ = c(8), t0;
2077
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
2078
+ display: "flex",
2079
+ flexDirection: "column",
2080
+ gap: contentSpacing.section
2081
+ }, $[0] = t0) : t0 = $[0];
2082
+ let t1;
2083
+ $[1] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsxs(Stack, {
2084
+ gap: 3,
2085
+ children: [/* @__PURE__ */ jsx(Flex, {
2086
+ align: "center",
2087
+ paddingY: 1,
2088
+ children: /* @__PURE__ */ jsx(Text, {
2089
+ size: 1,
2090
+ weight: "medium",
2091
+ children: "Navigating the Handbook"
2092
+ })
2093
+ }), /* @__PURE__ */ jsx(Text, {
2094
+ size: 1,
2095
+ muted: !0,
2096
+ children: "The sidebar lists everything the Handbook holds: these introductory pages, then the document types you can create, grouped by the role they play on the site, and finally any guides your team has written. Selecting an entry opens it here."
2097
+ })]
2098
+ }), $[1] = t1) : t1 = $[1];
2099
+ let t2;
2100
+ $[2] === Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsxs(Stack, {
2101
+ gap: 3,
2102
+ children: [/* @__PURE__ */ jsx(Flex, {
2103
+ align: "center",
2104
+ paddingY: 1,
2105
+ children: /* @__PURE__ */ jsx(Text, {
2106
+ size: 1,
2107
+ weight: "medium",
2108
+ children: "Understanding Fields"
2109
+ })
2110
+ }), /* @__PURE__ */ jsx(Text, {
2111
+ size: 1,
2112
+ muted: !0,
2113
+ children: "Selecting a document type lists its fields, each showing its name, the kind of value it holds, and what the field is for. The documentation is generated from the content model, so what you read always matches what you see while editing."
2114
+ })]
2115
+ }), $[2] = t2) : t2 = $[2];
2116
+ let t3, t4;
2117
+ $[3] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(Flex, {
2118
+ align: "center",
2119
+ paddingY: 1,
2120
+ children: /* @__PURE__ */ jsx(Text, {
2121
+ size: 1,
2122
+ weight: "medium",
2123
+ children: "Hints and Warnings"
2124
+ })
2125
+ }), t4 = /* @__PURE__ */ jsx(Text, {
2126
+ size: 1,
2127
+ muted: !0,
2128
+ children: "Icons beside a field name carry the guidance that would crowd its description if written into it. Hover or click one to read what it says, and use the key below to tell the three kinds apart."
2129
+ }), $[3] = t3, $[4] = t4) : (t3 = $[3], t4 = $[4]);
2130
+ let t5;
2131
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsxs(Stack, {
2132
+ gap: 3,
2133
+ children: [
2134
+ t3,
2135
+ t4,
2136
+ /* @__PURE__ */ jsx(Stack, {
2137
+ gap: 3,
2138
+ marginTop: 2,
2139
+ children: hintKinds.map(_temp$2)
2140
+ })
2141
+ ]
2142
+ }), $[5] = t5) : t5 = $[5];
2143
+ let t6;
2144
+ $[6] === Symbol.for("react.memo_cache_sentinel") ? (t6 = /* @__PURE__ */ jsxs(Stack, {
2145
+ gap: 3,
2146
+ children: [/* @__PURE__ */ jsx(Flex, {
2147
+ align: "center",
2148
+ paddingY: 1,
2149
+ children: /* @__PURE__ */ jsx(Text, {
2150
+ size: 1,
2151
+ weight: "medium",
2152
+ children: "Nested Fields"
2153
+ })
2154
+ }), /* @__PURE__ */ jsx(Text, {
2155
+ size: 1,
2156
+ muted: !0,
2157
+ children: "Some fields hold subfields of their own, such as a content block pairing a heading with body text. A control beneath the description counts them and expands to show each one, documented exactly as a top-level field is."
2158
+ })]
2159
+ }), $[6] = t6) : t6 = $[6];
2160
+ let t7;
2161
+ return $[7] === Symbol.for("react.memo_cache_sentinel") ? (t7 = /* @__PURE__ */ jsxs("div", {
2162
+ style: t0,
2163
+ children: [
2164
+ t1,
2165
+ t2,
2166
+ t5,
2167
+ t6,
2168
+ /* @__PURE__ */ jsxs(Stack, {
2169
+ gap: 3,
2170
+ children: [/* @__PURE__ */ jsx(Flex, {
2171
+ align: "center",
2172
+ paddingY: 1,
2173
+ children: /* @__PURE__ */ jsx(Text, {
2174
+ size: 1,
2175
+ weight: "medium",
2176
+ children: "Guides"
2177
+ })
2178
+ }), /* @__PURE__ */ jsx(Text, {
2179
+ size: 1,
2180
+ muted: !0,
2181
+ children: "Beneath the document types you may find guides, written by your team rather than generated from the content model. They carry what a field description cannot: house style, editorial process, and how all the pieces fit together."
2182
+ })]
2183
+ })
2184
+ ]
2185
+ }), $[7] = t7) : t7 = $[7], t7;
2186
+ }
2187
+ function _temp$2(t0) {
2188
+ let { name, icon: Icon } = t0;
2189
+ return /* @__PURE__ */ jsxs(Flex, {
2190
+ align: "center",
2191
+ gap: 3,
2192
+ children: [/* @__PURE__ */ jsx("div", {
2193
+ style: {
2194
+ display: "flex",
2195
+ alignItems: "center",
2196
+ flexShrink: 0,
2197
+ fontSize: "16px",
2198
+ color: "var(--card-icon-color)"
2199
+ },
2200
+ children: /* @__PURE__ */ jsx(Icon, { ...defaultIconProps })
2201
+ }), /* @__PURE__ */ jsx(Text, {
2202
+ size: 1,
2203
+ muted: !0,
2204
+ children: hintDescriptions[name]
2205
+ })]
2206
+ }, name);
2207
+ }
2208
+ /**
2209
+ * Builds the section holding the plugin's own introductory pages.
2210
+ *
2211
+ * @returns A single section listing the built-in pages, in the order they are shown.
2212
+ */
2213
+ function gettingStartedSections() {
2214
+ return [{
2215
+ title: "Getting Started",
2216
+ entries: [{
2217
+ id: "how-to-use-this-handbook",
2218
+ title: "How to use the Handbook",
2219
+ description: "A guide to navigating the Handbook, reading the documentation for each field, and making sense of its examples, hints, and nested structure.",
2220
+ icon: createSanityIcon(BookTextIcon),
2221
+ render: () => /* @__PURE__ */ jsx(HowToUse, {})
2222
+ }, {
2223
+ id: "document-types",
2224
+ title: "Document Types",
2225
+ description: "An overview of all document types, organised by role. Select a document type to view its fields, descriptions, and examples.",
2226
+ icon: createSanityIcon(LayoutGridIcon),
2227
+ render: () => /* @__PURE__ */ jsx(DocumentTypesOverview, {})
2228
+ }]
2229
+ }];
2230
+ }
2231
+ function PortableLink(t0) {
2232
+ let $ = c(10), children, props, style;
2233
+ $[0] === t0 ? (children = $[1], props = $[2], style = $[3]) : ({children, style, ...props} = t0, $[0] = t0, $[1] = children, $[2] = props, $[3] = style);
2234
+ let t1;
2235
+ $[4] === style ? t1 = $[5] : (t1 = {
2236
+ color: "var(--card-link-fg-color)",
2237
+ ...style
2238
+ }, $[4] = style, $[5] = t1);
2239
+ let t2;
2240
+ return $[6] !== children || $[7] !== props || $[8] !== t1 ? (t2 = /* @__PURE__ */ jsx("a", {
2241
+ target: "_blank",
2242
+ rel: "noopener noreferrer",
2243
+ style: t1,
2244
+ ...props,
2245
+ children
2246
+ }), $[6] = children, $[7] = props, $[8] = t1, $[9] = t2) : t2 = $[9], t2;
2247
+ }
2248
+ /** Overrides for a callout body, which takes the card's own text styling and leaves paragraphs unwrapped. */
2249
+ const components$1 = {
2250
+ block: { normal: ({ children }) => /* @__PURE__ */ jsx(Fragment, { children }) },
2251
+ marks: {
2252
+ code: ({ children }) => /* @__PURE__ */ jsx(PortableCode, { children }),
2253
+ link: ({ children, value }) => /* @__PURE__ */ jsx(PortableLink, {
2254
+ href: value?.href,
2255
+ children
2256
+ })
2257
+ }
2258
+ };
2259
+ function CalloutBlock(t0) {
2260
+ let $ = c(13), props, style, value;
2261
+ $[0] === t0 ? (props = $[1], style = $[2], value = $[3]) : ({value, style, ...props} = t0, $[0] = t0, $[1] = props, $[2] = style, $[3] = value);
2262
+ let t1;
2263
+ $[4] === style ? t1 = $[5] : (t1 = {
2264
+ marginBlock: contentSpacing.callout,
2265
+ ...style
2266
+ }, $[4] = style, $[5] = t1);
2267
+ let t2;
2268
+ $[6] === value.body ? t2 = $[7] : (t2 = /* @__PURE__ */ jsx(PortableText, {
2269
+ value: value.body,
2270
+ components: components$1
2271
+ }), $[6] = value.body, $[7] = t2);
2272
+ let t3;
2273
+ return $[8] !== props || $[9] !== t1 || $[10] !== t2 || $[11] !== value.variant ? (t3 = /* @__PURE__ */ jsx(CalloutContent, {
2274
+ variant: value.variant,
2275
+ style: t1,
2276
+ ...props,
2277
+ children: t2
2278
+ }), $[8] = props, $[9] = t1, $[10] = t2, $[11] = value.variant, $[12] = t3) : t3 = $[12], t3;
2279
+ }
2280
+ function CodeBlock(t0) {
2281
+ let $ = c(11), props, style, value;
2282
+ if ($[0] === t0 ? (props = $[1], style = $[2], value = $[3]) : ({value, style, ...props} = t0, $[0] = t0, $[1] = props, $[2] = style, $[3] = value), !isDefined(value.code)) return null;
2283
+ let t1;
2284
+ $[4] === style ? t1 = $[5] : (t1 = {
2285
+ marginBlock: contentSpacing.media,
2286
+ ...style
2287
+ }, $[4] = style, $[5] = t1);
2288
+ let t2;
2289
+ return $[6] !== props || $[7] !== t1 || $[8] !== value.code || $[9] !== value.language ? (t2 = /* @__PURE__ */ jsx(CodeContent, {
2290
+ code: value.code,
2291
+ language: value.language,
2292
+ style: t1,
2293
+ ...props
2294
+ }), $[6] = props, $[7] = t1, $[8] = value.code, $[9] = value.language, $[10] = t2) : t2 = $[10], t2;
2295
+ }
2296
+ function HorizontalRuleBlock(t0) {
2297
+ let $ = c(8), props, style;
2298
+ if ($[0] !== t0) {
2299
+ let { value: _value, style: t1, ...t2 } = t0;
2300
+ style = t1, props = t2, $[0] = t0, $[1] = props, $[2] = style;
2301
+ } else props = $[1], style = $[2];
2302
+ let t1;
2303
+ $[3] === style ? t1 = $[4] : (t1 = {
2304
+ marginBlock: contentSpacing.rule,
2305
+ ...style
2306
+ }, $[3] = style, $[4] = t1);
2307
+ let t2;
2308
+ return $[5] !== props || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(HorizontalRuleContent, {
2309
+ style: t1,
2310
+ ...props
2311
+ }), $[5] = props, $[6] = t1, $[7] = t2) : t2 = $[7], t2;
2312
+ }
2313
+ function ImageBlock(t0) {
2314
+ let $ = c(12), props, style, value;
2315
+ if ($[0] === t0 ? (props = $[1], style = $[2], value = $[3]) : ({value, style, ...props} = t0, $[0] = t0, $[1] = props, $[2] = style, $[3] = value), !isDefined(value.asset?.url)) return null;
2316
+ let t1;
2317
+ $[4] === style ? t1 = $[5] : (t1 = {
2318
+ marginBlock: contentSpacing.media,
2319
+ ...style
2320
+ }, $[4] = style, $[5] = t1);
2321
+ let t2;
2322
+ return $[6] !== props || $[7] !== t1 || $[8] !== value.alt || $[9] !== value.asset.url || $[10] !== value.caption ? (t2 = /* @__PURE__ */ jsx(ImageContent, {
2323
+ url: value.asset.url,
2324
+ alt: value.alt,
2325
+ caption: value.caption,
2326
+ style: t1,
2327
+ ...props
2328
+ }), $[6] = props, $[7] = t1, $[8] = value.alt, $[9] = value.asset.url, $[10] = value.caption, $[11] = t2) : t2 = $[11], t2;
2329
+ }
2330
+ function VideoBlock(t0) {
2331
+ let $ = c(11), props, style, value;
2332
+ if ($[0] === t0 ? (props = $[1], style = $[2], value = $[3]) : ({value, style, ...props} = t0, $[0] = t0, $[1] = props, $[2] = style, $[3] = value), !isDefined(value.asset?.url)) return null;
2333
+ let t1;
2334
+ $[4] === style ? t1 = $[5] : (t1 = {
2335
+ marginBlock: contentSpacing.media,
2336
+ ...style
2337
+ }, $[4] = style, $[5] = t1);
2338
+ let t2;
2339
+ return $[6] !== props || $[7] !== t1 || $[8] !== value.asset.url || $[9] !== value.caption ? (t2 = /* @__PURE__ */ jsx(VideoContent, {
2340
+ url: value.asset.url,
2341
+ caption: value.caption,
2342
+ style: t1,
2343
+ ...props
2344
+ }), $[6] = props, $[7] = t1, $[8] = value.asset.url, $[9] = value.caption, $[10] = t2) : t2 = $[10], t2;
2345
+ }
2346
+ function PortableList(t0) {
2347
+ let $ = c(12), props, style, t1;
2348
+ $[0] === t0 ? (props = $[1], style = $[2], t1 = $[3]) : ({ordered: t1, style, ...props} = t0, $[0] = t0, $[1] = props, $[2] = style, $[3] = t1);
2349
+ let ordered = t1 !== void 0 && t1, t2;
2350
+ $[4] === style ? t2 = $[5] : (t2 = {
2351
+ display: "flex",
2352
+ flexDirection: "column",
2353
+ gap: 6,
2354
+ margin: 0,
2355
+ paddingLeft: "1.25em",
2356
+ ...style
2357
+ }, $[4] = style, $[5] = t2);
2358
+ let listStyle = t2;
2359
+ if (ordered) {
2360
+ let t3;
2361
+ return $[6] !== listStyle || $[7] !== props ? (t3 = /* @__PURE__ */ jsx("ol", {
2362
+ style: listStyle,
2363
+ ...props
2364
+ }), $[6] = listStyle, $[7] = props, $[8] = t3) : t3 = $[8], t3;
2365
+ }
2366
+ let t3;
2367
+ return $[9] !== listStyle || $[10] !== props ? (t3 = /* @__PURE__ */ jsx("ul", {
2368
+ style: listStyle,
2369
+ ...props
2370
+ }), $[9] = listStyle, $[10] = props, $[11] = t3) : t3 = $[11], t3;
2371
+ }
2372
+ /**
2373
+ * Resolves the space around a list, which tightens once the list is nested inside another.
2374
+ *
2375
+ * @param level - Nesting depth of the list, counted from one.
2376
+ * @returns The vertical space in pixels.
2377
+ */
2378
+ function listSpacing(level) {
2379
+ return level > 1 ? contentSpacing.nestedList : contentSpacing.list;
2380
+ }
2381
+ /**
2382
+ * Component rendered for each block style, mark, and embedded type a guide's rich text can hold.
2383
+ * The marks and list items left out are deliberate — the library's own defaults already render them
2384
+ * as the surrounding text.
2385
+ */
2386
+ const components = {
2387
+ block: {
2388
+ h2: ({ children }) => /* @__PURE__ */ jsx(PortableHeading, {
2389
+ style: {
2390
+ marginBlockStart: contentSpacing.heading,
2391
+ marginBlockEnd: 4
2392
+ },
2393
+ children
2394
+ }),
2395
+ normal: ({ children }) => /* @__PURE__ */ jsx(PortableParagraph, {
2396
+ muted: !0,
2397
+ style: { marginBlock: contentSpacing.paragraph },
2398
+ children
2399
+ }),
2400
+ blockquote: ({ children }) => /* @__PURE__ */ jsx(PortableBlockquote, {
2401
+ muted: !0,
2402
+ style: { marginBlock: contentSpacing.blockquote },
2403
+ children
2404
+ })
2405
+ },
2406
+ list: {
2407
+ bullet: ({ children, value }) => /* @__PURE__ */ jsx(PortableParagraph, {
2408
+ muted: !0,
2409
+ style: { marginBlock: listSpacing(value.level) },
2410
+ children: /* @__PURE__ */ jsx(PortableList, { children })
2411
+ }),
2412
+ number: ({ children, value }) => /* @__PURE__ */ jsx(PortableParagraph, {
2413
+ muted: !0,
2414
+ style: { marginBlock: listSpacing(value.level) },
2415
+ children: /* @__PURE__ */ jsx(PortableList, {
2416
+ ordered: !0,
2417
+ children
2418
+ })
2419
+ })
2420
+ },
2421
+ marks: {
2422
+ code: ({ children }) => /* @__PURE__ */ jsx(PortableCode, { children }),
2423
+ link: ({ children, value }) => /* @__PURE__ */ jsx(PortableLink, {
2424
+ href: value?.href,
2425
+ children
2426
+ })
2427
+ }
2428
+ };
2429
+ /**
2430
+ * Adapts a block component to what Portable Text renders an embedded type with, narrowing the props
2431
+ * to the block's own value. The rendering props the library also passes would otherwise reach the DOM.
2432
+ *
2433
+ * @param Component - Component rendering the block.
2434
+ * @returns A component Portable Text can render the type with.
2435
+ */
2436
+ function blockRenderer(Component) {
2437
+ return function Block({ value }) {
2438
+ return /* @__PURE__ */ jsx(Component, { value });
2439
+ };
2440
+ }
2441
+ function PortableText$1(t0) {
2442
+ let $ = c(18), props, value;
2443
+ $[0] === t0 ? (props = $[1], value = $[2]) : ({value, ...props} = t0, $[0] = t0, $[1] = props, $[2] = value);
2444
+ let { blocks } = useHandbookContext(), t1;
2445
+ $[3] === Symbol.for("react.memo_cache_sentinel") ? (t1 = blockRenderer(ImageBlock), $[3] = t1) : t1 = $[3];
2446
+ let t2;
2447
+ $[4] === Symbol.for("react.memo_cache_sentinel") ? (t2 = blockRenderer(VideoBlock), $[4] = t2) : t2 = $[4];
2448
+ let t3;
2449
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = blockRenderer(CodeBlock), $[5] = t3) : t3 = $[5];
2450
+ let t4;
2451
+ $[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = blockRenderer(CalloutBlock), $[6] = t4) : t4 = $[6];
2452
+ let t5;
2453
+ $[7] === Symbol.for("react.memo_cache_sentinel") ? (t5 = blockRenderer(HorizontalRuleBlock), $[7] = t5) : t5 = $[7];
2454
+ let types;
2455
+ if ($[8] !== blocks) {
2456
+ types = {
2457
+ [imageTypeName]: t1,
2458
+ [videoTypeName]: t2,
2459
+ [codeTypeName]: t3,
2460
+ [calloutTypeName]: t4,
2461
+ [horizontalRuleTypeName]: t5
2462
+ };
2463
+ for (let block of blocks) types[block.schema.name] = blockRenderer(block.component);
2464
+ $[8] = blocks, $[9] = types;
2465
+ } else types = $[9];
2466
+ let t6;
2467
+ $[10] === types ? t6 = $[11] : (t6 = {
2468
+ ...components,
2469
+ types
2470
+ }, $[10] = types, $[11] = t6);
2471
+ let t7;
2472
+ $[12] !== t6 || $[13] !== value ? (t7 = /* @__PURE__ */ jsx(PortableText, {
2473
+ value,
2474
+ components: t6
2475
+ }), $[12] = t6, $[13] = value, $[14] = t7) : t7 = $[14];
2476
+ let t8;
2477
+ return $[15] !== props || $[16] !== t7 ? (t8 = /* @__PURE__ */ jsx("div", {
2478
+ ...props,
2479
+ children: t7
2480
+ }), $[15] = props, $[16] = t7, $[17] = t8) : t8 = $[17], t8;
2481
+ }
2482
+ /**
2483
+ * Builds a section for each guide group authored in the dataset.
2484
+ *
2485
+ * @param handbook - Handbook singleton holding the authored guide groups.
2486
+ * @returns One section per group, holding an entry per guide.
2487
+ */
2488
+ function guidesSections(handbook) {
2489
+ return handbook.groups.map(({ title, guides }) => ({
2490
+ title,
2491
+ entries: guides.map((guide) => ({
2492
+ id: guide._key,
2493
+ title: guide.title,
2494
+ description: guide.description,
2495
+ icon: createSanityIcon(BookOpenTextIcon),
2496
+ render: () => /* @__PURE__ */ jsx(PortableText$1, { value: guide.content })
2497
+ }))
2498
+ }));
2499
+ }
2500
+ /**
2501
+ * Composes every page the Handbook shows, in sidebar order.
2502
+ *
2503
+ * @returns Sections from the built-in pages, the configured document roles, and the authored guides.
2504
+ */
2505
+ function useSections() {
2506
+ let $ = c(4), { roles, handbook, loading } = useHandbookContext(), t0;
2507
+ return $[0] !== handbook || $[1] !== loading || $[2] !== roles ? (t0 = [
2508
+ ...gettingStartedSections(),
2509
+ ...documentTypesSections(roles),
2510
+ ...loading || !isDefined(handbook) ? [] : guidesSections(handbook)
2511
+ ], $[0] = handbook, $[1] = loading, $[2] = roles, $[3] = t0) : t0 = $[3], t0;
2512
+ }
2513
+ function Content(props) {
2514
+ let $ = c(18), { activeTab } = useHandbookContext(), sections = useSections(), T0, t0, t1, t2, t3, t4;
2515
+ if ($[0] !== activeTab || $[1] !== props || $[2] !== sections) {
2516
+ let t5;
2517
+ $[9] === activeTab ? t5 = $[10] : (t5 = (t6) => {
2518
+ let { id } = t6;
2519
+ return id === activeTab;
2520
+ }, $[9] = activeTab, $[10] = t5);
2521
+ let entry = sections.flatMap(_temp$1).find(t5);
2522
+ T0 = Pane, t0 = "handbook-content", t1 = 2.5, t2 = 320, t3 = props, t4 = isDefined(entry) && /* @__PURE__ */ jsx(ContentPanel, {
2523
+ id: entry.id,
2524
+ title: entry.title,
2525
+ description: entry.description,
2526
+ children: entry.render()
2527
+ }), $[0] = activeTab, $[1] = props, $[2] = sections, $[3] = T0, $[4] = t0, $[5] = t1, $[6] = t2, $[7] = t3, $[8] = t4;
2528
+ } else T0 = $[3], t0 = $[4], t1 = $[5], t2 = $[6], t3 = $[7], t4 = $[8];
2529
+ let t5;
2530
+ return $[11] !== T0 || $[12] !== t0 || $[13] !== t1 || $[14] !== t2 || $[15] !== t3 || $[16] !== t4 ? (t5 = /* @__PURE__ */ jsx(T0, {
2531
+ id: t0,
2532
+ flex: t1,
2533
+ minWidth: t2,
2534
+ ...t3,
2535
+ children: t4
2536
+ }), $[11] = T0, $[12] = t0, $[13] = t1, $[14] = t2, $[15] = t3, $[16] = t4, $[17] = t5) : t5 = $[17], t5;
2537
+ }
2538
+ function _temp$1(section) {
2539
+ return section.entries;
2540
+ }
2541
+ function SidebarHeading(t0) {
2542
+ let $ = c(9), props, title;
2543
+ $[0] === t0 ? (props = $[1], title = $[2]) : ({title, ...props} = t0, $[0] = t0, $[1] = props, $[2] = title);
2544
+ let t1;
2545
+ $[3] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
2546
+ cursor: "default",
2547
+ outline: "none"
2548
+ }, $[3] = t1) : t1 = $[3];
2549
+ let t2;
2550
+ $[4] === title ? t2 = $[5] : (t2 = /* @__PURE__ */ jsx(Card, {
2551
+ padding: 2,
2552
+ children: /* @__PURE__ */ jsx(Text, {
2553
+ size: 1,
2554
+ muted: !0,
2555
+ textOverflow: "ellipsis",
2556
+ weight: "semibold",
2557
+ style: t1,
2558
+ children: title
2559
+ })
2560
+ }), $[4] = title, $[5] = t2);
2561
+ let t3;
2562
+ return $[6] !== props || $[7] !== t2 ? (t3 = /* @__PURE__ */ jsx(Box, {
2563
+ paddingY: 2,
2564
+ ...props,
2565
+ children: t2
2566
+ }), $[6] = props, $[7] = t2, $[8] = t3) : t3 = $[8], t3;
2567
+ }
2568
+ function SidebarTab(t0) {
2569
+ let $ = c(25), Icon, id, label, props, style;
2570
+ $[0] === t0 ? (Icon = $[1], id = $[2], label = $[3], props = $[4], style = $[5]) : ({id, label, icon: Icon, style, ...props} = t0, $[0] = t0, $[1] = Icon, $[2] = id, $[3] = label, $[4] = props, $[5] = style);
2571
+ let { activeTab, setActiveTab, setSidebarExpanded } = useHandbookContext(), selected = activeTab === id, t1;
2572
+ $[6] !== id || $[7] !== setActiveTab || $[8] !== setSidebarExpanded ? (t1 = () => {
2573
+ setActiveTab(id), setSidebarExpanded(!1);
2574
+ }, $[6] = id, $[7] = setActiveTab, $[8] = setSidebarExpanded, $[9] = t1) : t1 = $[9];
2575
+ let t2;
2576
+ $[10] === style ? t2 = $[11] : (t2 = {
2577
+ cursor: "pointer",
2578
+ ...style
2579
+ }, $[10] = style, $[11] = t2);
2580
+ let t3 = `panel-${id}`, t4;
2581
+ $[12] === Symbol.for("react.memo_cache_sentinel") ? (t4 = { opacity: .5 }, $[12] = t4) : t4 = $[12];
2582
+ let t5;
2583
+ $[13] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsx(Box, {
2584
+ style: t4,
2585
+ children: /* @__PURE__ */ jsx(Text, {
2586
+ muted: !0,
2587
+ size: 1,
2588
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
2589
+ })
2590
+ }), $[13] = t5) : t5 = $[13];
2591
+ let t6;
2592
+ $[14] !== Icon || $[15] !== label ? (t6 = /* @__PURE__ */ jsx(SanityDefaultPreview, {
2593
+ status: t5,
2594
+ icon: Icon,
2595
+ layout: "compact",
2596
+ title: label
2597
+ }), $[14] = Icon, $[15] = label, $[16] = t6) : t6 = $[16];
2598
+ let t7;
2599
+ return $[17] !== id || $[18] !== props || $[19] !== selected || $[20] !== t1 || $[21] !== t2 || $[22] !== t3 || $[23] !== t6 ? (t7 = /* @__PURE__ */ jsx(PreviewCard, {
2600
+ id,
2601
+ as: "button",
2602
+ "data-as": "button",
2603
+ selected,
2604
+ marginBottom: 1,
2605
+ radius: 2,
2606
+ sizing: "border",
2607
+ tabIndex: -1,
2608
+ tone: "inherit",
2609
+ onClick: t1,
2610
+ style: t2,
2611
+ "aria-controls": t3,
2612
+ __unstable_focusRing: !0,
2613
+ ...props,
2614
+ children: t6
2615
+ }), $[17] = id, $[18] = props, $[19] = selected, $[20] = t1, $[21] = t2, $[22] = t3, $[23] = t6, $[24] = t7) : t7 = $[24], t7;
2616
+ }
2617
+ function Sidebar(props) {
2618
+ let $ = c(14), { sidebarTitle } = useHandbookContext(), sections = useSections(), t0;
2619
+ $[0] === sections ? t0 = $[1] : (t0 = sections.flatMap(_temp2), $[0] = sections, $[1] = t0);
2620
+ let items = t0, t1;
2621
+ $[2] === items ? t1 = $[3] : (t1 = function getItemDisabled(virtualIndex) {
2622
+ return items[virtualIndex]?.type === "heading";
2623
+ }, $[2] = items, $[3] = t1);
2624
+ let getItemDisabled = t1, t2;
2625
+ $[4] === sidebarTitle ? t2 = $[5] : (t2 = /* @__PURE__ */ jsx(PaneHeader, { title: sidebarTitle }), $[4] = sidebarTitle, $[5] = t2);
2626
+ let t3;
2627
+ $[6] !== getItemDisabled || $[7] !== items || $[8] !== sidebarTitle ? (t3 = /* @__PURE__ */ jsx(PaneContent, {
2628
+ overflow: "auto",
2629
+ children: /* @__PURE__ */ jsx(CommandList, {
2630
+ activeItemDataAttr: "data-hovered",
2631
+ ariaLabel: sidebarTitle,
2632
+ canReceiveFocus: !0,
2633
+ getItemDisabled,
2634
+ itemHeight: 37,
2635
+ items,
2636
+ onlyShowSelectionWhenActive: !0,
2637
+ paddingBottom: 1,
2638
+ paddingX: 3,
2639
+ renderItem: _temp3,
2640
+ wrapAround: !1
2641
+ })
2642
+ }), $[6] = getItemDisabled, $[7] = items, $[8] = sidebarTitle, $[9] = t3) : t3 = $[9];
2643
+ let t4;
2644
+ return $[10] !== props || $[11] !== t2 || $[12] !== t3 ? (t4 = /* @__PURE__ */ jsxs(Pane, {
2645
+ id: "handbook-sidebar",
2646
+ currentMaxWidth: 350,
2647
+ minWidth: 320,
2648
+ maxWidth: 640,
2649
+ ...props,
2650
+ children: [t2, t3]
2651
+ }), $[10] = props, $[11] = t2, $[12] = t3, $[13] = t4) : t4 = $[13], t4;
2652
+ }
2653
+ function _temp3(item) {
2654
+ return item.type === "heading" ? /* @__PURE__ */ jsx(SidebarHeading, { title: item.title }) : /* @__PURE__ */ jsx(SidebarTab, {
2655
+ id: item.id,
2656
+ label: item.label,
2657
+ icon: item.icon
2658
+ });
2659
+ }
2660
+ function _temp2(t0) {
2661
+ let { title, entries } = t0;
2662
+ return [{
2663
+ type: "heading",
2664
+ title
2665
+ }, ...entries.map(_temp)];
2666
+ }
2667
+ function _temp(entry) {
2668
+ return {
2669
+ type: "tab",
2670
+ id: entry.id,
2671
+ label: entry.title,
2672
+ icon: entry.icon
2673
+ };
2674
+ }
2675
+ function Panes() {
2676
+ let $ = c(10), { activeTab, sidebarExpanded } = useHandbookContext(), paneLayout = useContext(PaneLayoutContext), t0;
2677
+ $[0] === activeTab ? t0 = $[1] : (t0 = isDefined(activeTab), $[0] = activeTab, $[1] = t0);
2678
+ let hasContent = t0;
2679
+ if (paneLayout?.collapsed === !0) {
2680
+ let t1;
2681
+ return $[2] !== hasContent || $[3] !== sidebarExpanded ? (t1 = jsx(sidebarExpanded || !hasContent ? Sidebar : Content, {}), $[2] = hasContent, $[3] = sidebarExpanded, $[4] = t1) : t1 = $[4], t1;
2682
+ }
2683
+ let t1;
2684
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(Sidebar, {}), $[5] = t1) : t1 = $[5];
2685
+ let t2;
2686
+ $[6] === hasContent ? t2 = $[7] : (t2 = hasContent && /* @__PURE__ */ jsx(Content, {}), $[6] = hasContent, $[7] = t2);
2687
+ let t3;
2688
+ return $[8] === t2 ? t3 = $[9] : (t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t1, t2] }), $[8] = t2, $[9] = t3), t3;
2689
+ }
2690
+ function HandbookTool(t0) {
2691
+ let $ = c(10), { tool: t1 } = t0, { options } = t1, { media } = useTheme_v2(), [layoutCollapsed, setLayoutCollapsed] = useState(!1), t2;
2692
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t2 = function handleCollapse() {
2693
+ setLayoutCollapsed(!0);
2694
+ }, $[0] = t2) : t2 = $[0];
2695
+ let handleCollapse = t2, t3;
2696
+ $[1] === Symbol.for("react.memo_cache_sentinel") ? (t3 = function handleExpand() {
2697
+ setLayoutCollapsed(!1);
2698
+ }, $[1] = t3) : t3 = $[1];
2699
+ let handleExpand = t3;
2700
+ if (!isDefined(options)) return null;
2701
+ let t4 = layoutCollapsed ? void 0 : "fill", t5, t6;
2702
+ $[2] === Symbol.for("react.memo_cache_sentinel") ? (t5 = {
2703
+ minHeight: "100%",
2704
+ minWidth: "320px"
2705
+ }, t6 = /* @__PURE__ */ jsx(Panes, {}), $[2] = t5, $[3] = t6) : (t5 = $[2], t6 = $[3]);
2706
+ let t7;
2707
+ $[4] !== media[1] || $[5] !== t4 ? (t7 = /* @__PURE__ */ jsx(PaneLayout, {
2708
+ flex: 1,
2709
+ height: t4,
2710
+ minWidth: media[1],
2711
+ onCollapse: handleCollapse,
2712
+ onExpand: handleExpand,
2713
+ style: t5,
2714
+ children: t6
2715
+ }), $[4] = media[1], $[5] = t4, $[6] = t7) : t7 = $[6];
2716
+ let t8;
2717
+ return $[7] !== options || $[8] !== t7 ? (t8 = /* @__PURE__ */ jsx(HandbookProvider, {
2718
+ ...options,
2719
+ children: t7
2720
+ }), $[7] = options, $[8] = t7, $[9] = t8) : t8 = $[9], t8;
2721
+ }
2722
+ /** Editors the plugin was configured with, so the Structure helper need not be handed them a second time. */
2723
+ let configuredEditors;
2724
+ /**
2725
+ * Records the editors a plugin instance was configured with. A Studio running more than one workspace
2726
+ * keeps only the list from the workspace configured last, so those cases pass the list explicitly.
2727
+ *
2728
+ * @param editors - Email addresses permitted to edit Handbook documents.
2729
+ */
2730
+ function setConfiguredEditors(editors) {
2731
+ configuredEditors = editors;
2732
+ }
2733
+ /**
2734
+ * Checks whether an email address is permitted to edit, treating an absent list as unrestricted access.
2735
+ *
2736
+ * @param editors - Email addresses permitted to edit, defaulting to the configured list.
2737
+ * @param email - The email address to check.
2738
+ * @returns Whether the email is permitted to edit.
2739
+ */
2740
+ function isPermittedEditor(editors, email) {
2741
+ let permitted = editors ?? configuredEditors;
2742
+ return isDefined(permitted) ? isDefined(email) ? permitted.includes(email) : !1 : !0;
2743
+ }
2744
+ /**
2745
+ * Creates a Handbook tool for Sanity Studio, generating documentation from document type schemas
2746
+ * alongside the Portable Text guides authored in the dataset.
2747
+ *
2748
+ * @param config - Plugin configuration.
2749
+ * @returns Sanity plugin definition.
2750
+ * @public
2751
+ */
2752
+ const handbookPlugin = definePlugin((config) => {
2753
+ let { title, sidebarTitle, roles, blocks, editors, undocumentedFieldMessage } = config;
2754
+ setConfiguredEditors(editors);
2755
+ let resolved = {
2756
+ sidebarTitle: sidebarTitle ?? "Handbook",
2757
+ roles,
2758
+ blocks: blocks ?? [],
2759
+ undocumentedFieldMessage: undocumentedFieldMessage ?? "This field has not been documented yet. Contact your development team for guidance."
2760
+ }, guideType = createGuideType(resolved.blocks);
2761
+ return {
2762
+ name: "@driftime/sanity-plugin-handbook",
2763
+ schema: { types: [
2764
+ handbookType,
2765
+ guideType,
2766
+ imageType,
2767
+ videoType,
2768
+ codeType,
2769
+ calloutType,
2770
+ horizontalRuleType,
2771
+ ...resolved.blocks.map((block) => block.schema)
2772
+ ] },
2773
+ document: {
2774
+ newDocumentOptions: (templateItems, { creationContext, currentUser }) => {
2775
+ if (creationContext.type !== "global" && creationContext.type !== "structure") return templateItems;
2776
+ let hiddenTypes = isPermittedEditor(editors, currentUser?.email) ? singletonTypes : documentTypes;
2777
+ return templateItems.filter(({ templateId }) => ![...hiddenTypes].some((type) => templateId === type || templateId.startsWith(`${type}-`)));
2778
+ },
2779
+ actions: (actionComponents, { schemaType }) => singletonTypes.has(schemaType) ? actionComponents.filter(({ action }) => ![
2780
+ "delete",
2781
+ "duplicate",
2782
+ "unpublish"
2783
+ ].includes(action ?? "")) : actionComponents
2784
+ },
2785
+ tools: [{
2786
+ name: "handbook",
2787
+ title: title ?? "Handbook",
2788
+ icon: createSanityIcon(BookTextIcon),
2789
+ component: HandbookTool,
2790
+ options: resolved
2791
+ }]
2792
+ };
2033
2793
  });
2794
+ /**
2795
+ * Creates the Structure tool items for Handbook documents, yielding nothing when the current user is
2796
+ * not permitted to edit them.
2797
+ *
2798
+ * @param structureBuilder - The Sanity Structure builder instance.
2799
+ * @param context - The Structure context carrying the current user.
2800
+ * @param editors - Email addresses permitted to edit, defaulting to the configured list.
2801
+ * @returns The list items for the Handbook singleton and the guides list.
2802
+ * @public
2803
+ */
2804
+ function handbookStructure(structureBuilder, context, editors) {
2805
+ if (!isPermittedEditor(editors, context.currentUser?.email)) return [];
2806
+ let { listItem, document, documentTypeList } = structureBuilder;
2807
+ return [listItem().title("Handbook").icon(createSanityIcon(BookTextIcon)).child(document().id(handbookTypeName).schemaType(handbookTypeName).title("Handbook")), listItem().title("Handbook Guides").icon(createSanityIcon(BookOpenTextIcon)).child(documentTypeList(guideTypeName).title("Handbook Guides"))];
2808
+ }
2809
+ /**
2810
+ * Checks whether the current user is permitted to edit Handbook content, treating an absent list as
2811
+ * unrestricted access.
2812
+ *
2813
+ * @param editors - Email addresses permitted to edit, defaulting to the configured list.
2814
+ * @returns Whether the current user can edit Handbook documents.
2815
+ * @public
2816
+ */
2034
2817
  function useIsHandbookEditor(editors) {
2035
- const user = useCurrentUser();
2036
- return isPermittedEditor(editors, user?.email);
2037
- }
2038
- const handbookSingletonTypes = /* @__PURE__ */ new Set(["handbook.handbook"]), handbookDocumentTypes = /* @__PURE__ */ new Set(["handbook.handbook", "handbook.guide"]);
2039
- function isHandbookTemplate(templateId, typeSet) {
2040
- return typeSet.has(templateId) || [...typeSet].some((type) => templateId.startsWith(`${type}-`));
2041
- }
2042
- function validateGroup(index, group) {
2043
- const prefix = `sanity-handbook: groups[${index}]`;
2044
- if (!isDefined(group.title)) throw new Error(`${prefix} is missing a required "title" property.`);
2045
- if (!Array.isArray(group.documents) || group.documents.length === 0)
2046
- throw new Error(`${prefix} must have a non-empty "documents" array.`);
2047
- for (const document of group.documents) {
2048
- if (!isDefined(document.name))
2049
- throw new Error(`${prefix}.documents contains a document without a "name" property.`);
2050
- if (!Array.isArray(document.fields))
2051
- throw new TypeError(`${prefix}.documents.${document.name} is missing a "fields" array.`);
2052
- }
2818
+ let $ = c(3), t0 = useCurrentUser()?.email, t1;
2819
+ return $[0] !== editors || $[1] !== t0 ? (t1 = isPermittedEditor(editors, t0), $[0] = editors, $[1] = t0, $[2] = t1) : t1 = $[2], t1;
2053
2820
  }
2054
- function validateConfig(config) {
2055
- if (config.groups)
2056
- for (const [index, group] of config.groups.entries())
2057
- validateGroup(index, group);
2058
- }
2059
- function handbookPlugin(config) {
2060
- config && validateConfig(config);
2061
- const customBlocks = config?.blocks ?? [], editors = config?.editors;
2062
- setHandbookEditors(editors);
2063
- const guideType = createHandbookGuideType(customBlocks);
2064
- return definePlugin(() => ({
2065
- name: "@driftime/sanity-plugin-handbook",
2066
- schema: {
2067
- types: [
2068
- handbookType,
2069
- guideType,
2070
- handbookImageType,
2071
- handbookVideoType,
2072
- handbookCodeType,
2073
- handbookCalloutType,
2074
- handbookHorizontalRuleType,
2075
- ...customBlocks.map((block) => block.schema)
2076
- ]
2077
- },
2078
- document: {
2079
- newDocumentOptions: (templateItems, { creationContext, currentUser }) => creationContext.type === "global" || creationContext.type === "structure" ? isPermittedEditor(editors, currentUser?.email) ? templateItems.filter((item) => !isHandbookTemplate(item.templateId, handbookSingletonTypes)) : templateItems.filter((item) => !isHandbookTemplate(item.templateId, handbookDocumentTypes)) : templateItems,
2080
- actions: (actionComponents, { schemaType }) => handbookSingletonTypes.has(schemaType) ? actionComponents.filter(({ action }) => action !== "duplicate") : actionComponents
2081
- },
2082
- tools: [
2083
- {
2084
- name: "handbook",
2085
- title: config?.title ?? "Handbook",
2086
- icon: createSanityIcon(BookTextIcon),
2087
- component: createHandbookTool({ ...config, blocks: customBlocks })
2088
- }
2089
- ]
2090
- }))();
2091
- }
2092
- export {
2093
- handbookPlugin,
2094
- handbookStructure,
2095
- useIsHandbookEditor
2096
- };
2097
- //# sourceMappingURL=index.js.map
2821
+ export { handbookPlugin, handbookStructure, useIsHandbookEditor };
2822
+
2823
+ //# sourceMappingURL=index.js.map