sanity-plugin-taxonomy-manager 4.7.0 → 4.7.2
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.
- package/lib/index.d.ts +247 -12
- package/lib/index.esm.d.mts +247 -12
- package/lib/index.esm.esm.js +164 -168
- package/lib/index.esm.esm.js.map +1 -1
- package/lib/index.esm.mjs +164 -168
- package/lib/index.esm.mjs.map +1 -1
- package/lib/index.js +21 -25
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/inputs/ArrayHierarchyInput.tsx +147 -14
- package/src/components/inputs/ReferenceHierarchyInput.tsx +126 -14
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from '@sanity/ui'
|
|
16
16
|
import {useState, useEffect, useCallback} from 'react'
|
|
17
17
|
import type {ArrayFieldProps, ObjectOptions} from 'sanity'
|
|
18
|
-
import {useClient, useFormValue, isVersionId, isDraftId, usePerspective} from 'sanity'
|
|
18
|
+
import {FormField, useClient, useFormValue, isVersionId, isDraftId, usePerspective} from 'sanity'
|
|
19
19
|
|
|
20
20
|
import {useEmbeddingsRecs} from '../../hooks'
|
|
21
21
|
import NodeTree from '../../static/NodeTree'
|
|
@@ -44,14 +44,142 @@ type ArrayHierarchyInputProps = ArrayFieldProps & {
|
|
|
44
44
|
type FilterResult = Awaited<ReturnType<ReferenceOptions['filter']>>
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* used as an input for taxonomy array fields in Sanity Studio.
|
|
47
|
+
* Input component that replaces Sanity's default array field input with a
|
|
48
|
+
* hierarchical taxonomy tree browser. Studio users can browse taxonomy terms
|
|
49
|
+
* organized in their scheme hierarchy and select terms to add to the array field.
|
|
51
50
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* - Must be used with a `schemeFilter` or `branchFilter` helper in the field's
|
|
53
|
+
* `options.filter`. Rendering without a filter will display a configuration warning.
|
|
54
|
+
* - Supports only **single-schema arrays** (i.e., `of: [{type: 'reference'}]`). Arrays
|
|
55
|
+
* with multiple schema types will render a warning and fall back to the default input.
|
|
56
|
+
* - Taxonomy selection is disabled when viewing the published perspective.
|
|
57
|
+
* - When `browseOnly` is set in the filter configuration, Sanity's default search input
|
|
58
|
+
* is suppressed and only the tree browser is available for term selection.
|
|
59
|
+
* - When `expanded` is set in the filter configuration, the hierarchy tree loads open
|
|
60
|
+
* by default instead of collapsed.
|
|
54
61
|
*
|
|
62
|
+
* @param props - Standard Sanity `ArrayFieldProps` extended with an optional
|
|
63
|
+
* `embeddingsIndex` configuration object.
|
|
64
|
+
* @param props.embeddingsIndex - Optional configuration for AI-assisted term
|
|
65
|
+
* recommendations via a Sanity Embeddings Index. When provided, opening the tree
|
|
66
|
+
* browser queries the specified index and annotates matching taxonomy terms with
|
|
67
|
+
* a relevance score to help authors identify the most appropriate terms.
|
|
68
|
+
* @param props.embeddingsIndex.indexName - The name of the Sanity Embeddings Index
|
|
69
|
+
* to query. Must be an index that includes `skosConcept` documents.
|
|
70
|
+
* @param props.embeddingsIndex.fieldReferences - An array of field names from the
|
|
71
|
+
* current document whose values are concatenated and sent as the embeddings search
|
|
72
|
+
* query. All listed fields must contain values when the tree browser is opened;
|
|
73
|
+
* empty fields will display an error message in the tree view rather than scores.
|
|
74
|
+
* @param props.embeddingsIndex.maxResults - Maximum number of semantically matching
|
|
75
|
+
* terms to return from the embeddings index. Defaults to `3`.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* Basic usage with a scheme filter:
|
|
79
|
+
* ```js
|
|
80
|
+
* import {ArrayHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'
|
|
81
|
+
*
|
|
82
|
+
* defineField({
|
|
83
|
+
* name: 'categories',
|
|
84
|
+
* title: 'Categories',
|
|
85
|
+
* type: 'array',
|
|
86
|
+
* of: [
|
|
87
|
+
* {
|
|
88
|
+
* type: 'reference',
|
|
89
|
+
* to: {type: 'skosConcept'},
|
|
90
|
+
* options: {
|
|
91
|
+
* filter: schemeFilter({schemeId: 'f3deba'}),
|
|
92
|
+
* disableNew: true,
|
|
93
|
+
* },
|
|
94
|
+
* },
|
|
95
|
+
* ],
|
|
96
|
+
* components: {field: ArrayHierarchyInput},
|
|
97
|
+
* })
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* Branch filter with tree expanded by default:
|
|
102
|
+
* ```js
|
|
103
|
+
* import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
|
|
104
|
+
*
|
|
105
|
+
* defineField({
|
|
106
|
+
* name: 'habitats',
|
|
107
|
+
* title: 'Habitats',
|
|
108
|
+
* type: 'array',
|
|
109
|
+
* of: [
|
|
110
|
+
* {
|
|
111
|
+
* type: 'reference',
|
|
112
|
+
* to: {type: 'skosConcept'},
|
|
113
|
+
* options: {
|
|
114
|
+
* filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', expanded: true}),
|
|
115
|
+
* disableNew: true,
|
|
116
|
+
* },
|
|
117
|
+
* },
|
|
118
|
+
* ],
|
|
119
|
+
* components: {field: ArrayHierarchyInput},
|
|
120
|
+
* })
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* Browse-only mode (suppresses the default Sanity search input):
|
|
125
|
+
* ```js
|
|
126
|
+
* import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
|
|
127
|
+
*
|
|
128
|
+
* defineField({
|
|
129
|
+
* name: 'habitats',
|
|
130
|
+
* title: 'Habitats',
|
|
131
|
+
* type: 'array',
|
|
132
|
+
* of: [
|
|
133
|
+
* {
|
|
134
|
+
* type: 'reference',
|
|
135
|
+
* to: {type: 'skosConcept'},
|
|
136
|
+
* options: {
|
|
137
|
+
* filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', browseOnly: true}),
|
|
138
|
+
* disableNew: true,
|
|
139
|
+
* },
|
|
140
|
+
* },
|
|
141
|
+
* ],
|
|
142
|
+
* components: {field: ArrayHierarchyInput},
|
|
143
|
+
* })
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* AI-assisted recommendations via an embeddings index:
|
|
148
|
+
* ```jsx
|
|
149
|
+
* import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
|
|
150
|
+
*
|
|
151
|
+
* defineField({
|
|
152
|
+
* name: 'categories',
|
|
153
|
+
* title: 'Categories',
|
|
154
|
+
* type: 'array',
|
|
155
|
+
* of: [
|
|
156
|
+
* {
|
|
157
|
+
* type: 'reference',
|
|
158
|
+
* to: [{type: 'skosConcept'}],
|
|
159
|
+
* options: {
|
|
160
|
+
* filter: branchFilter({schemeId: 'f3deba', branchId: '25f826'}),
|
|
161
|
+
* disableNew: true,
|
|
162
|
+
* },
|
|
163
|
+
* },
|
|
164
|
+
* ],
|
|
165
|
+
* components: {
|
|
166
|
+
* field: (props) => (
|
|
167
|
+
* <ArrayHierarchyInput
|
|
168
|
+
* {...props}
|
|
169
|
+
* embeddingsIndex={{
|
|
170
|
+
* indexName: 'my-taxonomy-index',
|
|
171
|
+
* fieldReferences: ['title', 'description'],
|
|
172
|
+
* maxResults: 4,
|
|
173
|
+
* }}
|
|
174
|
+
* />
|
|
175
|
+
* ),
|
|
176
|
+
* },
|
|
177
|
+
* })
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @see {@link ReferenceHierarchyInput} for single-value `reference` fields
|
|
181
|
+
* @see {@link schemeFilter} for filtering by a full concept scheme
|
|
182
|
+
* @see {@link branchFilter} for filtering by a branch within a concept scheme
|
|
55
183
|
*/
|
|
56
184
|
export function ArrayHierarchyInput(props: ArrayHierarchyInputProps) {
|
|
57
185
|
const client = useClient({apiVersion: '2025-02-19'})
|
|
@@ -279,19 +407,24 @@ export function ArrayHierarchyInput(props: ArrayHierarchyInputProps) {
|
|
|
279
407
|
return props.renderDefault(props)
|
|
280
408
|
}
|
|
281
409
|
|
|
410
|
+
// Wrap the empty state in `FormField` so the field exposes the same
|
|
411
|
+
// DOM target Sanity's Validation panel uses for scroll-to-field /
|
|
412
|
+
// highlight on click. Without this wrapper, clicking a required
|
|
413
|
+
// browse-only field's validation error has no effect.
|
|
282
414
|
return (
|
|
283
|
-
<
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
415
|
+
<FormField
|
|
416
|
+
title={title}
|
|
417
|
+
description={props.description}
|
|
418
|
+
level={props.level}
|
|
419
|
+
validation={props.validation}
|
|
420
|
+
__unstable_presence={props.presence}
|
|
421
|
+
>
|
|
289
422
|
<Card padding={3} radius={2} border>
|
|
290
423
|
<Text muted align="center" size={1}>
|
|
291
424
|
No items
|
|
292
425
|
</Text>
|
|
293
426
|
</Card>
|
|
294
|
-
</
|
|
427
|
+
</FormField>
|
|
295
428
|
)
|
|
296
429
|
}
|
|
297
430
|
|
|
@@ -4,7 +4,7 @@ import type {DocumentId} from '@sanity/id-utils'
|
|
|
4
4
|
import {Grid, Stack, Button, Dialog, Box, Spinner, Text, Flex, Card} from '@sanity/ui'
|
|
5
5
|
import {useState, useEffect, useCallback} from 'react'
|
|
6
6
|
import type {ObjectFieldProps, ObjectOptions, Reference} from 'sanity'
|
|
7
|
-
import {isDraftId, useClient, useFormValue, usePerspective} from 'sanity'
|
|
7
|
+
import {FormField, isDraftId, useClient, useFormValue, usePerspective} from 'sanity'
|
|
8
8
|
|
|
9
9
|
import {useEmbeddingsRecs} from '../../hooks'
|
|
10
10
|
import NodeTree from '../../static/NodeTree'
|
|
@@ -33,13 +33,120 @@ type HierarchyInput = ObjectFieldProps<Reference> & {
|
|
|
33
33
|
type FilterResult = Awaited<ReturnType<ReferenceOptions['filter']>>
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* used as an input for taxonomy reference fields in Sanity Studio.
|
|
36
|
+
* Input component that replaces Sanity's default reference field input with a
|
|
37
|
+
* hierarchical taxonomy tree browser. Studio users can browse taxonomy terms
|
|
38
|
+
* organized in their scheme hierarchy and select a single term for the field.
|
|
40
39
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* - Must be used with a `schemeFilter` or `branchFilter` helper in the field's
|
|
42
|
+
* `options.filter`. Rendering without a filter will display a configuration warning.
|
|
43
|
+
* - Taxonomy selection is disabled when viewing the published perspective.
|
|
44
|
+
* - When `browseOnly` is set in the filter configuration, Sanity's default search input
|
|
45
|
+
* is suppressed and only the tree browser is available for term selection.
|
|
46
|
+
* - When `expanded` is set in the filter configuration, the hierarchy tree loads open
|
|
47
|
+
* by default instead of collapsed.
|
|
48
|
+
*
|
|
49
|
+
* @param props - Standard Sanity `ObjectFieldProps<Reference>` extended with an optional
|
|
50
|
+
* `embeddingsIndex` configuration object.
|
|
51
|
+
* @param props.embeddingsIndex - Optional configuration for AI-assisted term
|
|
52
|
+
* recommendations via a Sanity Embeddings Index. When provided, opening the tree
|
|
53
|
+
* browser queries the specified index and annotates matching taxonomy terms with
|
|
54
|
+
* a relevance score to help authors identify the most appropriate term.
|
|
55
|
+
* @param props.embeddingsIndex.indexName - The name of the Sanity Embeddings Index
|
|
56
|
+
* to query. Must be an index that includes `skosConcept` documents.
|
|
57
|
+
* @param props.embeddingsIndex.fieldReferences - An array of field names from the
|
|
58
|
+
* current document whose values are concatenated and sent as the embeddings search
|
|
59
|
+
* query. All listed fields must contain values when the tree browser is opened;
|
|
60
|
+
* empty fields will display an error message in the tree view rather than scores.
|
|
61
|
+
* @param props.embeddingsIndex.maxResults - Maximum number of semantically matching
|
|
62
|
+
* terms to return from the embeddings index. Defaults to `3`.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* Basic usage with a scheme filter:
|
|
66
|
+
* ```js
|
|
67
|
+
* import {ReferenceHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'
|
|
68
|
+
*
|
|
69
|
+
* defineField({
|
|
70
|
+
* name: 'gradeLevel',
|
|
71
|
+
* title: 'Grade Level',
|
|
72
|
+
* type: 'reference',
|
|
73
|
+
* to: {type: 'skosConcept'},
|
|
74
|
+
* options: {
|
|
75
|
+
* filter: schemeFilter({schemeId: 'f3deba'}),
|
|
76
|
+
* disableNew: true,
|
|
77
|
+
* },
|
|
78
|
+
* components: {field: ReferenceHierarchyInput},
|
|
79
|
+
* })
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* Branch filter with tree expanded by default:
|
|
84
|
+
* ```js
|
|
85
|
+
* import {ReferenceHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
|
|
86
|
+
*
|
|
87
|
+
* defineField({
|
|
88
|
+
* name: 'topics',
|
|
89
|
+
* title: 'Topics',
|
|
90
|
+
* type: 'reference',
|
|
91
|
+
* to: {type: 'skosConcept'},
|
|
92
|
+
* options: {
|
|
93
|
+
* filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', expanded: true}),
|
|
94
|
+
* disableNew: true,
|
|
95
|
+
* },
|
|
96
|
+
* components: {field: ReferenceHierarchyInput},
|
|
97
|
+
* })
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* Browse-only mode (suppresses the default Sanity search input):
|
|
102
|
+
* ```js
|
|
103
|
+
* import {ReferenceHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
|
|
104
|
+
*
|
|
105
|
+
* defineField({
|
|
106
|
+
* name: 'topics',
|
|
107
|
+
* title: 'Topics',
|
|
108
|
+
* type: 'reference',
|
|
109
|
+
* to: {type: 'skosConcept'},
|
|
110
|
+
* options: {
|
|
111
|
+
* filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', browseOnly: true}),
|
|
112
|
+
* disableNew: true,
|
|
113
|
+
* },
|
|
114
|
+
* components: {field: ReferenceHierarchyInput},
|
|
115
|
+
* })
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* AI-assisted recommendations via an embeddings index:
|
|
120
|
+
* ```jsx
|
|
121
|
+
* import {ReferenceHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'
|
|
122
|
+
*
|
|
123
|
+
* defineField({
|
|
124
|
+
* name: 'topics',
|
|
125
|
+
* title: 'Topics',
|
|
126
|
+
* type: 'reference',
|
|
127
|
+
* to: [{type: 'skosConcept'}],
|
|
128
|
+
* options: {
|
|
129
|
+
* filter: schemeFilter({schemeId: 'f3deba'}),
|
|
130
|
+
* disableNew: true,
|
|
131
|
+
* },
|
|
132
|
+
* components: {
|
|
133
|
+
* field: (props) => (
|
|
134
|
+
* <ReferenceHierarchyInput
|
|
135
|
+
* {...props}
|
|
136
|
+
* embeddingsIndex={{
|
|
137
|
+
* indexName: 'my-taxonomy-index',
|
|
138
|
+
* fieldReferences: ['title', 'metaDescription'],
|
|
139
|
+
* maxResults: 4,
|
|
140
|
+
* }}
|
|
141
|
+
* />
|
|
142
|
+
* ),
|
|
143
|
+
* },
|
|
144
|
+
* })
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @see {@link ArrayHierarchyInput} for multi-value `array` fields
|
|
148
|
+
* @see {@link schemeFilter} for filtering by a full concept scheme
|
|
149
|
+
* @see {@link branchFilter} for filtering by a branch within a concept scheme
|
|
43
150
|
*/
|
|
44
151
|
export function ReferenceHierarchyInput(props: HierarchyInput) {
|
|
45
152
|
const client = useClient({apiVersion: 'vX'})
|
|
@@ -223,19 +330,24 @@ export function ReferenceHierarchyInput(props: HierarchyInput) {
|
|
|
223
330
|
if (value) {
|
|
224
331
|
return props.renderDefault(props)
|
|
225
332
|
}
|
|
333
|
+
// Wrap the empty state in `FormField` so the field exposes the same
|
|
334
|
+
// DOM target Sanity's Validation panel uses for scroll-to-field /
|
|
335
|
+
// highlight on click. Without this wrapper, clicking a required
|
|
336
|
+
// browse-only field's validation error has no effect.
|
|
226
337
|
return (
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
338
|
+
<FormField
|
|
339
|
+
title={title}
|
|
340
|
+
description={props.description}
|
|
341
|
+
level={props.level}
|
|
342
|
+
validation={props.validation}
|
|
343
|
+
__unstable_presence={props.presence}
|
|
344
|
+
>
|
|
233
345
|
<Card padding={3} radius={2} border>
|
|
234
346
|
<Text muted align="center" size={1}>
|
|
235
347
|
No items
|
|
236
348
|
</Text>
|
|
237
349
|
</Card>
|
|
238
|
-
</
|
|
350
|
+
</FormField>
|
|
239
351
|
)
|
|
240
352
|
}
|
|
241
353
|
|