sanity-plugin-iconify 1.1.2 โ 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -6
- package/dist/index.cjs +106 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -8
- package/dist/index.d.ts +72 -8
- package/dist/index.js +106 -99
- package/dist/index.js.map +1 -1
- package/package.json +48 -54
- package/src/combobox/iconify-combobox.styles.tsx +9 -9
- package/src/combobox/iconify-combobox.tsx +64 -55
- package/src/combobox/search-input.tsx +7 -14
- package/src/combobox/search-result.tsx +36 -36
- package/src/combobox/unset-button.tsx +1 -1
- package/src/iconify-input.tsx +8 -17
- package/src/iconify-plugin.tsx +3 -3
- package/src/iconify-preview.tsx +3 -3
- package/src/lib/api.ts +2 -3
- package/src/lib/generate-types.js +0 -1
- package/src/lib/icon-types.gen.ts +1 -0
- package/src/lib/query-client.tsx +1 -1
- package/src/lib/types.ts +1 -1
- package/src/lib/use-pretty-icon-name.ts +2 -2
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: [
|
|
162
|
-
|
|
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"),
|
|
3
|
+
var jsxRuntime = require("react/jsx-runtime"), sanity = require("sanity"), ui = require("@sanity/ui"), theme = require("@sanity/ui/theme"), react = require("react"), downshift = require("downshift"), tsPattern = require("ts-pattern"), reactQuery = require("@tanstack/react-query"), useDebounce = require("use-debounce"), styled = require("styled-components"), react$1 = 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
|
}
|
|
@@ -27,13 +27,12 @@ function useSearch({ collections }) {
|
|
|
27
27
|
), { isLoading, isError, error, data, isPlaceholderData } = reactQuery.useQuery({
|
|
28
28
|
queryKey: ["search", collections, debouncedTerm],
|
|
29
29
|
queryFn: async ({ signal }) => {
|
|
30
|
-
var _a;
|
|
31
30
|
const url = new URL("/search", BASE_API_URL);
|
|
32
31
|
url.searchParams.append("query", debouncedTerm), url.searchParams.append("limit", "60"), collections && url.searchParams.append("prefixes", collections.join(","));
|
|
33
32
|
const result = debouncedTerm ? await fetchJson({ url, signal }) : null;
|
|
34
33
|
return result && Object.entries(result.collections).forEach(([prefix, info]) => {
|
|
35
34
|
queryClient2.setQueryData(["iconSetInfo", prefix], info);
|
|
36
|
-
}),
|
|
35
|
+
}), result?.icons ?? [];
|
|
37
36
|
},
|
|
38
37
|
enabled: debouncedTerm.length > 0,
|
|
39
38
|
placeholderData: reactQuery.keepPreviousData,
|
|
@@ -55,49 +54,46 @@ function useIconSetInfo({ prefix }) {
|
|
|
55
54
|
return reactQuery.useQuery({
|
|
56
55
|
queryKey: ["iconSetInfo", prefix],
|
|
57
56
|
queryFn: async ({ signal }) => {
|
|
58
|
-
|
|
59
|
-
if (!prefix)
|
|
60
|
-
return null;
|
|
57
|
+
if (!prefix) return null;
|
|
61
58
|
const url = new URL("/collection", BASE_API_URL);
|
|
62
|
-
url.searchParams.append("prefix", prefix), url.searchParams.append("info", "true");
|
|
63
|
-
const result = await fetchJson({ url, signal });
|
|
64
|
-
return (_a = result == null ? void 0 : result.info) != null ? _a : null;
|
|
59
|
+
return url.searchParams.append("prefix", prefix), url.searchParams.append("info", "true"), (await fetchJson({ url, signal }))?.info ?? null;
|
|
65
60
|
},
|
|
66
61
|
staleTime: 1 / 0
|
|
67
62
|
});
|
|
68
63
|
}
|
|
69
|
-
|
|
64
|
+
styled__default.default(ui.Grid)`
|
|
70
65
|
grid-template-columns: 1fr min-content;
|
|
71
66
|
position: relative;
|
|
72
|
-
|
|
67
|
+
`;
|
|
68
|
+
const OptionsWrapper = styled__default.default(ui.Box)`
|
|
73
69
|
box-sizing: border-box;
|
|
74
70
|
padding: 0.5rem;
|
|
75
71
|
|
|
76
72
|
& [role='listbox'] {
|
|
77
|
-
display:
|
|
78
|
-
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-wrap: wrap;
|
|
79
75
|
gap: 0.5rem;
|
|
80
|
-
list-style: none;
|
|
81
76
|
margin: 0;
|
|
82
77
|
padding: 0;
|
|
83
|
-
|
|
84
|
-
@media (min-width: 650px) {
|
|
85
|
-
grid-template-columns: repeat(10, minmax(min(100%, 2.5rem), 1fr));
|
|
86
|
-
}
|
|
78
|
+
list-style: none;
|
|
87
79
|
}
|
|
88
80
|
|
|
89
81
|
& [role='option'] {
|
|
90
82
|
display: grid;
|
|
91
83
|
place-items: center;
|
|
84
|
+
width: clamp(3rem, 10vw, 4rem);
|
|
92
85
|
|
|
93
86
|
& button {
|
|
94
|
-
aspect-ratio: 1;
|
|
95
87
|
cursor: pointer;
|
|
96
88
|
width: 100%;
|
|
97
89
|
|
|
98
90
|
& > [data-ui='Box'] {
|
|
99
91
|
display: flex;
|
|
100
92
|
}
|
|
93
|
+
|
|
94
|
+
& svg {
|
|
95
|
+
aspect-ratio: 1;
|
|
96
|
+
}
|
|
101
97
|
}
|
|
102
98
|
}
|
|
103
99
|
`;
|
|
@@ -105,80 +101,103 @@ function MessageWrapper({ children }) {
|
|
|
105
101
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { align: "center", muted: !0, children }) });
|
|
106
102
|
}
|
|
107
103
|
const SearchInput = react.forwardRef((props, ref) => {
|
|
108
|
-
const {
|
|
104
|
+
const { selectedIcon, suffix, ...rest } = props;
|
|
109
105
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
110
|
-
|
|
106
|
+
ui.TextInput,
|
|
111
107
|
{
|
|
112
|
-
|
|
108
|
+
...rest,
|
|
113
109
|
ref,
|
|
114
110
|
inputMode: "search",
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
placeholder: selectedIcon ? "Search and replace selected icon..." : "Search for an icon..."
|
|
111
|
+
icon: selectedIcon ? /* @__PURE__ */ jsxRuntime.jsx(react$1.Icon, { icon: selectedIcon }) : null,
|
|
112
|
+
placeholder: selectedIcon ? "Search and replace selected icon..." : "Search for an icon...",
|
|
113
|
+
suffix
|
|
119
114
|
}
|
|
120
115
|
);
|
|
121
116
|
});
|
|
122
117
|
SearchInput.displayName = "SearchInput";
|
|
123
|
-
|
|
124
|
-
const { state, data } = props;
|
|
125
|
-
return
|
|
126
|
-
|
|
118
|
+
const SearchResults = react.forwardRef((props, ref) => {
|
|
119
|
+
const { state, data, getItemProps, highlightedIndex, ...rest } = props;
|
|
120
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
121
|
+
(() => {
|
|
122
|
+
switch (state) {
|
|
123
|
+
case "initial":
|
|
124
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Search for icons" });
|
|
125
|
+
case "loading":
|
|
126
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Searching..." });
|
|
127
|
+
case "error":
|
|
128
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "Something went wrong..." });
|
|
129
|
+
case "empty":
|
|
130
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageWrapper, { children: "No icons found" });
|
|
131
|
+
}
|
|
132
|
+
})(),
|
|
133
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { ...rest, ref, style: { opacity: state === "stale" ? 0.5 : 1 }, children: (state === "data" || state === "stale") && data?.map((icon, index) => /* @__PURE__ */ jsxRuntime.jsx("li", { ...getItemProps({ item: icon, index }), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { padding: 3, mode: "bleed", selected: index === highlightedIndex, children: /* @__PURE__ */ jsxRuntime.jsx(react$1.Icon, { icon, width: "100%", height: "100%" }) }) }, icon)) })
|
|
134
|
+
] });
|
|
135
|
+
});
|
|
127
136
|
function UnsetButton(props) {
|
|
128
137
|
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 }) });
|
|
138
|
+
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
139
|
}
|
|
131
140
|
function IconifyCombobox(props) {
|
|
132
141
|
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({
|
|
133
142
|
collections
|
|
134
|
-
}),
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
}), {
|
|
144
|
+
isOpen,
|
|
145
|
+
getMenuProps,
|
|
146
|
+
getInputProps,
|
|
147
|
+
highlightedIndex,
|
|
148
|
+
getItemProps,
|
|
149
|
+
selectItem,
|
|
150
|
+
setInputValue
|
|
151
|
+
} = downshift.useCombobox({
|
|
152
|
+
items: data ?? [],
|
|
153
|
+
inputValue: term,
|
|
154
|
+
onInputValueChange({ inputValue, selectedItem }) {
|
|
155
|
+
inputValue !== selectedItem && setTerm(inputValue);
|
|
140
156
|
},
|
|
141
|
-
|
|
142
|
-
|
|
157
|
+
onSelectedItemChange({ selectedItem }) {
|
|
158
|
+
pushSelection(selectedItem), setTerm("", !0), setInputValue("");
|
|
159
|
+
}
|
|
160
|
+
}), handleUnset = react.useCallback(() => {
|
|
161
|
+
pushSelection(""), setTerm("", !0), selectItem("");
|
|
162
|
+
}, []);
|
|
143
163
|
return react.useEffect(() => {
|
|
144
164
|
isError && (console.error("Iconify input error:", error), toast.push({
|
|
145
165
|
id,
|
|
146
166
|
status: "error",
|
|
147
167
|
title: "Iconify input error",
|
|
148
|
-
description: error
|
|
168
|
+
description: error?.message
|
|
149
169
|
}));
|
|
150
|
-
}, [error, id, isError, toast]), /* @__PURE__ */ jsxRuntime.jsxs(
|
|
151
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
{
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
{
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
selectedIcon ? /* @__PURE__ */ jsxRuntime.jsx(UnsetButton, { onUnset: handleUnset }) : null
|
|
170
|
+
}, [error, id, isError, toast]), /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
172
|
+
SearchInput,
|
|
173
|
+
{
|
|
174
|
+
...getInputProps({ ref: inputRef }),
|
|
175
|
+
selectedIcon,
|
|
176
|
+
suffix: selectedIcon ? /* @__PURE__ */ jsxRuntime.jsx(UnsetButton, { onUnset: handleUnset }) : null
|
|
177
|
+
}
|
|
178
|
+
),
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
180
|
+
ui.Popover,
|
|
181
|
+
{
|
|
182
|
+
open: !0,
|
|
183
|
+
style: { display: isOpen ? "block" : "none" },
|
|
184
|
+
placement: "bottom",
|
|
185
|
+
arrow: !1,
|
|
186
|
+
matchReferenceWidth: !0,
|
|
187
|
+
constrainSize: !0,
|
|
188
|
+
referenceElement: inputRef.current,
|
|
189
|
+
content: /* @__PURE__ */ jsxRuntime.jsx(OptionsWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
190
|
+
SearchResults,
|
|
191
|
+
{
|
|
192
|
+
...getMenuProps(),
|
|
193
|
+
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"),
|
|
194
|
+
data,
|
|
195
|
+
getItemProps,
|
|
196
|
+
highlightedIndex
|
|
197
|
+
}
|
|
198
|
+
) })
|
|
199
|
+
}
|
|
200
|
+
)
|
|
182
201
|
] });
|
|
183
202
|
}
|
|
184
203
|
const queryClient = new reactQuery.QueryClient();
|
|
@@ -186,37 +205,26 @@ function QueryClientProvider(props) {
|
|
|
186
205
|
return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: props.children });
|
|
187
206
|
}
|
|
188
207
|
function usePrettyIconName(props) {
|
|
189
|
-
var _a, _b;
|
|
190
208
|
const { name } = props, iconMeta = react.useMemo(
|
|
191
|
-
() =>
|
|
192
|
-
var _a2;
|
|
193
|
-
return (_a2 = props.iconMeta) != null ? _a2 : name ? utils.stringToIcon(name) : null;
|
|
194
|
-
},
|
|
209
|
+
() => props.iconMeta ?? (name ? utils.stringToIcon(name) : null),
|
|
195
210
|
[name, props.iconMeta]
|
|
196
|
-
), iconSetInfo = useIconSetInfo({ prefix:
|
|
211
|
+
), iconSetInfo = useIconSetInfo({ prefix: iconMeta?.prefix ?? null });
|
|
197
212
|
return react.useMemo(
|
|
198
|
-
() => {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
} : null;
|
|
204
|
-
},
|
|
205
|
-
[iconMeta, (_b = iconSetInfo.data) == null ? void 0 : _b.name]
|
|
213
|
+
() => iconMeta ? {
|
|
214
|
+
name: changeCase.sentenceCase(iconMeta.name),
|
|
215
|
+
collection: iconSetInfo.data?.name ?? iconMeta.prefix
|
|
216
|
+
} : null,
|
|
217
|
+
[iconMeta, iconSetInfo.data?.name]
|
|
206
218
|
);
|
|
207
219
|
}
|
|
208
220
|
function IconifyInput(props) {
|
|
209
|
-
|
|
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(
|
|
221
|
+
const { config, value, onChange: pushChange, schemaType } = props, selectedIcon = value?.name ?? null, options = schemaType.options, collections = !!options?.collections?.length && options.collections || !!config?.collections?.length && config.collections || null, showName = options?.showName ?? config?.showName ?? !1, handleSelect = react.useCallback(
|
|
214
222
|
(icon) => {
|
|
215
223
|
pushChange(icon === "" ? sanity.unset() : sanity.set(icon, ["name"]));
|
|
216
224
|
},
|
|
217
225
|
[pushChange]
|
|
218
226
|
);
|
|
219
|
-
return /* @__PURE__ */ jsxRuntime.jsx(QueryClientProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.ThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
|
|
227
|
+
return /* @__PURE__ */ jsxRuntime.jsx(QueryClientProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.ThemeProvider, { theme: theme.buildTheme(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
|
|
220
228
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
221
229
|
IconifyCombobox,
|
|
222
230
|
{
|
|
@@ -229,14 +237,13 @@ function IconifyInput(props) {
|
|
|
229
237
|
] }) }) });
|
|
230
238
|
}
|
|
231
239
|
function IconifyNameDisplay(props) {
|
|
232
|
-
var _a;
|
|
233
240
|
const { name } = props, prettyName = usePrettyIconName({ name });
|
|
234
241
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 1, children: [
|
|
235
242
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, muted: !0, children: "Selected:" }),
|
|
236
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "semibold", children:
|
|
237
|
-
|
|
243
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "semibold", children: prettyName?.name ?? name }),
|
|
244
|
+
prettyName?.collection && /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 1, muted: !0, style: { fontStyle: "italic" }, children: [
|
|
238
245
|
"by ",
|
|
239
|
-
prettyName
|
|
246
|
+
prettyName?.collection
|
|
240
247
|
] })
|
|
241
248
|
] });
|
|
242
249
|
}
|
|
@@ -245,13 +252,12 @@ function IconifyPreview(props) {
|
|
|
245
252
|
return typeof title == "string" && iconName ? /* @__PURE__ */ jsxRuntime.jsx(QueryClientProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(IconifyPreviewInner, { ...props, iconName: title, iconMeta: iconName }) }) : props.renderDefault(props);
|
|
246
253
|
}
|
|
247
254
|
function IconifyPreviewInner(props) {
|
|
248
|
-
var _a;
|
|
249
255
|
const { iconMeta, iconName, ...previewProps } = props, prettyName = usePrettyIconName({ iconMeta });
|
|
250
256
|
return props.renderDefault({
|
|
251
257
|
...previewProps,
|
|
252
|
-
media: /* @__PURE__ */ jsxRuntime.jsx(react$
|
|
253
|
-
title:
|
|
254
|
-
subtitle: prettyName
|
|
258
|
+
media: /* @__PURE__ */ jsxRuntime.jsx(react$1.Icon, { icon: iconName }),
|
|
259
|
+
title: prettyName?.name ?? iconName,
|
|
260
|
+
subtitle: prettyName?.collection
|
|
255
261
|
});
|
|
256
262
|
}
|
|
257
263
|
const iconify = sanity.definePlugin((config = {}) => ({
|
package/dist/index.cjs.map
CHANGED
|
@@ -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: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n & [role='option'] {\n display: grid;\n place-items: center;\n width: clamp(3rem, 10vw, 4rem);\n\n & button {\n cursor: pointer;\n width: 100%;\n\n & > [data-ui='Box'] {\n display: flex;\n }\n\n & svg {\n aspect-ratio: 1;\n }\n }\n }\n`;\n\nexport function MessageWrapper({ children }: { children: ReactNode }) {\n return (\n <Card padding={4}>\n <Text align=\"center\" muted>\n {children}\n </Text>\n </Card>\n );\n}\n","import { Icon } from '@iconify/react';\nimport { TextInput } from '@sanity/ui';\nimport { forwardRef } from 'react';\n\ninterface SearchInputProps extends React.HTMLAttributes<HTMLInputElement> {\n selectedIcon: string | null;\n suffix?: React.ReactNode;\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>((props, ref) => {\n const { selectedIcon, suffix, ...rest } = props;\n\n return (\n <TextInput\n {...rest}\n ref={ref}\n inputMode=\"search\"\n icon={selectedIcon ? <Icon icon={selectedIcon} /> : null}\n placeholder={selectedIcon ? 'Search and replace selected icon...' : 'Search for an icon...'}\n suffix={suffix}\n />\n );\n});\n\nSearchInput.displayName = 'SearchInput';\n","import { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\nimport type { UseComboboxGetItemPropsOptions, UseComboboxGetItemPropsReturnValue } from 'downshift';\nimport { forwardRef } from 'react';\nimport { MessageWrapper } from './iconify-combobox.styles';\n\ntype GetItemProps = (\n options: UseComboboxGetItemPropsOptions<string>,\n) => UseComboboxGetItemPropsReturnValue;\n\nexport interface SearchResultsProps extends React.HTMLAttributes<HTMLUListElement> {\n state: 'initial' | 'loading' | 'error' | 'empty' | 'data' | 'stale';\n data?: string[];\n getItemProps: GetItemProps;\n highlightedIndex: number;\n}\n\nexport const SearchResults = forwardRef<HTMLUListElement, SearchResultsProps>((props, ref) => {\n const { state, data, getItemProps, highlightedIndex, ...rest } = props;\n\n return (\n <>\n {(() => {\n switch (state) {\n case 'initial':\n return <MessageWrapper>Search for icons</MessageWrapper>;\n case 'loading':\n return <MessageWrapper>Searching...</MessageWrapper>;\n case 'error':\n return <MessageWrapper>Something went wrong...</MessageWrapper>;\n case 'empty':\n return <MessageWrapper>No icons found</MessageWrapper>;\n }\n })()}\n\n <ul {...rest} ref={ref} style={{ opacity: state === 'stale' ? 0.5 : 1 }}>\n {(state === 'data' || state === 'stale') &&\n data?.map((icon, index) => (\n <li key={icon} {...getItemProps({ item: icon, index })}>\n <Button padding={3} mode=\"bleed\" selected={index === highlightedIndex}>\n <Icon icon={icon} width=\"100%\" height=\"100%\" />\n </Button>\n </li>\n ))}\n </ul>\n </>\n );\n});\n","import { TrashIcon } from '@sanity/icons';\nimport { Button, Card } from '@sanity/ui';\n\n// ------------ //\n// UNSET BUTTON //\n// ------------ //\n\ninterface UnsetButtonProps {\n onUnset: () => void;\n}\n\nexport function UnsetButton(props: UnsetButtonProps) {\n const { onUnset } = props;\n\n return (\n <Card border borderLeft={false} padding={1} display=\"flex\" radius={2}>\n <Button icon={<TrashIcon />} onClick={onUnset} mode=\"bleed\" fontSize={1} padding={2} />\n </Card>\n );\n}\n","import { Popover, useToast } from '@sanity/ui';\nimport { useCombobox } from 'downshift';\nimport { useCallback, useEffect, useId, useRef } from 'react';\nimport { match } from 'ts-pattern';\nimport { useSearch } from '../lib/api';\nimport { OptionsWrapper } from './iconify-combobox.styles';\nimport { SearchInput } from './search-input';\nimport type { SearchResultsProps } from './search-result';\nimport { SearchResults } from './search-result';\nimport { UnsetButton } from './unset-button';\n\nexport interface IconifyComboboxProps {\n selectedIcon: string | null;\n onSelect: (newValue: string) => void;\n collections: string[] | null;\n}\n\nexport function IconifyCombobox(props: IconifyComboboxProps) {\n const { selectedIcon, onSelect: pushSelection, collections } = props;\n\n const id = useId();\n const toast = useToast();\n const inputRef = useRef<HTMLInputElement>(null);\n\n const { term, setTerm, debouncedTerm, isLoading, isError, error, data, isPreviousData } =\n useSearch({\n collections,\n });\n\n const {\n isOpen,\n getMenuProps,\n getInputProps,\n highlightedIndex,\n getItemProps,\n selectItem,\n setInputValue,\n } = useCombobox({\n items: data ?? [],\n inputValue: term,\n onInputValueChange({ inputValue, selectedItem }) {\n if (inputValue !== selectedItem) {\n setTerm(inputValue);\n }\n },\n onSelectedItemChange({ selectedItem }) {\n pushSelection(selectedItem);\n setTerm('', true);\n setInputValue('');\n },\n });\n\n const handleUnset = useCallback(() => {\n pushSelection('');\n setTerm('', true);\n selectItem('');\n }, []);\n\n useEffect(() => {\n if (isError) {\n console.error('Iconify input error:', error);\n\n toast.push({\n id,\n status: 'error',\n title: 'Iconify input error',\n description: error?.message,\n });\n }\n }, [error, id, isError, toast]);\n\n return (\n <div>\n {/* @ts-expect-error wrong typings */}\n <SearchInput\n {...getInputProps({ ref: inputRef })}\n selectedIcon={selectedIcon}\n suffix={selectedIcon ? <UnsetButton onUnset={handleUnset} /> : null}\n />\n\n <Popover\n open={true}\n style={{ display: isOpen ? 'block' : 'none' }}\n placement=\"bottom\"\n arrow={false}\n matchReferenceWidth\n constrainSize\n referenceElement={inputRef.current}\n content={\n <OptionsWrapper>\n <SearchResults\n {...getMenuProps()}\n state={match<boolean>(true)\n .returnType<SearchResultsProps['state']>()\n .with(isLoading, () => 'loading')\n .with(!debouncedTerm, () => 'initial')\n .with(isError, () => 'error')\n .with(!data || data.length === 0, () => 'empty')\n .with(isPreviousData, () => 'stale')\n .otherwise(() => 'data')}\n data={data}\n getItemProps={getItemProps}\n highlightedIndex={highlightedIndex}\n />\n </OptionsWrapper>\n }\n />\n </div>\n );\n}\n","import {\n QueryClient,\n QueryClientProvider as ReactQueryClientProvider,\n} from '@tanstack/react-query';\nimport type { ReactNode } from 'react';\n\nexport const queryClient = new QueryClient();\n\nexport function QueryClientProvider(props: { children: ReactNode }) {\n return <ReactQueryClientProvider client={queryClient}>{props.children}</ReactQueryClientProvider>;\n}\n","import type { IconifyIconName } from '@iconify/utils';\nimport { stringToIcon } from '@iconify/utils';\nimport { sentenceCase } from 'change-case';\nimport { useMemo } from 'react';\nimport { useIconSetInfo } from './api';\n\ninterface UsePrettyIconNameProps {\n name?: string | null;\n iconMeta?: IconifyIconName | null;\n}\n\nexport function usePrettyIconName(props: UsePrettyIconNameProps) {\n const { name } = props;\n const iconMeta = useMemo(\n () => props.iconMeta ?? (name ? stringToIcon(name) : null),\n [name, props.iconMeta],\n );\n const iconSetInfo = useIconSetInfo({ prefix: iconMeta?.prefix ?? null });\n\n return useMemo(\n () =>\n iconMeta\n ? {\n name: sentenceCase(iconMeta.name),\n collection: iconSetInfo.data?.name ?? iconMeta.prefix,\n }\n : null,\n [iconMeta, iconSetInfo.data?.name],\n );\n}\n","import { Flex, Stack, Text, ThemeProvider } from '@sanity/ui';\nimport { buildTheme } from '@sanity/ui/theme';\nimport { useCallback } from 'react';\nimport type { ObjectInputProps } from 'sanity';\nimport { set, unset } from 'sanity';\nimport { IconifyCombobox } from './combobox';\nimport { QueryClientProvider } from './lib/query-client';\nimport type { IconifyPluginConfig, IconOptions } from './lib/types';\nimport { usePrettyIconName } from './lib/use-pretty-icon-name';\n\ninterface IconifyInputProps extends ObjectInputProps {\n config: IconifyPluginConfig;\n}\n\nexport function IconifyInput(props: IconifyInputProps) {\n const { config, value, onChange: pushChange, schemaType } = props;\n\n const selectedIcon: string | null = value?.name ?? null;\n\n const options: IconOptions = schemaType.options;\n const collections =\n (!!options?.collections?.length && options.collections) ||\n (!!config?.collections?.length && config.collections) ||\n null;\n const showName = options?.showName ?? config?.showName ?? false;\n\n const handleSelect = useCallback(\n (icon: string) => {\n pushChange(icon === '' ? unset() : set(icon, ['name']));\n },\n [pushChange],\n );\n\n return (\n <QueryClientProvider>\n <ThemeProvider theme={buildTheme()}>\n <Stack space={2}>\n <IconifyCombobox\n selectedIcon={selectedIcon}\n onSelect={handleSelect}\n collections={collections}\n />\n\n {showName && selectedIcon ? <IconifyNameDisplay name={selectedIcon} /> : null}\n </Stack>\n </ThemeProvider>\n </QueryClientProvider>\n );\n}\n\ninterface IconifyNameDisplayProps {\n name?: string | null;\n}\n\nexport function IconifyNameDisplay(props: IconifyNameDisplayProps) {\n const { name } = props;\n const prettyName = usePrettyIconName({ name });\n\n return (\n <Flex gap={1}>\n <Text size={1} muted>\n Selected:\n </Text>\n\n <Text size={1} weight=\"semibold\">\n {prettyName?.name ?? name}\n </Text>\n\n {prettyName?.collection && (\n <Text size={1} muted style={{ fontStyle: 'italic' }}>\n by {prettyName?.collection}\n </Text>\n )}\n </Flex>\n );\n}\n","import { Icon } from '@iconify/react';\nimport type { IconifyIconName } from '@iconify/utils';\nimport { stringToIcon } from '@iconify/utils';\nimport type { PreviewProps } from 'sanity';\nimport { QueryClientProvider } from './lib/query-client';\nimport { usePrettyIconName } from './lib/use-pretty-icon-name';\n\n// --------------- //\n// ICONIFY PREVIEW //\n// --------------- //\n\nexport function IconifyPreview(props: PreviewProps) {\n const { title } = props;\n const iconName = typeof props.title === 'string' ? stringToIcon(props.title) : null;\n\n // We check this double to avoid the TS error\n if (typeof title === 'string' && iconName) {\n return (\n <QueryClientProvider>\n <IconifyPreviewInner {...props} iconName={title} iconMeta={iconName} />\n </QueryClientProvider>\n );\n }\n\n return props.renderDefault(props);\n}\n\n// --------------------- //\n// ICONIFY PREVIEW INNER //\n// --------------------- //\n\ninterface IconifyPreviewInnerProps extends PreviewProps {\n iconName: string;\n iconMeta: IconifyIconName;\n}\n\nfunction IconifyPreviewInner(props: IconifyPreviewInnerProps) {\n const { iconMeta, iconName, ...previewProps } = props;\n const prettyName = usePrettyIconName({ iconMeta });\n\n return props.renderDefault({\n ...previewProps,\n media: <Icon icon={iconName} />,\n title: prettyName?.name ?? iconName,\n subtitle: prettyName?.collection,\n });\n}\n","import type { FieldProps, ObjectInputProps } from 'sanity';\nimport { definePlugin } from 'sanity';\nimport { IconifyInput } from './iconify-input';\nimport { IconifyPreview } from './iconify-preview';\nimport type { IconifyPluginConfig } from './lib/types';\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import { defineConfig } from 'sanity'\n * import { iconify } from 'sanity-plugin-iconify'\n *\n * export default defineConfig({\n * // ...\n * plugins: [iconify()],\n * })\n * ```\n */\nexport const iconify = definePlugin<IconifyPluginConfig | void>((config = {}) => {\n return {\n name: 'sanity-plugin-iconify',\n schema: {\n types: [\n {\n name: 'icon',\n title: 'Icon',\n type: 'object',\n fields: [\n {\n name: 'name',\n title: 'Name',\n type: 'string',\n },\n ],\n components: {\n input: (props: ObjectInputProps) => <IconifyInput {...props} config={config!} />,\n preview: IconifyPreview,\n\n // This makes sure the input component is not indented\n field: (props: FieldProps) => props.renderDefault({ ...props, level: 0 }),\n },\n },\n ],\n },\n };\n});\n"],"names":["queryClient","useQueryClient","useState","useDebounce","useCallback","useQuery","keepPreviousData","styled","Grid","Box","jsx","Card","Text","forwardRef","TextInput","Icon","jsxs","Fragment","Button","TrashIcon","useId","useToast","useRef","useCombobox","useEffect","Popover","match","QueryClient","ReactQueryClientProvider","useMemo","stringToIcon","sentenceCase","unset","set","ThemeProvider","buildTheme","Stack","Flex","definePlugin"],"mappings":"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"}
|