sanity-plugin-iconify 1.1.2 โ†’ 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,6 +11,7 @@
11
11
  ---
12
12
 
13
13
  ## ๐Ÿ“’ Table of Contents
14
+
14
15
  - [๐Ÿ“’ Table of Contents](#-table-of-contents)
15
16
  - [๐Ÿ“ Overview](#-overview)
16
17
  - [๐Ÿš€ Getting Started](#-getting-started)
@@ -30,7 +31,6 @@
30
31
 
31
32
  ---
32
33
 
33
-
34
34
  ## ๐Ÿ“ Overview
35
35
 
36
36
  Enhance your [Sanity](https://www.sanity.io/) project with the Iconify plugin, which introduces an Icon schema type and a custom input component. Leveraging the extensive library of open-source vector icons available through the [Iconify](https://iconify.design/), this plugin enables you to effortlessly select and integrate over 150,000 icons from popular icon sets directly into your Sanity project.
@@ -158,9 +158,11 @@ import { defineConfig } from 'sanity';
158
158
 
159
159
  export default defineConfig({
160
160
  //...
161
- plugins: [iconify({
162
- showName: true, // <-- Shows the selected icon name and collection underneath all icon pickers
163
- })],
161
+ plugins: [
162
+ iconify({
163
+ showName: true, // <-- Shows the selected icon name and collection underneath all icon pickers
164
+ }),
165
+ ],
164
166
  });
165
167
  ```
166
168
 
@@ -200,7 +202,7 @@ This name can be utilized in your frontend to render the icon dynamically. For i
200
202
  ```tsx
201
203
  import { Icon } from '@iconify/react';
202
204
 
203
- <Icon icon={icon.name} />
205
+ <Icon icon={icon.name} />;
204
206
  ```
205
207
 
206
208
  This will render an SVG on demand, which looks great and is very performant. There are also libraries/API's for:
@@ -214,7 +216,7 @@ For further information, you may refer to the [official documentation](https://i
214
216
 
215
217
  ### Preview
216
218
 
217
- The plugin includes a custom list preview that automatically renders the selected icon accompanied by its name and collection.
219
+ The plugin includes a custom list preview that automatically renders the selected icon accompanied by its name and collection.
218
220
 
219
221
  <img width="618" alt="array-of-icons" src="https://github.com/waspeer/sanity-plugin-iconify/assets/11842931/0c1c32a1-e796-434f-ae64-c134f9b51ab9">
220
222
 
@@ -255,18 +257,24 @@ Contributions, whether in the form of code enhancements, bug fixes, documentatio
255
257
  1. Fork the project repository. This creates a copy of the project on your account that you can modify without affecting the original project.
256
258
  2. Clone the forked repository to your local machine using a Git client like Git or GitHub Desktop.
257
259
  3. Create a new branch with a descriptive name (e.g., `new-feature-branch` or `bugfix-issue-123`).
260
+
258
261
  ```sh
259
262
  git checkout -b new-feature-branch
260
263
  ```
264
+
261
265
  1. Make changes to the project's codebase.
262
266
  2. Commit your changes to your local branch with a clear conventional commit message that explains the changes you've made.
267
+
263
268
  ```sh
264
269
  git commit -m 'feat: Implemented new feature.'
265
270
  ```
271
+
266
272
  1. Push your changes to your forked repository on GitHub using the following command
273
+
267
274
  ```sh
268
275
  git push origin new-feature-branch
269
276
  ```
277
+
270
278
  1. Create a new pull request to the original project repository. In the pull request, describe the changes you've made and why they are necessary. Make sure to update or add documentation as relevant. I will review your changes, provide feedback, or merge them into the main branch.
271
279
 
272
280
  ## ๐Ÿงช Develop & test
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var jsxRuntime = require("react/jsx-runtime"), sanity = require("sanity"), ui = require("@sanity/ui"), react = require("react"), react$1 = require("@headlessui/react"), tsPattern = require("ts-pattern"), reactQuery = require("@tanstack/react-query"), useDebounce = require("use-debounce"), styled = require("styled-components"), react$2 = require("@iconify/react"), icons = require("@sanity/icons"), utils = require("@iconify/utils"), changeCase = require("change-case");
3
+ var jsxRuntime = require("react/jsx-runtime"), sanity = require("sanity"), ui = require("@sanity/ui"), theme = require("@sanity/ui/theme"), react = require("react"), react$1 = require("@headlessui/react"), tsPattern = require("ts-pattern"), reactQuery = require("@tanstack/react-query"), useDebounce = require("use-debounce"), styled = require("styled-components"), react$2 = require("@iconify/react"), icons = require("@sanity/icons"), utils = require("@iconify/utils"), changeCase = require("change-case");
4
4
  function _interopDefaultCompat(e) {
5
5
  return e && typeof e == "object" && "default" in e ? e : { default: e };
6
6
  }
@@ -56,8 +56,7 @@ function useIconSetInfo({ prefix }) {
56
56
  queryKey: ["iconSetInfo", prefix],
57
57
  queryFn: async ({ signal }) => {
58
58
  var _a;
59
- if (!prefix)
60
- return null;
59
+ if (!prefix) return null;
61
60
  const url = new URL("/collection", BASE_API_URL);
62
61
  url.searchParams.append("prefix", prefix), url.searchParams.append("info", "true");
63
62
  const result = await fetchJson({ url, signal });
@@ -77,9 +76,9 @@ const ComboboxWrapper = styled__default.default(ui.Grid)`
77
76
  display: grid;
78
77
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 2.5rem), 1fr));
79
78
  gap: 0.5rem;
80
- list-style: none;
81
79
  margin: 0;
82
80
  padding: 0;
81
+ list-style: none;
83
82
 
84
83
  @media (min-width: 650px) {
85
84
  grid-template-columns: repeat(10, minmax(min(100%, 2.5rem), 1fr));
@@ -91,8 +90,8 @@ const ComboboxWrapper = styled__default.default(ui.Grid)`
91
90
  place-items: center;
92
91
 
93
92
  & button {
94
- aspect-ratio: 1;
95
93
  cursor: pointer;
94
+ aspect-ratio: 1;
96
95
  width: 100%;
97
96
 
98
97
  & > [data-ui='Box'] {
@@ -105,9 +104,9 @@ function MessageWrapper({ children }) {
105
104
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { align: "center", muted: !0, children }) });
106
105
  }
107
106
  const SearchInput = react.forwardRef((props, ref) => {
108
- const { term, selectedIcon, onChange } = props;
107
+ const { term, selectedIcon, onChange, suffix } = props;
109
108
  return /* @__PURE__ */ jsxRuntime.jsx(
110
- react$1.Combobox.Input,
109
+ react$1.ComboboxInput,
111
110
  {
112
111
  as: ui.TextInput,
113
112
  ref,
@@ -115,18 +114,19 @@ const SearchInput = react.forwardRef((props, ref) => {
115
114
  value: term,
116
115
  onChange,
117
116
  icon: selectedIcon ? /* @__PURE__ */ jsxRuntime.jsx(react$2.Icon, { icon: selectedIcon }) : null,
118
- placeholder: selectedIcon ? "Search and replace selected icon..." : "Search for an icon..."
117
+ placeholder: selectedIcon ? "Search and replace selected icon..." : "Search for an icon...",
118
+ suffix
119
119
  }
120
120
  );
121
121
  });
122
122
  SearchInput.displayName = "SearchInput";
123
123
  function SearchResults(props) {
124
124
  const { state, data } = props;
125
- return state === "initial" ? /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Search for icons" }) : state === "loading" ? /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Searching..." }) : state === "error" ? /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Something went wrong..." }) : state === "empty" ? /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "No icons found" }) : /* @__PURE__ */ jsxRuntime.jsx(react$1.Combobox.Options, { style: { opacity: state === "stale" ? 0.5 : 1 }, children: data.map((icon) => /* @__PURE__ */ jsxRuntime.jsx(react$1.Combobox.Option, { value: icon, children: ({ active }) => /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { padding: 3, mode: "bleed", selected: active, children: /* @__PURE__ */ jsxRuntime.jsx(react$2.Icon, { icon, width: "100%", height: "100%" }) }) }, icon)) });
125
+ return state === "initial" ? /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Search for icons" }) : state === "loading" ? /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Searching..." }) : state === "error" ? /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Something went wrong..." }) : state === "empty" ? /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "No icons found" }) : /* @__PURE__ */ jsxRuntime.jsx(react$1.ComboboxOptions, { style: { opacity: state === "stale" ? 0.5 : 1 }, children: data.map((icon) => /* @__PURE__ */ jsxRuntime.jsx(react$1.ComboboxOption, { value: icon, children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { padding: 3, mode: "bleed", selected: focus, children: /* @__PURE__ */ jsxRuntime.jsx(react$2.Icon, { icon, width: "100%", height: "100%" }) }) }, icon)) });
126
126
  }
127
127
  function UnsetButton(props) {
128
128
  const { onUnset } = props;
129
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { border: !0, borderLeft: !1, padding: 1, display: "flex", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.TrashIcon, {}), onClick: onUnset, mode: "bleed", fontSize: 1, padding: 2 }) });
129
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { border: !0, borderLeft: !1, padding: 1, display: "flex", radius: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.TrashIcon, {}), onClick: onUnset, mode: "bleed", fontSize: 1, padding: 2 }) });
130
130
  }
131
131
  function IconifyCombobox(props) {
132
132
  const { selectedIcon, onSelect: pushSelection, collections } = props, id = react.useId(), toast = ui.useToast(), inputRef = react.useRef(null), { term, setTerm, debouncedTerm, isLoading, isError, error, data, isPreviousData } = useSearch({
@@ -147,39 +147,37 @@ function IconifyCombobox(props) {
147
147
  title: "Iconify input error",
148
148
  description: error == null ? void 0 : error.message
149
149
  }));
150
- }, [error, id, isError, toast]), /* @__PURE__ */ jsxRuntime.jsxs(ComboboxWrapper, { children: [
151
- /* @__PURE__ */ jsxRuntime.jsx(react$1.Combobox, { onChange: handleSelect, children: ({ open }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
152
- /* @__PURE__ */ jsxRuntime.jsx(
153
- SearchInput,
154
- {
155
- ref: inputRef,
156
- term,
157
- selectedIcon,
158
- onChange: handleTermChange
159
- }
160
- ),
161
- /* @__PURE__ */ jsxRuntime.jsx(
162
- ui.Popover,
163
- {
164
- open,
165
- placement: "bottom",
166
- arrow: !1,
167
- matchReferenceWidth: !0,
168
- portal: !0,
169
- constrainSize: !0,
170
- referenceElement: inputRef.current,
171
- content: /* @__PURE__ */ jsxRuntime.jsx(OptionsWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(
172
- SearchResults,
173
- {
174
- state: tsPattern.match(!0).returnType().with(isLoading, () => "loading").with(!debouncedTerm, () => "initial").with(isError, () => "error").with(!data || data.length === 0, () => "empty").with(isPreviousData, () => "stale").otherwise(() => "data"),
175
- data
176
- }
177
- ) })
178
- }
179
- )
180
- ] }) }),
181
- selectedIcon ? /* @__PURE__ */ jsxRuntime.jsx(UnsetButton, { onUnset: handleUnset }) : null
182
- ] });
150
+ }, [error, id, isError, toast]), /* @__PURE__ */ jsxRuntime.jsx(ComboboxWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(react$1.Combobox, { onChange: handleSelect, children: ({ open }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
151
+ /* @__PURE__ */ jsxRuntime.jsx(
152
+ SearchInput,
153
+ {
154
+ ref: inputRef,
155
+ term,
156
+ selectedIcon,
157
+ onChange: handleTermChange,
158
+ suffix: selectedIcon ? /* @__PURE__ */ jsxRuntime.jsx(UnsetButton, { onUnset: handleUnset }) : null
159
+ }
160
+ ),
161
+ /* @__PURE__ */ jsxRuntime.jsx(
162
+ ui.Popover,
163
+ {
164
+ open,
165
+ placement: "bottom",
166
+ arrow: !1,
167
+ matchReferenceWidth: !0,
168
+ portal: !0,
169
+ constrainSize: !0,
170
+ referenceElement: inputRef.current,
171
+ content: /* @__PURE__ */ jsxRuntime.jsx(OptionsWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(
172
+ SearchResults,
173
+ {
174
+ state: tsPattern.match(!0).returnType().with(isLoading, () => "loading").with(!debouncedTerm, () => "initial").with(isError, () => "error").with(!data || data.length === 0, () => "empty").with(isPreviousData, () => "stale").otherwise(() => "data"),
175
+ data
176
+ }
177
+ ) })
178
+ }
179
+ )
180
+ ] }) }) });
183
181
  }
184
182
  const queryClient = new reactQuery.QueryClient();
185
183
  function QueryClientProvider(props) {
@@ -207,16 +205,13 @@ function usePrettyIconName(props) {
207
205
  }
208
206
  function IconifyInput(props) {
209
207
  var _a, _b, _c, _d, _e;
210
- 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, parentTheme = ui.useTheme(), theme = react.useMemo(
211
- () => parentTheme ? { ...parentTheme.sanity, color: ui.studioTheme.color } : ui.studioTheme,
212
- [parentTheme]
213
- ), handleSelect = react.useCallback(
208
+ 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 = react.useCallback(
214
209
  (icon) => {
215
210
  pushChange(icon === "" ? sanity.unset() : sanity.set(icon, ["name"]));
216
211
  },
217
212
  [pushChange]
218
213
  );
219
- return /* @__PURE__ */ jsxRuntime.jsx(QueryClientProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.ThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
214
+ return /* @__PURE__ */ jsxRuntime.jsx(QueryClientProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.ThemeProvider, { theme: theme.buildTheme(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
220
215
  /* @__PURE__ */ jsxRuntime.jsx(
221
216
  IconifyCombobox,
222
217
  {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","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 { IconifyInfo } from '@iconify/types';\nimport { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useCallback, useState } from 'react';\nimport { useDebounce } from 'use-debounce';\n\nimport { 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 { 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 list-style: none;\n margin: 0;\n padding: 0;\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 aspect-ratio: 1;\n cursor: pointer;\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 { Combobox } from '@headlessui/react';\nimport { Icon } from '@iconify/react';\nimport { TextInput } from '@sanity/ui';\nimport { ChangeEventHandler, forwardRef } from 'react';\n\n// ------------ //\n// SEARCH INPUT //\n// ------------ //\n\ninterface SearchInputProps {\n term: string;\n selectedIcon: string | null;\n onChange: ChangeEventHandler<HTMLInputElement>;\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>((props, ref) => {\n const { term, selectedIcon, onChange } = props;\n\n return (\n <Combobox.Input\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 />\n );\n});\n\nSearchInput.displayName = 'SearchInput';\n","import { Combobox } from '@headlessui/react';\nimport { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\n\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 <Combobox.Options style={{ opacity: state === 'stale' ? 0.5 : 1 }}>\n {data!.map((icon) => (\n <Combobox.Option key={icon} value={icon}>\n {({ active }) => (\n <Button padding={3} mode=\"bleed\" selected={active}>\n <Icon icon={icon} width=\"100%\" height=\"100%\" />\n </Button>\n )}\n </Combobox.Option>\n ))}\n </Combobox.Options>\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\">\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 { ChangeEventHandler, useCallback, useEffect, useId, useRef } from 'react';\nimport { match } from 'ts-pattern';\n\nimport { useSearch } from '../lib/api';\nimport { ComboboxWrapper, OptionsWrapper } from './iconify-combobox.styles';\nimport { SearchInput } from './search-input';\nimport { SearchResults, SearchResultsProps } 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 />\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\n {selectedIcon ? <UnsetButton onUnset={handleUnset} /> : null}\n </ComboboxWrapper>\n );\n}\n","import {\n QueryClient,\n QueryClientProvider as ReactQueryClientProvider,\n} from '@tanstack/react-query';\nimport { 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 { IconifyIconName, stringToIcon } from '@iconify/utils';\nimport { sentenceCase } from 'change-case';\nimport { useMemo } from 'react';\n\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, RootTheme, Stack, studioTheme, Text, ThemeProvider, useTheme } from '@sanity/ui';\nimport { useCallback, useMemo } from 'react';\nimport { ObjectInputProps, set, unset } from 'sanity';\n\nimport { IconifyCombobox } from './combobox';\nimport { QueryClientProvider } from './lib/query-client';\nimport { 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={theme}>\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 { IconifyIconName, stringToIcon } from '@iconify/utils';\nimport { PreviewProps } from 'sanity';\n\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 { definePlugin, FieldProps, ObjectInputProps } from 'sanity';\n\nimport { IconifyInput } from './iconify-input';\nimport { IconifyPreview } from './iconify-preview';\nimport { 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","useQueryClient","useState","useDebounce","useCallback","useQuery","keepPreviousData","styled","Grid","Box","jsx","Card","Text","forwardRef","Combobox","TextInput","Icon","Button","TrashIcon","useId","useToast","useRef","useEffect","jsxs","Fragment","Popover","match","QueryClient","ReactQueryClientProvider","useMemo","_a","stringToIcon","_b","sentenceCase","useTheme","studioTheme","unset","set","ThemeProvider","Stack","Flex","definePlugin"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","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","useQueryClient","useState","useDebounce","useCallback","useQuery","keepPreviousData","styled","Grid","Box","jsx","Card","Text","forwardRef","ComboboxInput","TextInput","Icon","ComboboxOptions","ComboboxOption","Button","TrashIcon","useId","useToast","useRef","useEffect","Combobox","jsxs","Fragment","Popover","match","QueryClient","ReactQueryClientProvider","useMemo","_a","stringToIcon","_b","sentenceCase","unset","set","ThemeProvider","buildTheme","Stack","Flex","definePlugin"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BaseSchemaDefinition } from 'sanity';
2
- import { IconifyInfo } from '@iconify/types';
2
+ import type { IconifyInfo } from '@iconify/types';
3
3
  import { Plugin as Plugin_2 } from 'sanity';
4
4
 
5
5
  export { BaseSchemaDefinition };
@@ -42,6 +42,7 @@ export declare type IconPrefix =
42
42
  | 'ph'
43
43
  | 'solar'
44
44
  | 'tabler'
45
+ | 'hugeicons'
45
46
  | 'mingcute'
46
47
  | 'ri'
47
48
  | 'bi'
@@ -94,6 +95,7 @@ export declare type IconPrefix =
94
95
  | 'lets-icons'
95
96
  | 'f7'
96
97
  | 'mage'
98
+ | 'marketeq'
97
99
  | 'fluent'
98
100
  | 'icon-park-outline'
99
101
  | 'icon-park-solid'
@@ -147,6 +149,8 @@ export declare type IconPrefix =
147
149
  | 'unjs'
148
150
  | 'brandico'
149
151
  | 'entypo-social'
152
+ | 'token'
153
+ | 'token-branded'
150
154
  | 'cryptocurrency'
151
155
  | 'cryptocurrency-color'
152
156
  | 'flag'
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BaseSchemaDefinition } from 'sanity';
2
- import { IconifyInfo } from '@iconify/types';
2
+ import type { IconifyInfo } from '@iconify/types';
3
3
  import { Plugin as Plugin_2 } from 'sanity';
4
4
 
5
5
  export { BaseSchemaDefinition };
@@ -42,6 +42,7 @@ export declare type IconPrefix =
42
42
  | 'ph'
43
43
  | 'solar'
44
44
  | 'tabler'
45
+ | 'hugeicons'
45
46
  | 'mingcute'
46
47
  | 'ri'
47
48
  | 'bi'
@@ -94,6 +95,7 @@ export declare type IconPrefix =
94
95
  | 'lets-icons'
95
96
  | 'f7'
96
97
  | 'mage'
98
+ | 'marketeq'
97
99
  | 'fluent'
98
100
  | 'icon-park-outline'
99
101
  | 'icon-park-solid'
@@ -147,6 +149,8 @@ export declare type IconPrefix =
147
149
  | 'unjs'
148
150
  | 'brandico'
149
151
  | 'entypo-social'
152
+ | 'token'
153
+ | 'token-branded'
150
154
  | 'cryptocurrency'
151
155
  | 'cryptocurrency-color'
152
156
  | 'flag'
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { unset, set, definePlugin } from "sanity";
3
- import { Grid, Box, Card, Text, TextInput, Button, useToast, Popover, useTheme, studioTheme, ThemeProvider, Stack, Flex } from "@sanity/ui";
3
+ import { Grid, Box, Card, Text, TextInput, Button, useToast, Popover, ThemeProvider, Stack, Flex } from "@sanity/ui";
4
+ import { buildTheme } from "@sanity/ui/theme";
4
5
  import { useState, useCallback, forwardRef, useId, useRef, useEffect, useMemo } from "react";
5
- import { Combobox } from "@headlessui/react";
6
+ import { ComboboxInput, ComboboxOptions, ComboboxOption, Combobox } from "@headlessui/react";
6
7
  import { match } from "ts-pattern";
7
8
  import { useQueryClient, useQuery, keepPreviousData, QueryClient, QueryClientProvider as QueryClientProvider$1 } from "@tanstack/react-query";
8
9
  import { useDebounce } from "use-debounce";
@@ -62,8 +63,7 @@ function useIconSetInfo({ prefix }) {
62
63
  queryKey: ["iconSetInfo", prefix],
63
64
  queryFn: async ({ signal }) => {
64
65
  var _a;
65
- if (!prefix)
66
- return null;
66
+ if (!prefix) return null;
67
67
  const url = new URL("/collection", BASE_API_URL);
68
68
  url.searchParams.append("prefix", prefix), url.searchParams.append("info", "true");
69
69
  const result = await fetchJson({ url, signal });
@@ -83,9 +83,9 @@ const ComboboxWrapper = styled(Grid)`
83
83
  display: grid;
84
84
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 2.5rem), 1fr));
85
85
  gap: 0.5rem;
