@sanity/embeddings-index-ui 1.0.3 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,14 +8,61 @@ var jsxRuntime = require('react/jsx-runtime');
8
8
  var ui = require('@sanity/ui');
9
9
  var icons = require('@sanity/icons');
10
10
  var require$$0 = require('react');
11
- var router = require('sanity/router');
12
11
  var desk = require('sanity/desk');
12
+ var router = require('sanity/router');
13
13
  function _interopDefaultCompat(e) {
14
14
  return e && typeof e === 'object' && 'default' in e ? e : {
15
15
  default: e
16
16
  };
17
17
  }
18
18
  var require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0);
19
+ function publicId(id) {
20
+ return id.replace("drafts.", "");
21
+ }
22
+ const featureName = "embeddingsIndexApi";
23
+ const FeatureEnabledContext = require$$0.createContext("loading");
24
+ function useIsFeatureEnabled() {
25
+ const client = sanity.useClient({
26
+ apiVersion: "2023-09-01"
27
+ });
28
+ const [status, setStatus] = require$$0.useState("loading");
29
+ require$$0.useEffect(() => {
30
+ client.request({
31
+ method: "GET",
32
+ url: "/projects/".concat(client.config().projectId, "/features/").concat(featureName)
33
+ }).then(isEnabled => {
34
+ setStatus(isEnabled === "true" || isEnabled === true ? "enabled" : "disabled");
35
+ }).catch(err => {
36
+ console.error(err);
37
+ setStatus("disabled");
38
+ });
39
+ }, [client]);
40
+ return status;
41
+ }
42
+ function FeatureEnabledProvider(props) {
43
+ const status = useIsFeatureEnabled();
44
+ return /* @__PURE__ */jsxRuntime.jsx(FeatureEnabledContext.Provider, {
45
+ value: status,
46
+ children: props.children
47
+ });
48
+ }
49
+ function useIsFeatureEnabledContext() {
50
+ return require$$0.useContext(FeatureEnabledContext);
51
+ }
52
+ function FeatureDisabledNotice() {
53
+ return /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
54
+ tone: "primary",
55
+ border: true,
56
+ padding: 2,
57
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
58
+ size: 1,
59
+ children: ["Embeddings index APIs are only available on the", " ", /* @__PURE__ */jsxRuntime.jsx("a", {
60
+ href: "https://sanity.io/pricing",
61
+ children: "Team tier and above"
62
+ }), ". Please upgrade to enable access."]
63
+ })
64
+ });
65
+ }
19
66
 
20
67
  /******************************************************************************
21
68
  Copyright (c) Microsoft Corporation.
@@ -1887,9 +1934,6 @@ function deleteIndex(indexName, client) {
1887
1934
  url: "/embeddings-index/".concat(dataset, "/").concat(indexName, "?projectId=").concat(projectId)
1888
1935
  });
1889
1936
  }
1890
- function publicId(id) {
1891
- return id.replace("drafts.", "");
1892
- }
1893
1937
  function useApiClient() {
1894
1938
  const client = sanity.useClient({
1895
1939
  apiVersion: "vX"
@@ -1906,107 +1950,20 @@ function useApiClient() {
1906
1950
  return client;
1907
1951
  }, [client]);
1908
1952
  }
1909
- const featureName = "embeddingsIndexApi";
1910
- const FeatureEnabledContext = require$$0.createContext("loading");
1911
- function useIsFeatureEnabled() {
1912
- const client = sanity.useClient({
1913
- apiVersion: "2023-09-01"
1914
- });
1915
- const [status, setStatus] = require$$0.useState("loading");
1916
- require$$0.useEffect(() => {
1917
- client.request({
1918
- method: "GET",
1919
- url: "/projects/".concat(client.config().projectId, "/features/").concat(featureName)
1920
- }).then(isEnabled => {
1921
- setStatus(isEnabled === "true" || isEnabled === true ? "enabled" : "disabled");
1922
- }).catch(err => {
1923
- console.error(err);
1924
- setStatus("disabled");
1925
- });
1926
- }, [client]);
1927
- return status;
1928
- }
1929
- function FeatureEnabledProvider(props) {
1930
- const status = useIsFeatureEnabled();
1931
- return /* @__PURE__ */jsxRuntime.jsx(FeatureEnabledContext.Provider, {
1932
- value: status,
1933
- children: props.children
1934
- });
1935
- }
1936
- function useIsFeatureEnabledContext() {
1937
- return require$$0.useContext(FeatureEnabledContext);
1938
- }
1939
- function FeatureDisabledNotice() {
1940
- return /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
1941
- tone: "primary",
1942
- border: true,
1943
- padding: 2,
1944
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
1945
- size: 1,
1946
- children: ["Embeddings index APIs are only available on the", " ", /* @__PURE__ */jsxRuntime.jsx("a", {
1947
- href: "https://sanity.io/pricing",
1948
- children: "Team tier and above"
1949
- }), ". Please upgrade to enable access."]
1950
- })
1951
- });
1952
- }
1953
+ const NO_RESULTS_VALUE = "";
1953
1954
  const NO_OPTIONS = [];
