sanity-plugin-iconify 2.0.0 → 2.0.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/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { unset, set, definePlugin } from "sanity";
3
3
  import { Grid, Box, Card, Text, TextInput, Button, useToast, Popover, ThemeProvider, Stack, Flex } from "@sanity/ui";
4
4
  import { buildTheme } from "@sanity/ui/theme";
5
5
  import { useState, useCallback, forwardRef, useId, useRef, useEffect, useMemo } from "react";
6
- import { ComboboxInput, ComboboxOptions, ComboboxOption, Combobox } from "@headlessui/react";
6
+ import { useCombobox } from "downshift";
7
7
  import { match } from "ts-pattern";
8
8
  import { useQueryClient, useQuery, keepPreviousData, QueryClient, QueryClientProvider as QueryClientProvider$1 } from "@tanstack/react-query";
9
9
  import { useDebounce } from "use-debounce";
@@ -34,13 +34,12 @@ function useSearch({ collections }) {
34
34
  ), { isLoading, isError, error, data, isPlaceholderData } = useQuery({
35
35
  queryKey: ["search", collections, debouncedTerm],
36
36
  queryFn: async ({ signal }) => {
37
- var _a;
38
37
  const url = new URL("/search", BASE_API_URL);
39
38
  url.searchParams.append("query", debouncedTerm), url.searchParams.append("limit", "60"), collections && url.searchParams.append("prefixes", collections.join(","));
40
39
  const result = debouncedTerm ? await fetchJson({ url, signal }) : null;
41
40
  return result && Object.entries(result.collections).forEach(([prefix, info]) => {
42
41
  queryClient2.setQueryData(["iconSetInfo", prefix], info);
43
- }), (_a = result == null ? void 0 : result.icons) != null ? _a : [];
42
+ }), result?.icons ?? [];
44
43
  },
45
44
  enabled: debouncedTerm.length > 0,
46
45
  placeholderData: keepPreviousData,
@@ -62,48 +61,46 @@ function useIconSetInfo({ prefix }) {
62
61
  return useQuery({
63
62
  queryKey: ["iconSetInfo", prefix],
64
63
  queryFn: async ({ signal }) => {
65
- var _a;
66
64
  if (!prefix) return null;
67
65
  const url = new URL("/collection", BASE_API_URL);
68
- url.searchParams.append("prefix", prefix), url.searchParams.append("info", "true");
69
- const result = await fetchJson({ url, signal });
70
- return (_a = result == null ? void 0 : result.info) != null ? _a : null;
66
+ return url.searchParams.append("prefix", prefix), url.searchParams.append("info", "true"), (await fetchJson({ url, signal }))?.info ?? null;
71
67
  },
72
68
  staleTime: 1 / 0
73
69
  });
74
70
  }
75
- const ComboboxWrapper = styled(Grid)`
71
+ styled(Grid)`
76
72
  grid-template-columns: 1fr min-content;
77
73
  position: relative;
78
- `, OptionsWrapper = styled(Box)`
74
+ `;
75
+ const OptionsWrapper = styled(Box)`
79
76
  box-sizing: border-box;
80
77
  padding: 0.5rem;
81
78
 
82
79
  & [role='listbox'] {
83
- display: grid;
84
- grid-template-columns: repeat(auto-fill, minmax(min(100%, 2.5rem), 1fr));
80
+ display: flex;
81
+ flex-wrap: wrap;
85
82
  gap: 0.5rem;
86
83
  margin: 0;
87
84
  padding: 0;
88
85
  list-style: none;
89
-
90
- @media (min-width: 650px) {
91
- grid-template-columns: repeat(10, minmax(min(100%, 2.5rem), 1fr));
92
- }
93
86
  }
94
87
 
95
88
  & [role='option'] {
96
89
  display: grid;
97
90
  place-items: center;
91
+ width: clamp(3rem, 10vw, 4rem);
98
92
 
99
93
  & button {
100
94
  cursor: pointer;
101
- aspect-ratio: 1;
102
95
  width: 100%;
103
96
 
104
97
  & > [data-ui='Box'] {
105
98
  display: flex;
106
99
  }
100
+
101
+ & svg {
102
+ aspect-ratio: 1;
103
+ }
107
104
  }
108
105
  }
