sanity-plugin-taxonomy-manager 4.7.2 → 5.0.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 (83) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +13 -108
  3. package/{lib → dist}/index.d.ts +66 -48
  4. package/dist/index.js +106 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +40 -46
  7. package/src/components/Children.tsx +4 -3
  8. package/src/components/Concepts.tsx +2 -2
  9. package/src/components/Hierarchy.test.tsx +92 -0
  10. package/src/components/Hierarchy.tsx +65 -30
  11. package/src/components/TopConcepts.tsx +2 -2
  12. package/src/components/TreeStructure.tsx +3 -3
  13. package/src/components/inputs/ArrayHierarchyInput.test.tsx +102 -0
  14. package/src/components/inputs/ArrayHierarchyInput.tsx +23 -24
  15. package/src/components/inputs/Identifier.tsx +1 -1
  16. package/src/components/inputs/InputHierarchy.test.tsx +38 -0
  17. package/src/components/inputs/InputHierarchy.tsx +20 -68
  18. package/src/components/inputs/ReferenceHierarchyInput.test.tsx +109 -0
  19. package/src/components/inputs/ReferenceHierarchyInput.tsx +24 -25
  20. package/src/components/interactions/ConceptDetailLink.tsx +0 -1
  21. package/src/components/interactions/ConceptEditAction.tsx +1 -1
  22. package/src/components/interactions/ConceptSelectLink.test.tsx +49 -0
  23. package/src/components/interactions/ConceptSelectLink.tsx +10 -6
  24. package/src/context.ts +34 -14
  25. package/src/core/__snapshots__/queries.test.ts.snap +386 -0
  26. package/src/core/__snapshots__/semanticRecommendations.test.ts.snap +10 -0
  27. package/src/core/createId.test.ts +35 -0
  28. package/src/core/filters.test.ts +64 -0
  29. package/src/core/filters.ts +68 -0
  30. package/src/core/ids.test.ts +68 -0
  31. package/src/core/ids.ts +61 -0
  32. package/src/core/mutations.test.ts +114 -0
  33. package/src/core/mutations.ts +105 -0
  34. package/src/core/ports.ts +59 -0
  35. package/src/core/queries.test.ts +50 -0
  36. package/src/{queries.ts → core/queries.ts} +7 -6
  37. package/src/core/semanticRecommendations.test.ts +160 -0
  38. package/src/core/semanticRecommendations.ts +127 -0
  39. package/src/core/tree/annotateRecommendations.test.ts +43 -0
  40. package/src/core/tree/annotateRecommendations.ts +30 -0
  41. package/src/core/tree/pruneConcepts.test.ts +77 -0
  42. package/src/core/tree/pruneConcepts.ts +72 -0
  43. package/src/core/validation.test.ts +42 -0
  44. package/src/core/validation.ts +42 -0
  45. package/src/helpers/baseIriField.ts +22 -0
  46. package/src/helpers/branchFilter.test.ts +48 -0
  47. package/src/helpers/branchFilter.ts +17 -26
  48. package/src/helpers/schemeFilter.test.ts +51 -0
  49. package/src/helpers/schemeFilter.ts +11 -23
  50. package/src/hooks/index.ts +1 -1
  51. package/src/hooks/useCreateConcept.tsx +33 -110
  52. package/src/hooks/useRemoveConcept.tsx +24 -36
  53. package/src/hooks/useSemanticRecommendations.tsx +75 -0
  54. package/src/index.test.ts +31 -0
  55. package/src/index.ts +2 -6
  56. package/src/seams/StudioDataAdapter.ts +81 -0
  57. package/src/seams/TaxonomyPortContext.tsx +33 -0
  58. package/src/skosConcept.tsx +23 -234
  59. package/src/skosConceptScheme.tsx +2 -4
  60. package/src/structure.tsx +60 -0
  61. package/src/test/FakeDataPort.test.ts +62 -0
  62. package/src/test/FakeDataPort.ts +69 -0
  63. package/src/test/inputHarness.tsx +71 -0
  64. package/src/test/renderWithUi.test.tsx +14 -0
  65. package/src/test/renderWithUi.tsx +24 -0
  66. package/src/test-setup.ts +35 -0
  67. package/src/types.tsx +30 -11
  68. package/src/views/ConceptUseView.tsx +4 -10
  69. package/lib/index.esm.d.mts +0 -492
  70. package/lib/index.esm.esm.js +0 -182
  71. package/lib/index.esm.esm.js.map +0 -1
  72. package/lib/index.esm.mjs +0 -182
  73. package/lib/index.esm.mjs.map +0 -1
  74. package/lib/index.js +0 -182
  75. package/lib/index.js.map +0 -1
  76. package/sanity.json +0 -8
  77. package/src/config.ts +0 -16
  78. package/src/helpers/baseIriField.tsx +0 -42
  79. package/src/hooks/useEmbeddingsRecs.tsx +0 -75
  80. package/src/skosConcept.module.css +0 -10
  81. package/src/structure.ts +0 -40
  82. package/v2-incompatible.js +0 -11
  83. /package/src/{helpers → core}/createId.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/core/createId.ts","../src/components/inputs/Identifier.tsx","../src/context.ts","../src/core/tree/annotateRecommendations.ts","../node_modules/.pnpm/sanity-plugin-utils@2.0.13_@emotion+is-prop-valid@1.4.0_react-dom@19.2.8_react@19.2.8___6c4a80c4beef846050b8ebd34a3bade7/node_modules/sanity-plugin-utils/dist/index.js","../src/core/queries.ts","../src/hooks/useSemanticRecommendations.tsx","../src/seams/TaxonomyPortContext.tsx","../src/seams/StudioDataAdapter.ts","../src/core/semanticRecommendations.ts","../src/core/ids.ts","../src/hooks/useCreateConcept.tsx","../src/hooks/useOpenNewConceptPane.tsx","../src/core/mutations.ts","../src/hooks/useRemoveConcept.tsx","../src/components/interactions/ConceptDetailDialogue.tsx","../src/components/interactions/ConceptDetailLink.tsx","../src/components/interactions/ConceptEditAction.tsx","../src/components/interactions/ConceptSelectLink.tsx","../src/components/interactions/StructureDetailDialogue.tsx","../src/components/interactions/ToggleButton.tsx","../node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js","../src/components/Children.tsx","../src/components/ChildConcepts.tsx","../src/components/Concepts.tsx","../src/components/guides/NewScheme.tsx","../src/hooks/useAddTitle.tsx","../src/components/guides/NoConcepts.tsx","../src/components/TopConcepts.tsx","../src/components/TreeStructure.tsx","../src/components/inputs/InputHierarchy.tsx","../src/static/NodeTree.tsx","../src/core/tree/pruneConcepts.ts","../src/components/Hierarchy.tsx","../src/components/TreeView.tsx","../src/components/inputs/ReferenceHierarchyInput.tsx","../src/components/inputs/ArrayHierarchyInput.tsx","../src/components/inputs/ManagementControls.tsx","../src/core/filters.ts","../src/helpers/schemeFilter.ts","../src/helpers/branchFilter.ts","../src/core/validation.ts","../src/helpers/baseIriField.ts","../src/components/inputs/RdfUri.tsx","../src/skosConcept.tsx","../src/skosConceptScheme.tsx","../node_modules/.pnpm/@sanity+types@6.6.0_@types+react@19.2.17/node_modules/@sanity/types/lib/index.js","../node_modules/.pnpm/@sanity+util@6.6.0_@types+react@19.2.17/node_modules/@sanity/util/lib/paths.js","../src/views/ConceptUseView.tsx","../src/structure.tsx","../src/index.ts"],"sourcesContent":["import {customAlphabet} from 'nanoid'\n\nimport type {Options} from '../types'\n\nconst defaultAlphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\nconst defaultLength = 6\nconst defaultPrefix = ''\n\n/**\n * #### Create Unique Identifier\n * Used for creating the unique identification segment\n * of URIs.\n */\nexport function createId(ident?: Options['ident']): string {\n const alphabet = ident?.pattern || defaultAlphabet\n const length = ident?.length || defaultLength\n const prefix = ident?.prefix || defaultPrefix\n const nanoid = customAlphabet(alphabet, length)\n return prefix + nanoid()\n}\n","import {GenerateIcon} from '@sanity/icons'\nimport {Button, Stack, useToast} from '@sanity/ui'\nimport {useCallback} from 'react'\nimport {set} from 'sanity'\nimport type {StringInputProps} from 'sanity'\n\nimport {createId} from '../../core/createId'\nimport type {Options} from '../../types'\n\ntype IdentifierProps = StringInputProps & {\n ident?: Options['ident']\n}\n\n/**\n * #### Create Unique Identifier\n * For schemes and concepts created in previous versions of the\n * plugin.\n * - Input is only visible if no identifier has been assigned\n * - Input disappears once an ID is generated\n */\nexport const Identifier = (props: IdentifierProps) => {\n const {onChange, ident} = props\n const toast = useToast()\n\n const handleChange = useCallback(() => {\n const id = createId(ident)\n onChange(set(id))\n toast.push({\n status: 'success',\n title: 'Identifier created.',\n closable: true,\n })\n }, [onChange, toast, ident])\n\n return (\n <Stack space={2}>\n <Button\n icon={GenerateIcon}\n mode=\"ghost\"\n width=\"fill\"\n onClick={handleChange}\n text=\"Generate identifier\"\n />\n </Stack>\n )\n}\n\nIdentifier.defaultProps = {\n ident: undefined,\n}\n","import {createContext} from 'react'\n\nimport type {ConceptSchemeDocument, Options} from './types'\n\ntype TreeContextType = {\n globalVisibility?: {treeId: string; treeVisibility: 'open' | 'closed'}\n editControls?: boolean\n setEditControls?: (value: boolean) => void\n}\n\nexport const SchemeContext = createContext<ConceptSchemeDocument | null>(null)\nexport const TreeContext = createContext<TreeContextType>({editControls: false})\n\n/**\n * The active perspective name from `usePerspective().selectedPerspectiveName`\n * (provided by TreeView): `undefined` for the default drafts view, otherwise a\n * release name or `'published'`. Drives perspective-aware queries and the gating\n * of edit controls.\n */\nexport const ReleaseContext = createContext<string | undefined>(undefined)\n\n/**\n * Plugin config the render tree needs at runtime. Provided around the structure\n * Tree View (see `createDefaultDocumentNode`); replaces the old `config.ts`\n * `getPluginConfig` singleton. Defaults to empty so input-component trees (which\n * never create concepts) render correctly without a provider.\n */\nexport type TaxonomyConfig = {ident?: Options['ident']}\nexport const TaxonomyConfigContext = createContext<TaxonomyConfig>({})\n\n/**\n * Connects the deep remove actions to Hierarchy's optimistic-removal layer:\n * removing a concept marks its id so the tree prunes it instantly, ahead of the\n * live listener catching up (see Hierarchy + core/tree/pruneConcepts). Defaults\n * to no-ops, so trees rendered without the provider — the input components,\n * which never remove — behave normally.\n */\nexport type OptimisticTreeContextType = {\n markRemoved: (id: string) => void\n unmarkRemoved: (id: string) => void\n}\nexport const OptimisticTreeContext = createContext<OptimisticTreeContextType>({\n markRemoved: () => undefined,\n unmarkRemoved: () => undefined,\n})\n","import {getPublishedId, type DocumentId} from '@sanity/id-utils'\n\nimport type {ChildConceptTerm} from '../../types'\n\n/**\n * Recursively annotate hierarchy nodes: mark a node `recommended` when its published\n * id is in the recommendation set, and set `hasMatchingDescendant` when any descendant\n * is recommended. Children are processed first so the flag propagates up the ancestor\n * chain. Pure: returns new nodes and never mutates the input.\n */\nexport function annotateRecommendations<T extends ChildConceptTerm>(\n node: T,\n recommendedIds: Set<string>\n): T {\n const recommended = recommendedIds.has(getPublishedId(node.id as DocumentId))\n\n const annotatedChildren = node.childConcepts?.map((child) =>\n annotateRecommendations(child, recommendedIds)\n )\n\n const hasMatchingDescendant =\n annotatedChildren?.some((child) => child.recommended || child.hasMatchingDescendant) ?? false\n\n return {\n ...node,\n ...(recommended ? {recommended: true} : {}),\n ...(hasMatchingDescendant ? {hasMatchingDescendant: true} : {}),\n ...(annotatedChildren ? {childConcepts: annotatedChildren} : {}),\n } as T\n}\n","import { c } from \"react/compiler-runtime\";\nimport { Badge, Box, Card, Flex, Menu, MenuItem, Stack, Text, TextInput } from \"@sanity/ui\";\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nimport { css, styled } from \"styled-components\";\nimport { AddCircleIcon } from \"@sanity/icons/AddCircle\";\nimport { RemoveCircleIcon } from \"@sanity/icons/RemoveCircle\";\nimport { RestoreIcon } from \"@sanity/icons/Restore\";\nimport { useContext, useEffect, useRef, useState } from \"react\";\nimport { UserAvatar, useClient, useDocumentStore, useWorkspace } from \"sanity\";\nimport { createImageUrlBuilder } from \"@sanity/image-url\";\nimport isEqual from \"react-fast-compare\";\nimport { catchError, distinctUntilChanged } from \"rxjs/operators\";\nimport { RouterContext } from \"sanity/router\";\nimport { usePaneRouter } from \"sanity/structure\";\nconst DEFAULT_PROPS = { tone: \"primary\" };\nfunction Feedback(props) {\n\tlet $ = c(12), t0;\n\t$[0] === props ? t0 = $[1] : (t0 = {\n\t\t...DEFAULT_PROPS,\n\t\t...props\n\t}, $[0] = props, $[1] = t0);\n\tlet { title, description, icon, tone, children } = t0, t1 = icon ? \"display icon\" : null, t2;\n\t$[2] !== children || $[3] !== description || $[4] !== title ? (t2 = children || /* @__PURE__ */ jsx(Box, {\n\t\tflex: 1,\n\t\tchildren: /* @__PURE__ */ jsxs(Stack, {\n\t\t\tgap: 4,\n\t\t\tchildren: [title ? /* @__PURE__ */ jsx(Text, {\n\t\t\t\tweight: \"semibold\",\n\t\t\t\tchildren: title\n\t\t\t}) : null, description ? /* @__PURE__ */ jsx(Text, {\n\t\t\t\tsize: 2,\n\t\t\t\tchildren: description\n\t\t\t}) : null]\n\t\t})\n\t}), $[2] = children, $[3] = description, $[4] = title, $[5] = t2) : t2 = $[5];\n\tlet t3;\n\t$[6] !== t1 || $[7] !== t2 ? (t3 = /* @__PURE__ */ jsxs(Flex, { children: [t1, t2] }), $[6] = t1, $[7] = t2, $[8] = t3) : t3 = $[8];\n\tlet t4;\n\treturn $[9] !== t3 || $[10] !== tone ? (t4 = /* @__PURE__ */ jsx(Card, {\n\t\ttone,\n\t\tpadding: 4,\n\t\tradius: 3,\n\t\tborder: !0,\n\t\tchildren: t3\n\t}), $[9] = t3, $[10] = tone, $[11] = t4) : t4 = $[11], t4;\n}\nconst StyledTable = /* @__PURE__ */ styled((t0) => {\n\tlet $ = c(4), t1;\n\t$[0] === t0 ? t1 = $[1] : (t1 = t0 === void 0 ? {} : t0, $[0] = t0, $[1] = t1);\n\tlet props = t1, t2;\n\treturn $[2] === props ? t2 = $[3] : (t2 = /* @__PURE__ */ jsx(Card, {\n\t\tas: \"table\",\n\t\t...props\n\t}), $[2] = props, $[3] = t2), t2;\n}).withConfig({\n\tdisplayName: \"StyledTable\",\n\tcomponentId: \"sc-j6xlpp-0\"\n})(() => css`display:table;width:100%;border-collapse:collapse;&:not([hidden]){display:table;border-collapse:collapse;}`);\nfunction Table(props) {\n\tlet $ = c(6), children, rest;\n\t$[0] === props ? (children = $[1], rest = $[2]) : ({children, ...rest} = props, $[0] = props, $[1] = children, $[2] = rest);\n\tlet t0;\n\treturn $[3] !== children || $[4] !== rest ? (t0 = /* @__PURE__ */ jsx(StyledTable, {\n\t\t...rest,\n\t\tchildren\n\t}), $[3] = children, $[4] = rest, $[5] = t0) : t0 = $[5], t0;\n}\nconst StyledRow = /* @__PURE__ */ styled((t0) => {\n\tlet $ = c(4), t1;\n\t$[0] === t0 ? t1 = $[1] : (t1 = t0 === void 0 ? {} : t0, $[0] = t0, $[1] = t1);\n\tlet props = t1, t2;\n\treturn $[2] === props ? t2 = $[3] : (t2 = /* @__PURE__ */ jsx(Card, {\n\t\tas: \"tr\",\n\t\t...props\n\t}), $[2] = props, $[3] = t2), t2;\n}).withConfig({\n\tdisplayName: \"StyledRow\",\n\tcomponentId: \"sc-j6xlpp-1\"\n})(() => css`display:table-row;&:not([hidden]){display:table-row;}`);\nfunction Row(props) {\n\tlet $ = c(6), children, rest;\n\t$[0] === props ? (children = $[1], rest = $[2]) : ({children, ...rest} = props, $[0] = props, $[1] = children, $[2] = rest);\n\tlet t0;\n\treturn $[3] !== children || $[4] !== rest ? (t0 = /* @__PURE__ */ jsx(StyledRow, {\n\t\t...rest,\n\t\tchildren\n\t}), $[3] = children, $[4] = rest, $[5] = t0) : t0 = $[5], t0;\n}\nconst StyledCell = /* @__PURE__ */ styled((t0) => {\n\tlet $ = c(4), t1;\n\t$[0] === t0 ? t1 = $[1] : (t1 = t0 === void 0 ? {} : t0, $[0] = t0, $[1] = t1);\n\tlet props = t1, t2;\n\treturn $[2] === props ? t2 = $[3] : (t2 = /* @__PURE__ */ jsx(Card, {\n\t\tas: \"td\",\n\t\t...props\n\t}), $[2] = props, $[3] = t2), t2;\n}).withConfig({\n\tdisplayName: \"StyledCell\",\n\tcomponentId: \"sc-j6xlpp-2\"\n})(() => css`display:table-cell;&:not([hidden]){display:table-cell;}`);\nfunction Cell(props) {\n\tlet $ = c(6), children, rest;\n\t$[0] === props ? (children = $[1], rest = $[2]) : ({children, ...rest} = props, $[0] = props, $[1] = children, $[2] = rest);\n\tlet t0;\n\treturn $[3] !== children || $[4] !== rest ? (t0 = /* @__PURE__ */ jsx(StyledCell, {\n\t\t...rest,\n\t\tchildren\n\t}), $[3] = children, $[4] = rest, $[5] = t0) : t0 = $[5], t0;\n}\nfunction chunkArray(array, size) {\n\tlet chunks = [];\n\tfor (let i = 0; i < array.length; i += size) chunks.push(array.slice(i, i + size));\n\treturn chunks;\n}\nfunction useProjectUsers(t0) {\n\tlet $ = c(11), { apiVersion } = t0, { currentUser } = useWorkspace(), t1 = apiVersion ?? \"2023-01-01\", t2;\n\t$[0] === t1 ? t2 = $[1] : (t2 = { apiVersion: t1 }, $[0] = t1, $[1] = t2);\n\tlet client = useClient(t2), t3;\n\t$[2] === Symbol.for(\"react.memo_cache_sentinel\") ? (t3 = [], $[2] = t3) : t3 = $[2];\n\tlet [users, setUsers] = useState(t3), t4;\n\t$[3] !== client || $[4] !== currentUser?.id || $[5] !== users.length ? (t4 = () => {\n\t\tlet { projectId } = client.config();\n\t\tusers.length || async function() {\n\t\t\ttry {\n\t\t\t\tlet aclData = await client.request({ url: `/projects/${projectId}/acl` }), userIdChunks = chunkArray(aclData.map(_temp$1), 200), usersWithRoles = (await Promise.all(userIdChunks.map((chunk) => client.request({ url: `/projects/${projectId}/users/${chunk.join(\",\")}` })))).flat().map((user_0) => {\n\t\t\t\t\tlet userRoles = aclData.find((aclUser) => aclUser.projectUserId === user_0.id)?.roles || [];\n\t\t\t\t\treturn Object.assign(user_0, {\n\t\t\t\t\t\tisCurrentUser: user_0.id === currentUser?.id,\n\t\t\t\t\t\troles: userRoles\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\tsetUsers(usersWithRoles);\n\t\t\t} catch (t5) {\n\t\t\t\tconsole.error(\"Failed to fetch users:\", t5);\n\t\t\t}\n\t\t}();\n\t}, $[3] = client, $[4] = currentUser?.id, $[5] = users.length, $[6] = t4) : t4 = $[6];\n\tlet t5 = currentUser?.id, t6;\n\treturn $[7] !== client || $[8] !== t5 || $[9] !== users.length ? (t6 = [\n\t\tclient,\n\t\tt5,\n\t\tusers.length\n\t], $[7] = client, $[8] = t5, $[9] = users.length, $[10] = t6) : t6 = $[10], useEffect(t4, t6), users;\n}\nfunction _temp$1(user) {\n\treturn user.projectUserId;\n}\nfunction searchUsers(users, searchString) {\n\treturn users.filter((user) => !!((user.displayName || \"\").toLowerCase().startsWith(searchString) || (user.givenName || \"\").toLowerCase().startsWith(searchString) || (user.middleName || \"\").toLowerCase().startsWith(searchString) || (user.familyName || \"\").toLowerCase().startsWith(searchString)));\n}\nconst LABELS = {\n\taddMe: \"Assign myself\",\n\tremoveMe: \"Unassign myself\",\n\tclear: \"Clear assignees\",\n\tsearchPlaceholder: \"Search users\",\n\tnotFound: \"No users found\"\n};\nfunction UserSelectMenu(props) {\n\tlet $ = c(42), { value, userList, onAdd, onRemove, onClear, style: t0 } = props, t1;\n\t$[0] === t0 ? t1 = $[1] : (t1 = t0 === void 0 ? {} : t0, $[0] = t0, $[1] = t1);\n\tlet style = t1, t2;\n\t$[2] === props.labels ? t2 = $[3] : (t2 = props?.labels ? {\n\t\t...LABELS,\n\t\t...props.labels\n\t} : LABELS, $[2] = props.labels, $[3] = t2);\n\tlet labels = t2, [searchString, setSearchString] = useState(\"\"), searchResults = searchUsers(userList || [], searchString), me, t3;\n\t$[4] !== userList || $[5] !== value ? (me = userList.find(_temp), t3 = me && value.includes(me.id), $[4] = userList, $[5] = value, $[6] = me, $[7] = t3) : (me = $[6], t3 = $[7]);\n\tlet meAssigned = t3, input = useRef(null), t4;\n\t$[8] === Symbol.for(\"react.memo_cache_sentinel\") ? (t4 = (event) => {\n\t\tsetSearchString(event.target.value);\n\t}, $[8] = t4) : t4 = $[8];\n\tlet handleSearchChange = t4, t5;\n\t$[9] !== onAdd || $[10] !== onRemove ? (t5 = (isChecked, user) => {\n\t\tisChecked ? onRemove && onRemove(user.id) : onAdd && onAdd(user.id);\n\t}, $[9] = onAdd, $[10] = onRemove, $[11] = t5) : t5 = $[11];\n\tlet handleSelect = t5, t6;\n\t$[12] !== me || $[13] !== onAdd ? (t6 = () => {\n\t\tme && onAdd && onAdd(me.id);\n\t}, $[12] = me, $[13] = onAdd, $[14] = t6) : t6 = $[14];\n\tlet handleAssignMyself = t6, t7;\n\t$[15] !== me || $[16] !== onRemove ? (t7 = () => {\n\t\tme && onRemove && onRemove(me.id);\n\t}, $[15] = me, $[16] = onRemove, $[17] = t7) : t7 = $[17];\n\tlet handleUnassignMyself = t7, t8;\n\t$[18] === onClear ? t8 = $[19] : (t8 = () => {\n\t\tonClear && onClear();\n\t}, $[18] = onClear, $[19] = t8);\n\tlet handleClearAssigneesClick = t8, T0 = Menu, t9;\n\t$[20] !== handleAssignMyself || $[21] !== handleUnassignMyself || $[22] !== labels.addMe || $[23] !== labels.removeMe || $[24] !== me || $[25] !== meAssigned ? (t9 = meAssigned ? /* @__PURE__ */ jsx(MenuItem, {\n\t\ttone: \"caution\",\n\t\tdisabled: !me,\n\t\tonClick: handleUnassignMyself,\n\t\ticon: RemoveCircleIcon,\n\t\ttext: labels.removeMe\n\t}) : /* @__PURE__ */ jsx(MenuItem, {\n\t\ttone: \"positive\",\n\t\tonClick: handleAssignMyself,\n\t\ticon: AddCircleIcon,\n\t\ttext: labels.addMe\n\t}), $[20] = handleAssignMyself, $[21] = handleUnassignMyself, $[22] = labels.addMe, $[23] = labels.removeMe, $[24] = me, $[25] = meAssigned, $[26] = t9) : t9 = $[26];\n\tlet t10 = value.length === 0, t11;\n\t$[27] !== handleClearAssigneesClick || $[28] !== labels.clear || $[29] !== t10 ? (t11 = /* @__PURE__ */ jsx(MenuItem, {\n\t\ttone: \"critical\",\n\t\tdisabled: t10,\n\t\tonClick: handleClearAssigneesClick,\n\t\ticon: RestoreIcon,\n\t\ttext: labels.clear\n\t}), $[27] = handleClearAssigneesClick, $[28] = labels.clear, $[29] = t10, $[30] = t11) : t11 = $[30];\n\tlet t12;\n\t$[31] !== labels.searchPlaceholder || $[32] !== searchString ? (t12 = /* @__PURE__ */ jsx(Box, {\n\t\tpadding: 1,\n\t\tchildren: /* @__PURE__ */ jsx(TextInput, {\n\t\t\tref: input,\n\t\t\tonChange: handleSearchChange,\n\t\t\tplaceholder: labels.searchPlaceholder,\n\t\t\tvalue: searchString\n\t\t})\n\t}), $[31] = labels.searchPlaceholder, $[32] = searchString, $[33] = t12) : t12 = $[33];\n\tlet t13 = searchString && searchResults?.length === 0 && /* @__PURE__ */ jsx(MenuItem, {\n\t\tdisabled: !0,\n\t\ttext: labels.notFound\n\t}), t14 = searchResults && searchResults.map((user_0) => /* @__PURE__ */ jsx(MenuItem, {\n\t\tpressed: value.includes(user_0.id),\n\t\tonClick: () => handleSelect(value.indexOf(user_0.id) > -1, user_0),\n\t\tchildren: /* @__PURE__ */ jsxs(Flex, {\n\t\t\talign: \"center\",\n\t\t\tchildren: [\n\t\t\t\t/* @__PURE__ */ jsx(UserAvatar, {\n\t\t\t\t\tuser: user_0,\n\t\t\t\t\tsize: 1\n\t\t\t\t}),\n\t\t\t\t/* @__PURE__ */ jsx(Box, {\n\t\t\t\t\tpaddingX: 2,\n\t\t\t\t\tflex: 1,\n\t\t\t\t\tchildren: /* @__PURE__ */ jsx(Text, { children: user_0.displayName })\n\t\t\t\t}),\n\t\t\t\tuser_0.isCurrentUser && /* @__PURE__ */ jsx(Badge, {\n\t\t\t\t\tfontSize: 1,\n\t\t\t\t\ttone: \"positive\",\n\t\t\t\t\tchildren: \"Me\"\n\t\t\t\t})\n\t\t\t]\n\t\t})\n\t}, user_0.id)), t15;\n\treturn $[34] !== T0 || $[35] !== style || $[36] !== t11 || $[37] !== t12 || $[38] !== t13 || $[39] !== t14 || $[40] !== t9 ? (t15 = /* @__PURE__ */ jsxs(T0, {\n\t\tstyle,\n\t\tchildren: [\n\t\t\tt9,\n\t\t\tt11,\n\t\t\tt12,\n\t\t\tt13,\n\t\t\tt14\n\t\t]\n\t}), $[34] = T0, $[35] = style, $[36] = t11, $[37] = t12, $[38] = t13, $[39] = t14, $[40] = t9, $[41] = t15) : t15 = $[41], t15;\n}\nfunction _temp(u) {\n\treturn u.isCurrentUser;\n}\nfunction useImageUrlBuilder(clientOptions) {\n\tlet $ = c(2), client = useClient(clientOptions), t0;\n\treturn $[0] === client ? t0 = $[1] : (t0 = createImageUrlBuilder(client), $[0] = client, $[1] = t0), t0;\n}\nfunction useImageUrlBuilderImage(source, clientOptions) {\n\tlet $ = c(3), builder = useImageUrlBuilder(clientOptions), t0;\n\treturn $[0] !== builder || $[1] !== source ? (t0 = source && builder ? builder.image(source) : null, $[0] = builder, $[1] = source, $[2] = t0) : t0 = $[2], t0;\n}\nconst DEFAULT_PARAMS = {}, DEFAULT_OPTIONS = { apiVersion: \"v2023-05-01\" };\nfunction useParams(params) {\n\tlet $ = c(4), t0;\n\t$[0] === params ? t0 = $[1] : (t0 = JSON.stringify(params || {}), $[0] = params, $[1] = t0);\n\tlet stringifiedParams = t0, t1;\n\treturn $[2] === stringifiedParams ? t1 = $[3] : (t1 = JSON.parse(stringifiedParams), $[2] = stringifiedParams, $[3] = t1), t1;\n}\nfunction useListeningQuery(query, t0) {\n\tlet $ = c(11), { params: t1, options: t2, initialValue: t3 } = t0, params = t1 === void 0 ? DEFAULT_PARAMS : t1, options = t2 === void 0 ? DEFAULT_OPTIONS : t2, initialValue = t3 === void 0 ? null : t3, [loading, setLoading] = useState(!0), [error, setError] = useState(null), [data, setData] = useState(initialValue), memoParams = useParams(params), memoOptions = useParams(options), subscription = useRef(null), documentStore = useDocumentStore(), t4, t5;\n\t$[0] !== documentStore || $[1] !== error || $[2] !== memoOptions || $[3] !== memoParams || $[4] !== query ? (t4 = () => {\n\t\tif (query && !error && !subscription.current) try {\n\t\t\tsubscription.current = documentStore.listenQuery(query, memoParams, memoOptions).pipe(distinctUntilChanged(isEqual), catchError((err_0) => (console.error(err_0), setError(err_0), setLoading(!1), setData(null), err_0))).subscribe((documents) => {\n\t\t\t\tsetData((current) => isEqual(current, documents) ? current : documents), setLoading(!1), setError(null);\n\t\t\t});\n\t\t} catch (t6) {\n\t\t\tlet err = t6;\n\t\t\tconsole.error(err), setLoading(!1), setError(err);\n\t\t}\n\t\treturn error && subscription.current && subscription.current.unsubscribe(), () => {\n\t\t\tsubscription.current &&= (subscription?.current?.unsubscribe(), null);\n\t\t};\n\t}, t5 = [\n\t\tquery,\n\t\terror,\n\t\tmemoParams,\n\t\tmemoOptions,\n\t\tdocumentStore\n\t], $[0] = documentStore, $[1] = error, $[2] = memoOptions, $[3] = memoParams, $[4] = query, $[5] = t4, $[6] = t5) : (t4 = $[5], t5 = $[6]), useEffect(t4, t5);\n\tlet t6;\n\treturn $[7] !== data || $[8] !== error || $[9] !== loading ? (t6 = {\n\t\tdata,\n\t\tloading,\n\t\terror\n\t}, $[7] = data, $[8] = error, $[9] = loading, $[10] = t6) : t6 = $[10], t6;\n}\nfunction useOpenInNewPane(id, type) {\n\tlet $ = c(6), routerContext = useContext(RouterContext), { routerPanesState, groupIndex } = usePaneRouter(), t0;\n\treturn $[0] !== groupIndex || $[1] !== id || $[2] !== routerContext || $[3] !== routerPanesState || $[4] !== type ? (t0 = () => {\n\t\tif (!routerContext || !id || !type) return;\n\t\tlet panes = [...routerPanesState];\n\t\tpanes.splice(groupIndex + 1, 0, [{\n\t\t\tid,\n\t\t\tparams: { type }\n\t\t}]);\n\t\tlet href = routerContext.resolvePathFromState({ panes });\n\t\trouterContext.navigateUrl({ path: href });\n\t}, $[0] = groupIndex, $[1] = id, $[2] = routerContext, $[3] = routerPanesState, $[4] = type, $[5] = t0) : t0 = $[5], t0;\n}\nexport { Cell, Feedback, Row, Table, UserSelectMenu, useImageUrlBuilder, useImageUrlBuilderImage, useListeningQuery, useOpenInNewPane, useProjectUsers };\n\n//# sourceMappingURL=index.js.map","/**\n * Maximum hierarchy depth the builders recurse to. This is the single knob for\n * the depth cap — raising it later (if performance permits and use cases\n * warrant) is a one-line change. Kept at its long-standing value of 6.\n */\nconst MAX_TREE_DEPTH = 6\n\n/**\n * #### Branch Builder\n * Recursive builder for successive branches of the concept hierarchy, down to\n * `MAX_TREE_DEPTH` levels deep.\n */\nconst branchBuilder = (level = 1): string | void => {\n let reference = '^.^.concepts[]._ref'\n let i = 1\n while (level > i) {\n reference = `^.${reference}`\n i++\n }\n if (level > MAX_TREE_DEPTH) {\n return ''\n }\n return `\"childConcepts\": *[_id in ${reference} && ^._id in broader[]._ref]|order(prefLabel)\n {\n \"id\": _id,\n \"level\": ${level},\n _originalId,\n prefLabel,\n definition,\n example,\n scopeNote,\n ${branchBuilder(level + 1) || ''}\n }`\n}\n\n/**\n * #### Trunk Builder\n * Fetch the top concepts, their child concepts, and orphan concepts\n * and their child concepts.\n *\n * To get orphans:\n * - filter to concepts in this scheme only\n * - filter out concepts that reference a topConcept in this scheme as\n * a broader term\n * - filter out concepts that reference other concepts in this scheme\n * as a broader term\n *\n * Used in Hierarchy.tsx\n */\nexport const trunkBuilder = (): string => {\n return `*[_id == $id][0] {\n _updatedAt,\n \"topConcepts\": topConcepts[]->|order(prefLabel) {\n \"id\": _id,\n \"level\": 0,\n _originalId,\n prefLabel,\n definition,\n example,\n scopeNote,\n ${branchBuilder() || ''}\n },\n \"concepts\": concepts[]->|order(prefLabel) {\n \"id\": _id,\n \"level\": 0,\n \"isOrphan\": \n coalesce(\n !array::intersects(\n broader[]._ref, (\n coalesce(^.concepts[]._ref, []) + coalesce(^.topConcepts[]._ref, [])\n )\n ),\n true),\n _originalId,\n prefLabel,\n definition,\n example,\n scopeNote,\n ${branchBuilder() || ''}\n }\n }`\n}\n\n/**\n * #### Input Builder\n * Accept a branchId parameter, and filter to topConcepts and Concepts\n * in that branch only. Then call branchBuilder recursively — it will\n * only build terms in the scheme referenced by that concept.\n *\n * - trunkBuilder() is called in Hierarchy.tsx\n * - inputBuilder() is called in InputHierarchy.tsx\n */\nexport const inputBuilder = (): string => {\n return `\n select($branchId != null => \n *[_id == $id][0] {\n _updatedAt,\n \"concepts\": concepts[$branchId in @->broader[]->.conceptId]->|order(prefLabel) {\n \"id\": _id,\n \"level\": 0,\n \"isOrphan\": true,\n _originalId,\n prefLabel,\n definition,\n example,\n scopeNote,\n ${branchBuilder() || ''}\n }\n },\n *[_id == $id][0] {\n _updatedAt,\n \"topConcepts\":topConcepts[]->|order(prefLabel){\n \"id\": _id,\n \"level\": 0,\n _originalId,\n prefLabel,\n definition,\n example,\n scopeNote,\n ${branchBuilder() || ''}\n }, \n \"concepts\": concepts[]->|order(prefLabel){\n \"id\": _id,\n \"level\": 0,\n \"isOrphan\": \n coalesce(\n !array::intersects(\n broader[]._ref, (\n coalesce(^.concepts[]._ref, []) + coalesce(^.topConcepts[]._ref, [])\n )\n ), \n true),\n _originalId,\n prefLabel,\n definition,\n example,\n scopeNote,\n ${branchBuilder() || ''}\n }\n }\n )`\n}\n","import {useState, useCallback, useMemo} from 'react'\nimport {useClient, useGetFormValue} from 'sanity'\n\nimport {\n assembleQueryText,\n recommendationsErrorMessage,\n recommendationsQuery,\n toConceptRecommendations,\n type RecommendationRow,\n} from '../core/semanticRecommendations'\nimport type {ConceptRecommendation, SemanticSearchConfig} from '../types'\n\n/**\n * GROQ API version for the recommendations query. `text::semanticSimilarity()`\n * is documented as a stable function, but its minimum dated API version isn't\n * published; `vX` is the channel known to expose it (and what the pre-migration\n * embeddings hook already used, so this is no stability regression). Pin to a\n * dated version once confirmed against the live API.\n */\nconst SEMANTIC_API_VERSION = 'vX'\n\n/** Default number of recommended terms — preserved from the prior behavior. */\nconst DEFAULT_MAX_RESULTS = 3\n\n/**\n * Studio-side implementation of the semantic-recommendations seam. Reads the\n * configured form fields, runs the `text::semanticSimilarity()` query against the\n * published perspective, and exposes the scored concepts plus a friendly error.\n * All decision-bearing logic (query, validation, mapping, error wording) lives in\n * the pure `core/semanticRecommendations`; this hook only wires Studio (client +\n * form values) and React state.\n */\nexport function useSemanticRecommendations(semanticSearch?: SemanticSearchConfig) {\n // Recommend established terms: score against the published perspective, matching\n // the old published embeddings index. Memoized so the client ref stays stable.\n const baseClient = useClient({apiVersion: SEMANTIC_API_VERSION})\n const client = useMemo(() => baseClient.withConfig({perspective: 'published'}), [baseClient])\n const getFormValue = useGetFormValue()\n\n const [conceptRecs, setConceptRecs] = useState<ConceptRecommendation[]>([])\n const [recsError, setRecsError] = useState<string | null>(null)\n\n const triggerSearch = useCallback(\n (schemeId?: string) => {\n setRecsError(null)\n // Recommendations are scoped to the field's scheme; without a resolved\n // schemeId there is nothing to scope against, so skip the search.\n if (!semanticSearch || !schemeId) return\n const {fieldReferences, maxResults = DEFAULT_MAX_RESULTS} = semanticSearch\n\n let searchQuery: string\n try {\n searchQuery = assembleQueryText(\n fieldReferences.map((name) => ({name, value: getFormValue([name])}))\n )\n } catch (error) {\n setRecsError(\n error instanceof Error ? error.message : 'One or more required fields are empty'\n )\n return\n }\n\n client\n .fetch(recommendationsQuery(), {searchQuery, maxResults, schemeId})\n .then((rows: RecommendationRow[]) => setConceptRecs(toConceptRecommendations(rows)))\n .catch((error) => {\n console.error('Error fetching semantic recommendations: ', error)\n setRecsError(recommendationsErrorMessage(error))\n })\n },\n [client, getFormValue, semanticSearch]\n )\n\n return {conceptRecs, recsError, triggerSearch}\n}\n","import {createContext, useContext} from 'react'\nimport type {ReactElement, ReactNode} from 'react'\n\nimport type {TaxonomyDataPort} from '../core/ports'\n\nimport {studioDataAdapter} from './StudioDataAdapter'\n\n/**\n * #### Taxonomy Port Context\n * Carries the active `TaxonomyDataPort`. The default is the real\n * `StudioDataAdapter`, so production renders need **no provider mounted** —\n * which matters because Sanity mounts our Tree View (structure) and our field\n * inputs (document forms) in separate trees with no shared root we own.\n *\n * Tests inject an in-memory fake:\n * `<TaxonomyPortProvider port={createFakeDataPort({tree})}>…</TaxonomyPortProvider>`.\n */\nconst TaxonomyPortContext = createContext<TaxonomyDataPort>(studioDataAdapter)\n\nexport function TaxonomyPortProvider({\n port,\n children,\n}: {\n port: TaxonomyDataPort\n children: ReactNode\n}): ReactElement {\n return <TaxonomyPortContext.Provider value={port}>{children}</TaxonomyPortContext.Provider>\n}\n\n/** Read the active data port (default: `StudioDataAdapter`). */\nexport function useTaxonomyDataPort(): TaxonomyDataPort {\n return useContext(TaxonomyPortContext)\n}\n","import {useCallback} from 'react'\nimport {useClient} from 'sanity'\nimport {useListeningQuery} from 'sanity-plugin-utils'\n\nimport type {ConceptPlan, ConceptTreeParams, TaxonomyDataPort, WatchResult} from '../core/ports'\nimport {inputBuilder, trunkBuilder} from '../core/queries'\nimport {useSemanticRecommendations} from '../hooks/useSemanticRecommendations'\nimport type {DocumentConcepts} from '../types'\n\n/**\n * #### Studio Data Adapter\n * The default `TaxonomyDataPort` implementation: today's behavior, lifted\n * verbatim behind the interface. Tree watching stays on Studio's\n * `documentStore.listenQuery` (via `useListeningQuery`), mutations replay\n * `core/mutations` plans onto `client.transaction()`, and recommendations run a\n * `text::semanticSimilarity()` GROQ query (`useSemanticRecommendations`). Watch\n * and mutation behavior matches the pre-port components; recommendations were\n * migrated off the deprecated Embeddings Index API in Stage 5.\n */\n\n// Content Releases API version — must be preserved on the mutation path.\nconst MUTATION_API_VERSION = '2025-02-19'\n\nfunction useWatchTree(params: ConceptTreeParams): WatchResult<DocumentConcepts> {\n const isInput = params.mode === 'input'\n const result = useListeningQuery<DocumentConcepts>(\n {\n fetch: isInput ? inputBuilder() : trunkBuilder(),\n listen: isInput\n ? `*[_type == \"skosConcept\" || _id == $id]`\n : `*[_type == \"skosConcept\" || _type == \"skosConceptScheme\" ]`,\n },\n {\n params: isInput\n ? // GROQ's select($branchId != null => …) needs null, not ''. ListenQueryParams\n // rejects null, so we cast past it — preserved from the original InputHierarchy.\n ({id: params.documentId, branchId: params.branchId} as any)\n : {id: params.documentId},\n options: {\n perspective: params.perspective === undefined ? 'drafts' : [params.perspective],\n },\n }\n ) as {data: DocumentConcepts | null; loading: boolean; error: unknown}\n\n return {\n data: result.data ?? null,\n loading: result.loading,\n error: result.error ? (result.error as Error) : null,\n }\n}\n\nfunction useApplyConceptPlan(): (plan: ConceptPlan) => Promise<void> {\n const client = useClient({apiVersion: MUTATION_API_VERSION})\n return useCallback(\n async (plan: ConceptPlan): Promise<void> => {\n if (plan.kind === 'remove') {\n await client\n .transaction()\n .createIfNotExists(plan.createIfNotExists)\n .patch(plan.schemeId, (patch) => patch.unset(plan.unsetPaths))\n .commit()\n return\n }\n await client\n .transaction()\n .createIfNotExists(plan.createIfNotExists)\n .create(plan.create)\n .patch(plan.schemeId, (patch) =>\n patch.setIfMissing({[plan.appendField]: []}).append(plan.appendField, [plan.reference])\n )\n .commit({autoGenerateArrayKeys: true})\n },\n [client]\n )\n}\n\nexport const studioDataAdapter: TaxonomyDataPort = {\n useWatchTree,\n useApplyConceptPlan,\n useSemanticRecommendations,\n}\n","import {getPublishedId, type DocumentId} from '@sanity/id-utils'\n\nimport type {ConceptRecommendation} from '../types'\n\n/**\n * #### Semantic Recommendations (pure core)\n * The decision-bearing logic for the semantic term-recommendation seam: the GROQ\n * query, the query-text assembly + validation, result mapping, and error\n * messaging. The Studio adapter (`useSemanticRecommendations`) supplies the form\n * values, runs the query, and owns React state; everything here is pure so it can\n * be unit-tested without Studio or the network.\n *\n * Replaces the deprecated Embeddings Index API (`/embeddings-index/query/…`,\n * `text::embedding()`) with dataset embeddings queried through\n * `text::semanticSimilarity()` — no named index, scored in GROQ.\n */\n\n/**\n * GROQ for the recommendations query. Scores the `skosConcept`s belonging to the\n * scheme identified by `$schemeId` — those referenced by that scheme's `topConcepts`\n * or `concepts` (concepts carry no scheme back-reference, so membership runs through\n * the scheme) — by semantic similarity to `$searchQuery`, returning the top\n * `$maxResults` as `{conceptId, score}`, most-relevant first. Scoping to the field's\n * scheme keeps recommendations within the vocabulary the field draws from rather than\n * the whole dataset. `text::semanticSimilarity()` is only valid inside `score()`, and\n * the dataset must have embeddings enabled or the query errors (surfaced via\n * {@link recommendationsErrorMessage}).\n *\n * Scoping is scheme-level: a `branchFilter` field still scores the whole scheme, not\n * just the displayed branch. Branch-level scoping is tracked in #93.\n */\nexport const recommendationsQuery = (): string =>\n `*[_type == \"skosConcept\" && _id in *[_type == \"skosConceptScheme\" && schemeId == $schemeId][0]{\n \"ids\": coalesce(topConcepts[]._ref, []) + coalesce(concepts[]._ref, [])\n }.ids] | score(text::semanticSimilarity($searchQuery)) | order(_score desc) [0...$maxResults] {\n \"conceptId\": _id,\n \"score\": _score\n }`\n\n/** A document field name paired with its current value, read from the edited document. */\nexport interface RecommendationField {\n name: string\n value: unknown\n}\n\n/**\n * Concatenate the referenced fields' values into the semantic-search query text.\n * Every field must hold a non-empty string; otherwise this throws with a message\n * naming the empty field(s), which the adapter surfaces as `recsError` rather than\n * searching against partial input. The messages are preserved verbatim from the\n * pre-migration embeddings hook.\n */\nexport function assembleQueryText(fields: RecommendationField[]): string {\n const values: string[] = []\n const emptyFields: string[] = []\n for (const {name, value} of fields) {\n if (typeof value === 'string' && value.trim() !== '') {\n values.push(value)\n } else {\n emptyFields.push(name)\n }\n }\n if (emptyFields.length === 1) {\n throw new Error(`Please fill out the ${emptyFields[0]} field to enable match scores.`)\n }\n if (emptyFields.length > 1) {\n throw new Error(\n `The following fields must be filled out to enable match scores: ${emptyFields.join(', ')}`\n )\n }\n return values.join(' ')\n}\n\n/** A raw row from {@link recommendationsQuery}, before id normalization. */\nexport interface RecommendationRow {\n conceptId: string\n score: number\n}\n\n/**\n * Map raw query rows to {@link ConceptRecommendation}s, normalizing each concept id\n * to its published form so they line up with `annotateRanks`, which keys the tree by\n * published id. Rows missing a string id or numeric score are dropped.\n */\nexport function toConceptRecommendations(\n rows: readonly RecommendationRow[] | null | undefined\n): ConceptRecommendation[] {\n if (!rows) return []\n const recs: ConceptRecommendation[] = []\n for (const row of rows) {\n if (!row || typeof row.conceptId !== 'string' || row.conceptId === '') continue\n if (typeof row.score !== 'number') continue\n recs.push({conceptId: getPublishedId(row.conceptId as DocumentId), score: row.score})\n }\n return recs\n}\n\n/**\n * The set of published concept ids that are semantic recommendations. The raw\n * `text::semanticSimilarity()` score is opaque and unitless (meaningful only for\n * relative ordering within one query), so we keep only set membership — a concept\n * is either recommended or it isn't — and let the query's `maxResults` bound the\n * size. De-duplicated by construction.\n */\nexport function recommendedConceptIds(recs: readonly ConceptRecommendation[]): Set<string> {\n return new Set(recs.map((rec) => rec.conceptId))\n}\n\n/** Friendly message shown when a dataset has no embeddings enabled. */\nconst EMBEDDINGS_DISABLED_MESSAGE = \"Semantic recommendations aren't enabled for this dataset.\"\n/** Fallback for any other recommendations failure. */\nconst GENERIC_RECS_ERROR_MESSAGE = 'Unable to load semantic recommendations.'\n\n/**\n * Map a failed recommendations fetch to a friendly `recsError` message. A dataset\n * without embeddings is the expected failure — `text::semanticSimilarity()` errors\n * there — so an embeddings-related error becomes a clear setup hint; anything else\n * falls back to a generic message. Either way the tree still renders, only without\n * scores.\n *\n * The embeddings-disabled detection matches on the error text; confirm it against\n * the live API error in a `pnpm dev` pass and widen the match if the wording differs.\n */\nexport function recommendationsErrorMessage(error: unknown): string {\n const text = error instanceof Error ? error.message : typeof error === 'string' ? error : ''\n return /embedding/i.test(text) ? EMBEDDINGS_DISABLED_MESSAGE : GENERIC_RECS_ERROR_MESSAGE\n}\n","import {\n DocumentId,\n getDraftId,\n getVersionId,\n getVersionNameFromId,\n isPublishedId,\n isVersionId,\n type VersionId,\n} from '@sanity/id-utils'\n\n/** The `_strengthenOnPublish` template applied to weak skosConcept references. */\nexport const SKOS_CONCEPT_STRENGTHEN = {type: 'skosConcept', template: {id: 'skosConcept'}} as const\n\nexport type SchemeMutationTarget = {\n isInRelease: boolean\n releaseName: string | undefined\n schemeId: string\n}\n\n/**\n * Resolve the document id a scheme mutation should write to, from the displayed\n * scheme id: the matching version id when the scheme is being edited inside a\n * release, otherwise its draft id. Shared by concept create/remove.\n */\nexport function deriveSchemeMutationTarget(displayedId: string): SchemeMutationTarget {\n const docId = DocumentId(displayedId)\n const isInRelease = isVersionId(docId)\n const releaseName = isInRelease ? getVersionNameFromId(docId as VersionId) : undefined\n const schemeId = isInRelease ? getVersionId(docId, releaseName as string) : getDraftId(docId)\n return {isInRelease, releaseName, schemeId}\n}\n\n/**\n * The id for a newly created concept, in the same release/draft context as its\n * scheme. `uuid` is supplied by the caller (kept pure/deterministic here).\n */\nexport function deriveNewConceptId(\n uuid: string,\n context: {isInRelease: boolean; releaseName: string | undefined},\n): string {\n const docId = DocumentId(uuid)\n return context.isInRelease\n ? getVersionId(docId, context.releaseName as string)\n : getDraftId(docId)\n}\n\nexport type ReferenceStrength = {\n _weak: boolean\n _strengthenOnPublish?: typeof SKOS_CONCEPT_STRENGTHEN\n}\n\n/**\n * Weak-reference flags for a reference to a concept that may not be published\n * yet. When the referenced concept is a draft or version (not published), the\n * reference must be weak and strengthened on publish so it survives until the\n * target is published.\n */\nexport function conceptReferenceStrength(referencedOriginalId: string): ReferenceStrength {\n const published = isPublishedId(DocumentId(referencedOriginalId))\n return published ? {_weak: false} : {_weak: true, _strengthenOnPublish: SKOS_CONCEPT_STRENGTHEN}\n}\n","import {useToast} from '@sanity/ui'\nimport {uuid} from '@sanity/uuid'\nimport {useCallback, useContext} from 'react'\n\nimport {TaxonomyConfigContext} from '../context'\nimport {createId} from '../core/createId'\nimport {planCreateConcept} from '../core/mutations'\nimport {useTaxonomyDataPort} from '../seams/TaxonomyPortContext'\nimport type {ConceptSchemeDocument} from '../types'\n\nimport {useOpenNewConceptPane} from './useOpenNewConceptPane'\n\n/**\n * #### Concept Creation Hook\n * Used for creating concepts and top concepts from the Concept Scheme hierarchy\n * view. The release/version-aware transaction is planned purely in\n * `core/mutations` and executed through the data port; this hook stays thin —\n * it generates the random ids/keys, builds the plan, and handles the toast +\n * new-pane navigation.\n */\nexport function useCreateConcept(document: ConceptSchemeDocument) {\n const toast = useToast()\n const openInNewPane = useOpenNewConceptPane()\n const port = useTaxonomyDataPort()\n const applyConceptPlan = port.useApplyConceptPlan()\n\n // Ident config (identifier generation) comes from plugin options via context.\n const {ident} = useContext(TaxonomyConfigContext)\n const schemaBaseIri = document.displayed.baseIri\n\n const createConcept = useCallback(\n (conceptType: 'topConcept' | 'concept', concept?: {id: string; _originalId?: string}) => {\n const plan = planCreateConcept({\n scheme: document.displayed,\n conceptType,\n broaderConcept: concept?.id\n ? {id: concept.id, _originalId: concept._originalId ?? ''}\n : undefined,\n newConceptUuid: uuid(),\n conceptId: createId(ident),\n schemeBaseIri: schemaBaseIri,\n newConceptKey: uuid(),\n broaderKey: uuid(),\n })\n\n applyConceptPlan(plan)\n .then(() => {\n toast.push({closable: true, status: 'success', title: 'Created new concept'})\n openInNewPane(plan.newConceptId)\n })\n .catch((err) => {\n toast.push({\n closable: true,\n status: 'error',\n title: 'Error creating concept',\n description: err instanceof Error ? err.message : 'Unknown error occurred',\n })\n })\n },\n [document.displayed, ident, schemaBaseIri, applyConceptPlan, toast, openInNewPane]\n )\n return createConcept\n}\n","import {useCallback, useContext} from 'react'\nimport {RouterContext} from 'sanity/router'\nimport {usePaneRouter} from 'sanity/structure'\n\n/**\n * Open in New Pane Link for Concepts\n */\nexport function useOpenNewConceptPane() {\n const routerContext = useContext(RouterContext)\n const {routerPanesState, groupIndex} = usePaneRouter()\n\n const openInNewPane = useCallback(\n (conceptId: string) => {\n if (!routerContext || !conceptId) {\n return\n }\n\n const panes = [...routerPanesState]\n panes.splice(groupIndex + 1, groupIndex + 1, [\n {\n id: conceptId,\n params: {type: 'skosConcept'},\n },\n ])\n\n const href = routerContext.resolvePathFromState({panes})\n routerContext.navigateUrl({path: href})\n },\n [routerContext, routerPanesState, groupIndex]\n )\n\n return openInNewPane\n}\n","import {DocumentId, getPublishedId} from '@sanity/id-utils'\n\nimport type {ConceptSchemeDocument, SkosConceptDocument, SkosConceptReference} from '../types'\n\nimport {\n conceptReferenceStrength,\n deriveNewConceptId,\n deriveSchemeMutationTarget,\n SKOS_CONCEPT_STRENGTHEN,\n} from './ids'\n\ntype SchemeDisplayed = ConceptSchemeDocument['displayed']\n\n/**\n * \"Describe, don't execute\": the create/remove planners below compute a pure\n * description of the transaction a concept mutation should run. The hooks stay\n * thin — they generate the random ids/keys, pass them in, and replay the plan\n * onto client.transaction(). This makes the release/version-aware mutation logic\n * exhaustively unit-testable without a Studio.\n */\n\nexport type CreateConceptPlan = {\n kind: 'create'\n schemeId: string\n newConceptId: string\n createIfNotExists: SchemeDisplayed & {_id: string}\n create: SkosConceptDocument\n appendField: 'topConcepts' | 'concepts'\n reference: SkosConceptReference\n}\n\nexport function planCreateConcept(input: {\n scheme: SchemeDisplayed\n conceptType: 'topConcept' | 'concept'\n broaderConcept?: {id: string; _originalId: string}\n newConceptUuid: string\n conceptId: string\n schemeBaseIri: string | undefined\n newConceptKey: string\n broaderKey: string\n}): CreateConceptPlan {\n const target = deriveSchemeMutationTarget(input.scheme._id)\n const newConceptId = deriveNewConceptId(input.newConceptUuid, target)\n\n const create: SkosConceptDocument = {\n _id: newConceptId,\n _type: 'skosConcept',\n conceptId: input.conceptId,\n prefLabel: '',\n baseIri: input.schemeBaseIri,\n broader: [],\n related: [],\n }\n\n if (input.broaderConcept) {\n create.broader = [\n {\n _key: input.broaderKey,\n _ref: getPublishedId(DocumentId(input.broaderConcept.id)),\n _type: 'reference',\n ...conceptReferenceStrength(input.broaderConcept._originalId),\n },\n ]\n }\n\n const reference: SkosConceptReference = {\n _ref: getPublishedId(DocumentId(newConceptId)),\n _type: 'reference',\n _key: input.newConceptKey,\n _strengthenOnPublish: SKOS_CONCEPT_STRENGTHEN,\n _weak: true,\n }\n\n return {\n kind: 'create',\n schemeId: target.schemeId,\n newConceptId,\n createIfNotExists: {...input.scheme, _id: target.schemeId},\n create,\n appendField: input.conceptType === 'topConcept' ? 'topConcepts' : 'concepts',\n reference,\n }\n}\n\nexport type RemoveConceptPlan = {\n kind: 'remove'\n schemeId: string\n createIfNotExists: SchemeDisplayed & {_id: string}\n unsetPaths: string[]\n}\n\nexport function planRemoveConcept(input: {\n scheme: SchemeDisplayed\n conceptRef: string\n conceptType: string\n}): RemoveConceptPlan {\n const field = input.conceptType === 'topConcept' ? 'topConcepts' : 'concepts'\n const {schemeId} = deriveSchemeMutationTarget(input.scheme._id)\n return {\n kind: 'remove',\n schemeId,\n createIfNotExists: {...input.scheme, _id: schemeId},\n unsetPaths: [`${field}[_ref==\"${input.conceptRef}\"]`],\n }\n}\n","import {useToast} from '@sanity/ui'\nimport {useCallback, useContext} from 'react'\n\nimport {OptimisticTreeContext} from '../context'\nimport {planRemoveConcept} from '../core/mutations'\nimport {useTaxonomyDataPort} from '../seams/TaxonomyPortContext'\nimport type {ConceptSchemeDocument} from '../types'\n\n/**\n * #### Concept Removal Hook\n * Used for removing concepts and top concepts from the Concept Scheme hierarchy\n * view. The release/version-aware transaction is planned purely in\n * `core/mutations` and executed through the data port; this hook replays the\n * plan, prunes the concept from the tree optimistically (reverting if the\n * mutation fails), and handles the toast.\n */\nexport function useRemoveConcept(document: ConceptSchemeDocument) {\n const toast = useToast()\n const port = useTaxonomyDataPort()\n const applyConceptPlan = port.useApplyConceptPlan()\n const {markRemoved, unmarkRemoved} = useContext(OptimisticTreeContext)\n\n // conceptId is the id of the concept to be removed\n const removeConcept = useCallback(\n (conceptId: string, conceptType: string, prefLabel?: string) => {\n const plan = planRemoveConcept({\n scheme: document.displayed,\n conceptRef: conceptId,\n conceptType,\n })\n\n // Prune from the tree immediately; the live listener reconciles after.\n markRemoved(conceptId)\n\n applyConceptPlan(plan)\n .then(() => {\n toast.push({\n closable: true,\n status: 'success',\n title: `${prefLabel ? `\"${prefLabel}\"` : 'Concept'} removed from scheme`,\n })\n })\n .catch((err) => {\n // Roll the optimistic removal back so the concept reappears.\n unmarkRemoved(conceptId)\n toast.push({\n closable: true,\n status: 'error',\n title: 'Error removing concept',\n description: err instanceof Error ? err.message : 'Unknown error occurred',\n })\n })\n },\n [applyConceptPlan, document.displayed, toast, markRemoved, unmarkRemoved]\n )\n return removeConcept\n}\n","import {InfoOutlineIcon} from '@sanity/icons'\nimport {Dialog, Box, Text, Stack, Label, Button, Tooltip} from '@sanity/ui'\nimport {useCallback, useState} from 'react'\n\nimport type {ChildConceptTerm, TopConceptTerm} from '../../types'\n\nconst MessageHelper = ({title, message}: {title: string; message: string}) => {\n return (\n <Stack space={2}>\n <Label size={1}>{title}</Label>\n <Text size={2} muted style={{whiteSpace: 'pre-wrap'}}>\n {message}\n </Text>\n </Stack>\n )\n}\n\n/**\n * #### Information Icon and Dialogue with Concept Details\n * - Affords Tree View access to Definition, Examples, and Scope Notes\n * - Rendered only when concept details are present\n */\nexport const ConceptDetailDialogue = ({\n concept,\n}: {\n concept: (ChildConceptTerm | TopConceptTerm) & {\n definition?: string\n example?: string\n scopeNote?: string\n }\n}) => {\n const [open, setOpen] = useState(false)\n const onClose = useCallback(() => setOpen(false), [])\n const onOpen = useCallback(() => setOpen(true), [])\n\n if (!concept || (!concept.definition && !concept.example && !concept.scopeNote)) return null\n\n return (\n <>\n <Tooltip\n delay={{open: 750}}\n content={\n <Box padding={1} sizing=\"content\">\n <Text muted size={1}>\n View concept details\n </Text>\n </Box>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <Button icon={InfoOutlineIcon} mode={'bleed'} onClick={onOpen} tone={'default'} />\n </Tooltip>\n\n {open && (\n <Dialog\n header={concept.prefLabel}\n id=\"dialog-example\"\n onClose={onClose}\n zOffset={1000}\n width={1}\n >\n <Box padding={4} paddingTop={2} paddingBottom={5}>\n <Stack space={4}>\n {concept.definition && (\n <MessageHelper title={'Definition'} message={concept.definition} />\n )}\n {concept.example && <MessageHelper title={'Examples'} message={concept.example} />}\n {concept.scopeNote && (\n <MessageHelper title={'Scope Notes'} message={concept.scopeNote} />\n )}\n </Stack>\n </Box>\n </Dialog>\n )}\n </>\n )\n}\n","import {Button, Text, Box, Badge, Tooltip} from '@sanity/ui'\nimport {useCallback, useContext} from 'react'\nimport {RouterContext} from 'sanity/router'\nimport {usePaneRouter} from 'sanity/structure'\n\nimport type {ChildConceptTerm} from '../../types'\n\n/**\n * #### Concept Detail Link\n * Renders a link to a concept in the hierarchy tree that opens in a new pane.\n */\nexport function ConceptDetailLink({\n concept,\n topConcept = false,\n orphan = false,\n}: {\n concept: ChildConceptTerm\n topConcept?: boolean\n orphan?: boolean\n}) {\n const routerContext = useContext(RouterContext)\n const {routerPanesState, groupIndex} = usePaneRouter()\n\n const {id, prefLabel} = concept ?? {}\n const displayLabel = prefLabel || '[new concept]'\n\n const openInNewPane = useCallback(() => {\n if (!routerContext || !id) {\n return\n }\n\n const panes = [...routerPanesState]\n panes.splice(groupIndex + 1, groupIndex + 1, [\n {\n id: id,\n params: {type: 'skosConcept'},\n },\n ])\n\n const href = routerContext.resolvePathFromState({panes})\n routerContext.navigateUrl({path: href})\n }, [id, routerContext, routerPanesState, groupIndex])\n\n return (\n <Tooltip\n delay={{open: 750}}\n content={\n <Box padding={1} sizing=\"content\">\n <Text muted size={1}>\n {`View \"${prefLabel}\"`}\n </Text>\n </Box>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n >\n <Button\n mode=\"bleed\"\n paddingLeft={0}\n onClick={openInNewPane}\n width=\"fill\"\n justify={'flex-start'}\n >\n <Text size={2} weight={topConcept ? 'bold' : 'regular'} textOverflow=\"ellipsis\">\n {displayLabel}\n {(topConcept || orphan) && (\n <Badge fontSize={0} marginLeft={3} style={{verticalAlign: 'middle'}}>\n {topConcept ? 'top concept' : 'orphan'}\n </Badge>\n )}\n </Text>\n </Button>\n </Tooltip>\n )\n}\n","import {TrashIcon, AddCircleIcon} from '@sanity/icons'\nimport {Box, Text, Button, Tooltip} from '@sanity/ui'\n// import {useCallback, useState} from 'react'\n\nexport const ConceptEditAction = ({\n action,\n handler,\n}: {\n action: 'remove' | 'add'\n handler: () => void\n}) => {\n // const [open, setOpen] = useState(false)\n // const onClose = useCallback(() => setOpen(false), [])\n // const onOpen = useCallback(() => setOpen(true), [])\n\n const typeMap = {\n add: {\n message: 'Add a child concept below this concept' as const,\n icon: AddCircleIcon,\n tone: 'positive' as const,\n },\n remove: {\n message: 'Remove this concept from this scheme' as const,\n icon: TrashIcon,\n tone: 'critical' as const,\n },\n }\n\n return (\n <Tooltip\n delay={{open: 750}}\n content={\n <Box padding={1} sizing=\"content\">\n <Text muted size={1}>\n {typeMap[action].message}\n </Text>\n </Box>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n >\n <Button\n icon={typeMap[action].icon}\n mode={'bleed'}\n onClick={handler}\n tone={typeMap[action].tone}\n aria-label={typeMap[action].message}\n />\n </Tooltip>\n )\n}\n","import {Button, Text, Box, Badge, Tooltip} from '@sanity/ui'\nimport {useCallback} from 'react'\n\nimport type {ChildConceptTerm} from '../../types'\n\n/**\n * #### Concept Select Link\n * Writes a concept _ref from the hierarchy tree to the current document\n */\nexport function ConceptSelectLink({\n concept,\n topConcept = false,\n orphan = false,\n selectConcept,\n}: {\n concept: ChildConceptTerm\n topConcept?: boolean\n orphan?: boolean\n selectConcept?: (conceptRef: {\n _ref: string\n _type: 'reference'\n _originalId: string | undefined\n }) => void\n}) {\n const {prefLabel, id, _originalId, recommended} = concept ?? {}\n const displayLabel = prefLabel || '[new concept]'\n\n const handleClick = useCallback(() => {\n if (!selectConcept) return\n\n const conceptRef = {\n _ref: id,\n _type: 'reference' as const,\n _originalId,\n }\n selectConcept(conceptRef)\n }, [id, _originalId, selectConcept])\n\n return (\n <>\n {selectConcept && (\n <Tooltip\n delay={{open: 750}}\n content={\n <Box padding={1} sizing=\"content\">\n <Text muted size={1}>\n {`Select \"${prefLabel}\"`}\n {recommended && ` (recommended)`}\n </Text>\n </Box>\n }\n fallbackPlacements={['right', 'left', 'bottom']}\n placement=\"top\"\n portal\n >\n <Button\n mode=\"bleed\"\n paddingLeft={0}\n onClick={handleClick}\n width=\"fill\"\n justify={'flex-start'}\n >\n <Text size={2} weight={topConcept ? 'bold' : 'regular'} textOverflow=\"ellipsis\">\n {displayLabel}\n {(topConcept || orphan) && (\n <Badge fontSize={0} marginLeft={3} style={{verticalAlign: 'middle'}}>\n {topConcept ? 'top concept' : 'orphan'}\n </Badge>\n )}\n {recommended && (\n <Badge\n tone=\"positive\"\n fontSize={0}\n marginLeft={3}\n style={{verticalAlign: 'middle'}}\n >\n recommended\n </Badge>\n )}\n </Text>\n </Button>\n </Tooltip>\n )}\n </>\n )\n}\n","import {InfoOutlineIcon, ErrorOutlineIcon} from '@sanity/icons'\nimport {Dialog, Box, Text, Button, Tooltip} from '@sanity/ui'\nimport {useCallback, useState} from 'react'\n\n/**\n * #### Information Icon and Dialogue with Structure Details\n * Provide feedback on concepts that are at the limit of\n * or have children beyond the supported hierarchy depth\n */\nexport const StructureDetailDialogue = ({\n message,\n title,\n type,\n}: {\n message: string\n title: string\n type: 'info' | 'warn' | 'error'\n}) => {\n const [open, setOpen] = useState(false)\n const onClose = useCallback(() => setOpen(false), [])\n const onOpen = useCallback(() => setOpen(true), [])\n\n const toneMap = {\n info: 'default' as const,\n warn: 'caution' as const,\n error: 'critical' as const,\n }\n\n return (\n <>\n <Tooltip\n delay={{open: 750}}\n content={\n <Box padding={1} sizing=\"content\">\n <Text muted size={1}>\n {title}\n </Text>\n </Box>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <Button\n icon={type == 'error' ? ErrorOutlineIcon : InfoOutlineIcon}\n mode={'bleed'}\n onClick={onOpen}\n tone={toneMap[type]}\n />\n </Tooltip>\n\n {open && (\n <Dialog header={title} id=\"dialog-example\" onClose={onClose} zOffset={1000} width={1}>\n <Box padding={4} paddingBottom={5}>\n <Text>{message}</Text>\n </Box>\n </Dialog>\n )}\n </>\n )\n}\n","// import styles from '../styles/toggleButton.module.css'\nimport {ToggleArrowRightIcon} from '@sanity/icons'\nimport {Button} from '@sanity/ui'\n\nimport styles from './ToggleButton.module.css'\n\nexport function ToggleButton({handler, visibility}: {handler: () => void; visibility: string}) {\n return (\n <Button\n icon={ToggleArrowRightIcon}\n mode={'bleed'}\n aria-expanded={visibility == 'open'}\n onClick={handler}\n className={styles.toggleButton}\n />\n )\n}\n","function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","import {Inline, Box, Flex} from '@sanity/ui'\nimport {useCallback, useContext, useState} from 'react'\n\nimport {ReleaseContext, SchemeContext, TreeContext} from '../context'\nimport {useCreateConcept, useRemoveConcept} from '../hooks'\nimport type {ChildConceptTerm, ConceptSchemeDocument} from '../types'\n\nimport {ChildConcepts} from './ChildConcepts'\nimport {ConceptDetailDialogue} from './interactions/ConceptDetailDialogue'\nimport {ConceptDetailLink} from './interactions/ConceptDetailLink'\nimport {ConceptEditAction} from './interactions/ConceptEditAction'\nimport {ConceptSelectLink} from './interactions/ConceptSelectLink'\nimport {StructureDetailDialogue} from './interactions/StructureDetailDialogue'\nimport {ToggleButton} from './interactions/ToggleButton'\n\n/**\n * #### Child Concept Component\n * Renders a list of child concepts and applicable\n * actions for a given concept.\n */\nexport const Children = ({\n concept,\n selectConcept,\n inputComponent = false,\n}: {\n concept: ChildConceptTerm\n selectConcept: (conceptId: {\n _ref: string\n _type: 'reference'\n _originalId: string | undefined\n }) => void\n inputComponent: boolean\n}) => {\n const document: ConceptSchemeDocument = useContext(SchemeContext) || ({} as ConceptSchemeDocument)\n const releaseContext = useContext(ReleaseContext)\n const {globalVisibility: {treeVisibility} = {treeVisibility: 'open' as const}} =\n useContext(TreeContext) || {}\n const createConcept = useCreateConcept(document)\n const removeConcept = useRemoveConcept(document)\n\n const handleAddChild = useCallback(() => {\n createConcept('concept', concept)\n }, [concept, createConcept])\n\n const handleRemoveConcept = useCallback(() => {\n removeConcept(concept.id, 'concept', concept?.prefLabel)\n }, [concept.id, concept?.prefLabel, removeConcept])\n\n const [levelVisibility, setLevelVisibility] = useState<'open' | 'closed'>(\n treeVisibility === 'closed' && concept.hasMatchingDescendant\n ? 'open'\n : treeVisibility || 'open',\n )\n\n const handleToggle = useCallback(() => {\n if (levelVisibility == 'open') {\n setLevelVisibility('closed')\n } else if (levelVisibility == 'closed') {\n setLevelVisibility('open')\n }\n }, [levelVisibility])\n\n return (\n <Box className={levelVisibility}>\n <Flex align={'center'} justify={'space-between'} wrap={'nowrap'}>\n {/* Toggle, label, tag — left half of flexbox */}\n <Flex align=\"center\" gap={0} flex={1} style={{minWidth: 0}}>\n {concept?.childConcepts && concept.childConcepts.length > 0 && (\n <ToggleButton handler={handleToggle} visibility={levelVisibility} />\n )}\n {!concept?.prefLabel && (\n <Box\n flex={1}\n marginLeft={!concept?.childConcepts || concept.childConcepts.length == 0 ? 5 : 0}\n >\n <ConceptDetailLink concept={concept} />\n </Box>\n )}\n {concept?.prefLabel && (\n <Box\n flex={1}\n marginLeft={!concept?.childConcepts || concept.childConcepts.length == 0 ? 5 : 0}\n >\n {inputComponent ? (\n <ConceptSelectLink concept={concept} selectConcept={selectConcept} />\n ) : (\n <ConceptDetailLink concept={concept} />\n )}\n </Box>\n )}\n </Flex>\n {/* Concept info and edit actions — right half of flexbox */}\n {inputComponent && <ConceptDetailDialogue concept={concept} />}\n {!inputComponent &&\n releaseContext !== 'published' &&\n concept?.level &&\n concept.level < 5 && (\n <Inline>\n <ConceptEditAction action={'add'} handler={handleAddChild} />\n <ConceptEditAction action={'remove'} handler={handleRemoveConcept} />\n </Inline>\n )}\n {!inputComponent &&\n releaseContext !== 'published' &&\n concept.childConcepts?.length == 0 &&\n concept.level == 5 && (\n <Inline>\n <StructureDetailDialogue\n type={'warn'}\n title={'Taxonomy Manager structure notice'}\n message={\n 'This concept is at the maximum Taxonomy Manager hierarchy depth of 5 levels. Additional child terms are not shown in the hierarchy tree.'\n }\n />\n <ConceptEditAction action={'remove'} handler={handleRemoveConcept} />\n </Inline>\n )}\n {concept?.childConcepts && concept?.childConcepts?.length > 0 && concept.level == 5 && (\n <Inline>\n <StructureDetailDialogue\n type={'error'}\n title={'Taxonomy Manager structure warning'}\n message={\n 'This concept has unlisted child concepts. The maximum validated hierarchy depth is 5 levels.'\n }\n />\n {!inputComponent && releaseContext !== 'published' && (\n <ConceptEditAction action={'remove'} handler={handleRemoveConcept} />\n )}\n </Inline>\n )}\n </Flex>\n {/* Child elements the next level down, if any */}\n {concept?.childConcepts &&\n concept.childConcepts.length > 0 &&\n concept?.level &&\n concept.level < 5 && (\n <ChildConcepts\n concepts={concept.childConcepts}\n selectConcept={selectConcept}\n inputComponent={inputComponent}\n childVisibility={levelVisibility}\n />\n )}\n </Box>\n )\n}\n","import {Box, Stack} from '@sanity/ui'\n\nimport type {ChildConceptTerm} from '../types'\n\nimport {Children} from './Children'\n\n/**\n * #### Child Concepts\n * Lenders a list of child concepts for a given concept\n * with a `<ul>` wrapper for each level of nesting\n */\nexport const ChildConcepts = ({\n concepts,\n inputComponent = false,\n selectConcept,\n childVisibility,\n}: {\n concepts: ChildConceptTerm[]\n selectConcept: (conceptId: {\n _ref: string\n _type: 'reference'\n _originalId: string | undefined\n }) => void\n inputComponent: boolean\n childVisibility: string // retype to 'open' | 'closed\n}) => {\n return (\n // the container for child terms\n <Box marginLeft={4} marginTop={2} display={childVisibility == 'closed' ? 'none' : 'block'}>\n <Stack space={3}>\n {concepts.map((concept: ChildConceptTerm) => {\n return (\n <Children\n key={concept.id}\n concept={concept}\n selectConcept={selectConcept}\n inputComponent={inputComponent}\n />\n )\n })}\n </Stack>\n </Box>\n )\n}\n","import {Inline, Box, Flex} from '@sanity/ui'\nimport {useCallback, useContext, useState} from 'react'\n\nimport {ReleaseContext, SchemeContext} from '../context'\nimport {useCreateConcept, useRemoveConcept} from '../hooks'\nimport type {ChildConceptTerm, ConceptSchemeDocument} from '../types'\n\nimport {ChildConcepts} from './ChildConcepts'\nimport {ConceptDetailDialogue} from './interactions/ConceptDetailDialogue'\nimport {ConceptDetailLink} from './interactions/ConceptDetailLink'\nimport {ConceptEditAction} from './interactions/ConceptEditAction'\nimport {ConceptSelectLink} from './interactions/ConceptSelectLink'\nimport {ToggleButton} from './interactions/ToggleButton'\n\ntype ConceptProps = {\n concept: ChildConceptTerm\n treeVisibility: string\n inputComponent: boolean\n selectConcept: (conceptId: {\n _ref: string\n _type: 'reference'\n _originalId: string | undefined\n }) => void\n}\n\n/**\n * #### Concept Component\n * Renders a list of concepts for a given schema.\n */\nexport const Concepts = ({\n concept,\n treeVisibility,\n inputComponent,\n selectConcept,\n}: ConceptProps) => {\n const document: ConceptSchemeDocument = useContext(SchemeContext) || ({} as ConceptSchemeDocument)\n const releaseContext = useContext(ReleaseContext)\n\n const hasTopConcept = !!document.displayed?.topConcepts?.length && !inputComponent\n\n const createConcept = useCreateConcept(document)\n const removeConcept = useRemoveConcept(document)\n\n const [levelVisibility, setLevelVisibility] = useState(\n treeVisibility === 'closed' && concept.hasMatchingDescendant ? 'open' : treeVisibility,\n )\n\n const handleToggle = useCallback(() => {\n if (levelVisibility == 'open') {\n setLevelVisibility('closed')\n } else if (levelVisibility == 'closed') {\n setLevelVisibility('open')\n }\n }, [levelVisibility])\n\n const handleAddChild = useCallback(() => {\n createConcept('concept', concept)\n }, [concept, createConcept])\n\n const handleRemoveConcept = useCallback(() => {\n removeConcept(concept.id, 'concept', concept?.prefLabel)\n }, [concept.id, concept?.prefLabel, removeConcept])\n\n return (\n <Box className={levelVisibility}>\n <Flex align={'center'} justify={'space-between'} wrap={'nowrap'}>\n {/* Toggle, label, tag — left half of flexbox */}\n <Flex align=\"center\" gap={0} flex={1} style={{minWidth: 0}}>\n {concept?.childConcepts && concept.childConcepts.length > 0 && (\n <ToggleButton handler={handleToggle} visibility={levelVisibility} />\n )}\n {!concept?.prefLabel && (\n <Box\n flex={1}\n marginLeft={!concept?.childConcepts || concept.childConcepts.length == 0 ? 5 : 0}\n >\n <ConceptDetailLink concept={concept} orphan={hasTopConcept} />\n </Box>\n )}\n {concept?.prefLabel && (\n <Box\n flex={1}\n marginLeft={!concept?.childConcepts || concept.childConcepts.length == 0 ? 5 : 0}\n >\n {inputComponent ? (\n <ConceptSelectLink\n concept={concept}\n selectConcept={selectConcept}\n orphan={hasTopConcept}\n />\n ) : (\n <ConceptDetailLink concept={concept} orphan={hasTopConcept} />\n )}\n </Box>\n )}\n </Flex>\n {/* Concept info and edit actions — right half of flexbox */}\n {inputComponent && <ConceptDetailDialogue concept={concept} />}\n {!inputComponent && releaseContext !== 'published' && (\n <Inline>\n <ConceptEditAction action={'add'} handler={handleAddChild} />\n <ConceptEditAction action={'remove'} handler={handleRemoveConcept} />\n </Inline>\n )}\n </Flex>\n {concept?.childConcepts && concept.childConcepts.length > 0 && (\n <ChildConcepts\n concepts={concept.childConcepts}\n selectConcept={selectConcept}\n inputComponent={inputComponent}\n childVisibility={levelVisibility}\n />\n )}\n </Box>\n )\n}\n","import {AddIcon} from '@sanity/icons'\nimport {Card, Label, Stack, Text, Button, Dialog, Box, TextArea, TextInput} from '@sanity/ui'\nimport {useCallback, useState} from 'react'\nimport type {SanityDocument} from 'sanity'\n\nimport {useAddTitle} from '../../hooks'\n\n/**\n * #### New Concept Scheme Guide\n * - Prompts adding title and description to new concept scheme.\n * - Data must be saved to newly created Concept Scheme documents before\n * add top concept / add concept buttons will work.\n */\nexport const NewScheme = ({document}: {document: SanityDocument}) => {\n const [open, setOpen] = useState(false)\n const [titleValue, setTitleValue] = useState('')\n const [descriptionValue, setDescriptionValue] = useState('')\n const onClose = useCallback(() => setOpen(false), [])\n const onOpen = useCallback(() => setOpen(true), [])\n\n const handleTitleChange = useCallback((event: any) => {\n setTitleValue(event.currentTarget.value)\n }, [])\n const handleDescriptionChange = useCallback((event: any) => {\n setDescriptionValue(event.currentTarget.value)\n }, [])\n\n const addTitle = useAddTitle()\n\n const handleAddTitle = useCallback(() => {\n addTitle(document, titleValue, descriptionValue)\n }, [addTitle, descriptionValue, document, titleValue])\n\n return (\n <div style={{marginTop: '2rem'}}>\n <Card padding={[3, 3, 4]} radius={2} shadow={1} tone=\"primary\">\n <Stack space={6}>\n <Stack space={4}>\n <Label size={4}>New Concept Scheme</Label>\n <Text size={2}>\n To start using hierarchy view taxonomy builder, first give your concept scheme a name\n and optional description. You can also use the \"Editor\" tab to add concepts to the\n tree manually.\n </Text>\n </Stack>\n <Button tone=\"primary\" fontSize={2} icon={AddIcon} onClick={onOpen} text=\"Add Title\" />\n </Stack>\n </Card>\n {open && (\n <Dialog\n header=\"Title & Description\"\n id=\"title-description\"\n onClose={onClose}\n zOffset={1000}\n width={1}\n >\n <Box padding={4}>\n <Stack space={4}>\n <Stack space={2}>\n <Label size={1}>Title</Label>\n <Text size={1} muted>\n Describe the concept scheme in one or two words.\n </Text>\n </Stack>\n <TextInput\n fontSize={2}\n onChange={handleTitleChange}\n padding={3}\n placeholder=\"\"\n value={titleValue}\n />\n <Stack space={2}>\n <Label size={1}>Description (optional)</Label>\n <Text size={1} muted>\n Describe the intended use of this concept scheme.\n </Text>\n </Stack>\n <TextArea\n fontSize={2}\n onChange={handleDescriptionChange}\n padding={3}\n placeholder=\"\"\n value={descriptionValue}\n rows={3}\n />\n <Button tone=\"primary\" fontSize={2} onClick={handleAddTitle} text=\"Save\" />\n </Stack>\n </Box>\n </Dialog>\n )}\n </div>\n )\n}\n","import {useToast} from '@sanity/ui'\nimport {useCallback} from 'react'\nimport {useClient} from 'sanity'\n\n/**\n * #### Add Title and Description to New Concept Scheme\n * Good for user experience, and also needed to write the\n * new scheme to the content lake, prior to which add top\n * concept / add concept buttons will not work.\n */\nexport function useAddTitle() {\n const toast = useToast()\n const client = useClient({apiVersion: '2021-10-21'})\n\n const addTitle = useCallback(\n (document: any, titleValue: string, descriptionValue?: string) => {\n const documentId = document.displayed?._id\n const schemaBaseIri = document.displayed?.baseIri\n const schemeId = document.displayed?.schemeId\n\n const doc = {\n _id: `drafts.${documentId}`,\n _type: 'skosConceptScheme',\n schemeId: schemeId,\n baseIri: schemaBaseIri,\n title: titleValue,\n description: descriptionValue ? descriptionValue : '',\n }\n\n client\n .createIfNotExists(doc)\n .then((_) => {\n if (descriptionValue) {\n return toast.push({\n closable: true,\n status: 'success',\n title: 'Title and Description added.',\n })\n }\n return toast.push({\n closable: true,\n status: 'success',\n title: 'Title added.',\n })\n })\n .catch((err) => {\n toast.push({\n closable: true,\n status: 'error',\n title: 'There has been an error',\n description: err.message,\n })\n })\n },\n [client, toast]\n )\n\n return addTitle\n}\n","import {Card, Label, Stack, Text} from '@sanity/ui'\n\n/**\n * #### No Concepts Guide\n * Prompts adding concepts to an empty scheme.\n */\nexport const NoConcepts = () => {\n return (\n <div style={{marginTop: '2rem'}}>\n <Card padding={[3, 3, 4]} radius={2} shadow={1} tone=\"primary\">\n <Stack space={4}>\n <Label size={4}>No Concepts</Label>\n <Text size={2}>\n There are not yet any concepts assigned to this scheme. To create a multi-level\n hierarchy with specific entry points, create Top Concepts first, then add child concepts\n to them. To create a flat list of concepts, create Concepts directly.\n </Text>\n </Stack>\n </Card>\n </div>\n )\n}\n","import {Flex, Inline, Box} from '@sanity/ui'\nimport {useCallback, useContext, useState} from 'react'\n\nimport {ReleaseContext, SchemeContext} from '../context'\nimport {useCreateConcept, useRemoveConcept} from '../hooks'\nimport type {ConceptSchemeDocument, TopConceptTerm} from '../types'\n\nimport {ChildConcepts} from './ChildConcepts'\nimport {ConceptDetailDialogue} from './interactions/ConceptDetailDialogue'\nimport {ConceptDetailLink} from './interactions/ConceptDetailLink'\nimport {ConceptEditAction} from './interactions/ConceptEditAction'\nimport {ConceptSelectLink} from './interactions/ConceptSelectLink'\nimport {ToggleButton} from './interactions/ToggleButton'\n\ntype TopConceptsProps = {\n concept: TopConceptTerm\n treeVisibility: string\n inputComponent: boolean\n selectConcept: (conceptId: {_ref: string; _type: 'reference'}) => void\n}\n\n/**\n * #### Top Concept Component\n * Renders a list of top concepts for a given schema.\n */\nexport const TopConcepts = ({\n concept,\n treeVisibility,\n inputComponent,\n selectConcept,\n}: TopConceptsProps) => {\n const document: ConceptSchemeDocument = useContext(SchemeContext) || ({} as ConceptSchemeDocument)\n const releaseContext = useContext(ReleaseContext)\n\n const createConcept = useCreateConcept(document)\n const removeConcept = useRemoveConcept(document)\n\n const [levelVisibility, setLevelVisibility] = useState(\n treeVisibility === 'closed' && concept.hasMatchingDescendant ? 'open' : treeVisibility,\n )\n\n const handleToggle = useCallback(() => {\n if (levelVisibility == 'open') {\n setLevelVisibility('closed')\n } else if (levelVisibility == 'closed') {\n setLevelVisibility('open')\n }\n }, [levelVisibility])\n\n const handleAddChild = useCallback(() => {\n createConcept('concept', concept)\n }, [concept, createConcept])\n\n const handleRemoveConcept = useCallback(() => {\n removeConcept(concept?.id, 'topConcept', concept?.prefLabel)\n }, [concept?.id, concept?.prefLabel, removeConcept])\n\n return (\n <Box className={levelVisibility}>\n <Flex align={'center'} justify={'space-between'} wrap={'nowrap'}>\n {/* Toggle, label, tag — left half of flexbox */}\n <Flex align=\"center\" gap={0} flex={1} style={{minWidth: 0}}>\n {concept?.childConcepts && concept.childConcepts.length > 0 && (\n <ToggleButton handler={handleToggle} visibility={levelVisibility} />\n )}\n {!concept?.prefLabel && (\n <Box\n flex={1}\n marginLeft={!concept?.childConcepts || concept.childConcepts.length == 0 ? 5 : 0}\n >\n <ConceptDetailLink concept={concept} topConcept />\n </Box>\n )}\n {concept?.prefLabel && (\n <Box\n flex={1}\n marginLeft={!concept?.childConcepts || concept.childConcepts.length == 0 ? 5 : 0}\n >\n {inputComponent ? (\n <ConceptSelectLink concept={concept} selectConcept={selectConcept} topConcept />\n ) : (\n <ConceptDetailLink concept={concept} topConcept />\n )}\n </Box>\n )}\n </Flex>\n {/* Concept info and edit actions — right half of flexbox */}\n {inputComponent && <ConceptDetailDialogue concept={concept} />}\n {!inputComponent && releaseContext !== 'published' && (\n <Inline>\n <ConceptEditAction action={'add'} handler={handleAddChild} />\n <ConceptEditAction action={'remove'} handler={handleRemoveConcept} />\n </Inline>\n )}\n </Flex>\n {/* Child Concepts */}\n {concept?.childConcepts && concept.childConcepts.length > 0 && (\n <ChildConcepts\n concepts={concept.childConcepts}\n selectConcept={selectConcept}\n inputComponent={inputComponent}\n childVisibility={levelVisibility}\n />\n )}\n </Box>\n )\n}\n","import {Box, Stack} from '@sanity/ui'\nimport {useContext} from 'react'\n\nimport {TreeContext} from '../context'\nimport type {DocumentConcepts, TopConceptTerm, ChildConceptTerm} from '../types'\n\nimport {Concepts} from './Concepts'\nimport {NoConcepts} from './guides'\nimport {TopConcepts} from './TopConcepts'\n\n/**\n * #### Tree View\n * Fetches the complete tree of concepts in a concept scheme, stemming\n * from Top Concepts or Orphans. Displays the tree in a nested list.\n */\nexport const TreeStructure = ({\n concepts,\n inputComponent,\n selectConcept,\n}: {\n concepts: DocumentConcepts | null\n inputComponent: boolean\n selectConcept: (conceptId: {_ref: string; _type: 'reference'; _originalId?: string}) => void\n}) => {\n const {globalVisibility: {treeId, treeVisibility} = {treeId: 'default', treeVisibility: 'open'}} =\n useContext(TreeContext) || {}\n\n if (!concepts?.topConcepts?.length && !concepts?.concepts?.length) {\n return <NoConcepts />\n }\n\n return (\n <Box paddingTop={4}>\n <Stack space={3} style={{listStyle: 'none', paddingLeft: '0', marginBlockStart: '0'}}>\n {concepts?.topConcepts?.map((concept: TopConceptTerm) => (\n <TopConcepts\n key={`${concept?.id}+${treeId}`}\n concept={concept}\n treeVisibility={treeVisibility}\n inputComponent={inputComponent}\n selectConcept={selectConcept}\n />\n ))}\n {concepts?.concepts\n ?.filter((concept: ChildConceptTerm) => concept?.isOrphan)\n .map((concept: ChildConceptTerm) => {\n return (\n <Concepts\n key={`${concept.id}+${treeId}`}\n concept={concept}\n treeVisibility={treeVisibility}\n inputComponent={inputComponent}\n selectConcept={selectConcept}\n />\n )\n })}\n </Stack>\n </Box>\n )\n}\n","import type {DocumentId} from '@sanity/id-utils'\nimport {getPublishedId} from '@sanity/id-utils'\nimport {Flex, Spinner, Box, Text, Card} from '@sanity/ui'\nimport {nanoid} from 'nanoid'\nimport {useContext, useMemo} from 'react'\n\nimport {ReleaseContext, SchemeContext, TreeContext} from '../../context'\nimport {recommendedConceptIds} from '../../core/semanticRecommendations'\nimport {annotateRecommendations} from '../../core/tree/annotateRecommendations'\nimport {useTaxonomyDataPort} from '../../seams/TaxonomyPortContext'\nimport type {ConceptSchemeDocument, TreeViewProps} from '../../types'\nimport {TreeStructure} from '../TreeStructure'\n\n/**\n * #### Input Hierarchy Component\n * - Provides a frame for global controls and tree structure\n * - Fetches the complete tree of concepts in a concept scheme.\n * - Displays the tree in a nested list.\n * @param inputComponent - Specifies whether the component is a Studio\n * input component. Set in HierarchyInput and passed through TreeView\n */\nexport const InputHierarchy = ({\n branchId = '',\n selectConcept,\n inputComponent,\n expanded,\n conceptRecs,\n recsError,\n}: TreeViewProps) => {\n const document: ConceptSchemeDocument = useContext(SchemeContext) || ({} as ConceptSchemeDocument)\n const documentId = getPublishedId(document.displayed?._id as DocumentId)\n const releaseContext = useContext(ReleaseContext)\n const initialVisibility = expanded ? 'open' : 'closed'\n const port = useTaxonomyDataPort()\n const {data, loading, error} = port.useWatchTree({\n mode: 'input',\n documentId,\n branchId,\n perspective: releaseContext,\n })\n\n // Mark which concepts are recommendations (by published id):\n const recommendedIds = useMemo(() => recommendedConceptIds(conceptRecs ?? []), [conceptRecs])\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const treeId = useMemo(() => nanoid(6), [recommendedIds])\n\n // Compute merged data with useMemo:\n const mergedData = useMemo(() => {\n if (!data || recommendedIds.size === 0 || recsError) return data\n return {\n topConcepts: data.topConcepts?.map((tc) => annotateRecommendations(tc, recommendedIds)),\n concepts: data.concepts?.map((c) => annotateRecommendations(c, recommendedIds)),\n }\n }, [data, recommendedIds, recsError])\n\n if (loading) {\n return (\n <Box padding={5}>\n <Flex\n align=\"center\"\n direction=\"column\"\n gap={5}\n height=\"fill\"\n justify=\"center\"\n style={{paddingTop: '1rem'}}\n >\n <Spinner muted />\n <Text muted size={1}>\n Loading hierarchy…\n </Text>\n </Flex>\n </Box>\n )\n } else if (error) {\n console.warn(error)\n return (\n <Box padding={4}>\n <Card padding={[3]} radius={2} shadow={1} tone=\"caution\">\n <Text size={1}>\n There was a problem loading terms. Please check the scheme configuration and try again.\n </Text>\n </Card>\n </Box>\n )\n } else if (!data) {\n return (\n <Box padding={4}>\n <Card padding={[3]} radius={2} shadow={1} tone=\"caution\">\n <Text size={1}>\n This configuration does not have any terms associated with it. Please check the scheme\n and branch supplied and try again.\n </Text>\n </Card>\n </Box>\n )\n }\n return (\n <TreeContext.Provider value={{globalVisibility: {treeId, treeVisibility: initialVisibility}}}>\n <Box padding={4} paddingTop={0}>\n {recsError && (\n <Card marginTop={2} padding={3} radius={2} shadow={1} tone=\"caution\">\n <Text size={2}>{recsError}</Text>\n </Card>\n )}\n <TreeStructure\n concepts={mergedData}\n inputComponent={inputComponent || false}\n selectConcept={selectConcept || (() => undefined)}\n />\n </Box>\n </TreeContext.Provider>\n )\n}\n","export default function NodeTree() {\n return (\n <svg\n data-sanity-icon\n width=\"25\"\n height=\"25\"\n viewBox=\"0 0 25 25\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M5.5 6.5V5.9H4.9V6.5H5.5ZM11.5 6.5H12.1V5.9H11.5V6.5ZM5.5 9H4.9V9.6H5.5V9ZM11.5 9V9.6H12.1V9H11.5ZM13.5 11V10.4H12.9V11H13.5ZM19.5 11H20.1V10.4H19.5V11ZM13.5 13.5H12.9V14.1H13.5V13.5ZM19.5 13.5V14.1H20.1V13.5H19.5ZM13.5 16V15.4H12.9V16H13.5ZM19.5 16H20.1V15.4H19.5V16ZM13.5 18.5H12.9V19.1H13.5V18.5ZM19.5 18.5V19.1H20.1V18.5H19.5ZM5.5 7.1H11.5V5.9H5.5V7.1ZM6.1 9V6.5H4.9V9H6.1ZM11.5 8.4H5.5V9.6H11.5V8.4ZM10.9 6.5V9H12.1V6.5H10.9ZM13.5 11.6H19.5V10.4H13.5V11.6ZM14.1 13.5V11H12.9V13.5H14.1ZM19.5 12.9H13.5V14.1H19.5V12.9ZM18.9 11V13.5H20.1V11H18.9ZM13.5 16.6H19.5V15.4H13.5V16.6ZM14.1 18.5V16H12.9V18.5H14.1ZM19.5 17.9H13.5V19.1H19.5V17.9ZM18.9 16V18.5H20.1V16H18.9ZM8 17.85H13.5V16.65H8V17.85ZM8 12.85H13.5V11.65H8V12.85ZM7.9 9.5V17.85H9.1V9.5H7.9Z\"\n fill=\"currentColor\"\n />\n </svg>\n )\n}\n","import type {ChildConceptTerm, DocumentConcepts} from '../../types'\n\ntype ConceptNodeList = readonly {id: string; childConcepts?: ChildConceptTerm[]}[] | undefined\n\n/**\n * Recursively remove every concept whose `id` is in `removedIds` from a concept\n * tree — top concepts, orphan/concepts, and all nested `childConcepts`. Returns\n * a new tree without mutating the input; passes `null` and an empty removal set\n * through unchanged (same reference).\n *\n * Used by the optimistic-removal layer in `Hierarchy`: a concept unset from a\n * scheme disappears tree-wide (the trunk query gates every node on scheme\n * membership), so pruning by id mirrors what the live listener will eventually\n * return — letting the tree update instantly instead of waiting on the refetch.\n */\nexport function pruneConcepts(\n data: DocumentConcepts | null,\n removedIds: ReadonlySet<string>\n): DocumentConcepts | null {\n if (!data || removedIds.size === 0) return data\n return {\n ...data,\n topConcepts: (data.topConcepts ?? [])\n .filter((concept) => !removedIds.has(concept.id))\n .map((concept) =>\n concept.childConcepts\n ? {...concept, childConcepts: pruneChildren(concept.childConcepts, removedIds)}\n : concept\n ),\n concepts: (data.concepts ?? [])\n .filter((concept) => !removedIds.has(concept.id))\n .map((concept) =>\n concept.childConcepts\n ? {...concept, childConcepts: pruneChildren(concept.childConcepts, removedIds)}\n : concept\n ),\n }\n}\n\nfunction pruneChildren(\n children: ChildConceptTerm[],\n removedIds: ReadonlySet<string>\n): ChildConceptTerm[] {\n return children\n .filter((concept) => !removedIds.has(concept.id))\n .map((concept) =>\n concept.childConcepts\n ? {...concept, childConcepts: pruneChildren(concept.childConcepts, removedIds)}\n : concept\n )\n}\n\n/**\n * Collect every concept `id` present anywhere in the tree (top, orphan, and all\n * nested children). Used to reconcile the optimistic removal set against fresh\n * listener data — once an id is gone from the data, it can be forgotten.\n */\nexport function collectConceptIds(data: DocumentConcepts | null): Set<string> {\n const ids = new Set<string>()\n const walk = (concepts: ConceptNodeList): void => {\n if (!concepts) return\n for (const concept of concepts) {\n ids.add(concept.id)\n walk(concept.childConcepts)\n }\n }\n if (data) {\n walk(data.topConcepts)\n walk(data.concepts)\n }\n return ids\n}\n","import {AddCircleIcon} from '@sanity/icons'\nimport type {DocumentId} from '@sanity/id-utils'\nimport {getPublishedId} from '@sanity/id-utils'\nimport {Flex, Spinner, Stack, Box, Text, Inline, Card, Button} from '@sanity/ui'\nimport {nanoid} from 'nanoid'\nimport {useCallback, useContext, useEffect, useMemo, useState} from 'react'\n\nimport {OptimisticTreeContext, SchemeContext, TreeContext, ReleaseContext} from '../context'\nimport {collectConceptIds, pruneConcepts} from '../core/tree/pruneConcepts'\nimport {useCreateConcept} from '../hooks'\nimport {useTaxonomyDataPort} from '../seams/TaxonomyPortContext'\nimport type {ConceptSchemeDocument, TreeViewProps} from '../types'\n\nimport {NewScheme} from './guides'\nimport {TreeStructure} from './TreeStructure'\n\n/**\n * #### Hierarchy Component\n * Provides a frame for global controls and tree structure and displays\n * controls to add concepts or top concepts when in draft mode or release mode.\n * @param inputComponent - Whether this is an input component.\n * @param branchId - Input component: The branch ID to fetch concepts from.\n * @param selectConcept - Input component: The function to call when a concept is selected.\n */\nexport const Hierarchy = ({\n inputComponent = false,\n // branchId = '',\n selectConcept,\n}: TreeViewProps) => {\n const document: ConceptSchemeDocument = useContext(SchemeContext) || ({} as ConceptSchemeDocument)\n const documentId = getPublishedId(document.displayed?._id as DocumentId)\n const releaseContext = useContext(ReleaseContext)\n\n const port = useTaxonomyDataPort()\n const createConcept = useCreateConcept(document)\n const createTopConcept = useCallback(() => {\n createConcept('topConcept')\n }, [createConcept])\n const createEntryConcept = useCallback(() => {\n createConcept('concept')\n }, [createConcept])\n\n // Expand & Collapse Controls\n // short IDs are used on treeId to initiate a re-rendering of all child\n // elements on expand/collapse and re-initialize any local toggle state\n // that had been set.\n const [globalVisibility, setGlobalVisibility] = useState<{\n treeId: string\n treeVisibility: 'open' | 'closed'\n }>({\n treeId: nanoid(6),\n treeVisibility: 'open',\n })\n const handleExpand = useCallback(() => {\n setGlobalVisibility({treeId: nanoid(6), treeVisibility: 'open'})\n }, [])\n const handleCollapse = useCallback(() => {\n setGlobalVisibility({treeId: nanoid(6), treeVisibility: 'closed'})\n }, [])\n\n // Optimistic removal: prune a removed concept from the tree immediately, then\n // let the live listener reconcile (see core/tree/pruneConcepts). markRemoved is\n // reached by the deep remove actions through OptimisticTreeContext below.\n const [removedIds, setRemovedIds] = useState<Set<string>>(() => new Set())\n const markRemoved = useCallback((id: string) => {\n setRemovedIds((prev) => {\n if (prev.has(id)) return prev\n const next = new Set(prev)\n next.add(id)\n return next\n })\n }, [])\n const unmarkRemoved = useCallback((id: string) => {\n setRemovedIds((prev) => {\n if (!prev.has(id)) return prev\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n }, [])\n const optimisticValue = useMemo(\n () => ({markRemoved, unmarkRemoved}),\n [markRemoved, unmarkRemoved],\n )\n\n const {data, loading, error} = port.useWatchTree({\n mode: 'trunk',\n documentId,\n perspective: releaseContext,\n })\n\n // Once fresh data no longer contains a removed id, stop tracking it so the\n // optimistic set self-cleans and never prunes a later re-added concept.\n useEffect(() => {\n setRemovedIds((prev) => {\n if (prev.size === 0) return prev\n const present = collectConceptIds(data)\n const next = new Set([...prev].filter((id) => present.has(id)))\n return next.size === prev.size ? prev : next\n })\n }, [data])\n\n const prunedData = useMemo(() => pruneConcepts(data, removedIds), [data, removedIds])\n\n if (loading) {\n return (\n <Box padding={4} paddingTop={6}>\n <Flex align=\"center\" direction=\"column\" gap={5} height=\"fill\" justify=\"center\">\n <Spinner muted />\n <Text muted size={1}>\n Loading hierarchy…\n </Text>\n </Flex>\n </Box>\n )\n } else if (error) {\n console.error(error)\n return <div>Error here</div>\n } else if (!prunedData) {\n return <NewScheme document={document} />\n }\n return (\n <TreeContext.Provider value={{globalVisibility}}>\n <Box padding={4}>\n <>\n <Stack space={4}>\n <Card borderBottom paddingBottom={1} display={'flex'} flex={1}>\n <Flex justify={'space-between'} flex={1}>\n <Card>\n {(prunedData.topConcepts?.filter(\n (concept) => (concept?.childConcepts?.length ?? 0) > 0,\n ).length > 0 ||\n prunedData.concepts?.filter(\n (concept) => (concept?.childConcepts?.length ?? 0) > 0,\n ).length > 0) && (\n <Inline space={1}>\n <Button\n text={'Collapse'}\n paddingY={2}\n mode={'bleed'}\n onClick={handleCollapse}\n />\n <Text weight=\"semibold\" muted size={1}>\n |\n </Text>\n <Button text={'Expand'} paddingY={2} mode={'bleed'} onClick={handleExpand} />\n </Inline>\n )}\n </Card>\n <Card>\n {releaseContext !== 'published' && (\n <Inline space={1}>\n <Button\n text={'Add Top Concept'}\n icon={AddCircleIcon}\n mode={'bleed'}\n tone={'positive'}\n paddingY={2}\n onClick={createTopConcept}\n />\n <Button\n text={'Add Concept'}\n icon={AddCircleIcon}\n mode={'bleed'}\n tone={'positive'}\n paddingY={2}\n onClick={createEntryConcept}\n />\n </Inline>\n )}\n </Card>\n </Flex>\n </Card>\n </Stack>\n <OptimisticTreeContext.Provider value={optimisticValue}>\n <TreeStructure\n concepts={prunedData}\n inputComponent={inputComponent}\n selectConcept={selectConcept || (() => undefined)}\n />\n </OptimisticTreeContext.Provider>\n </>\n </Box>\n </TreeContext.Provider>\n )\n}\n\nexport default Hierarchy\n","import {Box, Container, Stack, Text} from '@sanity/ui'\nimport {usePerspective} from 'sanity'\n\nimport {ReleaseContext, SchemeContext} from '../context'\nimport type {ConceptSchemeDocument, TreeViewProps} from '../types'\n\nimport {Hierarchy} from './Hierarchy'\nimport {InputHierarchy} from './inputs'\n\n/**\n * #### Tree View Component Wrapper\n * This is the view component for the hierarchy tree. It is the\n * top level of concept scheme views and is passed into Desk\n * structure to render the primary view for taxonomy documents.\n * @param document - The document to render.\n * @param branchId - The branch ID to fetch concepts from.\n * @param inputComponent - Specifies whether the component is Studio input component, which will hide tree view controls and chrome.\n * @param selectConcept - The function to call when a concept is selected.\n */\nexport const TreeView = ({\n document,\n branchId,\n inputComponent = false,\n selectConcept,\n expanded,\n conceptRecs,\n recsError,\n}: TreeViewProps) => {\n const {selectedPerspectiveName} = usePerspective()\n return (\n <SchemeContext.Provider value={document || ({} as ConceptSchemeDocument)}>\n <ReleaseContext.Provider value={selectedPerspectiveName}>\n {inputComponent ? (\n <InputHierarchy\n inputComponent={inputComponent}\n branchId={branchId}\n selectConcept={selectConcept}\n expanded={expanded}\n conceptRecs={conceptRecs}\n recsError={recsError}\n />\n ) : (\n <Container width={1}>\n {document?.displayed?.description && (\n <Box padding={4} paddingTop={6}>\n <Stack space={4}>\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n Description\n </Text>\n <Text size={2} muted>\n {document?.displayed.description}\n </Text>\n </Stack>\n </Stack>\n </Box>\n )}\n <Hierarchy inputComponent={inputComponent} branchId={branchId} />\n </Container>\n )}\n </ReleaseContext.Provider>\n </SchemeContext.Provider>\n )\n}\n\nexport default TreeView\n","import {isVersionId} from '@sanity/id-utils'\nimport type {DocumentId} from '@sanity/id-utils'\nimport {Grid, Stack, Button, Dialog, Box, Spinner, Text, Flex, Card} from '@sanity/ui'\nimport {useState, useEffect, useCallback} from 'react'\nimport type {ObjectFieldProps, ObjectOptions, Reference} from 'sanity'\nimport {FormField, isDraftId, useClient, useFormValue, usePerspective} from 'sanity'\n\nimport {useTaxonomyDataPort} from '../../seams/TaxonomyPortContext'\nimport NodeTree from '../../static/NodeTree'\nimport type {ConceptSchemeDocument, SemanticSearchConfig} from '../../types'\nimport {TreeView} from '../TreeView'\n\ntype ReferenceOptions = ObjectOptions & {\n filter: ({getClient}: {getClient: () => ReturnType<typeof useClient>}) => Promise<{\n filter: string\n params: {\n concepts: string[]\n topConcepts?: string[]\n schemeId: string\n branchId?: string\n }\n expanded?: boolean\n browseOnly?: boolean\n }>\n}\n\ntype HierarchyInput = ObjectFieldProps<Reference> & {\n semanticSearch?: SemanticSearchConfig\n}\n\n// Extract the return type of the filter function\ntype FilterResult = Awaited<ReturnType<ReferenceOptions['filter']>>\n\n/**\n * Input component that replaces Sanity's default reference field input with a\n * hierarchical taxonomy tree browser. Studio users can browse taxonomy terms\n * organized in their scheme hierarchy and select a single term for the field.\n *\n * @remarks\n * - Must be used with a `schemeFilter` or `branchFilter` helper in the field's\n * `options.filter`. Rendering without a filter will display a configuration warning.\n * - Taxonomy selection is disabled when viewing the published perspective.\n * - When `browseOnly` is set in the filter configuration, Sanity's default search input\n * is suppressed and only the tree browser is available for term selection.\n * - When `expanded` is set in the filter configuration, the hierarchy tree loads open\n * by default instead of collapsed.\n *\n * @param props - Standard Sanity `ObjectFieldProps<Reference>` extended with an optional\n * `semanticSearch` configuration object.\n * @param props.semanticSearch - Optional configuration for AI-assisted term\n * recommendations. When provided, opening the tree browser scores `skosConcept`\n * documents against the dataset's embeddings (`text::semanticSimilarity()`) and\n * annotates matching taxonomy terms with a relevance score to help authors\n * identify the most appropriate term. Requires dataset embeddings to be enabled.\n * @param props.semanticSearch.fieldReferences - An array of field names from the\n * current document whose values are concatenated and sent as the search query.\n * All listed fields must contain values when the tree browser is opened; empty\n * fields will display a message in the tree view rather than scores.\n * @param props.semanticSearch.maxResults - Maximum number of semantically matching\n * terms to return. Defaults to `3`.\n *\n * @example\n * Basic usage with a scheme filter:\n * ```js\n * import {ReferenceHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'\n *\n * defineField({\n * name: 'gradeLevel',\n * title: 'Grade Level',\n * type: 'reference',\n * to: {type: 'skosConcept'},\n * options: {\n * filter: schemeFilter({schemeId: 'f3deba'}),\n * disableNew: true,\n * },\n * components: {field: ReferenceHierarchyInput},\n * })\n * ```\n *\n * @example\n * Branch filter with tree expanded by default:\n * ```js\n * import {ReferenceHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'\n *\n * defineField({\n * name: 'topics',\n * title: 'Topics',\n * type: 'reference',\n * to: {type: 'skosConcept'},\n * options: {\n * filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', expanded: true}),\n * disableNew: true,\n * },\n * components: {field: ReferenceHierarchyInput},\n * })\n * ```\n *\n * @example\n * Browse-only mode (suppresses the default Sanity search input):\n * ```js\n * import {ReferenceHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'\n *\n * defineField({\n * name: 'topics',\n * title: 'Topics',\n * type: 'reference',\n * to: {type: 'skosConcept'},\n * options: {\n * filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', browseOnly: true}),\n * disableNew: true,\n * },\n * components: {field: ReferenceHierarchyInput},\n * })\n * ```\n *\n * @example\n * AI-assisted recommendations via dataset embeddings:\n * ```jsx\n * import {ReferenceHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'\n *\n * defineField({\n * name: 'topics',\n * title: 'Topics',\n * type: 'reference',\n * to: [{type: 'skosConcept'}],\n * options: {\n * filter: schemeFilter({schemeId: 'f3deba'}),\n * disableNew: true,\n * },\n * components: {\n * field: (props) => (\n * <ReferenceHierarchyInput\n * {...props}\n * semanticSearch={{\n * fieldReferences: ['title', 'metaDescription'],\n * maxResults: 4,\n * }}\n * />\n * ),\n * },\n * })\n * ```\n *\n * @see {@link ArrayHierarchyInput} for multi-value `array` fields\n * @see {@link schemeFilter} for filtering by a full concept scheme\n * @see {@link branchFilter} for filtering by a branch within a concept scheme\n */\nexport function ReferenceHierarchyInput(props: HierarchyInput) {\n const client = useClient({apiVersion: 'vX'})\n\n // the resource document in which the input component appears:\n const documentId = useFormValue(['_id']) as string\n\n // name of the field to input a value\n const {name, title, value, semanticSearch} = props\n\n const port = useTaxonomyDataPort()\n const {conceptRecs, recsError, triggerSearch} = port.useSemanticRecommendations(semanticSearch)\n\n // Get release and draft status of the document\n const isInRelease = isVersionId(documentId as DocumentId)\n const isDraft = isDraftId(documentId as DocumentId)\n\n // Selected Perspective is also used in the Tree view component. Consider tidying.\n const {selectedPerspectiveName} = usePerspective()\n\n const [schemeLoading, setSchemeLoading] = useState(true)\n const [valuesLoading, setValuesLoading] = useState(true)\n const [open, setOpen] = useState(false)\n\n // the skosConceptScheme document identified by the field filter options:\n const [scheme, setScheme] = useState<ConceptSchemeDocument | undefined>(undefined)\n\n // State to store resolved filter values:\n const [filterValues, setFilterValues] = useState<FilterResult | undefined>()\n\n // use filterValues if available, otherwise fallback to default:\n const {schemeId, branchId = null} = filterValues?.params || {}\n\n const {filter} = props.schemaType.options as ReferenceOptions\n\n // Fetch filter values from `reference` field filter asynchronously.\n useEffect(() => {\n async function fetchFilterValues() {\n try {\n const resolvedFilterValues = await filter({getClient: () => client})\n setFilterValues(resolvedFilterValues)\n // Store the resolved filter values in state\n setValuesLoading(false)\n } catch (error) {\n console.error('Error fetching filter values: ', error)\n }\n }\n fetchFilterValues().catch((error) => console.error('Error fetching filter values: ', error))\n }, [filter, client])\n\n // get the skosConceptScheme document identified by the field filter options\n useEffect(() => {\n if (!schemeId) return\n client\n .fetch('{\"displayed\": *[schemeId == $schemeId][0]}', {schemeId})\n .then((res: {displayed?: ConceptSchemeDocument['displayed']}) => {\n if (res?.displayed) {\n setScheme(res as ConceptSchemeDocument)\n setSchemeLoading(false)\n }\n })\n .catch((err) => console.warn(err))\n }, [client, schemeId])\n\n const browseHierarchy = useCallback(() => {\n setOpen(true)\n triggerSearch(schemeId)\n }, [triggerSearch, schemeId])\n\n const handleClose = useCallback(() => {\n setOpen(false)\n }, [])\n\n /**\n * #### Term Select Action\n * Writes the selected taxonomy term to the document field\n */\n const handleAction = useCallback(\n (conceptId: {\n _ref: string\n _type: 'reference'\n _originalId?: string\n _strengthenOnPublish?: {type: 'skosConcept'; template: {id: 'skosConcept'}}\n _weak?: boolean\n }) => {\n if (\n isDraftId(conceptId?._originalId as DocumentId) ||\n isVersionId(conceptId?._originalId as DocumentId)\n ) {\n conceptId._strengthenOnPublish = {\n type: 'skosConcept',\n template: {id: 'skosConcept'},\n }\n conceptId._weak = true\n }\n\n delete conceptId._originalId\n\n // if there is a draft document, patch the new reference and\n // commit the change\n if (isDraft || isInRelease) {\n client\n .patch(documentId)\n .set({[name]: conceptId})\n .commit()\n .then(() => setOpen(false))\n .catch((err) => console.error(err))\n return\n }\n // if there is not a draft document, fetch the published\n // version and create a new document with the published\n // document id in the `drafts.` path and the new reference\n client\n .fetch('*[_id == $id][0]', {id: documentId})\n .then((res: ConceptSchemeDocument) => {\n res._id = `drafts.${res._id}`\n res[name] = conceptId\n client.create(res).catch((error) => console.error('Error creating draft: ', error))\n })\n .then(() => setOpen(false))\n .catch((err) => console.error(err))\n },\n [client, documentId, isDraft, isInRelease, name],\n )\n\n // Check to be sure a filter is present\n if (!(props.schemaType.options as ReferenceOptions)?.filter) {\n return (\n <Stack space={3}>\n {props.renderDefault(props)}\n <Box padding={4}>\n <Card padding={[3]} radius={2} shadow={1} tone=\"caution\">\n <Text size={1}>\n The <code>ReferenceHierarchyInput()</code> component must be used with an accompanying{' '}\n <code>schemeFilter()</code> or <code>branchFilter()</code>. Please add an appropriate\n filter to the configuration for the {title} field.\n </Text>\n </Card>\n </Box>\n </Stack>\n )\n }\n // ... and that it is a scheme or branch filter and configured correctly\n else if ((props.schemaType.options as ReferenceOptions)?.filter.length === 0) {\n return (\n <Stack space={3}>\n {props.renderDefault(props)}\n <Box padding={4}>\n <Card padding={[3]} radius={2} shadow={1} tone=\"caution\">\n <Text size={1}>\n There was a problem loading your filter settings. Please check the{' '}\n <code>schemeFilter()</code> or <code>branchFilter()</code> configuration for the{' '}\n {title} field.\n </Text>\n </Card>\n </Box>\n </Stack>\n )\n } else if (schemeLoading || valuesLoading) {\n return (\n <Box padding={5}>\n <Flex\n align=\"center\"\n direction=\"column\"\n gap={5}\n height=\"fill\"\n justify=\"center\"\n style={{paddingTop: '1rem'}}\n >\n <Spinner muted />\n <Text muted size={1}>\n Loading input component…\n </Text>\n </Flex>\n </Box>\n )\n }\n const isPublished = selectedPerspectiveName === 'published'\n\n // Render the browse-only preview UI\n const renderBrowseOnlyPreview = () => {\n if (value) {\n return props.renderDefault(props)\n }\n // Wrap the empty state in `FormField` so the field exposes the same\n // DOM target Sanity's Validation panel uses for scroll-to-field /\n // highlight on click. Without this wrapper, clicking a required\n // browse-only field's validation error has no effect.\n return (\n <FormField\n title={title}\n path={props.path}\n description={props.description}\n level={props.level}\n validation={props.validation}\n __unstable_presence={props.presence}\n >\n <Card padding={3} radius={2} border>\n <Text muted align=\"center\" size={1}>\n No items\n </Text>\n </Card>\n </FormField>\n )\n }\n\n return (\n <Stack space={4}>\n {filterValues?.browseOnly ? renderBrowseOnlyPreview() : props.renderDefault(props)}\n\n <Grid columns={1} gap={3}>\n <Button\n disabled={isPublished}\n icon={NodeTree}\n text=\"Browse taxonomy tree\"\n mode=\"ghost\"\n onClick={browseHierarchy}\n />\n </Grid>\n {open && scheme && (\n <Dialog\n header={title}\n id=\"concept-select-dialog\"\n onClose={handleClose}\n zOffset={900}\n width={1}\n >\n <Box padding={10}>\n <TreeView\n document={scheme}\n branchId={branchId}\n inputComponent\n selectConcept={handleAction}\n expanded={filterValues?.expanded}\n conceptRecs={conceptRecs}\n recsError={recsError}\n />\n </Box>\n </Dialog>\n )}\n </Stack>\n )\n}\n","import type {DocumentId} from '@sanity/id-utils'\nimport {\n Grid,\n Stack,\n Button,\n Dialog,\n Box,\n Card,\n Label,\n Text,\n useToast,\n Flex,\n Spinner,\n} from '@sanity/ui'\nimport {useState, useEffect, useCallback} from 'react'\nimport type {ArrayFieldProps, ObjectOptions} from 'sanity'\nimport {FormField, useClient, useFormValue, isVersionId, isDraftId, usePerspective} from 'sanity'\n\nimport {useTaxonomyDataPort} from '../../seams/TaxonomyPortContext'\nimport NodeTree from '../../static/NodeTree'\nimport type {ConceptSchemeDocument, SemanticSearchConfig} from '../../types'\nimport {TreeView} from '../TreeView'\n\ntype ReferenceOptions = ObjectOptions & {\n filter: ({getClient}: {getClient: () => ReturnType<typeof useClient>}) => Promise<{\n filter: string\n params: {\n concepts: string[]\n topConcepts?: string[]\n schemeId: string\n branchId?: string\n }\n expanded?: boolean\n browseOnly?: boolean\n }>\n}\n\ntype ArrayHierarchyInputProps = ArrayFieldProps & {\n semanticSearch?: SemanticSearchConfig\n}\n\n// Extract the return type of the filter function\ntype FilterResult = Awaited<ReturnType<ReferenceOptions['filter']>>\n\n/**\n * Input component that replaces Sanity's default array field input with a\n * hierarchical taxonomy tree browser. Studio users can browse taxonomy terms\n * organized in their scheme hierarchy and select terms to add to the array field.\n *\n * @remarks\n * - Must be used with a `schemeFilter` or `branchFilter` helper in the field's\n * `options.filter`. Rendering without a filter will display a configuration warning.\n * - Supports only **single-schema arrays** (i.e., `of: [{type: 'reference'}]`). Arrays\n * with multiple schema types will render a warning and fall back to the default input.\n * - Taxonomy selection is disabled when viewing the published perspective.\n * - When `browseOnly` is set in the filter configuration, Sanity's default search input\n * is suppressed and only the tree browser is available for term selection.\n * - When `expanded` is set in the filter configuration, the hierarchy tree loads open\n * by default instead of collapsed.\n *\n * @param props - Standard Sanity `ArrayFieldProps` extended with an optional\n * `semanticSearch` configuration object.\n * @param props.semanticSearch - Optional configuration for AI-assisted term\n * recommendations. When provided, opening the tree browser scores `skosConcept`\n * documents against the dataset's embeddings (`text::semanticSimilarity()`) and\n * annotates matching taxonomy terms with a relevance score to help authors\n * identify the most appropriate terms. Requires dataset embeddings to be enabled.\n * @param props.semanticSearch.fieldReferences - An array of field names from the\n * current document whose values are concatenated and sent as the search query.\n * All listed fields must contain values when the tree browser is opened; empty\n * fields will display a message in the tree view rather than scores.\n * @param props.semanticSearch.maxResults - Maximum number of semantically matching\n * terms to return. Defaults to `3`.\n *\n * @example\n * Basic usage with a scheme filter:\n * ```js\n * import {ArrayHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'\n *\n * defineField({\n * name: 'categories',\n * title: 'Categories',\n * type: 'array',\n * of: [\n * {\n * type: 'reference',\n * to: {type: 'skosConcept'},\n * options: {\n * filter: schemeFilter({schemeId: 'f3deba'}),\n * disableNew: true,\n * },\n * },\n * ],\n * components: {field: ArrayHierarchyInput},\n * })\n * ```\n *\n * @example\n * Branch filter with tree expanded by default:\n * ```js\n * import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'\n *\n * defineField({\n * name: 'habitats',\n * title: 'Habitats',\n * type: 'array',\n * of: [\n * {\n * type: 'reference',\n * to: {type: 'skosConcept'},\n * options: {\n * filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', expanded: true}),\n * disableNew: true,\n * },\n * },\n * ],\n * components: {field: ArrayHierarchyInput},\n * })\n * ```\n *\n * @example\n * Browse-only mode (suppresses the default Sanity search input):\n * ```js\n * import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'\n *\n * defineField({\n * name: 'habitats',\n * title: 'Habitats',\n * type: 'array',\n * of: [\n * {\n * type: 'reference',\n * to: {type: 'skosConcept'},\n * options: {\n * filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', browseOnly: true}),\n * disableNew: true,\n * },\n * },\n * ],\n * components: {field: ArrayHierarchyInput},\n * })\n * ```\n *\n * @example\n * AI-assisted recommendations via an embeddings index:\n * ```jsx\n * import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'\n *\n * defineField({\n * name: 'categories',\n * title: 'Categories',\n * type: 'array',\n * of: [\n * {\n * type: 'reference',\n * to: [{type: 'skosConcept'}],\n * options: {\n * filter: branchFilter({schemeId: 'f3deba', branchId: '25f826'}),\n * disableNew: true,\n * },\n * },\n * ],\n * components: {\n * field: (props) => (\n * <ArrayHierarchyInput\n * {...props}\n * semanticSearch={{\n * fieldReferences: ['title', 'description'],\n * maxResults: 4,\n * }}\n * />\n * ),\n * },\n * })\n * ```\n *\n * @see {@link ReferenceHierarchyInput} for single-value `reference` fields\n * @see {@link schemeFilter} for filtering by a full concept scheme\n * @see {@link branchFilter} for filtering by a branch within a concept scheme\n */\nexport function ArrayHierarchyInput(props: ArrayHierarchyInputProps) {\n const client = useClient({apiVersion: '2025-02-19'})\n\n // the resource document in which the input component appears:\n const documentId = useFormValue(['_id']) as string\n // name of the field to input a value:\n const {name, title, value = [], semanticSearch} = props\n\n // Get release and draft status of the document\n const isInRelease = isVersionId(documentId as DocumentId)\n const isDraft = isDraftId(documentId as DocumentId)\n // Selected Perspective is also used in the Tree view component. Consider tidying.\n const {selectedPerspectiveName} = usePerspective()\n\n const [schemeLoading, setSchemeLoading] = useState(true)\n const [valuesLoading, setValuesLoading] = useState(true)\n const [open, setOpen] = useState(false)\n\n // the skosConceptScheme document identified by the field filter options:\n const [scheme, setScheme] = useState({})\n // State to store resolved filter values:\n const [filterValues, setFilterValues] = useState<FilterResult | undefined>()\n\n // use filterValues if available, otherwise fallback to default:\n const {schemeId, branchId = null} = filterValues?.params || {}\n\n const {filter} = props.schemaType.of[0].options as ReferenceOptions\n\n const port = useTaxonomyDataPort()\n const {conceptRecs, recsError, triggerSearch} = port.useSemanticRecommendations(semanticSearch)\n\n const toast = useToast()\n\n // Fetch filter values from `reference` field filter asynchronously\n useEffect(() => {\n async function fetchFilterValues() {\n try {\n const resolvedFilterValues = await filter({getClient: () => client})\n setFilterValues(resolvedFilterValues)\n // Store the resolved filter values in state\n setValuesLoading(false)\n } catch (error) {\n console.error('Error fetching filter values: ', error)\n }\n }\n fetchFilterValues().catch((error) => console.error('Error fetching filter values: ', error))\n }, [filter, client])\n\n // get the skosConceptScheme document identified by the field filter options\n useEffect(() => {\n if (!schemeId) return\n client\n .fetch(`{\"displayed\": *[schemeId == \"${schemeId}\"][0]}`)\n .then((res: {displayed?: ConceptSchemeDocument['displayed']}) => {\n if (res?.displayed) {\n setScheme(res)\n setSchemeLoading(false)\n }\n })\n .catch((err) => console.warn(err))\n }, [client, schemeId])\n\n const browseHierarchy = useCallback(() => {\n setOpen(true)\n triggerSearch(schemeId)\n }, [triggerSearch, schemeId])\n\n const handleClose = useCallback(() => {\n setOpen(false)\n }, [])\n\n /**\n * #### Term Select Action\n * Writes the selected taxonomy term to the array field\n */\n const handleAction = useCallback(\n (conceptId: {\n _ref: string\n _type: 'reference'\n _originalId?: string\n _strengthenOnPublish?: {type: 'skosConcept'; template: {id: 'skosConcept'}}\n _weak?: boolean\n }) => {\n if (\n isDraftId(conceptId?._originalId as string) ||\n isVersionId(conceptId?._originalId as string)\n ) {\n conceptId._strengthenOnPublish = {\n type: 'skosConcept',\n template: {id: 'skosConcept'},\n }\n conceptId._weak = true\n }\n\n delete conceptId._originalId\n\n // If the ref of the selected term is already in the field close the dialog\n // and provide a toast message that tht entry is already in the field.\n const typedValue = value as Array<{_key: string; _ref: string}> | undefined\n if (typedValue?.map((item) => item._ref).includes(conceptId._ref)) {\n setOpen(false)\n toast.push({\n status: 'warning',\n title: 'Taxonomy Term Not Added',\n description: 'The selected concept is already included in this field.',\n duration: 5000,\n closable: true,\n })\n return\n }\n // if there is a draft document, patch the new reference and\n // commit the change\n if (isDraft || isInRelease) {\n client\n .patch(documentId)\n .setIfMissing({[name]: []})\n .append(name, [conceptId])\n .commit({autoGenerateArrayKeys: true})\n .then(() => setOpen(false))\n .catch((err) => console.error(err))\n return\n }\n // if there is not a draft document, fetch the published\n // version and create a new document with the published\n // document id in the `drafts.` path and the new reference\n client\n .fetch(`*[_id == \"${documentId}\"][0]`)\n .then((res: ConceptSchemeDocument) => {\n res._id = `drafts.${res._id}`\n client.create(res).catch((error) => console.error('Error creating draft: ', error))\n })\n .then(() => {\n client\n .patch(`drafts.${documentId}`)\n .setIfMissing({[name]: []})\n .append(name, [conceptId])\n .commit({autoGenerateArrayKeys: true})\n .then(() => setOpen(false))\n .catch((err) => console.error(err))\n })\n .catch((err) => console.error(err))\n },\n [value, isDraft, isInRelease, client, documentId, toast, name],\n )\n\n // Check to be sure a filter is present\n if (!(props.schemaType.of[0].options as ReferenceOptions)?.filter) {\n return (\n <Stack space={3}>\n {props.renderDefault(props)}\n <Box padding={4}>\n <Card padding={[3]} radius={2} shadow={1} tone=\"caution\">\n <Text size={1}>\n The <code>ArrayHierarchyInput()</code> component must be used with an accompanying{' '}\n <code>schemeFilter()</code> or <code>branchFilter()</code>. Please add an appropriate\n filter to the configuration for the {title} field.\n </Text>\n </Card>\n </Box>\n </Stack>\n )\n }\n // ... and that it is a scheme or branch filter and configured correctly\n else if ((props.schemaType.of[0].options as ReferenceOptions)?.filter?.length === 0) {\n return (\n <Stack space={3}>\n {props.renderDefault(props)}\n <Box padding={4}>\n <Card padding={[3]} radius={2} shadow={1} tone=\"caution\">\n <Text size={1}>\n There was a problem loading your filter settings. Please check the{' '}\n <code>schemeFilter()</code> or <code>branchFilter()</code> configuration for the{' '}\n {title} field.\n </Text>\n </Card>\n </Box>\n </Stack>\n )\n }\n // Check to see if array uses more than one schema and bail with a notification if more than one is detected.\n else if (props.schemaType.of.length > 1) {\n return (\n <Stack space={3}>\n {props.renderDefault(props)}\n <Card padding={[3]} radius={2} shadow={1} tone=\"caution\">\n <Stack space={4}>\n <Stack space={2}>\n <Label size={2}>Input Component Not Supported for Multi-Schema Arrays</Label>\n <Text size={1}>\n The Sanity Taxonomy Manager Hierarchy Input Component is not designed to support\n array inputs with more than one schema type. Please see the{' '}\n <a href=\"https://sanitytaxonomymanager.com\">Taxonomy Manager docs</a> for more\n information.\n </Text>\n </Stack>\n </Stack>\n </Card>\n </Stack>\n )\n } else if (schemeLoading || valuesLoading) {\n return (\n <Box padding={5}>\n <Flex\n align=\"center\"\n direction=\"column\"\n gap={5}\n height=\"fill\"\n justify=\"center\"\n style={{paddingTop: '1rem'}}\n >\n <Spinner muted />\n <Text muted size={1}>\n Loading input component…\n </Text>\n </Flex>\n </Box>\n )\n }\n\n const isPublished = selectedPerspectiveName === 'published'\n\n // Render the browse-only preview UI for arrays\n const renderBrowseOnlyPreview = () => {\n if (value.length > 0) {\n return props.renderDefault(props)\n }\n\n // Wrap the empty state in `FormField` so the field exposes the same\n // DOM target Sanity's Validation panel uses for scroll-to-field /\n // highlight on click. Without this wrapper, clicking a required\n // browse-only field's validation error has no effect.\n return (\n <FormField\n title={title}\n path={props.path}\n description={props.description}\n level={props.level}\n validation={props.validation}\n __unstable_presence={props.presence}\n >\n <Card padding={3} radius={2} border>\n <Text muted align=\"center\" size={1}>\n No items\n </Text>\n </Card>\n </FormField>\n )\n }\n\n return (\n <Stack space={3}>\n {filterValues?.browseOnly ? renderBrowseOnlyPreview() : props.renderDefault(props)}\n\n <Grid columns={1} gap={3}>\n <Button\n disabled={isPublished}\n icon={NodeTree}\n text=\"Browse taxonomy tree\"\n mode=\"ghost\"\n onClick={browseHierarchy}\n />\n </Grid>\n {open && (\n <Dialog\n header={title}\n id=\"concept-select-dialog\"\n onClose={handleClose}\n zOffset={900}\n width={1}\n >\n <Box>\n <TreeView\n document={scheme as ConceptSchemeDocument}\n branchId={branchId}\n inputComponent\n selectConcept={handleAction}\n expanded={filterValues?.expanded}\n conceptRecs={conceptRecs}\n recsError={recsError}\n />\n </Box>\n </Dialog>\n )}\n </Stack>\n )\n}\n","import {Button, Inline, Stack, useToast} from '@sanity/ui'\nimport {useCallback} from 'react'\nimport {unset} from 'sanity'\n\n/**\n * #### Input Component for Deprecated Management Controls Field\n * The Management Controls field was used for a previous version\n * of the plugin and was set by default when creating a new scheme.\n * It has been set to \"Deprecated.\" This control will allow users\n * to delete the value from the input to hide the field, without\n * otherwise seeing an error int their schema.\n * - Input is only visible if no identifier has been assigned\n * - Input disappears once an ID is generated\n */\nexport const ManagementControls = (props: any) => {\n const {onChange} = props\n const toast = useToast()\n\n const handleChange = useCallback(() => {\n onChange(unset())\n toast.push({\n status: 'success',\n title: 'Value removed.',\n duration: 2500,\n closable: true,\n })\n }, [onChange, toast])\n\n return (\n <Stack space={2}>\n <Inline space={[3, 3, 4]}>\n {props.renderDefault(props)}\n <Button tone=\"primary\" fontSize={2} onClick={handleChange} text=\"Remove Value\" />\n </Inline>\n </Stack>\n )\n}\n","/**\n * Pure halves of the reference-field filters. The public `schemeFilter` /\n * `branchFilter` factories (in ../helpers) keep the impure GROQ fetch; the\n * validation and result-assembly below are pure and unit-tested here.\n */\n\nexport type SchemeFilterResult = {\n filter: string\n params: {schemeId: string; concepts: string[]; topConcepts: string[]}\n expanded?: boolean\n browseOnly?: boolean\n}\n\nexport type BranchFilterResult = {\n filter: string\n params: {schemeId: string; branchId: string; concepts: string[]}\n expanded?: boolean\n browseOnly?: boolean\n}\n\n/** Throws if the scheme id is missing or not a string. */\nexport function assertSchemeId(schemeId: unknown): asserts schemeId is string {\n if (!schemeId || typeof schemeId !== 'string') {\n throw new Error('Invalid or missing schemeId: scheme Id must be a string')\n }\n}\n\n/** Throws if the branch id is missing or not a string. */\nexport function assertBranchId(branchId: unknown): asserts branchId is string {\n if (!branchId || typeof branchId !== 'string') {\n throw new Error('Invalid or missing branchId: branch Id must be a string')\n }\n}\n\n/** Assemble the scheme reference-filter result from the fetched concept refs. */\nexport function buildSchemeFilterResult(input: {\n schemeId: string\n concepts: string[]\n topConcepts: string[]\n expanded?: boolean\n browseOnly?: boolean\n}): SchemeFilterResult {\n const {schemeId, concepts, topConcepts, expanded, browseOnly} = input\n return {\n filter: `(_id in $concepts\n || _id in $topConcepts)`,\n params: {concepts, topConcepts, schemeId},\n expanded,\n browseOnly,\n }\n}\n\n/** Assemble the branch reference-filter result from the fetched concept refs. */\nexport function buildBranchFilterResult(input: {\n schemeId: string\n branchId: string\n concepts: string[]\n expanded?: boolean\n browseOnly?: boolean\n}): BranchFilterResult {\n const {schemeId, branchId, concepts, expanded, browseOnly} = input\n return {\n filter: `_id in $concepts`,\n params: {concepts, schemeId, branchId},\n expanded,\n browseOnly,\n }\n}\n","import type {useClient} from 'sanity'\n\nimport {assertSchemeId, buildSchemeFilterResult, type SchemeFilterResult} from '../core/filters'\n\ntype SchemeOptions = {\n schemeId: string\n expanded?: boolean\n browseOnly?: boolean\n}\n\n/**\n * #### Reference Field Scheme Filter\n * Pluggable Function for Filtering to a Single SKOS Concept Scheme.\n * @param {string} schemeId - The unique six character concept identifier for\n * the Concept Scheme to which you wish to filter.\n * @param {boolean} [expanded] - Set to `true` to display open hierarchy trees for\n * input components. Input component trees load closed by default.\n * @param {boolean} [browseOnly] - Set to `true` to hide the default Sanity search\n * input and display only the \"Browse Taxonomy Tree\" button for selecting terms.\n * @returns A reference type filter for Concepts and Top Concepts in\n * the selected Concept Scheme test\n * @example\n * ```ts\n * import { schemeFilter } from 'sanity-plugin-taxonomy-manager'\n * ...\n * {\n * name: 'test',\n * type: 'array',\n * of: [\n * {\n * type: 'reference',\n * to: {type: 'skosConcept'},\n * options: {\n * filter: schemeFilter({\n * schemeId: 'a1b2c3',\n * expanded: true, // optional; defaults to false (closed tree)\n * browseOnly: true, // optional; hides search input\n * }),\n * disableNew: true,\n * },\n * },\n * ],\n * }\n * ```\n */\nexport const schemeFilter = (\n options: SchemeOptions,\n): (({\n getClient,\n}: {\n getClient: (clientOptions: {apiVersion: string}) => ReturnType<typeof useClient>\n}) => Promise<SchemeFilterResult>) => {\n // Get and validate the schemeId from options\n const {schemeId} = options || {}\n assertSchemeId(schemeId)\n\n return async (props) => {\n const client = props?.getClient({apiVersion: '2025-02-19'})\n if (!client) {\n throw new Error('Client not available')\n }\n // Fetch concepts and topConcepts for the given schemeId\n\n const {concepts, topConcepts} = (await client.fetch(\n `{\n \"concepts\": *[_type==\"skosConceptScheme\" && schemeId == \"${schemeId}\"].concepts[]._ref,\n \"topConcepts\": *[_type==\"skosConceptScheme\" && schemeId == \"${schemeId}\"].topConcepts[]._ref\n }`,\n )) as {concepts: string[]; topConcepts: string[]}\n // schemeId is included in params for use by the ArrayHierarchyInput component\n return buildSchemeFilterResult({\n schemeId,\n concepts,\n topConcepts,\n expanded: options?.expanded,\n browseOnly: options?.browseOnly,\n })\n }\n}\n","import type {useClient} from 'sanity'\n\nimport {\n assertBranchId,\n assertSchemeId,\n buildBranchFilterResult,\n type BranchFilterResult,\n} from '../core/filters'\n\ntype BranchOptions = {\n schemeId: string\n branchId: string\n expanded?: boolean\n browseOnly?: boolean\n}\n\n/**\n * #### Reference Field Scheme & Branch Filter\n * A pluggable Function for Filtering to a Top Concept Branch within a SKOS Concept Scheme\n * @param {string} schemeId - The unique six character concept identifier for\n * the Concept Scheme to which you wish to filter.\n * @param {string} branchId - The unique six character concept identifier of\n * a branch. Child concepts will be returned.\n * @param {boolean} [expanded] - Set to `true` to display open hierarchy trees for\n * input components. Input component trees load closed by default.\n * @param {boolean} [browseOnly] - Set to `true` to hide the default Sanity search\n * input and display only the \"Browse Taxonomy Tree\" button for selecting terms.\n * @returns A reference type filter for the child concepts of the designated branch in the selected Concept Scheme\n * @example\n * ```ts\n * import { branchFilter } from 'sanity-plugin-taxonomy-manager'\n * ...\n * {\n * name: 'test',\n * type: 'array',\n * of: [\n * {\n * type: 'reference',\n * to: {type: 'skosConcept'},\n * options: {\n * filter: branchFilter({\n * schemeId: 'a1b2c3',\n * branchId: 'd4e5f6',\n * expanded: true, // optional; defaults to false (closed tree)\n * browseOnly: true, // optional; hides search input\n * }),\n * disableNew: true,\n * },\n * },\n * ],\n * }\n * ```\n */\nexport const branchFilter = (\n options: BranchOptions,\n): (({\n getClient,\n}: {\n getClient: (clientOptions: {apiVersion: string}) => ReturnType<typeof useClient>\n}) => Promise<BranchFilterResult>) => {\n const {schemeId, branchId = null} = options || {}\n assertSchemeId(schemeId)\n assertBranchId(branchId)\n\n return async (props) => {\n const client = props?.getClient({apiVersion: '2023-01-01'})\n if (!client) {\n throw new Error('Client not available')\n }\n\n // Fetch concepts for the given schemeId and branchId\n\n const {concepts} = (await client.fetch(\n `{ \n \"concepts\": *[\n _id in *[_type==\"skosConceptScheme\" && schemeId == $schemeId].concepts[]._ref\n && ($branchId in broader[]->conceptId\n || $branchId in broader[]->broader[]->conceptId\n || $branchId in broader[]->broader[]->broader[]->conceptId\n || $branchId in broader[]->broader[]->broader[]->broader[]->conceptId\n || $branchId in broader[]->broader[]->broader[]->broader[]->broader[]->conceptId)\n ]._id\n }`,\n {schemeId, branchId},\n )) as {concepts: string[]}\n // schemeId is included in params for use by the ArrayHierarchyInput component\n return buildBranchFilterResult({\n schemeId,\n branchId,\n concepts,\n expanded: options?.expanded,\n browseOnly: options?.browseOnly,\n })\n }\n}\n","import {DocumentId, getPublishedId} from '@sanity/id-utils'\nimport type {SanityDocument} from 'sanity'\n\n/**\n * #### Concept reference filter\n * Reference-field `options.filter` for broader/related concept fields: excludes\n * the concept itself and any concepts already chosen as broader/related, keeping\n * the two relationship sets mutually exclusive. Pure — the host calls it with\n * the current document.\n */\nexport function conceptFilter({document}: {document: SanityDocument}) {\n const publishedId = getPublishedId(DocumentId(document._id))\n return {\n filter: '!(_id in $broader || _id in $related || _id == $self)',\n params: {\n self: publishedId,\n broader: Array.isArray(document?.broader)\n ? document.broader.map(({_ref}: {_ref: string}) => _ref)\n : [],\n related: Array.isArray(document?.related)\n ? document.related.map(({_ref}: {_ref: string}) => _ref)\n : [],\n },\n }\n}\n\n/**\n * #### Preferred-label uniqueness result\n * Given the id of an existing published concept that already uses a candidate\n * prefLabel (or null/undefined if none), decide the validation result. Returns\n * the error message when the match is a *different* document, otherwise `true`.\n * The fetch that finds the existing concept stays in the schema (impure).\n */\nexport function prefLabelUniquenessResult(\n existingConceptId: string | null | undefined,\n currentDocumentId: string | undefined,\n): string | true {\n if (existingConceptId && !currentDocumentId?.includes(existingConceptId)) {\n return 'Preferred Label must be unique.'\n }\n return true\n}\n","import {defineField} from 'sanity'\n\nimport {RdfUri} from '../components/inputs'\n\n/**\n * #### Base Universal Resource Identifier object for Sanity Taxonomy Manager\n * Used for Concept and Concept Scheme URI fields\n */\nexport default [\n defineField({\n name: 'baseIri',\n title: 'Base URI',\n type: 'url',\n validation: (Rule) =>\n Rule.required().error(`Please supply a base URI in the format 'http://example.com/'`),\n description:\n 'The root URI (Uniform Resource Identifier) used to create unique concept identifiers.',\n components: {\n input: RdfUri as any,\n },\n }),\n]\n","import {Stack, Text} from '@sanity/ui'\nimport {useFormValue} from 'sanity'\nimport type {StringInputProps} from 'sanity'\n\n/**\n * #### SKOS Concept Base URI input component\n * Used for Concept and Concept Scheme URI preview\n */\nexport function RdfUri(props: StringInputProps) {\n const conceptId = useFormValue(['conceptId'])\n const schemeId = useFormValue(['schemeId'])\n return (\n <Stack space={2}>\n {props.renderDefault(props)}\n <Text muted size={1}>\n <>\n <strong>RDF URI: </strong>\n {props.value ? props.value : '[base URI not defined] '}\n {conceptId || schemeId || ' [identifier not assigned]'}\n </>\n </Text>\n </Stack>\n )\n}\n","import {AiOutlineTag, AiOutlineTags} from 'react-icons/ai'\nimport {defineType, defineField} from 'sanity'\n\nimport {Identifier} from './components/inputs'\nimport {createId} from './core/createId'\nimport {conceptFilter, prefLabelUniquenessResult} from './core/validation'\nimport baseIriField from './helpers/baseIriField'\nimport type {Options} from './types'\n\n/**\n * Sanity document scheme for SKOS Taxonomy Concepts\n */\nexport default function skosConcept(\n baseUri?: Options['baseUri'],\n customConceptFields: Options['customConceptFields'] = [],\n ident?: Options['ident'],\n) {\n return defineType({\n name: 'skosConcept',\n title: 'Concept',\n type: 'document',\n icon: AiOutlineTags,\n initialValue: async (_, context) => {\n if (baseUri)\n return {\n baseIri: baseUri,\n broader: [], // an empty array is needed here in order to return concepts with no \"broader\" for \"related\"\n related: [], // an empty array is needed here in order to return concepts with no \"broader\" for \"related\"\n }\n\n const {getClient} = context\n const client = getClient({apiVersion: '2021-03-25'})\n const baseIri =\n (await client.fetch<string | null>(`\n *[(_type == 'skosConcept' || _type == 'skosConceptScheme') && defined(baseIri)]| order(_createdAt desc)[0].baseIri\n `)) ?? undefined\n return {\n baseIri: baseIri,\n broader: [], // an empty array is needed here in order to return concepts with no \"broader\" for \"related\"\n related: [], // an empty array is needed here in order to return concepts with no \"broader\" for \"related\"\n }\n },\n fields: [\n defineField({\n name: 'prefLabel',\n title: 'Preferred Label',\n type: 'string',\n description: 'The preferred lexical label for this concept.',\n validation: (Rule) =>\n Rule.required().custom((prefLabel, context) => {\n const {getClient} = context\n const client = getClient({apiVersion: '2025-06-10'}).withConfig({perspective: 'raw'})\n return client\n .fetch(\n `*[_type == \"skosConcept\" && prefLabel == \"${\n prefLabel as string\n }\" && !(_id in path(\"drafts.**\") || _id in path(\"versions.**\"))][0]._id`,\n )\n .then((conceptId) =>\n prefLabelUniquenessResult(conceptId as string | null, context.document?._id),\n )\n }),\n }),\n defineField({\n name: 'definition',\n title: 'Definition',\n type: 'text',\n description: 'A complete explanation of the intended meaning of the concept.',\n rows: 3,\n }),\n defineField({\n name: 'example',\n title: 'Examples',\n type: 'text',\n description: 'An example of the use of the concept.',\n rows: 3,\n }),\n defineField({\n name: 'scopeNote',\n title: 'Scope Note',\n type: 'text',\n description:\n 'A brief statement on the intended meaning of this concept, especially as an indication of how the use of the concept is limited in indexing practice.',\n rows: 3,\n }),\n defineField({\n name: 'altLabel',\n title: 'Alternate Label(s)',\n type: 'array',\n description: 'Synonyms, near-synonyms, abbreviations, and acronyms to a concept.',\n of: [{type: 'string'}],\n validation: (Rule) => Rule.unique(),\n }),\n defineField({\n name: 'hiddenLabel',\n title: 'Hidden Label(s)',\n type: 'array',\n description:\n 'Character strings that need to be accessible to applications performing text-based indexing and search operations, but which should not be displayed to end users.',\n of: [{type: 'string'}],\n validation: (Rule) => Rule.unique(),\n }),\n ...baseIriField,\n defineField({\n name: 'conceptId',\n title: 'Identifier',\n description:\n \"Generate or re-generate the identifier for this concept according to parameters set in Taxonomy Manager plugin options. Note that this changes the concept's URI, which is not advisable if the concept is already in use in production. Use with caution.\",\n type: 'string',\n initialValue: createId(ident),\n hidden: ({document}) => !!document?.conceptId && !ident?.regenUi,\n readOnly: ({document}) => !!document?.conceptId,\n components: {\n input: (props) => <Identifier {...props} ident={ident} />,\n },\n }),\n defineField({\n name: 'broader',\n title: 'Broader Concept(s)',\n description:\n 'Create hierarchy between concepts, for example to create category/subcategory, part/whole, or class/instance relationships.',\n type: 'array',\n of: [\n {\n type: 'reference',\n to: {type: 'skosConcept'},\n options: {\n filter: conceptFilter,\n },\n },\n ],\n }),\n defineField({\n name: 'related',\n title: 'Related Concept(s)',\n description:\n 'Indicate that two concepts are inherently \"related\", but that one is not in any way more general than the other.',\n type: 'array',\n of: [\n {\n type: 'reference',\n to: [{type: 'skosConcept'}],\n options: {\n filter: conceptFilter,\n },\n },\n ],\n }),\n ...customConceptFields,\n defineField({\n name: 'historyNote',\n title: 'History Notes',\n type: 'text',\n description: 'Significant changes to the meaning or the form of this concept.',\n rows: 3,\n }),\n defineField({\n name: 'editorialNote',\n title: 'Editorial Notes',\n type: 'text',\n description:\n 'Information to aid in administrative housekeeping, such as reminders of editorial work still to be done, or warnings in the event that future editorial changes might be made.',\n rows: 3,\n }),\n defineField({\n name: 'changeNote',\n title: 'Change Notes',\n type: 'text',\n description:\n 'Fine-grained changes to a concept, for the purposes of administration and maintenance.',\n rows: 3,\n }),\n ],\n orderings: [\n {\n title: 'Top Concepts',\n name: 'topConcept',\n by: [\n {field: 'topConcept', direction: 'desc'},\n {field: 'prefLabel', direction: 'asc'},\n ],\n },\n {\n title: 'Preferred Label',\n name: 'prefLabel',\n by: [{field: 'prefLabel', direction: 'asc'}],\n },\n ],\n preview: {\n select: {\n title: 'prefLabel',\n },\n prepare({title}: {title: string}) {\n return {\n title: title,\n media: AiOutlineTag,\n }\n },\n },\n })\n}\n","import {defineArrayMember, defineField, defineType} from 'sanity'\n\nimport {Identifier, ManagementControls} from './components/inputs'\nimport baseIriField from './helpers/baseIriField'\nimport {createId} from './core/createId'\nimport NodeTree from './static/NodeTree'\nimport type {Options} from './types'\n\n/**\n * Sanity document scheme for SKOS Concept Schemes\n */\nexport default function skosConceptScheme(\n baseUri?: Options['baseUri'],\n customSchemeFields: Options['customSchemeFields'] = [],\n ident?: Options['ident'],\n) {\n return defineType({\n name: 'skosConceptScheme',\n title: 'Concept Scheme',\n type: 'document',\n icon: NodeTree,\n initialValue: async (_, context) => {\n if (baseUri) return {baseIri: baseUri}\n const {getClient} = context\n const client = getClient({apiVersion: '2021-03-25'})\n const baseIri =\n (await client.fetch<string | null>(`\n *[(_type == 'skosConcept' || _type == 'skosConceptScheme') && defined(baseIri)]| order(_createdAt desc)[0].baseIri\n `)) ?? undefined\n return {\n baseIri: baseIri,\n }\n },\n fields: [\n defineField({\n name: 'title',\n title: 'Title',\n type: 'string',\n description:\n 'Taxonomy schemes group concepts into defined sets, such as thesauri, classification schemes, or facets. Concepts may belong to many (or no) concept schemes, and you may create as many (or few) concept schemes as you like',\n }),\n defineField({\n name: 'description',\n title: 'Description',\n type: 'text',\n rows: 5,\n description: 'Describe the intended use of this scheme.',\n }),\n defineField({\n name: 'controls',\n title: 'Concept Management Controls',\n deprecated: {\n reason:\n 'This field was used for a previous version of the plugin and is no longer needed. Remove the value to hide this field.',\n },\n type: 'boolean',\n readOnly: true,\n hidden: ({document}) => document?.controls === undefined,\n components: {\n input: ManagementControls,\n },\n }),\n ...baseIriField,\n defineField({\n name: 'schemeId',\n title: 'Identifier',\n description:\n \"Generate or re-generate the identifier for this scheme according to parameters set in Taxonomy Manager plugin options. Note that this changes the scheme's URI, which is not advisable if the scheme already is use in production. Use with caution.\",\n type: 'string',\n initialValue: createId(ident),\n hidden: ({document}) => !!document?.schemeId && !ident?.regenUi,\n readOnly: ({document}) => !!document?.schemeId,\n components: {\n input: (props) => <Identifier {...props} ident={ident} />,\n },\n }),\n defineField({\n name: 'topConcepts',\n title: 'Top Concepts',\n type: 'array',\n validation: (Rule) => Rule.unique(),\n of: [\n defineArrayMember({\n type: 'reference',\n to: [{type: 'skosConcept'}],\n }),\n ],\n options: {\n sortable: false,\n },\n }),\n defineField({\n name: 'concepts',\n title: 'Concepts',\n type: 'array',\n validation: (Rule) => Rule.unique(),\n of: [\n defineArrayMember({\n type: 'reference',\n to: [{type: 'skosConcept'}],\n }),\n ],\n options: {\n sortable: false,\n },\n }),\n ...customSchemeFields,\n ],\n preview: {\n select: {\n title: 'title',\n },\n prepare({title}: {title: string}) {\n return {\n title: title,\n media: NodeTree,\n }\n },\n },\n })\n}\n","function isObject(obj) {\n return typeof obj == \"object\" && obj !== null && !Array.isArray(obj);\n}\nfunction isReference(reference) {\n return isObject(reference) && typeof reference._ref == \"string\";\n}\nfunction isImage(value) {\n return isObject(value) && isReference(value.asset) && value.asset._ref.startsWith(\"image-\");\n}\nfunction isCrossDatasetReference(reference) {\n return isObject(reference) && typeof reference._ref == \"string\" && typeof reference._dataset == \"string\" && typeof reference._projectId == \"string\";\n}\nfunction isSanityDocument(document) {\n return isObject(document) && typeof document._id == \"string\" && typeof document._type == \"string\";\n}\nfunction isTypedObject(obj) {\n return isObject(obj) && typeof obj._type == \"string\";\n}\nfunction isKeyedObject(obj) {\n return isObject(obj) && typeof obj._key == \"string\";\n}\nfunction isGlobalDocumentReference(reference) {\n return !isObject(reference) || typeof reference._ref != \"string\" ? !1 : reference._ref.split(\":\").length === 3;\n}\nfunction isValidationErrorMarker(marker) {\n return marker.level === \"error\";\n}\nfunction isValidationWarningMarker(marker) {\n return marker.level === \"warning\";\n}\nfunction isValidationInfoMarker(marker) {\n return marker.level === \"info\";\n}\nconst MEDIA_LIBRARY_ASSET_ASPECT_TYPE_NAME = \"sanity.asset.aspect\";\nfunction isAssetAspect(maybeAssetAspect) {\n return typeof maybeAssetAspect == \"object\" && maybeAssetAspect !== null && \"_type\" in maybeAssetAspect && maybeAssetAspect._type === MEDIA_LIBRARY_ASSET_ASPECT_TYPE_NAME;\n}\nfunction defineAssetAspect(definition) {\n const { assetType, name } = definition;\n return {\n _type: MEDIA_LIBRARY_ASSET_ASPECT_TYPE_NAME,\n _id: `${name}`,\n definition,\n ...assetType && {\n assetType: Array.isArray(assetType) ? assetType : [assetType]\n },\n public: definition.public\n };\n}\nfunction isCreateMutation(mutation) {\n return \"create\" in mutation;\n}\nfunction isCreateIfNotExistsMutation(mutation) {\n return \"createIfNotExists\" in mutation;\n}\nfunction isCreateOrReplaceMutation(mutation) {\n return \"createOrReplace\" in mutation;\n}\nfunction isDeleteMutation(mutation) {\n return \"delete\" in mutation;\n}\nfunction isPatchMutation(mutation) {\n return \"patch\" in mutation;\n}\nconst reKeySegment = /_key\\s*==\\s*['\"](.*)['\"]/, reIndexTuple = /^\\d*:\\d*$/;\nfunction isIndexSegment(segment) {\n return typeof segment == \"number\" || typeof segment == \"string\" && /^\\[\\d+\\]$/.test(segment);\n}\nfunction isKeySegment(segment) {\n return typeof segment == \"string\" ? reKeySegment.test(segment.trim()) : typeof segment == \"object\" && \"_key\" in segment;\n}\nfunction isIndexTuple(segment) {\n if (typeof segment == \"string\" && reIndexTuple.test(segment))\n return !0;\n if (!Array.isArray(segment) || segment.length !== 2)\n return !1;\n const [from, to] = segment;\n return (typeof from == \"number\" || from === \"\") && (typeof to == \"number\" || to === \"\");\n}\nfunction isRecord$1(value) {\n return !!value && (typeof value == \"object\" || typeof value == \"function\");\n}\nfunction isPortableTextTextBlock(value) {\n return isRecord$1(value) && typeof value._type == \"string\" && // block types can be named, so expect anything here.\n Array.isArray(value.children) && value.children.every((child) => isRecord$1(child)) && (\"markDefs\" in value ? Array.isArray(value.markDefs) && value.markDefs.every((def) => isRecord$1(def)) : !0) && (\"style\" in value ? typeof value.style == \"string\" : !0);\n}\nfunction isPortableTextSpan(value) {\n return isRecord$1(value) && value._type === \"span\" && typeof value.text == \"string\" && (\"marks\" in value ? Array.isArray(value.marks) && value.marks.every((mark) => typeof mark == \"string\") : !0);\n}\nfunction isPortableTextListBlock(value) {\n return isPortableTextTextBlock(value) && \"listItem\" in value && typeof value.listItem == \"string\" && \"level\" in value && Number.isInteger(value.level);\n}\nfunction isRecord(value) {\n return !!value && (typeof value == \"object\" || typeof value == \"function\");\n}\nfunction isDocumentSchemaType(type) {\n if (!isObjectSchemaType(type))\n return !1;\n let current = type;\n for (; current; ) {\n if (current.name === \"document\")\n return !0;\n current = current.type;\n }\n return !1;\n}\nfunction isObjectSchemaType(type) {\n return isRecord(type) ? type.jsonType === \"object\" : !1;\n}\nfunction isArraySchemaType(type) {\n return isRecord(type) ? type.jsonType === \"array\" : !1;\n}\nfunction isArrayOfBlocksSchemaType(type) {\n return isArraySchemaType(type) && type.of.some((memberType) => isBlockSchemaType(memberType));\n}\nfunction isArrayOfObjectsSchemaType(type) {\n return isArraySchemaType(type) && type.of.every((memberType) => isObjectSchemaType(memberType));\n}\nfunction isArrayOfPrimitivesSchemaType(type) {\n return isArraySchemaType(type) && type.of.every((memberType) => isPrimitiveSchemaType(memberType));\n}\nfunction isArrayOfStringsSchemaType(type) {\n return isArraySchemaType(type) && type.of.every((memberType) => isStringSchemaType(memberType));\n}\nfunction isBooleanSchemaType(type) {\n return isRecord(type) ? type.jsonType === \"boolean\" : !1;\n}\nfunction isStringSchemaType(type) {\n return isRecord(type) ? type.jsonType === \"string\" : !1;\n}\nfunction isDateTimeSchemaType(type) {\n return isStringSchemaType(type) ? type.name === \"datetime\" : !1;\n}\nfunction isNumberSchemaType(type) {\n return isRecord(type) ? type.jsonType === \"number\" : !1;\n}\nfunction isPrimitiveSchemaType(type) {\n return isBooleanSchemaType(type) || isStringSchemaType(type) || isNumberSchemaType(type);\n}\nfunction isReferenceSchemaType(type) {\n return isRecord(type) && (type.name === \"reference\" || isReferenceSchemaType(type.type));\n}\nfunction isImageSchemaType(type) {\n return isRecord(type) && (type.name === \"image\" || isImageSchemaType(type.type));\n}\nfunction isFileSchemaType(type) {\n return isRecord(type) && (type.name === \"file\" || isFileSchemaType(type.type));\n}\nfunction isDeprecatedSchemaType(type) {\n return isRecord(type) ? typeof type.deprecated < \"u\" : !1;\n}\nfunction isDeprecationConfiguration(type) {\n return isRecord(type) ? typeof type.deprecated < \"u\" : !1;\n}\nfunction isCrossDatasetReferenceSchemaType(type) {\n return isRecord(type) && (type.name === \"crossDatasetReference\" || isCrossDatasetReferenceSchemaType(type.type));\n}\nfunction isTitledListValue(item) {\n return typeof item == \"object\" && item !== null && \"title\" in item && \"value\" in item;\n}\nfunction isSpanSchemaType(type) {\n return isRecord(type) ? Array.isArray(type.annotations) && Array.isArray(type.decorators) : !1;\n}\nfunction isBlockSchemaType(type) {\n if (!isRecord(type) || !Array.isArray(type.fields)) return !1;\n const maybeSpanChildren = type.fields.find(isBlockChildrenObjectField), maybeStyle = type.fields.find(isBlockStyleObjectField), maybeList = type.fields.find(isBlockListObjectField);\n return isBlockChildrenObjectField(maybeSpanChildren) && isBlockStyleObjectField(maybeStyle) && isBlockListObjectField(maybeList);\n}\nfunction isBlockStyleObjectField(field) {\n return !isRecord(field) || field.name !== \"style\" ? !1 : isRecord(field.type) && field.type.jsonType === \"string\";\n}\nfunction isBlockListObjectField(field) {\n return !isRecord(field) || field.name !== \"listItem\" ? !1 : isRecord(field.type) && field.type.jsonType === \"string\";\n}\nfunction isBlockChildrenObjectField(field) {\n return !isRecord(field) || field.name !== \"children\" || !isArraySchemaType(field.type) ? !1 : field.type.of.some(isSpanSchemaType);\n}\nfunction defineType(schemaDefinition, defineOptions) {\n return schemaDefinition;\n}\nfunction defineField(schemaField, defineOptions) {\n return schemaField;\n}\nfunction defineArrayMember(arrayOfSchema, defineOptions) {\n return arrayOfSchema;\n}\nfunction typed(input) {\n return input;\n}\nconst searchStrategies = [\"groq2024\", \"groqLegacy\"];\nfunction isSearchStrategy(maybeSearchStrategy) {\n return searchStrategies.includes(maybeSearchStrategy);\n}\nfunction isSlug(thing) {\n return isObject(thing) && typeof thing.current == \"string\";\n}\nfunction isCreateSquashedMutation(mutation) {\n return \"createSquashed\" in mutation;\n}\nfunction isValidationError(node) {\n return node.level === \"error\";\n}\nfunction isValidationWarning(node) {\n return node.level === \"warning\";\n}\nfunction isValidationInfo(node) {\n return node.level === \"info\";\n}\nexport {\n MEDIA_LIBRARY_ASSET_ASPECT_TYPE_NAME,\n defineArrayMember,\n defineAssetAspect,\n defineField,\n defineType,\n isArrayOfBlocksSchemaType,\n isArrayOfObjectsSchemaType,\n isArrayOfPrimitivesSchemaType,\n isArrayOfStringsSchemaType,\n isArraySchemaType,\n isAssetAspect,\n isBlockChildrenObjectField,\n isBlockListObjectField,\n isBlockSchemaType,\n isBlockStyleObjectField,\n isBooleanSchemaType,\n isCreateIfNotExistsMutation,\n isCreateMutation,\n isCreateOrReplaceMutation,\n isCreateSquashedMutation,\n isCrossDatasetReference,\n isCrossDatasetReferenceSchemaType,\n isDateTimeSchemaType,\n isDeleteMutation,\n isDeprecatedSchemaType,\n isDeprecationConfiguration,\n isDocumentSchemaType,\n isFileSchemaType,\n isGlobalDocumentReference,\n isImage,\n isImageSchemaType,\n isIndexSegment,\n isIndexTuple,\n isKeySegment,\n isKeyedObject,\n isNumberSchemaType,\n isObjectSchemaType,\n isPatchMutation,\n isPortableTextListBlock,\n isPortableTextSpan,\n isPortableTextTextBlock,\n isPrimitiveSchemaType,\n isReference,\n isReferenceSchemaType,\n isSanityDocument,\n isSearchStrategy,\n isSlug,\n isSpanSchemaType,\n isStringSchemaType,\n isTitledListValue,\n isTypedObject,\n isValidationError,\n isValidationErrorMarker,\n isValidationInfo,\n isValidationInfoMarker,\n isValidationWarning,\n isValidationWarningMarker,\n searchStrategies,\n typed\n};\n//# sourceMappingURL=index.js.map\n","import { isIndexSegment, isKeySegment, isIndexTuple } from \"@sanity/types\";\nconst rePropName = /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g, reKeySegment = /_key\\s*==\\s*['\"](.*)['\"]/, EMPTY_PATH = [], FOCUS_TERMINATOR = \"$\", GROQ_DATA_TYPE_VALUES = [\"true\", \"false\", \"null\"];\nfunction get(obj, path, defaultVal) {\n const select = typeof path == \"string\" ? fromString(path) : path;\n if (!Array.isArray(select))\n throw new Error(\"Path must be an array or a string\");\n let acc = obj;\n for (let i = 0; i < select.length; i++) {\n const segment = select[i];\n if (isIndexSegment(segment)) {\n if (!Array.isArray(acc))\n return defaultVal;\n acc = acc[segment];\n }\n if (isKeySegment(segment)) {\n if (!Array.isArray(acc))\n return defaultVal;\n acc = acc.find((item) => item._key === segment._key);\n }\n if (typeof segment == \"string\" && (acc = typeof acc == \"object\" && acc !== null ? acc[segment] : void 0), typeof acc > \"u\")\n return defaultVal;\n }\n return acc;\n}\nconst pathsMemo = /* @__PURE__ */ new Map();\nfunction pathFor(path) {\n if (path.length === 0)\n return EMPTY_PATH;\n const asString = toString(path);\n return pathsMemo.has(asString) ? pathsMemo.get(asString) : (pathsMemo.set(asString, path), Object.freeze(path), path);\n}\nfunction isEqual(path, otherPath) {\n return path.length === otherPath.length && path.every((segment, i) => isSegmentEqual(segment, otherPath[i]));\n}\nfunction numEqualSegments(path, otherPath) {\n const length = Math.min(path.length, otherPath.length);\n for (let i = 0; i < length; i++)\n if (!isSegmentEqual(path[i], otherPath[i]))\n return i;\n return length;\n}\nfunction isSegmentEqual(segmentA, segmentB) {\n return isKeySegment(segmentA) && isKeySegment(segmentB) ? segmentA._key === segmentB._key : isIndexSegment(segmentA) ? Number(segmentA) === Number(segmentB) : isIndexTuple(segmentA) && isIndexTuple(segmentB) ? segmentA[0] === segmentB[0] && segmentA[1] === segmentB[1] : segmentA === segmentB;\n}\nfunction hasFocus(focusPath, path) {\n const withoutTerminator = focusPath[focusPath.length - 1] === FOCUS_TERMINATOR ? focusPath.slice(0, -1) : focusPath;\n return isEqual(withoutTerminator, path);\n}\nfunction hasItemFocus(focusPath, item) {\n return focusPath.length === 1 && isSegmentEqual(focusPath[0], item);\n}\nfunction isExpanded(segment, focusPath) {\n const [head, ...tail] = focusPath;\n return tail.length > 0 && isSegmentEqual(segment, head);\n}\nfunction startsWith(prefix, path) {\n return prefix.every((segment, i) => isSegmentEqual(segment, path[i]));\n}\nfunction trimLeft(prefix, path) {\n if (prefix.length === 0 || path.length === 0)\n return path;\n const [prefixHead, ...prefixTail] = prefix, [pathHead, ...pathTail] = path;\n return isSegmentEqual(prefixHead, pathHead) ? pathFor(trimLeft(prefixTail, pathTail)) : path;\n}\nfunction trimRight(suffix, path) {\n const sufLen = suffix.length, pathLen = path.length;\n if (sufLen === 0 || pathLen === 0)\n return path;\n let i = 0;\n for (; i < sufLen && i < pathLen && isSegmentEqual(path[pathLen - i - 1], suffix[sufLen - i - 1]); )\n i++;\n return pathFor(path.slice(0, pathLen - i));\n}\nfunction trimChildPath(path, childPath) {\n return startsWith(path, childPath) ? trimLeft(path, childPath) : EMPTY_PATH;\n}\nfunction toString(path) {\n if (!Array.isArray(path))\n throw new Error(\"Path is not an array\");\n return path.reduce((target, segment, i) => {\n const isHead = i === 0;\n if (typeof segment == \"number\")\n return `${target}[${segment}]`;\n if (typeof segment == \"string\")\n return isHead ? segment : GROQ_DATA_TYPE_VALUES.includes(segment) ? `${target}[\"${segment}\"]` : `${target}.${segment}`;\n if (isKeySegment(segment) && segment._key)\n return `${target}[_key==\"${segment._key}\"]`;\n if (Array.isArray(segment)) {\n const [from, to] = segment;\n return `${target}[${from}:${to}]`;\n }\n throw new Error(`Unsupported path segment \\`${JSON.stringify(segment)}\\``);\n }, \"\");\n}\nfunction _resolveKeyedPath(value, path) {\n if (path.length === 0)\n return path;\n const [next, ...rest] = path;\n if (typeof next == \"number\") {\n if (!Array.isArray(value) || !(next in value))\n return [];\n const item = value[next];\n return [typeof item?._key == \"string\" ? { _key: item._key } : next, ..._resolveKeyedPath(item, rest)];\n }\n const nextVal = get(value, [next]);\n return [next, ..._resolveKeyedPath(nextVal, rest)];\n}\nfunction resolveKeyedPath(value, path) {\n if (!Array.isArray(path))\n throw new Error(\"Path is not an array\");\n return pathFor(_resolveKeyedPath(value, path));\n}\nfunction fromString(path) {\n if (typeof path != \"string\")\n throw new Error(\"Path is not a string\");\n const segments = path.match(rePropName);\n if (!segments)\n throw new Error(\"Invalid path string\");\n return segments.map(normalizePathSegment);\n}\nfunction normalizePathSegment(segment) {\n return isIndexSegment(segment) ? normalizeIndexSegment(segment) : isKeySegment(segment) ? normalizeKeySegment(segment) : isIndexTuple(segment) ? normalizeIndexTupleSegment(segment) : segment;\n}\nfunction normalizeIndexSegment(segment) {\n return Number(segment.replace(/[^\\d]/g, \"\"));\n}\nfunction normalizeKeySegment(segment) {\n return { _key: segment.match(reKeySegment)[1] };\n}\nfunction normalizeIndexTupleSegment(segment) {\n const [from, to] = segment.split(\":\").map((seg) => seg === \"\" ? seg : Number(seg));\n return [from, to];\n}\nexport {\n FOCUS_TERMINATOR,\n _resolveKeyedPath,\n fromString,\n get,\n hasFocus,\n hasItemFocus,\n isEqual,\n isExpanded,\n isSegmentEqual,\n numEqualSegments,\n pathFor,\n resolveKeyedPath,\n startsWith,\n toString,\n trimChildPath,\n trimLeft,\n trimRight\n};\n//# sourceMappingURL=paths.js.map\n","import {Flex, Spinner, Stack, Box, Card, Inline, Text, Button} from '@sanity/ui'\nimport {fromString as pathFromString} from '@sanity/util/paths'\nimport {useCallback} from 'react'\nimport {Preview, useSchema, usePerspective, getPublishedId} from 'sanity'\nimport type {UserViewComponent} from 'sanity/structure'\nimport {usePaneRouter} from 'sanity/structure'\nimport {Feedback, useListeningQuery} from 'sanity-plugin-utils'\n\ninterface TagReference {\n _id: string\n _type: string\n title: string\n}\n\nexport const ConceptUseView: UserViewComponent<Record<string, never>> = ({\n document,\n}: {\n document: {displayed: {_id?: string}}\n}) => {\n const {selectedPerspectiveName} = usePerspective()\n const {routerPanesState, groupIndex, handleEditReference} = usePaneRouter()\n const schema = useSchema()\n\n const refId = getPublishedId((document.displayed as {_id?: string})?._id ?? '')\n\n const handleClick = useCallback(\n (id: string, type: string) => {\n const childParams = routerPanesState[groupIndex + 1]?.[0].params || {}\n const {parentRefPath} = childParams\n\n handleEditReference({\n id,\n type,\n parentRefPath: parentRefPath ? pathFromString(parentRefPath) : [``],\n template: {id},\n })\n },\n [routerPanesState, groupIndex, handleEditReference],\n )\n\n const {data, loading, error} = useListeningQuery<TagReference[]>(\n `*[!(_type in [\"skosConcept\",\"skosConceptScheme\"]) && references($refId)]{_id,_type,title}`,\n {\n params: {refId},\n options: {\n perspective: selectedPerspectiveName ? [selectedPerspectiveName] : 'drafts',\n },\n },\n )\n\n if (loading) {\n return (\n <Box padding={5}>\n <Flex\n align=\"center\"\n direction=\"column\"\n gap={5}\n height=\"fill\"\n justify=\"center\"\n style={{paddingTop: '1rem'}}\n >\n <Spinner muted />\n <Text muted size={1}>\n Loading usage…\n </Text>\n </Flex>\n </Box>\n )\n }\n\n if (error) {\n return (\n <Stack padding={4} space={5}>\n <Feedback tone={'caution'}>There was en error fetching use data</Feedback>\n </Stack>\n )\n }\n\n if (!data?.length) {\n return (\n <Stack padding={4} space={5}>\n <Feedback>This concept is not currently in use</Feedback>\n </Stack>\n )\n }\n\n return (\n <Box padding={4} paddingTop={4}>\n <Stack space={2}>\n <Card borderBottom paddingTop={3} paddingBottom={3}>\n <Inline paddingTop={1}>\n <Text weight=\"semibold\" muted size={1}>\n Resource count (all schemes): {data.length}\n </Text>\n </Inline>\n </Card>\n <Stack space={1}>\n {data?.map((d: TagReference) => {\n const schemaType = schema.get(d._type)\n return (\n schemaType && (\n <Button\n key={d._id}\n onClick={() => handleClick(d._id, d._type)}\n padding={2}\n mode=\"bleed\"\n >\n <Preview value={d} schemaType={schemaType} layout=\"block\" />\n </Button>\n )\n )\n })}\n </Stack>\n </Stack>\n </Box>\n )\n}\n","import {EditIcon, DocumentsIcon} from '@sanity/icons'\nimport type {StructureBuilder, ListBuilder, DefaultDocumentNodeResolver} from 'sanity/structure'\n\nimport {TreeView} from './components/TreeView'\nimport {TaxonomyConfigContext} from './context'\nimport NodeTree from './static/NodeTree'\nimport type {Options, TreeViewProps} from './types'\nimport {ConceptUseView} from './views/ConceptUseView'\n\n/**\n * #### Default Desk Structure for Concept and Concept Scheme\n * Sets defaultDocumentNode. Consider exporting in the future,\n * if there is a use case for mixing taxonomy views in the main\n * desk structure.\n */\nexport const structure = (S: StructureBuilder): ListBuilder =>\n S.list()\n .title('Taxonomy Manager')\n .items([\n S.documentTypeListItem('skosConceptScheme').title('Concept Schemes'),\n S.documentTypeListItem('skosConcept').title('Concepts'),\n ])\n\n/**\n * #### Default Document Node (factory)\n * Builds the `defaultDocumentNode` resolver, closing over plugin config so the\n * structure Tree View can read `ident` from React context — replacing the old\n * `config.ts` `getPluginConfig` singleton. Called once at plugin init, so the\n * wrapper component identity stays stable across resolver invocations.\n */\nexport const createDefaultDocumentNode = (\n config: {ident?: Options['ident']} = {}\n): DefaultDocumentNodeResolver => {\n // Provide plugin config to the structure Tree View subtree (the only place\n // concept creation reads `ident`). Input-component trees render without this\n // provider and fall back to the context default — they never create concepts.\n const TreeViewWithConfig = (props: TreeViewProps) => (\n <TaxonomyConfigContext.Provider value={{ident: config.ident}}>\n <TreeView {...props} />\n </TaxonomyConfigContext.Provider>\n )\n\n return (S, {schemaType}) => {\n // Conditionally return a different configuration based on the schema type\n switch (schemaType) {\n case 'skosConceptScheme':\n return S.document().views([\n S.view.component(TreeViewWithConfig).title('Tree View').icon(NodeTree),\n S.view.form().icon(EditIcon),\n ])\n case 'skosConcept':\n return S.document().views([\n S.view.form().icon(EditIcon),\n S.view.component(ConceptUseView).title('Tagged Resources').icon(DocumentsIcon),\n ])\n default:\n return S.document().views([S.view.form().icon(EditIcon)])\n }\n }\n}\n","import {definePlugin} from 'sanity'\nimport {structureTool} from 'sanity/structure'\n\nimport {ReferenceHierarchyInput, ArrayHierarchyInput} from './components/inputs'\nimport {TreeView} from './components/TreeView'\nimport {schemeFilter, branchFilter} from './helpers'\nimport skosConcept from './skosConcept'\nimport skosConceptScheme from './skosConceptScheme'\nimport NodeTree from './static/NodeTree'\nimport {createDefaultDocumentNode, structure} from './structure'\nimport type {Options} from './types'\n\n/**\n * #### Sanity Taxonomy Manager\n * Defines a Sanity plugin for managing SKOS compliant taxonomies in Sanity Studio.\n * #### Options\n * @param baseUri - The base URI to use for SKOS concepts and concept schemes. BaseURI should follow an IANA http/s scheme and should terminate with either a / or #.\n * @param customConceptFields - An array of additional fields to add to the skosConcept type.\n * @param customSchemeFields - An array of additional fields to add to the skosConceptScheme type.\n * #### Identifier Configuration\n * @param ident.pattern - The character set to use for identifiers (default: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz').\n * @param ident.length - The length of the generated identifier (default: 6).\n * @param ident.prefix - A prefix to prepend to generated identifiers, for example to use Wikidata style IDs like \"Q27521\" (default: '').\n * @param ident.regenUi - Whether to display the \"Create Unique Identifier\" button in the UI by default.\n * @returns A Sanity plugin object.\n */\nconst taxonomyManager = definePlugin((options?: Options) => {\n const {baseUri, customConceptFields, customSchemeFields, ident} = options || {}\n\n return {\n name: 'taxonomyManager',\n options,\n schema: {\n types: [\n skosConcept(baseUri, customConceptFields, ident),\n skosConceptScheme(baseUri, customSchemeFields, ident),\n ],\n },\n plugins: [\n structureTool({\n name: 'taxonomy',\n title: 'Taxonomy',\n structure,\n defaultDocumentNode: createDefaultDocumentNode({ident}),\n icon: NodeTree,\n }),\n ],\n }\n})\n\nexport {\n taxonomyManager,\n TreeView,\n schemeFilter,\n branchFilter,\n ReferenceHierarchyInput,\n ArrayHierarchyInput,\n}\n"],"names":["createId","ident","alphabet","pattern","length","prefix","customAlphabet","nanoid","Identifier","props","onChange","toast","useToast","handleChange","useCallback","id","set","push","status","title","closable","jsx","Stack","space","children","Button","icon","GenerateIcon","mode","width","onClick","text","defaultProps","SchemeContext","createContext","TreeContext","editControls","ReleaseContext","TaxonomyConfigContext","OptimisticTreeContext","markRemoved","unmarkRemoved","annotateRecommendations","node","recommendedIds","recommended","has","getPublishedId","annotatedChildren","childConcepts","map","child","hasMatchingDescendant","some","DEFAULT_PROPS","tone","Feedback","t0","$","c","t2","t3","t4","description","t1","Box","flex","gap","Text","weight","size","jsxs","Flex","Card","padding","radius","border","DEFAULT_PARAMS","DEFAULT_OPTIONS","apiVersion","useParams","params","JSON","stringify","stringifiedParams","parse","useListeningQuery","query","t5","t6","options","initialValue","loading","setLoading","useState","error","setError","data","setData","memoParams","memoOptions","subscription","useRef","documentStore","useDocumentStore","current","listenQuery","pipe","distinctUntilChanged","isEqual","catchError","err_0","console","subscribe","documents","err","unsubscribe","useEffect","branchBuilder","level","reference","i","DEFAULT_MAX_RESULTS","TaxonomyPortContext","useWatchTree","isInput","result","fetch","listen","documentId","branchId","perspective","useApplyConceptPlan","client","useClient","async","plan","kind","transaction","createIfNotExists","create","patch","schemeId","setIfMissing","appendField","append","commit","autoGenerateArrayKeys","unset","unsetPaths","useSemanticRecommendations","semanticSearch","baseClient","useMemo","withConfig","getFormValue","useGetFormValue","conceptRecs","setConceptRecs","recsError","setRecsError","triggerSearch","fieldReferences","maxResults","searchQuery","fields","values","emptyFields","name","value","trim","Error","join","assembleQueryText","message","then","rows","recs","row","conceptId","score","toConceptRecommendations","catch","test","recommendationsErrorMessage","useTaxonomyDataPort","useContext","SKOS_CONCEPT_STRENGTHEN","type","template","deriveSchemeMutationTarget","displayedId","docId","DocumentId","isInRelease","isVersionId","releaseName","getVersionNameFromId","getVersionId","getDraftId","useCreateConcept","document","openInNewPane","routerContext","RouterContext","routerPanesState","groupIndex","usePaneRouter","panes","splice","href","resolvePathFromState","navigateUrl","path","useOpenNewConceptPane","applyConceptPlan","schemaBaseIri","displayed","baseIri","conceptType","concept","input","target","scheme","_id","newConceptId","uuid","context","deriveNewConceptId","newConceptUuid","_type","prefLabel","schemeBaseIri","broader","related","referencedOriginalId","broaderConcept","_key","broaderKey","_ref","_originalId","isPublishedId","_weak","_strengthenOnPublish","newConceptKey","planCreateConcept","useRemoveConcept","field","conceptRef","planRemoveConcept","MessageHelper","Label","muted","style","whiteSpace","ConceptDetailDialogue","open","setOpen","onClose","onOpen","definition","example","scopeNote","Fragment","Tooltip","delay","content","sizing","fallbackPlacements","placement","portal","InfoOutlineIcon","Dialog","header","zOffset","paddingTop","paddingBottom","ConceptDetailLink","topConcept","orphan","displayLabel","paddingLeft","justify","textOverflow","Badge","fontSize","marginLeft","verticalAlign","ConceptEditAction","action","handler","typeMap","add","AddCircleIcon","remove","TrashIcon","ConceptSelectLink","selectConcept","handleClick","StructureDetailDialogue","ErrorOutlineIcon","info","warn","ToggleButton","visibility","ToggleArrowRightIcon","className","css","ref","insertAt","head","getElementsByTagName","createElement","firstChild","insertBefore","appendChild","styleSheet","cssText","createTextNode","Children","inputComponent","releaseContext","globalVisibility","treeVisibility","createConcept","removeConcept","handleAddChild","handleRemoveConcept","levelVisibility","setLevelVisibility","handleToggle","align","wrap","minWidth","Inline","ChildConcepts","concepts","childVisibility","marginTop","display","Concepts","hasTopConcept","topConcepts","NewScheme","titleValue","setTitleValue","descriptionValue","setDescriptionValue","handleTitleChange","event","currentTarget","handleDescriptionChange","addTitle","doc","_","useAddTitle","handleAddTitle","shadow","AddIcon","TextInput","placeholder","TextArea","NoConcepts","TopConcepts","TreeStructure","treeId","listStyle","marginBlockStart","filter","isOrphan","InputHierarchy","expanded","initialVisibility","port","Set","rec","mergedData","tc","direction","height","Spinner","Provider","NodeTree","viewBox","fill","xmlns","d","pruneChildren","removedIds","Hierarchy","createTopConcept","createEntryConcept","setGlobalVisibility","handleExpand","handleCollapse","setRemovedIds","prev","next","delete","optimisticValue","present","ids","walk","collectConceptIds","prunedData","pruneConcepts","borderBottom","paddingY","TreeView","selectedPerspectiveName","usePerspective","Container","ReferenceHierarchyInput","useFormValue","isDraft","isDraftId","schemeLoading","setSchemeLoading","valuesLoading","setValuesLoading","setScheme","filterValues","setFilterValues","schemaType","resolvedFilterValues","getClient","fetchFilterValues","res","browseHierarchy","handleClose","handleAction","renderDefault","isPublished","browseOnly","FormField","validation","__unstable_presence","presence","Grid","columns","disabled","ArrayHierarchyInput","of","item","includes","duration","ManagementControls","assertSchemeId","schemeFilter","buildSchemeFilterResult","branchFilter","assertBranchId","buildBranchFilterResult","conceptFilter","self","Array","isArray","baseIriField","defineField","Rule","required","components","skosConcept","baseUri","customConceptFields","defineType","AiOutlineTags","custom","prefLabelUniquenessResult","existingConceptId","currentDocumentId","unique","hidden","regenUi","readOnly","to","orderings","by","preview","select","prepare","media","AiOutlineTag","skosConceptScheme","customSchemeFields","deprecated","reason","controls","defineArrayMember","sortable","reKeySegment","reIndexTuple","rePropName","fromString","segments","match","normalizePathSegment","segment","isIndexSegment","Number","replace","normalizeIndexSegment","isKeySegment","normalizeKeySegment","from","isIndexTuple","split","seg","normalizeIndexTupleSegment","ConceptUseView","handleEditReference","schema","useSchema","refId","childParams","parentRefPath","pathFromString","get","Preview","layout","structure","S","list","items","documentTypeListItem","createDefaultDocumentNode","config","TreeViewWithConfig","views","view","component","form","EditIcon","DocumentsIcon","taxonomyManager","definePlugin","types","plugins","structureTool","defaultDocumentNode"],"mappings":"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","x_google_ignoreList":[4,21,46,47]}