1954
1955
  const NO_FILTER = () => true;
1955
- function SemanticSearchReferenceInput(props) {
1956
- var _a, _b, _c;
1957
- const defaultEnabled = ((_c = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex) == null ? void 0 : _c.searchMode) === "embeddings";
1958
- const featureState = useIsFeatureEnabledContext();
1959
- const [semantic, setSemantic] = require$$0.useState(defaultEnabled);
1960
- const toggleSemantic = require$$0.useCallback(() => setSemantic(current => !current), []);
1961
- return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
1962
- gap: 2,
1963
- flex: 1,
1964
- style: {
1965
- width: "100%"
1966
- },
1967
- children: [semantic && featureState == "loading" ? /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
1968
- padding: 2,
1969
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
1970
- }) : null, semantic && featureState == "disabled" ? /* @__PURE__ */jsxRuntime.jsx(FeatureDisabledNotice, {}) : null, /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
1971
- flex: 1,
1972
- style: {
1973
- maxHeight: 36,
1974
- overflow: "hidden"
1975
- },
1976
- children: semantic && featureState == "enabled" ? /* @__PURE__ */jsxRuntime.jsx(SemanticSearchInput, {
1977
- ...props
1978
- }) : props.renderDefault(props)
1979
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
1980
- icon: semantic ? icons.EarthGlobeIcon : icons.LinkIcon,
1981
- onClick: toggleSemantic,
1982
- mode: "bleed",
1983
- title: semantic ? "Switch to standard reference search" : "Switch to semantic reference search"
1984
- })]
1985
- });
1986
- }
1987
- function useDebouncedValue(value, ms) {
1988
- const [debouncedValue, setDebouncedValue] = require$$0.useState(value);
1989
- require$$0.useEffect(() => {
1990
- const timeoutId = setTimeout(() => {
1991
- setDebouncedValue(value);
1992
- }, ms);
1993
- return () => clearTimeout(timeoutId);
1994
- }, [value, ms]);
1995
- return debouncedValue;
1996
- }
1997
- function SemanticSearchInput(props) {
1956
+ const SemanticSearchAutocomplete = require$$0.forwardRef(function SemanticSearchAutocomplete2(props, ref) {
1998
1957
  const {
1999
- onPathFocus,
2000
- onChange,
1958
+ indexConfig,
1959
+ filterResult,
1960
+ getEmptySearchValue,
2001
1961
  readOnly,
2002
- schemaType,
2003
- value
1962
+ onFocus,
1963
+ onBlur,
1964
+ onSelect,
1965
+ typeFilter
2004
1966
  } = props;
2005
- const {
2006
- value: currentDocument
2007
- } = desk.useDocumentPane();
2008
- const docRef = require$$0.useRef(currentDocument);
2009
- const autocompleteRef = require$$0.useRef(null);
2010
1967
  const id = require$$0.useId();
2011
1968
  const [query, setQuery] = require$$0.useState("");
2012
1969
  const queryRef = require$$0.useRef(query);
@@ -2015,29 +1972,16 @@ function SemanticSearchInput(props) {
2015
1972
  const [searching, setSearching] = require$$0.useState(false);
2016
1973
  const [options, setOptions] = require$$0.useState(NO_OPTIONS);
2017
1974
  const client = useApiClient();
2018
- require$$0.useEffect(() => {
2019
- docRef.current = currentDocument;
2020
- }, [currentDocument]);
2021
- require$$0.useEffect(() => {
2022
- var _a;
2023
- if (value == null ? void 0 : value._ref) {
2024
- (_a = autocompleteRef.current) == null ? void 0 : _a.focus();
2025
- }
2026
- }, []);
2027
- const handleFocus = require$$0.useCallback(() => onPathFocus(["_ref"]), [onPathFocus]);
2028
- const handleBlur = require$$0.useCallback(() => onPathFocus([]), [onPathFocus]);
2029
1975
  const runIndexQuery = require$$0.useCallback(queryString => {
2030
- var _a, _b, _c, _d, _e;
1976
+ var _a;
2031
1977
  setSearching(true);
2032
- const refSchema = schemaType;
2033
- const indexName = (_b = (_a = refSchema.options) == null ? void 0 : _a.embeddingsIndex) == null ? void 0 : _b.indexName;
2034
- const maxResults = (_d = (_c = refSchema.options) == null ? void 0 : _c.embeddingsIndex) == null ? void 0 : _d.maxResults;
2035
- const typeFilter = refSchema.to.map(ref => ref.name);
1978
+ const indexName = indexConfig == null ? void 0 : indexConfig.indexName;
1979
+ const maxResults = indexConfig == null ? void 0 : indexConfig.maxResults;
2036
1980
  if (!indexName) {
2037
- throw new Error("Reference option embeddingsIndex.indexName is required, but was missing in type ".concat(refSchema.name));
1981
+ throw new Error("Reference option embeddingsIndex.indexName is required, but was missing");
2038
1982
  }
2039
1983
  queryIndex({
2040
- query: queryString.trim().length ? queryString : (_e = JSON.stringify(docRef.current)) != null ? _e : "",
1984
+ query: queryString.trim().length ? queryString : (_a = getEmptySearchValue()) != null ? _a : "",
2041
1985
  indexName,
2042
1986
  maxResults,
2043
1987
  filter: {
@@ -2046,10 +1990,18 @@ function SemanticSearchInput(props) {
2046
1990
  }, client).then(result => {
2047
1991
  if (queryRef.current === queryString) {
2048
1992
  setSearching(false);
2049
- setOptions(result.filter(r => r.value.documentId !== publicId(docRef.current._id)).map(r => sanity.typed({
1993
+ setOptions([]);
1994
+ const resultOptions = result.filter(hit => filterResult ? filterResult(hit) : true).map(r => sanity.typed({
2050
1995
  result: r,
2051
1996
  value: r.value.documentId
2052
- })));
1997
+ }));
1998
+ if (resultOptions.length) {
1999
+ setOptions(resultOptions);
2000
+ } else {
2001
+ setOptions([{
2002
+ value: NO_RESULTS_VALUE
2003
+ }]);
2004
+ }
2053
2005
  }
2054
2006
  }).catch(e => {
2055
2007
  if (queryRef.current === queryString) {
@@ -2057,23 +2009,13 @@ function SemanticSearchInput(props) {
2057
2009
  }
2058
2010
  throw e;
2059
2011
  });
2060
- }, [client, schemaType]);
2012
+ }, [client, indexConfig, getEmptySearchValue, filterResult, typeFilter]);
2061
2013
  require$$0.useEffect(() => {
2062
2014
  if (prevDebouncedQuery.current !== debouncedQuery) {
2063
2015
  runIndexQuery(debouncedQuery);
2064
2016
  }
2065
2017
  prevDebouncedQuery.current = debouncedQuery;
2066
2018
  }, [debouncedQuery, runIndexQuery]);
2067
- const handleChange = require$$0.useCallback(nextId => {
2068
- if (!nextId) {
2069
- onChange(sanity.unset());
2070
- onPathFocus([]);
2071
- return;
2072
- }
2073
- const patches = [sanity.setIfMissing({}), sanity.set(schemaType.name, ["_type"]), sanity.set(publicId(nextId), ["_ref"]), sanity.unset(["_weak"]), sanity.unset(["_strengthenOnPublish"])];
2074
- onChange(patches);
2075
- onPathFocus([]);
2076
- }, [onChange, onPathFocus, schemaType.name]);
2077
2019
  const openButtonConfig = require$$0.useMemo(() => ({
2078
2020
  onClick: () => runIndexQuery(queryRef.current)
2079
2021
  }), [runIndexQuery, queryRef]);
@@ -2082,52 +2024,190 @@ function SemanticSearchInput(props) {
2082
2024
  queryRef.current = newQuery;
2083
2025
  setQuery(newQuery);
2084
2026
  }, [setQuery]);
2027
+ const handleChange = require$$0.useCallback(value => {
2028
+ if (value === NO_RESULTS_VALUE) {
2029
+ setOptions(NO_OPTIONS);
2030
+ return;
2031
+ }
2032
+ const option = options.filter(r => "result" in r).find(r => r.result.value.documentId === value);
2033
+ if (option && onSelect) {
2034
+ onSelect(option.result);
2035
+ }
2036
+ }, [onSelect, options]);
2085
2037
  return /* @__PURE__ */jsxRuntime.jsx(ui.Autocomplete, {
2086
2038
  id,
2087
- ref: autocompleteRef,
2039
+ ref,
2088
2040
  "data-testid": "semantic-autocomplete",
2089
2041
  placeholder: "Type to search...",
2090
2042
  openButton: openButtonConfig,
2091
- onFocus: handleFocus,
2043
+ onFocus,
2092
2044
  onChange: handleChange,
2093
2045
  loading: searching,
2094
- onBlur: handleBlur,
2046
+ onBlur,
2095
2047
  readOnly,
2096
2048
  filterOption: NO_FILTER,
2097
2049
  onQueryChange: handleQueryChange,
2098
2050
  options,
2099
2051
  renderOption: AutocompleteOption
2100
2052
  });
2101
- }
2053
+ });
2102
2054
  function AutocompleteOption(props) {
2103
- const value = props.result.value;
2055
+ if ("result" in props) {
2056
+ const value = props.result.value;
2057
+ return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
2058
+ mode: "bleed",
2059
+ padding: 1,
2060
+ style: {
2061
+ width: "100%"
2062
+ },
2063
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2064
+ gap: 2,
2065
+ align: "center",
2066
+ children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2067
+ flex: 1,
2068
+ children: /* @__PURE__ */jsxRuntime.jsx(DocumentPreview, {
2069
+ documentId: value.documentId,
2070
+ schemaTypeName: value.type
2071
+ })
2072
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2073
+ padding: 2,
2074
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
2075
+ size: 1,
2076
+ muted: true,
2077
+ title: "Relevance",
2078
+ children: [Math.floor(props.result.score * 100), "%"]
2079
+ })
2080
+ })]
2081
+ })
2082
+ });
2083
+ }
2104
2084
  return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