86
- list-style: none;
87
86
  margin: 0;
88
87
  padding: 0;
88
+ list-style: none;
89
89
 
90
90
  @media (min-width: 650px) {
91
91
  grid-template-columns: repeat(10, minmax(min(100%, 2.5rem), 1fr));
@@ -97,8 +97,8 @@ const ComboboxWrapper = styled(Grid)`
97
97
  place-items: center;
98
98
 
99
99
  & button {
100
- aspect-ratio: 1;
101
100
  cursor: pointer;
101
+ aspect-ratio: 1;
102
102
  width: 100%;
103
103
 
104
104
  & > [data-ui='Box'] {
@@ -111,9 +111,9 @@ function MessageWrapper({ children }) {
111
111
  return /* @__PURE__ */ jsx(Card, { padding: 4, children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, children }) });
112
112
  }
113
113
  const SearchInput = forwardRef((props, ref) => {
114
- const { term, selectedIcon, onChange } = props;
114
+ const { term, selectedIcon, onChange, suffix } = props;
115
115
  return /* @__PURE__ */ jsx(
116
- Combobox.Input,
116
+ ComboboxInput,
117
117
  {
118
118
  as: TextInput,
119
119
  ref,
@@ -121,18 +121,19 @@ const SearchInput = forwardRef((props, ref) => {
121
121
  value: term,
122
122
  onChange,
123
123
  icon: selectedIcon ? /* @__PURE__ */ jsx(Icon, { icon: selectedIcon }) : null,
124
- placeholder: selectedIcon ? "Search and replace selected icon..." : "Search for an icon..."
124
+ placeholder: selectedIcon ? "Search and replace selected icon..." : "Search for an icon...",
125
+ suffix
125
126
  }
126
127
  );
127
128
  });
128
129
  SearchInput.displayName = "SearchInput";
129
130
  function SearchResults(props) {
130
131
  const { state, data } = props;
131
- 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(Combobox.Options, { style: { opacity: state === "stale" ? 0.5 : 1 }, children: data.map((icon) => /* @__PURE__ */ jsx(Combobox.Option, { value: icon, children: ({ active }) => /* @__PURE__ */ jsx(Button, { padding: 3, mode: "bleed", selected: active, children: /* @__PURE__ */ jsx(Icon, { icon, width: "100%", height: "100%" }) }) }, icon)) });
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)) });
132
133
  }
133
134
  function UnsetButton(props) {
134
135
  const { onUnset } = props;
135
- return /* @__PURE__ */ jsx(Card, { border: !0, borderLeft: !1, padding: 1, display: "flex", children: /* @__PURE__ */ jsx(Button, { icon: /* @__PURE__ */ jsx(TrashIcon, {}), onClick: onUnset, mode: "bleed", fontSize: 1, padding: 2 }) });
136
+ 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 }) });
136
137
  }
137
138
  function IconifyCombobox(props) {
138
139
  const { selectedIcon, onSelect: pushSelection, collections } = props, id = useId(), toast = useToast(), inputRef = useRef(null), { term, setTerm, debouncedTerm, isLoading, isError, error, data, isPreviousData } = useSearch({
@@ -153,39 +154,37 @@ function IconifyCombobox(props) {
153
154
  title: "Iconify input error",
154
155
  description: error == null ? void 0 : error.message
155
156
  }));
156
- }, [error, id, isError, toast]), /* @__PURE__ */ jsxs(ComboboxWrapper, { children: [
157
- /* @__PURE__ */ jsx(Combobox, { onChange: handleSelect, children: ({ open }) => /* @__PURE__ */ jsxs(Fragment, { children: [
158
- /* @__PURE__ */ jsx(
159
- SearchInput,
160
- {
161
- ref: inputRef,
162
- term,
163
- selectedIcon,
164
- onChange: handleTermChange
165
- }
166
- ),
167
- /* @__PURE__ */ jsx(
168
- Popover,
169
- {
170
- open,
171
- placement: "bottom",
172
- arrow: !1,
173
- matchReferenceWidth: !0,
174
- portal: !0,
175
- constrainSize: !0,
176
- referenceElement: inputRef.current,
177
- content: /* @__PURE__ */ jsx(OptionsWrapper, { children: /* @__PURE__ */ jsx(
178
- SearchResults,
179
- {
180
- state: match(!0).returnType().with(isLoading, () => "loading").with(!debouncedTerm, () => "initial").with(isError, () => "error").with(!data || data.length === 0, () => "empty").with(isPreviousData, () => "stale").otherwise(() => "data"),
181
- data
182
- }
183
- ) })
184
- }
185
- )
186
- ] }) }),
187
- selectedIcon ? /* @__PURE__ */ jsx(UnsetButton, { onUnset: handleUnset }) : null
188
- ] });
157
+ }, [error, id, isError, toast]), /* @__PURE__ */ jsx(ComboboxWrapper, { children: /* @__PURE__ */ jsx(Combobox, { onChange: handleSelect, children: ({ open }) => /* @__PURE__ */ jsxs(Fragment, { children: [
158
+ /* @__PURE__ */ jsx(
159
+ SearchInput,
160
+ {
161
+ ref: inputRef,
162
+ term,
163
+ selectedIcon,
164
+ onChange: handleTermChange,
165
+ suffix: selectedIcon ? /* @__PURE__ */ jsx(UnsetButton, { onUnset: handleUnset }) : null
166
+ }
167
+ ),
168
+ /* @__PURE__ */ jsx(
169
+ Popover,
170
+ {
171
+ open,
172
+ placement: "bottom",
173
+ arrow: !1,
174
+ matchReferenceWidth: !0,
175
+ portal: !0,
176
+ constrainSize: !0,
177
+ referenceElement: inputRef.current,
178
+ content: /* @__PURE__ */ jsx(OptionsWrapper, { children: /* @__PURE__ */ jsx(
179
+ SearchResults,
180
+ {
181
+ 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
183
+ }
184
+ ) })
185
+ }
186
+ )
187
+ ] }) }) });
189
188
  }
190
189
  const queryClient = new QueryClient();
191
190
  function QueryClientProvider(props) {
@@ -213,16 +212,13 @@ function usePrettyIconName(props) {
213
212
  }
214
213
  function IconifyInput(props) {
215
214
  var _a, _b, _c, _d, _e;
216
- 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, parentTheme = useTheme(), theme = useMemo(
217
- () => parentTheme ? { ...parentTheme.sanity, color: studioTheme.color } : studioTheme,
218
- [parentTheme]
219
- ), handleSelect = useCallback(
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(
220
216
  (icon) => {
221
217
  pushChange(icon === "" ? unset() : set(icon, ["name"]));
222
218
  },
223
219
  [pushChange]
224
220
  );
225
- return /* @__PURE__ */ jsx(QueryClientProvider, { children: /* @__PURE__ */ jsx(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
221
+ return /* @__PURE__ */ jsx(QueryClientProvider, { children: /* @__PURE__ */ jsx(ThemeProvider, { theme: buildTheme(), children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
226
222
  /* @__PURE__ */ jsx(
227
223
  IconifyCombobox,
228
224
  {
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 { IconifyInfo } from '@iconify/types';\nimport { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useCallback, useState } from 'react';\nimport { useDebounce } from 'use-debounce';\n\nimport { 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 { 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 list-style: none;\n margin: 0;\n padding: 0;\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 aspect-ratio: 1;\n cursor: pointer;\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 { Combobox } from '@headlessui/react';\nimport { Icon } from '@iconify/react';\nimport { TextInput } from '@sanity/ui';\nimport { ChangeEventHandler, forwardRef } from 'react';\n\n// ------------ //\n// SEARCH INPUT //\n// ------------ //\n\ninterface SearchInputProps {\n term: string;\n selectedIcon: string | null;\n onChange: ChangeEventHandler<HTMLInputElement>;\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>((props, ref) => {\n const { term, selectedIcon, onChange } = props;\n\n return (\n <Combobox.Input\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 />\n );\n});\n\nSearchInput.displayName = 'SearchInput';\n","import { Combobox } from '@headlessui/react';\nimport { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\n\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 <Combobox.Options style={{ opacity: state === 'stale' ? 0.5 : 1 }}>\n {data!.map((icon) => (\n <Combobox.Option key={icon} value={icon}>\n {({ active }) => (\n <Button padding={3} mode=\"bleed\" selected={active}>\n <Icon icon={icon} width=\"100%\" height=\"100%\" />\n </Button>\n )}\n </Combobox.Option>\n ))}\n </Combobox.Options>\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\">\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 { ChangeEventHandler, useCallback, useEffect, useId, useRef } from 'react';\nimport { match } from 'ts-pattern';\n\nimport { useSearch } from '../lib/api';\nimport { ComboboxWrapper, OptionsWrapper } from './iconify-combobox.styles';\nimport { SearchInput } from './search-input';\nimport { SearchResults, SearchResultsProps } 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 />\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\n {selectedIcon ? <UnsetButton onUnset={handleUnset} /> : null}\n </ComboboxWrapper>\n );\n}\n","import {\n QueryClient,\n QueryClientProvider as ReactQueryClientProvider,\n} from '@tanstack/react-query';\nimport { 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 { IconifyIconName, stringToIcon } from '@iconify/utils';\nimport { sentenceCase } from 'change-case';\nimport { useMemo } from 'react';\n\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, RootTheme, Stack, studioTheme, Text, ThemeProvider, useTheme } from '@sanity/ui';\nimport { useCallback, useMemo } from 'react';\nimport { ObjectInputProps, set, unset } from 'sanity';\n\nimport { IconifyCombobox } from './combobox';\nimport { QueryClientProvider } from './lib/query-client';\nimport { 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={theme}>\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 { IconifyIconName, stringToIcon } from '@iconify/utils';\nimport { PreviewProps } from 'sanity';\n\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 { definePlugin, FieldProps, ObjectInputProps } from 'sanity';\n\nimport { IconifyInput } from './iconify-input';\nimport { IconifyPreview } from './iconify-preview';\nimport { 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: 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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-iconify",
3
- "version": "1.1.2",
3
+ "version": "2.0.0",
4
4
  "description": "Icon picker based on Iconify",
5
5
  "keywords": [
6
6
  "sanity",
@@ -29,7 +29,6 @@
29
29
  },
30
30
  "main": "./dist/index.cjs",
31
31
  "module": "./dist/index.js",
32
- "source": "./src/index.ts",
33
32
  "types": "./dist/index.d.ts",
34
33
  "files": [
35
34
  "dist",
@@ -46,73 +45,68 @@
46
45
  "prepublish-only": "run-s build",
47
46
  "watch": "pkg-utils watch --strict",
48
47
  "generate-types": "node src/lib/generate-types",
49
- "prepare": "husky install"
48
+ "prepare": "husky"
50
49
  },
51
50
  "browserslist": "extends @sanity/browserslist-config",
52
51
  "dependencies": {
53
- "@headlessui/react": "^1.7.18",
54
- "@iconify/react": "^4.1.1",
55
- "@iconify/utils": "^2.1.22",
56
- "@sanity/icons": "^2.11.4",
52
+ "@headlessui/react": "^2.0.4",
53
+ "@iconify/react": "^5.0.1",
54
+ "@iconify/utils": "^2.1.24",
55
+ "@sanity/icons": "^3.2.0",
57
56
  "@sanity/incompatible-plugin": "^1.0.4",
58
- "@sanity/ui": "^1.9.3",
59
- "@tanstack/react-query": "^5.28.6",
60
- "change-case": "^5.4.3",
61
- "ts-pattern": "^5.0.8",
62
- "use-debounce": "^10.0.0"
57
+ "@sanity/ui": "^2.3.5",
58
+ "@tanstack/react-query": "^5.45.0",
59
+ "change-case": "^5.4.4",
60
+ "ts-pattern": "^5.2.0",
61
+ "use-debounce": "^10.0.1"
63
62
  },
64
63
  "devDependencies": {
65
- "@commitlint/cli": "^19.2.1",
66
- "@commitlint/config-conventional": "^19.1.0",
64
+ "@commitlint/cli": "^19.3.0",
65
+ "@commitlint/config-conventional": "^19.2.2",
67
66
  "@commitlint/load": "^19.2.0",
68
- "@iconify/json": "^2.2.195",
67
+ "@iconify/json": "^2.2.218",
69
68
  "@iconify/types": "^2.0.0",
70
- "@sanity/pkg-utils": "^5.1.4",
71
- "@sanity/plugin-kit": "^3.1.10",
72
- "@sanity/semantic-release-preset": "^4.1.7",
73
- "@tanstack/eslint-plugin-query": "^5.28.6",
74
- "@tanstack/react-query-devtools": "^5.28.6",
75
- "@types/react": "^18.2.69",
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",
76
75
  "@types/styled-components": "^5.1.34",
77
- "@typescript-eslint/eslint-plugin": "^7.3.1",
78
- "@typescript-eslint/parser": "^7.3.1",
79
- "eslint": "^8.57.0",
80
- "eslint-config-prettier": "^9.1.0",
81
- "eslint-config-sanity": "^7.1.2",
82
- "eslint-plugin-prettier": "^5.1.3",
83
- "eslint-plugin-react": "^7.34.1",
84
- "eslint-plugin-react-hooks": "^4.6.0",
76
+ "@waspeer/config": "^2.2.0",
77
+ "eslint": "^9.4.0",
85
78
  "husky": "^9.0.11",
86
- "lint-staged": "^15.2.2",
79
+ "lint-staged": "^15.2.7",
87
80
  "npm-run-all": "^4.1.5",
88
- "prettier": "^3.2.5",
89
- "prettier-plugin-packagejson": "^2.4.12",
90
- "react": "^18.2.0",
91
- "react-dom": "^18.2.0",
92
- "react-is": "^18.2.0",
93
- "rimraf": "^5.0.5",
94
- "sanity": "^3.35.2",
95
- "typescript": "^5.4.3"
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"
96
88
  },
97
89
  "peerDependencies": {
98
90
  "react": "^18",
99
91
  "sanity": "^3",
100
- "styled-components": "^5.2 || ^6"
92
+ "styled-components": "^6"
101
93
  },
102
94
  "engines": {
103
- "node": ">=14"
95
+ "node": ">=18"
104
96
  },
105
97
  "pnpm": {
106
98
  "overrides": {
107
99
  "@babel/traverse@<7.23.2": ">=7.23.2",
108
- "postcss@<8.4.31": ">=8.4.31",
100
+ "conventional-changelog-conventionalcommits": "^8",
109
101
  "follow-redirects@<1.15.4": ">=1.15.4",
110
- "follow-redirects@<=1.15.5": ">=1.15.6"
102
+ "follow-redirects@<=1.15.5": ">=1.15.6",
103
+ "postcss@<8.4.31": ">=8.4.31"
111
104
  }
112
105
  },
113
106
  "sanityPlugin": {
114
107
  "verifyPackage": {
115
- "scripts": false
108
+ "scripts": false,
109
+ "eslintImports": false
116
110
  }
117
111
  }
118
112
  }
@@ -1,5 +1,5 @@
1
1
  import { Box, Card, Grid, Text } from '@sanity/ui';
2
- import { ReactNode } from 'react';
2
+ import type { ReactNode } from 'react';
3
3
  import styled from 'styled-components';
4
4
 
5
5
  export const ComboboxWrapper = styled(Grid)`
@@ -15,9 +15,9 @@ export const OptionsWrapper = styled(Box)`
15
15
  display: grid;
16
16
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 2.5rem), 1fr));
17
17
  gap: 0.5rem;
18
- list-style: none;
19
18
  margin: 0;
20
19
  padding: 0;
20
+ list-style: none;
21
21
 
22
22
  @media (min-width: 650px) {
23
23
  grid-template-columns: repeat(10, minmax(min(100%, 2.5rem), 1fr));
@@ -29,8 +29,8 @@ export const OptionsWrapper = styled(Box)`
29
29
  place-items: center;
30
30
 
31
31
  & button {
32
- aspect-ratio: 1;
33
32
  cursor: pointer;
33
+ aspect-ratio: 1;
34
34
  width: 100%;
35
35
 
36
36
  & > [data-ui='Box'] {
@@ -1,12 +1,13 @@
1
1
  import { Combobox } from '@headlessui/react';
2
2
  import { Popover, useToast } from '@sanity/ui';
3
- import { ChangeEventHandler, useCallback, useEffect, useId, useRef } from 'react';
3
+ import type { ChangeEventHandler } from 'react';
4
+ import { useCallback, useEffect, useId, useRef } from 'react';
4
5
  import { match } from 'ts-pattern';
5
-
6
6
  import { useSearch } from '../lib/api';
7
7
  import { ComboboxWrapper, OptionsWrapper } from './iconify-combobox.styles';
8
8
  import { SearchInput } from './search-input';
9
- import { SearchResults, SearchResultsProps } from './search-result';
9
+ import type { SearchResultsProps } from './search-result';
10
+ import { SearchResults } from './search-result';
10
11
  import { UnsetButton } from './unset-button';
11
12
 
12
13
  export interface IconifyComboboxProps {
@@ -65,6 +66,7 @@ export function IconifyCombobox(props: IconifyComboboxProps) {
65
66
  term={term}
66
67
  selectedIcon={selectedIcon}
67
68
  onChange={handleTermChange}
69
+ suffix={selectedIcon ? <UnsetButton onUnset={handleUnset} /> : null}
68
70
  />
69
71
 
70
72
  <Popover
@@ -94,8 +96,6 @@ export function IconifyCombobox(props: IconifyComboboxProps) {
94
96
  </>
95
97
  )}
96
98
  </Combobox>
97
-
98
- {selectedIcon ? <UnsetButton onUnset={handleUnset} /> : null}
99
99
  </ComboboxWrapper>
100
100
  );
101
101
  }
@@ -1,7 +1,8 @@
1
- import { Combobox } from '@headlessui/react';
1
+ import { ComboboxInput } from '@headlessui/react';
2
2
  import { Icon } from '@iconify/react';
3
3
  import { TextInput } from '@sanity/ui';
4
- import { ChangeEventHandler, forwardRef } from 'react';
4
+ import type { ChangeEventHandler } from 'react';
5
+ import { forwardRef } from 'react';
5
6
 
6
7
  // ------------ //
7
8
  // SEARCH INPUT //
@@ -11,13 +12,14 @@ interface SearchInputProps {
11
12
  term: string;
12
13
  selectedIcon: string | null;
13
14
  onChange: ChangeEventHandler<HTMLInputElement>;
15
+ suffix?: React.ReactNode;
14
16
  }
15
17
 
16
18
  export const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>((props, ref) => {
17
- const { term, selectedIcon, onChange } = props;
19
+ const { term, selectedIcon, onChange, suffix } = props;
18
20
 
19
21
  return (
20
- <Combobox.Input
22
+ <ComboboxInput
21
23
  as={TextInput}
22
24
  ref={ref}
23
25
  inputMode="search"
@@ -25,6 +27,7 @@ export const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>((props
25
27
  onChange={onChange}
26
28
  icon={selectedIcon ? <Icon icon={selectedIcon} /> : null}
27
29
  placeholder={selectedIcon ? 'Search and replace selected icon...' : 'Search for an icon...'}
30
+ suffix={suffix}
28
31
  />
29
32
  );
30
33
  });
@@ -1,7 +1,6 @@
1
- import { Combobox } from '@headlessui/react';
1
+ import { ComboboxOption, ComboboxOptions } from '@headlessui/react';
2
2
  import { Icon } from '@iconify/react';
3
3
  import { Button } from '@sanity/ui';
4
-
5
4
  import { MessageWrapper } from './iconify-combobox.styles';
6
5
 
7
6
  // -------------- //
@@ -33,16 +32,16 @@ export function SearchResults(props: SearchResultsProps) {
33
32
  }
34
33
 
35
34
  return (
36
- <Combobox.Options style={{ opacity: state === 'stale' ? 0.5 : 1 }}>
35
+ <ComboboxOptions style={{ opacity: state === 'stale' ? 0.5 : 1 }}>
37
36
  {data!.map((icon) => (
38
- <Combobox.Option key={icon} value={icon}>
39
- {({ active }) => (
40
- <Button padding={3} mode="bleed" selected={active}>
37
+ <ComboboxOption key={icon} value={icon}>
38
+ {({ focus }) => (
39
+ <Button padding={3} mode="bleed" selected={focus}>
41
40
  <Icon icon={icon} width="100%" height="100%" />
42
41
  </Button>
43
42
  )}
44
- </Combobox.Option>
43
+ </ComboboxOption>
45
44
  ))}
46
- </Combobox.Options>
45
+ </ComboboxOptions>
47
46
  );
48
47
  }
@@ -13,7 +13,7 @@ export function UnsetButton(props: UnsetButtonProps) {
13
13
  const { onUnset } = props;
14
14
 
15
15
  return (
16
- <Card border borderLeft={false} padding={1} display="flex">
16
+ <Card border borderLeft={false} padding={1} display="flex" radius={2}>
17
17
  <Button icon={<TrashIcon />} onClick={onUnset} mode="bleed" fontSize={1} padding={2} />
18
18
  </Card>
19
19
  );
@@ -1,10 +1,11 @@
1
- import { Flex, RootTheme, Stack, studioTheme, Text, ThemeProvider, useTheme } from '@sanity/ui';
2
- import { useCallback, useMemo } from 'react';
3
- import { ObjectInputProps, set, unset } from 'sanity';
4
-
1
+ import { Flex, Stack, Text, ThemeProvider } from '@sanity/ui';
2
+ import { buildTheme } from '@sanity/ui/theme';
3
+ import { useCallback } from 'react';
4
+ import type { ObjectInputProps } from 'sanity';
5
+ import { set, unset } from 'sanity';
5
6
  import { IconifyCombobox } from './combobox';
6
7
  import { QueryClientProvider } from './lib/query-client';
7
- import { IconifyPluginConfig, IconOptions } from './lib/types';
8
+ import type { IconifyPluginConfig, IconOptions } from './lib/types';
8
9
  import { usePrettyIconName } from './lib/use-pretty-icon-name';
9
10
 
10
11
  // -------------- //
@@ -27,11 +28,11 @@ export function IconifyInput(props: IconifyInputProps) {
27
28
  null;
28
29
  const showName = options?.showName ?? config?.showName ?? false;
29
30
 
30
- const parentTheme = useTheme();
31
- const theme: RootTheme = useMemo(
32
- () => (parentTheme ? { ...parentTheme.sanity, color: studioTheme.color } : studioTheme),
33
- [parentTheme],
34
- );
31
+ // const parentTheme = useTheme();
32
+ // const theme: RootTheme = useMemo(
33
+ // () => (parentTheme ? { ...parentTheme.sanity, color: studioTheme.color } : studioTheme),
34
+ // [parentTheme],
35
+ // );
35
36
 
36
37
  const handleSelect = useCallback(
37
38
  (icon: string) => {
@@ -42,7 +43,7 @@ export function IconifyInput(props: IconifyInputProps) {
42
43
 
43
44
  return (
44
45
  <QueryClientProvider>
45
- <ThemeProvider theme={theme}>
46
+ <ThemeProvider theme={buildTheme()}>
46
47
  <Stack space={2}>
47
48
  <IconifyCombobox
48
49
  selectedIcon={selectedIcon}
@@ -1,8 +1,8 @@
1
- import { definePlugin, FieldProps, ObjectInputProps } from 'sanity';
2
-
1
+ import type { FieldProps, ObjectInputProps } from 'sanity';
2
+ import { definePlugin } from 'sanity';
3
3
  import { IconifyInput } from './iconify-input';
4
4
  import { IconifyPreview } from './iconify-preview';
5
- import { IconifyPluginConfig } from './lib/types';
5
+ import type { IconifyPluginConfig } from './lib/types';
6
6
 
7
7
  /**
8
8
  * Usage in `sanity.config.ts` (or .js)
@@ -1,7 +1,7 @@
1
1
  import { Icon } from '@iconify/react';
2
- import { IconifyIconName, stringToIcon } from '@iconify/utils';
3
- import { PreviewProps } from 'sanity';
4
-
2
+ import type { IconifyIconName } from '@iconify/utils';
3
+ import { stringToIcon } from '@iconify/utils';
4
+ import type { PreviewProps } from 'sanity';
5
5
  import { QueryClientProvider } from './lib/query-client';
6
6
  import { usePrettyIconName } from './lib/use-pretty-icon-name';
7
7
 
package/src/lib/api.ts CHANGED
@@ -1,9 +1,8 @@
1
- import { IconifyInfo } from '@iconify/types';
1
+ import type { IconifyInfo } from '@iconify/types';
2
2
  import { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query';
3
3
  import { useCallback, useState } from 'react';
4
4
  import { useDebounce } from 'use-debounce';
5
-
6
- import { IconifySearchResult } from './types';
5
+ import type { IconifySearchResult } from './types';
7
6
 
8
7
  const BASE_API_URL = 'https://api.iconify.design';
9
8
 
@@ -1,5 +1,4 @@
1
1
  import { writeFile } from 'node:fs/promises';
2
-
3
2
  import { lookupCollections } from '@iconify/json';
4
3
 
5
4
  /**
@@ -2,7 +2,7 @@ import {
2
2
  QueryClient,
3
3
  QueryClientProvider as ReactQueryClientProvider,
4
4
  } from '@tanstack/react-query';
5
- import { ReactNode } from 'react';
5
+ import type { ReactNode } from 'react';
6
6
 
7
7
  export const queryClient = new QueryClient();
8
8
 
package/src/lib/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { IconifyInfo } from '@iconify/types';
1
+ import type { IconifyInfo } from '@iconify/types';
2
2
  import type { BaseSchemaDefinition } from 'sanity';
3
3
 
4
4
  // If this line errors, the type definitions have not been generated.
@@ -1,7 +1,7 @@
1
- import { IconifyIconName, stringToIcon } from '@iconify/utils';
1
+ import type { IconifyIconName } from '@iconify/utils';
2
+ import { stringToIcon } from '@iconify/utils';
2
3
  import { sentenceCase } from 'change-case';
3
4
  import { useMemo } from 'react';
4
-
5
5
  import { useIconSetInfo } from './api';
6
6
 
7
7
  interface UsePrettyIconNameProps {