109
106
  `;
@@ -111,15 +108,13 @@ function MessageWrapper({ children }) {
111
108
  return /* @__PURE__ */ jsx(Card, { padding: 4, children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, children }) });
112
109
  }
113
110
  const SearchInput = forwardRef((props, ref) => {
114
- const { term, selectedIcon, onChange, suffix } = props;
111
+ const { selectedIcon, suffix, ...rest } = props;
115
112
  return /* @__PURE__ */ jsx(
116
- ComboboxInput,
113
+ TextInput,
117
114
  {
118
- as: TextInput,
115
+ ...rest,
119
116
  ref,
120
117
  inputMode: "search",
121
- value: term,
122
- onChange,
123
118
  icon: selectedIcon ? /* @__PURE__ */ jsx(Icon, { icon: selectedIcon }) : null,
124
119
  placeholder: selectedIcon ? "Search and replace selected icon..." : "Search for an icon...",
125
120
  suffix
@@ -127,10 +122,24 @@ const SearchInput = forwardRef((props, ref) => {
127
122
  );
128
123
  });
129
124
  SearchInput.displayName = "SearchInput";
130
- function SearchResults(props) {
131
- const { state, data } = props;
132
- return state === "initial" ? /* @__PURE__ */ jsx(MessageWrapper, { children: "Search for icons" }) : state === "loading" ? /* @__PURE__ */ jsx(MessageWrapper, { children: "Searching..." }) : state === "error" ? /* @__PURE__ */ jsx(MessageWrapper, { children: "Something went wrong..." }) : state === "empty" ? /* @__PURE__ */ jsx(MessageWrapper, { children: "No icons found" }) : /* @__PURE__ */ jsx(ComboboxOptions, { style: { opacity: state === "stale" ? 0.5 : 1 }, children: data.map((icon) => /* @__PURE__ */ jsx(ComboboxOption, { value: icon, children: ({ focus }) => /* @__PURE__ */ jsx(Button, { padding: 3, mode: "bleed", selected: focus, children: /* @__PURE__ */ jsx(Icon, { icon, width: "100%", height: "100%" }) }) }, icon)) });
133
- }
125
+ const SearchResults = forwardRef((props, ref) => {
126
+ const { state, data, getItemProps, highlightedIndex, ...rest } = props;
127
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
128
+ (() => {
129
+ switch (state) {
130
+ case "initial":
131
+ return /* @__PURE__ */ jsx(MessageWrapper, { children: "Search for icons" });
132
+ case "loading":
133
+ return /* @__PURE__ */ jsx(MessageWrapper, { children: "Searching..." });
134
+ case "error":
135
+ return /* @__PURE__ */ jsx(MessageWrapper, { children: "Something went wrong..." });
136
+ case "empty":
137
+ return /* @__PURE__ */ jsx(MessageWrapper, { children: "No icons found" });
138
+ }
139
+ })(),
140
+ /* @__PURE__ */ jsx("ul", { ...rest, ref, style: { opacity: state === "stale" ? 0.5 : 1 }, children: (state === "data" || state === "stale") && data?.map((icon, index) => /* @__PURE__ */ jsx("li", { ...getItemProps({ item: icon, index }), children: /* @__PURE__ */ jsx(Button, { padding: 3, mode: "bleed", selected: index === highlightedIndex, children: /* @__PURE__ */ jsx(Icon, { icon, width: "100%", height: "100%" }) }) }, icon)) })
141
+ ] });
142
+ });
134
143
  function UnsetButton(props) {
135
144
  const { onUnset } = props;
136
145
  return /* @__PURE__ */ jsx(Card, { border: !0, borderLeft: !1, padding: 1, display: "flex", radius: 2, children: /* @__PURE__ */ jsx(Button, { icon: /* @__PURE__ */ jsx(TrashIcon, {}), onClick: onUnset, mode: "bleed", fontSize: 1, padding: 2 }) });
@@ -138,81 +147,85 @@ function UnsetButton(props) {
138
147
  function IconifyCombobox(props) {
139
148
  const { selectedIcon, onSelect: pushSelection, collections } = props, id = useId(), toast = useToast(), inputRef = useRef(null), { term, setTerm, debouncedTerm, isLoading, isError, error, data, isPreviousData } = useSearch({
140
149
  collections
141
- }), handleTermChange = useCallback(
142
- (event) => setTerm(event.target.value),
143
- [setTerm]
144
- ), handleSelect = useCallback(
145
- (icon) => {
146
- pushSelection(icon), setTerm("", !0);
150
+ }), {
151
+ isOpen,
152
+ getMenuProps,
153
+ getInputProps,
154
+ highlightedIndex,
155
+ getItemProps,
156
+ selectItem,
157
+ setInputValue
158
+ } = useCombobox({
159
+ items: data ?? [],
160
+ inputValue: term,
161
+ onInputValueChange({ inputValue, selectedItem }) {
162
+ inputValue !== selectedItem && setTerm(inputValue);
147
163
  },
148
- [pushSelection, setTerm]
149
- ), handleUnset = useCallback(() => handleSelect(""), [handleSelect]);
164
+ onSelectedItemChange({ selectedItem }) {
165
+ selectedItem && (pushSelection(selectedItem), setTerm("", !0), setInputValue(""));
166
+ }
167
+ }), handleUnset = useCallback(() => {
168
+ pushSelection(""), setTerm("", !0), selectItem("");
169
+ }, []);
150
170
  return useEffect(() => {
151
171
  isError && (console.error("Iconify input error:", error), toast.push({
152
172
  id,
153
173
  status: "error",
154
174
  title: "Iconify input error",
155
- description: error == null ? void 0 : error.message
175
+ description: error?.message
156
176
  }));
157
- }, [error, id, isError, toast]), /* @__PURE__ */ jsx(ComboboxWrapper, { children: /* @__PURE__ */ jsx(Combobox, { onChange: handleSelect, children: ({ open }) => /* @__PURE__ */ jsxs(Fragment, { children: [
177
+ }, [error, id, isError, toast]), /* @__PURE__ */ jsxs("div", { children: [
158
178
  /* @__PURE__ */ jsx(
159
179
  SearchInput,
160
180
  {
161
- ref: inputRef,
162
- term,
181
+ ...getInputProps({ ref: inputRef }),
163
182
  selectedIcon,
164
- onChange: handleTermChange,
165
183
  suffix: selectedIcon ? /* @__PURE__ */ jsx(UnsetButton, { onUnset: handleUnset }) : null
166
184
  }
167
185
  ),
168
186
  /* @__PURE__ */ jsx(
169
187
  Popover,
170
188
  {
171
- open,
189
+ open: !0,
190
+ style: { display: isOpen ? "block" : "none" },
172
191
  placement: "bottom",
173
192
  arrow: !1,
174
193
  matchReferenceWidth: !0,
175
- portal: !0,
176
194
  constrainSize: !0,
177
195
  referenceElement: inputRef.current,
178
196
  content: /* @__PURE__ */ jsx(OptionsWrapper, { children: /* @__PURE__ */ jsx(
179
197
  SearchResults,
180
198
  {
199
+ ...getMenuProps(),
181
200
  state: match(!0).returnType().with(isLoading, () => "loading").with(!debouncedTerm, () => "initial").with(isError, () => "error").with(!data || data.length === 0, () => "empty").with(isPreviousData, () => "stale").otherwise(() => "data"),
182
- data
201
+ data,
202
+ getItemProps,
203
+ highlightedIndex
183
204
  }
184
205
  ) })
185
206
  }
186
207
  )
187
- ] }) }) });
208
+ ] });
188
209
  }
189
210
  const queryClient = new QueryClient();
190
211
  function QueryClientProvider(props) {
191
212
  return /* @__PURE__ */ jsx(QueryClientProvider$1, { client: queryClient, children: props.children });
192
213
  }
193
214
  function usePrettyIconName(props) {
194
- var _a, _b;
195
215
  const { name } = props, iconMeta = useMemo(
196
- () => {
197
- var _a2;
198
- return (_a2 = props.iconMeta) != null ? _a2 : name ? stringToIcon(name) : null;
199
- },
216
+ () => props.iconMeta ?? (name ? stringToIcon(name) : null),
200
217
  [name, props.iconMeta]
201
- ), iconSetInfo = useIconSetInfo({ prefix: (_a = iconMeta == null ? void 0 : iconMeta.prefix) != null ? _a : null });
218
+ ), iconSetInfo = useIconSetInfo({ prefix: iconMeta?.prefix ?? null });
202
219
  return useMemo(
203
- () => {
204
- var _a2, _b2;
205
- return iconMeta ? {
206
- name: sentenceCase(iconMeta.name),
207
- collection: (_b2 = (_a2 = iconSetInfo.data) == null ? void 0 : _a2.name) != null ? _b2 : iconMeta.prefix
208
- } : null;
209
- },
210
- [iconMeta, (_b = iconSetInfo.data) == null ? void 0 : _b.name]
220
+ () => iconMeta ? {
221
+ name: sentenceCase(iconMeta.name),
222
+ collection: iconSetInfo.data?.name ?? iconMeta.prefix
223
+ } : null,
224
+ [iconMeta, iconSetInfo.data?.name]
211
225
  );
212
226
  }
213
227
  function IconifyInput(props) {
214
- var _a, _b, _c, _d, _e;
215
- const { config, value, onChange: pushChange, schemaType } = props, selectedIcon = (_a = value == null ? void 0 : value.name) != null ? _a : null, options = schemaType.options, collections = !!((_b = options == null ? void 0 : options.collections) != null && _b.length) && options.collections || !!((_c = config == null ? void 0 : config.collections) != null && _c.length) && config.collections || null, showName = (_e = (_d = options == null ? void 0 : options.showName) != null ? _d : config == null ? void 0 : config.showName) != null ? _e : !1, handleSelect = useCallback(
228
+ const { config, value, onChange: pushChange, schemaType } = props, selectedIcon = value?.name ?? null, options = schemaType.options, collections = !!options?.collections?.length && options.collections || !!config?.collections?.length && config.collections || null, showName = options?.showName ?? config?.showName ?? !1, handleSelect = useCallback(
216
229
  (icon) => {
217
230
  pushChange(icon === "" ? unset() : set(icon, ["name"]));
218
231
  },
@@ -231,14 +244,13 @@ function IconifyInput(props) {
231
244
  ] }) }) });
232
245
  }
233
246
  function IconifyNameDisplay(props) {
234
- var _a;
235
247
  const { name } = props, prettyName = usePrettyIconName({ name });
236
248
  return /* @__PURE__ */ jsxs(Flex, { gap: 1, children: [
237
249
  /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Selected:" }),
238
- /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: (_a = prettyName == null ? void 0 : prettyName.name) != null ? _a : name }),
239
- (prettyName == null ? void 0 : prettyName.collection) && /* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children: [
250
+ /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: prettyName?.name ?? name }),
251
+ prettyName?.collection && /* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children: [
240
252
  "by ",
241
- prettyName == null ? void 0 : prettyName.collection
253
+ prettyName?.collection
242
254
  ] })
243
255
  ] });
244
256
  }
@@ -247,13 +259,12 @@ function IconifyPreview(props) {
247
259
  return typeof title == "string" && iconName ? /* @__PURE__ */ jsx(QueryClientProvider, { children: /* @__PURE__ */ jsx(IconifyPreviewInner, { ...props, iconName: title, iconMeta: iconName }) }) : props.renderDefault(props);
248
260
  }
249
261
  function IconifyPreviewInner(props) {
250
- var _a;
251
262
  const { iconMeta, iconName, ...previewProps } = props, prettyName = usePrettyIconName({ iconMeta });
252
263
  return props.renderDefault({
253
264
  ...previewProps,
254
265
  media: /* @__PURE__ */ jsx(Icon, { icon: iconName }),
255
- title: (_a = prettyName == null ? void 0 : prettyName.name) != null ? _a : iconName,
256
- subtitle: prettyName == null ? void 0 : prettyName.collection
266
+ title: prettyName?.name ?? iconName,
267
+ subtitle: prettyName?.collection
257
268
  });
258
269
  }
259
270
  const iconify = definePlugin((config = {}) => ({
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/lib/api.ts","../src/combobox/iconify-combobox.styles.tsx","../src/combobox/search-input.tsx","../src/combobox/search-result.tsx","../src/combobox/unset-button.tsx","../src/combobox/iconify-combobox.tsx","../src/lib/query-client.tsx","../src/lib/use-pretty-icon-name.ts","../src/iconify-input.tsx","../src/iconify-preview.tsx","../src/iconify-plugin.tsx"],"sourcesContent":["import type { IconifyInfo } from '@iconify/types';\nimport { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useCallback, useState } from 'react';\nimport { useDebounce } from 'use-debounce';\nimport type { IconifySearchResult } from './types';\n\nconst BASE_API_URL = 'https://api.iconify.design';\n\nfunction fetchJson<T>({ url, signal }: { url: string | URL; signal?: AbortSignal }): Promise<T> {\n return fetch(url, { signal })\n .then((response) => {\n if (!response.ok) {\n throw new Error(`Network error: status ${response.status}`);\n }\n\n return response.json();\n })\n .then(\n (result) => result as T,\n (error) => {\n if (error instanceof Error) {\n throw error;\n } else {\n console.error(`Unknown error: ${error}`);\n throw new Error('Something went wrong');\n }\n },\n );\n}\n\nexport function useSearch({ collections }: { collections: string[] | null }) {\n const queryClient = useQueryClient();\n const [term, setTerm] = useState('');\n const [debouncedTerm, setDebouncedTerm] = useDebounce(term, 500);\n\n const updateTerm = useCallback(\n (newTerm: string, updateImmediately = false) => {\n setTerm(newTerm);\n\n if (updateImmediately) {\n setDebouncedTerm(newTerm);\n }\n },\n [setDebouncedTerm],\n );\n\n const { isLoading, isError, error, data, isPlaceholderData } = useQuery<string[], Error>({\n queryKey: ['search', collections, debouncedTerm],\n queryFn: async ({ signal }) => {\n const url = new URL(`/search`, BASE_API_URL);\n\n url.searchParams.append('query', debouncedTerm);\n url.searchParams.append('limit', '60');\n\n if (collections) {\n url.searchParams.append('prefixes', collections.join(','));\n }\n\n const result = debouncedTerm ? await fetchJson<IconifySearchResult>({ url, signal }) : null;\n\n if (result) {\n // Cache the info for each collection\n Object.entries(result.collections).forEach(([prefix, info]) => {\n queryClient.setQueryData<IconifyInfo>(['iconSetInfo', prefix], info);\n });\n }\n\n return result?.icons ?? [];\n },\n enabled: debouncedTerm.length > 0,\n placeholderData: keepPreviousData,\n staleTime: 5 * 60 * 1000, // 5 minutes\n });\n\n return {\n term,\n setTerm: updateTerm,\n debouncedTerm,\n isLoading,\n isError,\n error,\n data,\n isPreviousData: isPlaceholderData,\n };\n}\n\nexport function useIconSetInfo({ prefix }: { prefix?: string | null }) {\n return useQuery<IconifyInfo | null, Error>({\n queryKey: ['iconSetInfo', prefix],\n queryFn: async ({ signal }) => {\n if (!prefix) return null;\n\n const url = new URL('/collection', BASE_API_URL);\n\n url.searchParams.append('prefix', prefix);\n url.searchParams.append('info', 'true');\n\n const result = await fetchJson<{ info: IconifyInfo }>({ url, signal });\n\n return result?.info ?? null;\n },\n staleTime: Infinity,\n });\n}\n","import { Box, Card, Grid, Text } from '@sanity/ui';\nimport type { ReactNode } from 'react';\nimport styled from 'styled-components';\n\nexport const ComboboxWrapper = styled(Grid)`\n grid-template-columns: 1fr min-content;\n position: relative;\n`;\n\nexport const OptionsWrapper = styled(Box)`\n box-sizing: border-box;\n padding: 0.5rem;\n\n & [role='listbox'] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 2.5rem), 1fr));\n gap: 0.5rem;\n margin: 0;\n padding: 0;\n list-style: none;\n\n @media (min-width: 650px) {\n grid-template-columns: repeat(10, minmax(min(100%, 2.5rem), 1fr));\n }\n }\n\n & [role='option'] {\n display: grid;\n place-items: center;\n\n & button {\n cursor: pointer;\n aspect-ratio: 1;\n width: 100%;\n\n & > [data-ui='Box'] {\n display: flex;\n }\n }\n }\n`;\n\nexport function MessageWrapper({ children }: { children: ReactNode }) {\n return (\n <Card padding={4}>\n <Text align=\"center\" muted>\n {children}\n </Text>\n </Card>\n );\n}\n","import { ComboboxInput } from '@headlessui/react';\nimport { Icon } from '@iconify/react';\nimport { TextInput } from '@sanity/ui';\nimport type { ChangeEventHandler } from 'react';\nimport { forwardRef } from 'react';\n\n// ------------ //\n// SEARCH INPUT //\n// ------------ //\n\ninterface SearchInputProps {\n term: string;\n selectedIcon: string | null;\n onChange: ChangeEventHandler<HTMLInputElement>;\n suffix?: React.ReactNode;\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>((props, ref) => {\n const { term, selectedIcon, onChange, suffix } = props;\n\n return (\n <ComboboxInput\n as={TextInput}\n ref={ref}\n inputMode=\"search\"\n value={term}\n onChange={onChange}\n icon={selectedIcon ? <Icon icon={selectedIcon} /> : null}\n placeholder={selectedIcon ? 'Search and replace selected icon...' : 'Search for an icon...'}\n suffix={suffix}\n />\n );\n});\n\nSearchInput.displayName = 'SearchInput';\n","import { ComboboxOption, ComboboxOptions } from '@headlessui/react';\nimport { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\nimport { MessageWrapper } from './iconify-combobox.styles';\n\n// -------------- //\n// SEARCH RESULTS //\n// -------------- //\n\nexport interface SearchResultsProps {\n state: 'initial' | 'loading' | 'error' | 'empty' | 'data' | 'stale';\n data?: string[];\n}\n\nexport function SearchResults(props: SearchResultsProps) {\n const { state, data } = props;\n\n if (state === 'initial') {\n return <MessageWrapper>Search for icons</MessageWrapper>;\n }\n\n if (state === 'loading') {\n return <MessageWrapper>Searching...</MessageWrapper>;\n }\n\n if (state === 'error') {\n return <MessageWrapper>Something went wrong...</MessageWrapper>;\n }\n\n if (state === 'empty') {\n return <MessageWrapper>No icons found</MessageWrapper>;\n }\n\n return (\n <ComboboxOptions style={{ opacity: state === 'stale' ? 0.5 : 1 }}>\n {data!.map((icon) => (\n <ComboboxOption key={icon} value={icon}>\n {({ focus }) => (\n <Button padding={3} mode=\"bleed\" selected={focus}>\n <Icon icon={icon} width=\"100%\" height=\"100%\" />\n </Button>\n )}\n </ComboboxOption>\n ))}\n </ComboboxOptions>\n );\n}\n","import { TrashIcon } from '@sanity/icons';\nimport { Button, Card } from '@sanity/ui';\n\n// ------------ //\n// UNSET BUTTON //\n// ------------ //\n\ninterface UnsetButtonProps {\n onUnset: () => void;\n}\n\nexport function UnsetButton(props: UnsetButtonProps) {\n const { onUnset } = props;\n\n return (\n <Card border borderLeft={false} padding={1} display=\"flex\" radius={2}>\n <Button icon={<TrashIcon />} onClick={onUnset} mode=\"bleed\" fontSize={1} padding={2} />\n </Card>\n );\n}\n","import { Combobox } from '@headlessui/react';\nimport { Popover, useToast } from '@sanity/ui';\nimport type { ChangeEventHandler } from 'react';\nimport { useCallback, useEffect, useId, useRef } from 'react';\nimport { match } from 'ts-pattern';\nimport { useSearch } from '../lib/api';\nimport { ComboboxWrapper, OptionsWrapper } from './iconify-combobox.styles';\nimport { SearchInput } from './search-input';\nimport type { SearchResultsProps } from './search-result';\nimport { SearchResults } from './search-result';\nimport { UnsetButton } from './unset-button';\n\nexport interface IconifyComboboxProps {\n selectedIcon: string | null;\n onSelect: (newValue: string) => void;\n collections: string[] | null;\n}\n\nexport function IconifyCombobox(props: IconifyComboboxProps) {\n const { selectedIcon, onSelect: pushSelection, collections } = props;\n\n const id = useId();\n const toast = useToast();\n const inputRef = useRef<HTMLInputElement>(null);\n\n const { term, setTerm, debouncedTerm, isLoading, isError, error, data, isPreviousData } =\n useSearch({\n collections,\n });\n\n const handleTermChange: ChangeEventHandler<HTMLInputElement> = useCallback(\n (event) => setTerm(event.target.value),\n [setTerm],\n );\n\n const handleSelect = useCallback(\n (icon: string) => {\n pushSelection(icon);\n setTerm('', true);\n },\n [pushSelection, setTerm],\n );\n\n const handleUnset = useCallback(() => handleSelect(''), [handleSelect]);\n\n useEffect(() => {\n if (isError) {\n console.error('Iconify input error:', error);\n\n toast.push({\n id,\n status: 'error',\n title: 'Iconify input error',\n description: error?.message,\n });\n }\n }, [error, id, isError, toast]);\n\n return (\n <ComboboxWrapper>\n <Combobox onChange={handleSelect}>\n {({ open }) => (\n <>\n <SearchInput\n ref={inputRef}\n term={term}\n selectedIcon={selectedIcon}\n onChange={handleTermChange}\n suffix={selectedIcon ? <UnsetButton onUnset={handleUnset} /> : null}\n />\n\n <Popover\n open={open}\n placement=\"bottom\"\n arrow={false}\n matchReferenceWidth\n portal\n constrainSize\n referenceElement={inputRef.current}\n content={\n <OptionsWrapper>\n <SearchResults\n state={match<boolean>(true)\n .returnType<SearchResultsProps['state']>()\n .with(isLoading, () => 'loading')\n .with(!debouncedTerm, () => 'initial')\n .with(isError, () => 'error')\n .with(!data || data.length === 0, () => 'empty')\n .with(isPreviousData, () => 'stale')\n .otherwise(() => 'data')}\n data={data}\n />\n </OptionsWrapper>\n }\n />\n </>\n )}\n </Combobox>\n </ComboboxWrapper>\n );\n}\n","import {\n QueryClient,\n QueryClientProvider as ReactQueryClientProvider,\n} from '@tanstack/react-query';\nimport type { ReactNode } from 'react';\n\nexport const queryClient = new QueryClient();\n\nexport function QueryClientProvider(props: { children: ReactNode }) {\n return <ReactQueryClientProvider client={queryClient}>{props.children}</ReactQueryClientProvider>;\n}\n","import type { IconifyIconName } from '@iconify/utils';\nimport { stringToIcon } from '@iconify/utils';\nimport { sentenceCase } from 'change-case';\nimport { useMemo } from 'react';\nimport { useIconSetInfo } from './api';\n\ninterface UsePrettyIconNameProps {\n name?: string | null;\n iconMeta?: IconifyIconName | null;\n}\n\nexport function usePrettyIconName(props: UsePrettyIconNameProps) {\n const { name } = props;\n const iconMeta = useMemo(\n () => props.iconMeta ?? (name ? stringToIcon(name) : null),\n [name, props.iconMeta],\n );\n const iconSetInfo = useIconSetInfo({ prefix: iconMeta?.prefix ?? null });\n\n return useMemo(\n () =>\n iconMeta\n ? {\n name: sentenceCase(iconMeta.name),\n collection: iconSetInfo.data?.name ?? iconMeta.prefix,\n }\n : null,\n [iconMeta, iconSetInfo.data?.name],\n );\n}\n","import { Flex, Stack, Text, ThemeProvider } from '@sanity/ui';\nimport { buildTheme } from '@sanity/ui/theme';\nimport { useCallback } from 'react';\nimport type { ObjectInputProps } from 'sanity';\nimport { set, unset } from 'sanity';\nimport { IconifyCombobox } from './combobox';\nimport { QueryClientProvider } from './lib/query-client';\nimport type { IconifyPluginConfig, IconOptions } from './lib/types';\nimport { usePrettyIconName } from './lib/use-pretty-icon-name';\n\n// -------------- //\n// ICONIFY INPUT //\n// -------------- //\n\ninterface IconifyInputProps extends ObjectInputProps {\n config: IconifyPluginConfig;\n}\n\nexport function IconifyInput(props: IconifyInputProps) {\n const { config, value, onChange: pushChange, schemaType } = props;\n\n const selectedIcon: string | null = value?.name ?? null;\n\n const options: IconOptions = schemaType.options;\n const collections =\n (!!options?.collections?.length && options.collections) ||\n (!!config?.collections?.length && config.collections) ||\n null;\n const showName = options?.showName ?? config?.showName ?? false;\n\n // const parentTheme = useTheme();\n // const theme: RootTheme = useMemo(\n // () => (parentTheme ? { ...parentTheme.sanity, color: studioTheme.color } : studioTheme),\n // [parentTheme],\n // );\n\n const handleSelect = useCallback(\n (icon: string) => {\n pushChange(icon === '' ? unset() : set(icon, ['name']));\n },\n [pushChange],\n );\n\n return (\n <QueryClientProvider>\n <ThemeProvider theme={buildTheme()}>\n <Stack space={2}>\n <IconifyCombobox\n selectedIcon={selectedIcon}\n onSelect={handleSelect}\n collections={collections}\n />\n\n {showName && selectedIcon ? <IconifyNameDisplay name={selectedIcon} /> : null}\n </Stack>\n </ThemeProvider>\n </QueryClientProvider>\n );\n}\n\ninterface IconifyNameDisplayProps {\n name?: string | null;\n}\n\nfunction IconifyNameDisplay(props: IconifyNameDisplayProps) {\n const { name } = props;\n const prettyName = usePrettyIconName({ name });\n\n return (\n <Flex gap={1}>\n <Text size={1} muted>\n Selected:\n </Text>\n\n <Text size={1} weight=\"semibold\">\n {prettyName?.name ?? name}\n </Text>\n\n {prettyName?.collection && (\n <Text size={1} muted style={{ fontStyle: 'italic' }}>\n by {prettyName?.collection}\n </Text>\n )}\n </Flex>\n );\n}\n","import { Icon } from '@iconify/react';\nimport type { IconifyIconName } from '@iconify/utils';\nimport { stringToIcon } from '@iconify/utils';\nimport type { PreviewProps } from 'sanity';\nimport { QueryClientProvider } from './lib/query-client';\nimport { usePrettyIconName } from './lib/use-pretty-icon-name';\n\n// --------------- //\n// ICONIFY PREVIEW //\n// --------------- //\n\nexport function IconifyPreview(props: PreviewProps) {\n const { title } = props;\n const iconName = typeof props.title === 'string' ? stringToIcon(props.title) : null;\n\n // We check this double to avoid the TS error\n if (typeof title === 'string' && iconName) {\n return (\n <QueryClientProvider>\n <IconifyPreviewInner {...props} iconName={title} iconMeta={iconName} />\n </QueryClientProvider>\n );\n }\n\n return props.renderDefault(props);\n}\n\n// --------------------- //\n// ICONIFY PREVIEW INNER //\n// --------------------- //\n\ninterface IconifyPreviewInnerProps extends PreviewProps {\n iconName: string;\n iconMeta: IconifyIconName;\n}\n\nfunction IconifyPreviewInner(props: IconifyPreviewInnerProps) {\n const { iconMeta, iconName, ...previewProps } = props;\n const prettyName = usePrettyIconName({ iconMeta });\n\n return props.renderDefault({\n ...previewProps,\n media: <Icon icon={iconName} />,\n title: prettyName?.name ?? iconName,\n subtitle: prettyName?.collection,\n });\n}\n","import type { FieldProps, ObjectInputProps } from 'sanity';\nimport { definePlugin } from 'sanity';\nimport { IconifyInput } from './iconify-input';\nimport { IconifyPreview } from './iconify-preview';\nimport type { IconifyPluginConfig } from './lib/types';\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import { defineConfig } from 'sanity'\n * import { iconify } from 'sanity-plugin-iconify'\n *\n * export default defineConfig({\n * // ...\n * plugins: [iconify()],\n * })\n * ```\n */\nexport const iconify = definePlugin<IconifyPluginConfig | void>((config = {}) => {\n return {\n name: 'sanity-plugin-iconify',\n schema: {\n types: [\n {\n name: 'icon',\n title: 'Icon',\n type: 'object',\n fields: [\n {\n name: 'name',\n title: 'Name',\n type: 'string',\n },\n ],\n components: {\n input: (props: ObjectInputProps) => <IconifyInput {...props} config={config!} />,\n preview: IconifyPreview,\n\n // This makes sure the input component is not indented\n field: (props: FieldProps) => props.renderDefault({ ...props, level: 0 }),\n },\n },\n ],\n },\n };\n});\n"],"names":["queryClient","ReactQueryClientProvider","_a","_b"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/lib/api.ts","../src/combobox/iconify-combobox.styles.tsx","../src/combobox/search-input.tsx","../src/combobox/search-result.tsx","../src/combobox/unset-button.tsx","../src/combobox/iconify-combobox.tsx","../src/lib/query-client.tsx","../src/lib/use-pretty-icon-name.ts","../src/iconify-input.tsx","../src/iconify-preview.tsx","../src/iconify-plugin.tsx"],"sourcesContent":["import type { IconifyInfo } from '@iconify/types';\nimport { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useCallback, useState } from 'react';\nimport { useDebounce } from 'use-debounce';\nimport type { IconifySearchResult } from './types';\n\nconst BASE_API_URL = 'https://api.iconify.design';\n\nfunction fetchJson<T>({ url, signal }: { url: string | URL; signal?: AbortSignal }): Promise<T> {\n return fetch(url, { signal })\n .then((response) => {\n if (!response.ok) {\n throw new Error(`Network error: status ${response.status}`);\n }\n\n return response.json();\n })\n .then(\n (result) => result as T,\n (error) => {\n if (error instanceof Error) {\n throw error;\n } else {\n console.error(`Unknown error: ${error}`);\n throw new Error('Something went wrong');\n }\n },\n );\n}\n\nexport function useSearch({ collections }: { collections: string[] | null }) {\n const queryClient = useQueryClient();\n const [term, setTerm] = useState('');\n const [debouncedTerm, setDebouncedTerm] = useDebounce(term, 500);\n\n const updateTerm = useCallback(\n (newTerm: string, updateImmediately = false) => {\n setTerm(newTerm);\n\n if (updateImmediately) {\n setDebouncedTerm(newTerm);\n }\n },\n [setDebouncedTerm],\n );\n\n const { isLoading, isError, error, data, isPlaceholderData } = useQuery<string[], Error>({\n queryKey: ['search', collections, debouncedTerm],\n queryFn: async ({ signal }) => {\n const url = new URL(`/search`, BASE_API_URL);\n\n url.searchParams.append('query', debouncedTerm);\n url.searchParams.append('limit', '60');\n\n if (collections) {\n url.searchParams.append('prefixes', collections.join(','));\n }\n\n const result = debouncedTerm ? await fetchJson<IconifySearchResult>({ url, signal }) : null;\n\n if (result) {\n // Cache the info for each collection\n Object.entries(result.collections).forEach(([prefix, info]) => {\n queryClient.setQueryData<IconifyInfo>(['iconSetInfo', prefix], info);\n });\n }\n\n return result?.icons ?? [];\n },\n enabled: debouncedTerm.length > 0,\n placeholderData: keepPreviousData,\n staleTime: 5 * 60 * 1000, // 5 minutes\n });\n\n return {\n term,\n setTerm: updateTerm,\n debouncedTerm,\n isLoading,\n isError,\n error,\n data,\n isPreviousData: isPlaceholderData,\n };\n}\n\nexport function useIconSetInfo({ prefix }: { prefix?: string | null }) {\n return useQuery<IconifyInfo | null, Error>({\n queryKey: ['iconSetInfo', prefix],\n queryFn: async ({ signal }) => {\n if (!prefix) return null;\n\n const url = new URL('/collection', BASE_API_URL);\n\n url.searchParams.append('prefix', prefix);\n url.searchParams.append('info', 'true');\n\n const result = await fetchJson<{ info: IconifyInfo }>({ url, signal });\n\n return result?.info ?? null;\n },\n staleTime: Infinity,\n });\n}\n","import { Box, Card, Grid, Text } from '@sanity/ui';\nimport type { ReactNode } from 'react';\nimport styled from 'styled-components';\n\nexport const ComboboxWrapper = styled(Grid)`\n grid-template-columns: 1fr min-content;\n position: relative;\n`;\n\nexport const OptionsWrapper = styled(Box)`\n box-sizing: border-box;\n padding: 0.5rem;\n\n & [role='listbox'] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n & [role='option'] {\n display: grid;\n place-items: center;\n width: clamp(3rem, 10vw, 4rem);\n\n & button {\n cursor: pointer;\n width: 100%;\n\n & > [data-ui='Box'] {\n display: flex;\n }\n\n & svg {\n aspect-ratio: 1;\n }\n }\n }\n`;\n\nexport function MessageWrapper({ children }: { children: ReactNode }) {\n return (\n <Card padding={4}>\n <Text align=\"center\" muted>\n {children}\n </Text>\n </Card>\n );\n}\n","import { Icon } from '@iconify/react';\nimport { TextInput } from '@sanity/ui';\nimport { forwardRef } from 'react';\n\ninterface SearchInputProps extends React.HTMLAttributes<HTMLInputElement> {\n selectedIcon: string | null;\n suffix?: React.ReactNode;\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>((props, ref) => {\n const { selectedIcon, suffix, ...rest } = props;\n\n return (\n <TextInput\n {...rest}\n ref={ref}\n inputMode=\"search\"\n icon={selectedIcon ? <Icon icon={selectedIcon} /> : null}\n placeholder={selectedIcon ? 'Search and replace selected icon...' : 'Search for an icon...'}\n suffix={suffix}\n />\n );\n});\n\nSearchInput.displayName = 'SearchInput';\n","import { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\nimport type { UseComboboxGetItemPropsOptions, UseComboboxGetItemPropsReturnValue } from 'downshift';\nimport { forwardRef } from 'react';\nimport { MessageWrapper } from './iconify-combobox.styles';\n\ntype GetItemProps = (\n options: UseComboboxGetItemPropsOptions<string>,\n) => UseComboboxGetItemPropsReturnValue;\n\nexport interface SearchResultsProps extends React.HTMLAttributes<HTMLUListElement> {\n state: 'initial' | 'loading' | 'error' | 'empty' | 'data' | 'stale';\n data?: string[];\n getItemProps: GetItemProps;\n highlightedIndex: number;\n}\n\nexport const SearchResults = forwardRef<HTMLUListElement, SearchResultsProps>((props, ref) => {\n const { state, data, getItemProps, highlightedIndex, ...rest } = props;\n\n return (\n <>\n {(() => {\n switch (state) {\n case 'initial':\n return <MessageWrapper>Search for icons</MessageWrapper>;\n case 'loading':\n return <MessageWrapper>Searching...</MessageWrapper>;\n case 'error':\n return <MessageWrapper>Something went wrong...</MessageWrapper>;\n case 'empty':\n return <MessageWrapper>No icons found</MessageWrapper>;\n }\n })()}\n\n <ul {...rest} ref={ref} style={{ opacity: state === 'stale' ? 0.5 : 1 }}>\n {(state === 'data' || state === 'stale') &&\n data?.map((icon, index) => (\n <li key={icon} {...getItemProps({ item: icon, index })}>\n <Button padding={3} mode=\"bleed\" selected={index === highlightedIndex}>\n <Icon icon={icon} width=\"100%\" height=\"100%\" />\n </Button>\n </li>\n ))}\n </ul>\n </>\n );\n});\n","import { TrashIcon } from '@sanity/icons';\nimport { Button, Card } from '@sanity/ui';\n\n// ------------ //\n// UNSET BUTTON //\n// ------------ //\n\ninterface UnsetButtonProps {\n onUnset: () => void;\n}\n\nexport function UnsetButton(props: UnsetButtonProps) {\n const { onUnset } = props;\n\n return (\n <Card border borderLeft={false} padding={1} display=\"flex\" radius={2}>\n <Button icon={<TrashIcon />} onClick={onUnset} mode=\"bleed\" fontSize={1} padding={2} />\n </Card>\n );\n}\n","import { Popover, useToast } from '@sanity/ui';\nimport { useCombobox } from 'downshift';\nimport { useCallback, useEffect, useId, useRef } from 'react';\nimport { match } from 'ts-pattern';\nimport { useSearch } from '../lib/api';\nimport { OptionsWrapper } from './iconify-combobox.styles';\nimport { SearchInput } from './search-input';\nimport type { SearchResultsProps } from './search-result';\nimport { SearchResults } from './search-result';\nimport { UnsetButton } from './unset-button';\n\nexport interface IconifyComboboxProps {\n selectedIcon: string | null;\n onSelect: (newValue: string) => void;\n collections: string[] | null;\n}\n\nexport function IconifyCombobox(props: IconifyComboboxProps) {\n const { selectedIcon, onSelect: pushSelection, collections } = props;\n\n const id = useId();\n const toast = useToast();\n const inputRef = useRef<HTMLInputElement>(null);\n\n const { term, setTerm, debouncedTerm, isLoading, isError, error, data, isPreviousData } =\n useSearch({\n collections,\n });\n\n const {\n isOpen,\n getMenuProps,\n getInputProps,\n highlightedIndex,\n getItemProps,\n selectItem,\n setInputValue,\n } = useCombobox({\n items: data ?? [],\n inputValue: term,\n onInputValueChange({ inputValue, selectedItem }) {\n if (inputValue !== selectedItem) {\n setTerm(inputValue);\n }\n },\n onSelectedItemChange({ selectedItem }) {\n if (selectedItem) {\n pushSelection(selectedItem);\n setTerm('', true);\n setInputValue('');\n }\n },\n });\n\n const handleUnset = useCallback(() => {\n pushSelection('');\n setTerm('', true);\n selectItem('');\n }, []);\n\n useEffect(() => {\n if (isError) {\n console.error('Iconify input error:', error);\n\n toast.push({\n id,\n status: 'error',\n title: 'Iconify input error',\n description: error?.message,\n });\n }\n }, [error, id, isError, toast]);\n\n return (\n <div>\n {/* @ts-expect-error wrong typings */}\n <SearchInput\n {...getInputProps({ ref: inputRef })}\n selectedIcon={selectedIcon}\n suffix={selectedIcon ? <UnsetButton onUnset={handleUnset} /> : null}\n />\n\n <Popover\n open={true}\n style={{ display: isOpen ? 'block' : 'none' }}\n placement=\"bottom\"\n arrow={false}\n matchReferenceWidth\n constrainSize\n referenceElement={inputRef.current}\n content={\n <OptionsWrapper>\n <SearchResults\n {...getMenuProps()}\n state={match<boolean>(true)\n .returnType<SearchResultsProps['state']>()\n .with(isLoading, () => 'loading')\n .with(!debouncedTerm, () => 'initial')\n .with(isError, () => 'error')\n .with(!data || data.length === 0, () => 'empty')\n .with(isPreviousData, () => 'stale')\n .otherwise(() => 'data')}\n data={data}\n getItemProps={getItemProps}\n highlightedIndex={highlightedIndex}\n />\n </OptionsWrapper>\n }\n />\n </div>\n );\n}\n","import {\n QueryClient,\n QueryClientProvider as ReactQueryClientProvider,\n} from '@tanstack/react-query';\nimport type { ReactNode } from 'react';\n\nexport const queryClient = new QueryClient();\n\nexport function QueryClientProvider(props: { children: ReactNode }) {\n return <ReactQueryClientProvider client={queryClient}>{props.children}</ReactQueryClientProvider>;\n}\n","import type { IconifyIconName } from '@iconify/utils';\nimport { stringToIcon } from '@iconify/utils';\nimport { sentenceCase } from 'change-case';\nimport { useMemo } from 'react';\nimport { useIconSetInfo } from './api';\n\ninterface UsePrettyIconNameProps {\n name?: string | null;\n iconMeta?: IconifyIconName | null;\n}\n\nexport function usePrettyIconName(props: UsePrettyIconNameProps) {\n const { name } = props;\n const iconMeta = useMemo(\n () => props.iconMeta ?? (name ? stringToIcon(name) : null),\n [name, props.iconMeta],\n );\n const iconSetInfo = useIconSetInfo({ prefix: iconMeta?.prefix ?? null });\n\n return useMemo(\n () =>\n iconMeta\n ? {\n name: sentenceCase(iconMeta.name),\n collection: iconSetInfo.data?.name ?? iconMeta.prefix,\n }\n : null,\n [iconMeta, iconSetInfo.data?.name],\n );\n}\n","import { Flex, Stack, Text, ThemeProvider } from '@sanity/ui';\nimport { buildTheme } from '@sanity/ui/theme';\nimport { useCallback } from 'react';\nimport type { ObjectInputProps } from 'sanity';\nimport { set, unset } from 'sanity';\nimport { IconifyCombobox } from './combobox';\nimport { QueryClientProvider } from './lib/query-client';\nimport type { IconifyPluginConfig, IconOptions } from './lib/types';\nimport { usePrettyIconName } from './lib/use-pretty-icon-name';\n\ninterface IconifyInputProps extends ObjectInputProps {\n config: IconifyPluginConfig;\n}\n\nexport function IconifyInput(props: IconifyInputProps) {\n const { config, value, onChange: pushChange, schemaType } = props;\n\n const selectedIcon: string | null = value?.name ?? null;\n\n const options: IconOptions = schemaType.options;\n const collections =\n (!!options?.collections?.length && options.collections) ||\n (!!config?.collections?.length && config.collections) ||\n null;\n const showName = options?.showName ?? config?.showName ?? false;\n\n const handleSelect = useCallback(\n (icon: string) => {\n pushChange(icon === '' ? unset() : set(icon, ['name']));\n },\n [pushChange],\n );\n\n return (\n <QueryClientProvider>\n <ThemeProvider theme={buildTheme()}>\n <Stack space={2}>\n <IconifyCombobox\n selectedIcon={selectedIcon}\n onSelect={handleSelect}\n collections={collections}\n />\n\n {showName && selectedIcon ? <IconifyNameDisplay name={selectedIcon} /> : null}\n </Stack>\n </ThemeProvider>\n </QueryClientProvider>\n );\n}\n\ninterface IconifyNameDisplayProps {\n name?: string | null;\n}\n\nexport function IconifyNameDisplay(props: IconifyNameDisplayProps) {\n const { name } = props;\n const prettyName = usePrettyIconName({ name });\n\n return (\n <Flex gap={1}>\n <Text size={1} muted>\n Selected:\n </Text>\n\n <Text size={1} weight=\"semibold\">\n {prettyName?.name ?? name}\n </Text>\n\n {prettyName?.collection && (\n <Text size={1} muted style={{ fontStyle: 'italic' }}>\n by {prettyName?.collection}\n </Text>\n )}\n </Flex>\n );\n}\n","import { Icon } from '@iconify/react';\nimport type { IconifyIconName } from '@iconify/utils';\nimport { stringToIcon } from '@iconify/utils';\nimport type { PreviewProps } from 'sanity';\nimport { QueryClientProvider } from './lib/query-client';\nimport { usePrettyIconName } from './lib/use-pretty-icon-name';\n\n// --------------- //\n// ICONIFY PREVIEW //\n// --------------- //\n\nexport function IconifyPreview(props: PreviewProps) {\n const { title } = props;\n const iconName = typeof props.title === 'string' ? stringToIcon(props.title) : null;\n\n // We check this double to avoid the TS error\n if (typeof title === 'string' && iconName) {\n return (\n <QueryClientProvider>\n <IconifyPreviewInner {...props} iconName={title} iconMeta={iconName} />\n </QueryClientProvider>\n );\n }\n\n return props.renderDefault(props);\n}\n\n// --------------------- //\n// ICONIFY PREVIEW INNER //\n// --------------------- //\n\ninterface IconifyPreviewInnerProps extends PreviewProps {\n iconName: string;\n iconMeta: IconifyIconName;\n}\n\nfunction IconifyPreviewInner(props: IconifyPreviewInnerProps) {\n const { iconMeta, iconName, ...previewProps } = props;\n const prettyName = usePrettyIconName({ iconMeta });\n\n return props.renderDefault({\n ...previewProps,\n media: <Icon icon={iconName} />,\n title: prettyName?.name ?? iconName,\n subtitle: prettyName?.collection,\n });\n}\n","import type { FieldProps, ObjectInputProps } from 'sanity';\nimport { definePlugin } from 'sanity';\nimport { IconifyInput } from './iconify-input';\nimport { IconifyPreview } from './iconify-preview';\nimport type { IconifyPluginConfig } from './lib/types';\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import { defineConfig } from 'sanity'\n * import { iconify } from 'sanity-plugin-iconify'\n *\n * export default defineConfig({\n * // ...\n * plugins: [iconify()],\n * })\n * ```\n */\nexport const iconify = definePlugin<IconifyPluginConfig | void>((config = {}) => {\n return {\n name: 'sanity-plugin-iconify',\n schema: {\n types: [\n {\n name: 'icon',\n title: 'Icon',\n type: 'object',\n fields: [\n {\n name: 'name',\n title: 'Name',\n type: 'string',\n },\n ],\n components: {\n input: (props: ObjectInputProps) => <IconifyInput {...props} config={config!} />,\n preview: IconifyPreview,\n\n // This makes sure the input component is not indented\n field: (props: FieldProps) => props.renderDefault({ ...props, level: 0 }),\n },\n },\n ],\n },\n };\n});\n"],"names":["queryClient","ReactQueryClientProvider"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-iconify",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Icon picker based on Iconify",
5
5
  "keywords": [
6
6
  "sanity",
@@ -37,70 +37,77 @@
37
37
  "v2-incompatible.js"
38
38
  ],
39
39
  "scripts": {
40
- "build": "run-s clean && plugin-kit verify-package --silent && pkg-utils build --strict && pkg-utils --strict",
41
- "clean": "rimraf dist",
40
+ "build": "run-s build:clean build:verify build:bundle build:check",
41
+ "build:bundle": "pkg-utils build --strict",
42
+ "build:check": "pkg-utils --strict",
43
+ "build:clean": "rimraf dist",
44
+ "build:verify": "plugin-kit verify-package --silent",
45
+ "dev": "tsx dev/vite.ts",
42
46
  "format": "prettier --write --cache --ignore-unknown .",
43
- "link-watch": "pnpm run generate-types && plugin-kit link-watch",
44
- "lint": "eslint .",
45
- "prepublish-only": "run-s build",
46
- "watch": "pkg-utils watch --strict",
47
47
  "generate-types": "node src/lib/generate-types",
48
- "prepare": "husky"
48
+ "lint": "eslint .",
49
+ "release": "release-it",
50
+ "watch": "pkg-utils watch --strict"
49
51
  },
50
52
  "browserslist": "extends @sanity/browserslist-config",
51
53
  "dependencies": {
52
- "@headlessui/react": "^2.0.4",
53
- "@iconify/react": "^5.0.1",
54
- "@iconify/utils": "^2.1.24",
55
- "@sanity/icons": "^3.2.0",
56
- "@sanity/incompatible-plugin": "^1.0.4",
57
- "@sanity/ui": "^2.3.5",
58
- "@tanstack/react-query": "^5.45.0",
54
+ "@iconify/react": "^6.0.0",
55
+ "@iconify/utils": "^2.3.0",
56
+ "@sanity/icons": "^3.7.0",
57
+ "@sanity/incompatible-plugin": "^1.0.5",
58
+ "@sanity/ui": "^2.15.14",
59
+ "@tanstack/react-query": "^5.75.0",
59
60
  "change-case": "^5.4.4",
60
- "ts-pattern": "^5.2.0",
61
- "use-debounce": "^10.0.1"
61
+ "downshift": "^9.0.9",
62
+ "ts-pattern": "^5.7.0",
63
+ "use-debounce": "^10.0.4"
62
64
  },
63
65
  "devDependencies": {
64
- "@commitlint/cli": "^19.3.0",
65
- "@commitlint/config-conventional": "^19.2.2",
66
- "@commitlint/load": "^19.2.0",
67
- "@iconify/json": "^2.2.218",
66
+ "@commitlint/cli": "^19.8.0",
67
+ "@commitlint/config-conventional": "^19.8.0",
68
+ "@iconify/json": "^2.2.333",
68
69
  "@iconify/types": "^2.0.0",
69
- "@sanity/pkg-utils": "^6.9.3",
70
- "@sanity/plugin-kit": "^4.0.17",
71
- "@sanity/semantic-release-preset": "^5.0.0",
72
- "@tanstack/eslint-plugin-query": "^5.43.1",
73
- "@tanstack/react-query-devtools": "^5.45.0",
74
- "@types/react": "^18.3.3",
70
+ "@release-it/conventional-changelog": "^10.0.1",
71
+ "@sanity/pkg-utils": "^7.2.2",
72
+ "@sanity/plugin-kit": "^4.0.19",
73
+ "@tanstack/eslint-plugin-query": "^5.74.7",
74
+ "@tanstack/react-query-devtools": "^5.75.0",
75
+ "@types/react": "^19.1.2",
75
76
  "@types/styled-components": "^5.1.34",
76
- "@waspeer/config": "^2.2.0",
77
- "eslint": "^9.4.0",
78
- "husky": "^9.0.11",
79
- "lint-staged": "^15.2.7",
80
- "npm-run-all": "^4.1.5",
81
- "prettier": "^3.3.2",
82
- "react": "^18.3.1",
83
- "react-dom": "^18.3.1",
84
- "react-is": "^18.3.1",
85
- "rimraf": "^5.0.7",
86
- "sanity": "^3.46.0",
87
- "typescript": "^5.4.5"
77
+ "@waspeer/config": "^2.4.5",
78
+ "eslint": "^9.25.1",
79
+ "lefthook": "^1.11.12",
80
+ "npm-run-all2": "^7.0.2",
81
+ "prettier": "^3.5.3",
82
+ "react": "^19.1.0",
83
+ "react-dom": "^19.1.0",
84
+ "react-is": "^19.1.0",
85
+ "release-it": "^19.0.1",
86
+ "rimraf": "^6.0.1",
87
+ "sanity": "^3.87.0",
88
+ "tsx": "^4.19.4",
89
+ "typescript": "^5.8.3",
90
+ "vite": "^6.3.4"
88
91
  },
89
92
  "peerDependencies": {
90
- "react": "^18",
93
+ "react": "^18 || ^19",
91
94
  "sanity": "^3",
92
95
  "styled-components": "^6"
93
96
  },
97
+ "packageManager": "pnpm@10.4.1+sha512.c753b6c3ad7afa13af388fa6d808035a008e30ea9993f58c6663e2bc5ff21679aa834db094987129aa4d488b86df57f7b634981b2f827cdcacc698cc0cfb88af",
94
98
  "engines": {
95
99
  "node": ">=18"
96
100
  },
97
101
  "pnpm": {
102
+ "onlyBuiltDependencies": [
103
+ "esbuild",
104
+ "lefthook"
105
+ ],
98
106
  "overrides": {
99
- "@babel/traverse@<7.23.2": ">=7.23.2",
100
- "conventional-changelog-conventionalcommits": "^8",
101
- "follow-redirects@<1.15.4": ">=1.15.4",
102
- "follow-redirects@<=1.15.5": ">=1.15.6",
103
- "postcss@<8.4.31": ">=8.4.31"
107
+ "esbuild@<=0.24.2": ">=0.25.0",
108
+ "eslint": "^9",
109
+ "micromatch@<4.0.8": ">=4.0.8",
110
+ "prismjs@<1.30.0": ">=1.30.0"
104
111
  }
105
112
  },
106
113
  "sanityPlugin": {
@@ -12,30 +12,30 @@ export const OptionsWrapper = styled(Box)`
12
12
  padding: 0.5rem;
13
13
 
14
14
  & [role='listbox'] {
15
- display: grid;
16
- grid-template-columns: repeat(auto-fill, minmax(min(100%, 2.5rem), 1fr));
15
+ display: flex;
16
+ flex-wrap: wrap;
17
17
  gap: 0.5rem;
18
18
  margin: 0;
19
19
  padding: 0;
20
20
  list-style: none;
21
-
22
- @media (min-width: 650px) {
23
- grid-template-columns: repeat(10, minmax(min(100%, 2.5rem), 1fr));
24
- }
25
21
  }
26
22
 
27
23
  & [role='option'] {
28
24
  display: grid;
29
25
  place-items: center;
26
+ width: clamp(3rem, 10vw, 4rem);
30
27
 
31
28
  & button {
32
29
  cursor: pointer;
33
- aspect-ratio: 1;
34
30
  width: 100%;
35
31
 
36
32
  & > [data-ui='Box'] {
37
33
  display: flex;
38
34
  }
35
+
36
+ & svg {
37
+ aspect-ratio: 1;
38
+ }
39
39
  }
40
40
  }
41
41
  `;