2105
2085
  mode: "bleed",
2106
2086
  padding: 1,
2107
2087
  style: {
2108
2088
  width: "100%"
2109
2089
  },
2110
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2090
+ disabled: true,
2091
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
2111
2092
  gap: 2,
2112
2093
  align: "center",
2113
- children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2114
- flex: 1,
2115
- children: /* @__PURE__ */jsxRuntime.jsx(DocumentPreview, {
2116
- documentId: value.documentId,
2117
- schemaTypeName: value.type
2118
- })
2119
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2120
- padding: 2,
2121
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
2122
- size: 1,
2123
- muted: true,
2124
- title: "Relevance",
2125
- children: [Math.floor(props.result.score * 100), "%"]
2126
- })
2127
- })]
2094
+ children: "No results."
2128
2095
  })
2129
2096
  });
2130
2097
  }
2098
+ function useDebouncedValue(value, ms) {
2099
+ const [debouncedValue, setDebouncedValue] = require$$0.useState(value);
2100
+ require$$0.useEffect(() => {
2101
+ const timeoutId = setTimeout(() => {
2102
+ setDebouncedValue(value);
2103
+ }, ms);
2104
+ return () => clearTimeout(timeoutId);
2105
+ }, [value, ms]);
2106
+ return debouncedValue;
2107
+ }
2108
+ function useEmeddingsConfig(embeddingsIndexConfig, defaultConfig) {
2109
+ return require$$0.useMemo(() => {
2110
+ if (embeddingsIndexConfig === true || !embeddingsIndexConfig) {
2111
+ if (!(defaultConfig == null ? void 0 : defaultConfig.indexName)) {
2112
+ throw new Error("Default embeddingsIndex config is missing. When options.embeddingsIndex: true, embeddingsIndexReferenceInput plugin config is required.");
2113
+ }
2114
+ return defaultConfig;
2115
+ }
2116
+ const finalConfig = {
2117
+ ...defaultConfig,
2118
+ ...embeddingsIndexConfig
2119
+ };
2120
+ if (!(finalConfig == null ? void 0 : finalConfig.indexName)) {
2121
+ throw new Error("indexName is missing. Either set it in options.embeddingsIndex or configure defaults using plugin config.");
2122
+ }
2123
+ return finalConfig;
2124
+ }, [defaultConfig, embeddingsIndexConfig]);
2125
+ }
2126
+ function SemanticSearchReferenceInput(props) {
2127
+ var _a, _b;
2128
+ const embeddingsIndexConfig = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex;
2129
+ const config = useEmeddingsConfig(embeddingsIndexConfig, props.defaultConfig);
2130
+ const defaultEnabled = config.searchMode === "embeddings";
2131
+ const featureState = useIsFeatureEnabledContext();
2132
+ const [semantic, setSemantic] = require$$0.useState(defaultEnabled);
2133
+ const toggleSemantic = require$$0.useCallback(() => setSemantic(current => !current), []);
2134
+ return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2135
+ gap: 2,
2136
+ flex: 1,
2137
+ style: {
2138
+ width: "100%"
2139
+ },
2140
+ children: [semantic && featureState == "loading" ? /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2141
+ padding: 2,
2142
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
2143
+ }) : null, semantic && featureState == "disabled" ? /* @__PURE__ */jsxRuntime.jsx(FeatureDisabledNotice, {}) : null, /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2144
+ flex: 1,
2145
+ style: {
2146
+ maxHeight: 36,
2147
+ overflow: "hidden"
2148
+ },
2149
+ children: semantic && featureState == "enabled" ? /* @__PURE__ */jsxRuntime.jsx(SemanticSearchInput, {
2150
+ ...props,
2151
+ indexConfig: config
2152
+ }) : props.renderDefault(props)
2153
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
2154
+ icon: semantic ? icons.EarthGlobeIcon : icons.LinkIcon,
2155
+ onClick: toggleSemantic,
2156
+ mode: "bleed",
2157
+ title: semantic ? "Switch to standard reference search" : "Switch to semantic reference search"
2158
+ })]
2159
+ });
2160
+ }
2161
+ function SemanticSearchInput(props) {
2162
+ const {
2163
+ indexConfig,
2164
+ onPathFocus,
2165
+ onChange,
2166
+ readOnly,
2167
+ schemaType,
2168
+ value
2169
+ } = props;
2170
+ const {
2171
+ value: currentDocument
2172
+ } = desk.useDocumentPane();
2173
+ const docRef = require$$0.useRef(currentDocument);
2174
+ const autocompleteRef = require$$0.useRef(null);
2175
+ require$$0.useEffect(() => {
2176
+ docRef.current = currentDocument;
2177
+ }, [currentDocument]);
2178
+ require$$0.useEffect(() => {
2179
+ var _a;
2180
+ if (value == null ? void 0 : value._ref) {
2181
+ (_a = autocompleteRef.current) == null ? void 0 : _a.focus();
2182
+ }
2183
+ }, []);
2184
+ const handleFocus = require$$0.useCallback(() => onPathFocus(["_ref"]), [onPathFocus]);
2185
+ const handleBlur = require$$0.useCallback(() => onPathFocus([]), [onPathFocus]);
2186
+ const handleChange = require$$0.useCallback(result => {
2187
+ if (!result) {
2188
+ onChange(sanity.unset());
2189
+ onPathFocus([]);
2190
+ return;
2191
+ }
2192
+ const patches = [sanity.setIfMissing({}), sanity.set(schemaType.name, ["_type"]), sanity.set(publicId(result.value.documentId), ["_ref"]), sanity.unset(["_weak"]), sanity.unset(["_strengthenOnPublish"])];
2193
+ onChange(patches);
2194
+ onPathFocus([]);
2195
+ }, [onChange, onPathFocus, schemaType.name]);
2196
+ const filterResult = require$$0.useCallback(r => r.value.documentId !== publicId(docRef.current._id), [docRef]);
2197
+ const getEmptySearchValue = require$$0.useCallback(() => JSON.stringify(docRef.current), [docRef]);
2198
+ const typeFilter = require$$0.useMemo(() => schemaType.to.map(refType => refType.name), [schemaType]);
2199
+ return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchAutocomplete, {
2200
+ ref: autocompleteRef,
2201
+ typeFilter,
2202
+ indexConfig,
2203
+ onSelect: handleChange,
2204
+ onFocus: handleFocus,
2205
+ onBlur: handleBlur,
2206
+ getEmptySearchValue,
2207
+ filterResult,
2208
+ readOnly
2209
+ });
2210
+ }
2131
2211
  function isType(schemaType, typeName) {
2132
2212
  if (schemaType.name === typeName) {
2133
2213
  return true;
@@ -2137,30 +2217,35 @@ function isType(schemaType, typeName) {
2137
2217
  }
2138
2218
  return isType(schemaType.type, typeName);
2139
2219
  }
2140
- const embeddingsIndexReferenceInput = sanity.definePlugin({
2141
- name: "@sanity/embeddings-index-reference-input",
2142
- studio: {
2143
- components: {
2144
- layout: props => {
2145
- return /* @__PURE__ */jsxRuntime.jsx(FeatureEnabledProvider, {
2146
- children: props.renderDefault(props)
2147
- });
2148
- }
2149
- }
2150
- },
2151
- form: {
2152
- components: {
2153
- input: props => {
2154
- var _a, _b;
2155
- if (sanity.isObjectInputProps(props) && isType(props.schemaType, "reference") && ((_b = (_a = props.schemaType.options) == null ? void 0 : _a.embeddingsIndex) == null ? void 0 : _b.indexName)) {
2156
- return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchReferenceInput, {
2157
- ...props
2220
+ const embeddingsIndexReferenceInput = sanity.definePlugin(defaultConfig => {
2221
+ const config = typeof defaultConfig === "object" ? defaultConfig : void 0;
2222
+ return {
2223
+ name: "@sanity/embeddings-index-reference-input",
2224
+ studio: {
2225
+ components: {
2226
+ layout: props => {
2227
+ return /* @__PURE__ */jsxRuntime.jsx(FeatureEnabledProvider, {
2228
+ children: props.renderDefault(props)
2158
2229
  });
2159
2230
  }
2160
- return props.renderDefault(props);
2231
+ }
2232
+ },
2233
+ form: {
2234
+ components: {
2235
+ input: props => {
2236
+ var _a, _b;
2237
+ const embeddingsIndexConfig = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex;
2238
+ if (sanity.isObjectInputProps(props) && isType(props.schemaType, "reference") && (embeddingsIndexConfig === true || (embeddingsIndexConfig == null ? void 0 : embeddingsIndexConfig.indexName))) {
2239
+ return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchReferenceInput, {
2240
+ ...props,
2241
+ defaultConfig: config
2242
+ });
2243
+ }
2244
+ return props.renderDefault(props);
2245
+ }
2161
2246
  }
2162
2247
  }
2163
- }
2248
+ };
2164
2249
  });
2165
2250
  const defaultProjection = "{...}";
2166
2251
  function useDefaultIndex(schema, dataset) {
@@ -2175,6 +2260,7 @@ function IndexFormInput(props) {
2175
2260
  var _a;
2176
2261
  const {
2177
2262
  label,
2263
+ description,
2178
2264
  index,
2179
2265
  prop,
2180
2266
  onChange,
@@ -2188,6 +2274,7 @@ function IndexFormInput(props) {
2188
2274
  })), [onChange, prop]);
2189
2275
  return /* @__PURE__ */jsxRuntime.jsx(FormInput, {
2190
2276
  label,
2277
+ description,
2191
2278
  onChange: handleChange,
2192
2279
  value: (_a = index[prop]) != null ? _a : "",
2193
2280
  readOnly,
@@ -2198,6 +2285,7 @@ function IndexFormInput(props) {
2198
2285
  function FormInput(props) {
2199
2286
  const {
2200
2287
  label,
2288
+ description,
2201
2289
  onChange,
2202
2290
  value,
2203
2291
  readOnly,
@@ -2215,6 +2303,12 @@ function FormInput(props) {
2215
2303
  htmlFor: id,
2216
2304
  children: label
2217
2305
  })
2306
+ }), description && /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2307
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
2308
+ size: 1,
2309
+ muted: true,
2310
+ children: description
2311
+ })
2218
2312
  }), type === "text" ? /* @__PURE__ */jsxRuntime.jsx(ui.TextInput, {
2219
2313
  id,
2220
2314
  value,
@@ -2369,18 +2463,20 @@ function IndexEditor(props) {
2369
2463
  onChange: setIndex,
2370
2464
  readOnly: true
2371
2465
  }), /* @__PURE__ */jsxRuntime.jsx(IndexFormInput, {
2372
- label: "Projection",
2373
- placeholder: defaultIndex.projection,
2466
+ label: "Filter",
2467
+ description: "Must be a valid GROQ filter",
2468
+ placeholder: defaultIndex.filter,
2374
2469
  index,
2375
- prop: "projection",
2470
+ prop: "filter",
2376
2471
  onChange: setIndex,
2377
2472
  readOnly,
2378
2473
  type: "textarea"
2379
2474
  }), /* @__PURE__ */jsxRuntime.jsx(IndexFormInput, {
2380
- label: "Filter",
2381
- placeholder: defaultIndex.filter,
2475
+ label: "Projection",
2476
+ description: "Must be a valid GROQ projection, starting { and ending with }",
2477
+ placeholder: defaultIndex.projection,
2382
2478
  index,
2383
- prop: "filter",
2479
+ prop: "projection",
2384
2480
  onChange: setIndex,
2385
2481
  readOnly,
2386
2482
  type: "textarea"
@@ -2417,6 +2513,7 @@ function IndexList(props) {
2417
2513
  borderBottom: true,
2418
2514
  flex: 1,
2419
2515
  paddingBottom: 2,
2516
+ padding: 3,
2420
2517
  children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2421
2518
  children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2422
2519
  flex: 1,
@@ -2471,12 +2568,15 @@ function IndexRow(props) {
2471
2568
  const onSelect = require$$0.useCallback(() => onIndexSelected(index), [onIndexSelected, index]);
2472
2569
  return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
2473
2570
  tone: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "primary" : "default",
2474
- mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "bleed",
2571
+ mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "ghost",
2475
2572
  onClick: onSelect,
2573
+ padding: 3,
2476
2574
  children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2477
2575
  children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2478
2576
  flex: 1,
2479
- children: index.indexName
2577
+ children: /* @__PURE__ */jsxRuntime.jsx("strong", {
2578
+ children: index.indexName
2579
+ })
2480
2580
  }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2481
2581
  flex: 1,
2482
2582
  children: index.dataset
@@ -2490,102 +2590,31 @@ function IndexRow(props) {
2490
2590
  })
2491
2591
  }, index.indexName);
2492
2592
  }
2493
- const NO_RESULTS = [];
2494
2593
  function QueryIndex(props) {
2495
2594
  const {
2496
2595
  indexName
2497
2596
  } = props;
2498
- const [query, setQuery] = require$$0.useState("");
2499
- const [searching, setSearching] = require$$0.useState(false);
2500
- const [results, setResults] = require$$0.useState(NO_RESULTS);
2501
- const client = useApiClient();
2502
- const search = require$$0.useCallback(queryString => {
2503
- setSearching(true);
2504
- return queryIndex({
2505
- query: queryString,
2506
- indexName,
2507
- maxResults: 5
2508
- }, client).then(setResults).finally(() => setSearching(false));
2509
- }, [client, indexName]);
2510
- const onInputChange = require$$0.useCallback(e => {
2511
- setQuery(e.currentTarget.value);
2512
- }, []);
2513
- const onKeyDown = require$$0.useCallback(e => {
2514
- if (e.key === "Enter") {
2515
- search(query).catch(console.error);
2516
- }
2517
- }, [search, query]);
2518
- return /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
2519
- space: 3,
2520
- flex: 1,
2521
- children: [/* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
2522
- flex: 1,
2523
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
2524
- flex: 1,
2525
- children: /* @__PURE__ */jsxRuntime.jsx(ui.TextInput, {
2526
- iconRight: searching ? /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2527
- style: {
2528
- marginTop: 5
2529
- },
2530
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
2531
- }) : icons.SearchIcon,
2532
- placeholder: "Find documents",
2533
- value: query,
2534
- disabled: searching,
2535
- onChange: onInputChange,
2536
- onKeyDown
2537
- })
2538
- })
2539
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
2540
- gap: 4,
2541
- style: {
2542
- opacity: searching ? 0.5 : 1
2543
- },
2544
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2545
- flex: 1,
2546
- children: /* @__PURE__ */jsxRuntime.jsx(ResultList, {
2547
- results,
2548
- query
2549
- })
2550
- })
2551
- })]
2552
- });
2553
- }
2554
- function ResultList(props) {
2597
+ const getEmpty = require$$0.useCallback(() => "anything", []);
2598
+ const indexConfig = require$$0.useMemo(() => ({
2599
+ indexName,
2600
+ maxResults: 8
2601
+ }), [indexName]);
2555
2602
  const {
2556
- results,
2557
- query
2558
- } = props;
2559
- return /* @__PURE__ */jsxRuntime.jsx(ui.Stack, {
2560
- space: 4,
2561
- height: "fill",
2562
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
2563
- space: 2,
2564
- children: [results.map(r => /* @__PURE__ */jsxRuntime.jsx(ResultEntry, {
2565
- result: r
2566
- }, r.value.documentId)), !results.length && query ? "No results." : null]
2567
- })
2568
- });
2569
- }
2570
- function ResultEntry(props) {
2571
- const value = props.result.value;
2572
- return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2573
- gap: 4,
2574
- align: "center",
2575
- children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2576
- flex: 1,
2577
- children: /* @__PURE__ */jsxRuntime.jsx(DocumentPreview, {
2578
- documentId: value.documentId,
2579
- schemaTypeName: value.type,
2580
- button: true
2603
+ resolveIntentLink,
2604
+ navigateUrl
2605
+ } = router.useRouter();
2606
+ const onSelect = require$$0.useCallback(hit => {
2607
+ navigateUrl({
2608
+ path: resolveIntentLink("edit", {
2609
+ id: hit.value.documentId,
2610
+ type: hit.value.type
2581
2611
  })
2582
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2583
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
2584
- muted: true,
2585
- size: 1,
2586
- children: [Math.floor(props.result.score * 100), " %"]
2587
- })
2588
- })]
2612
+ });
2613
+ }, [resolveIntentLink, navigateUrl]);
2614
+ return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchAutocomplete, {
2615
+ getEmptySearchValue: getEmpty,
2616
+ indexConfig,
2617
+ onSelect
2589
2618
  });
2590
2619
  }
2591
2620
  function IndexInfo(_ref3) {