sanity-plugin-iconify 3.0.0-beta.2 → 3.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 +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/combobox/iconify-combobox.tsx +0 -1
- package/src/lib/icon-types.gen.ts +1 -1
- package/src/lib/types.test.ts +29 -1
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@ Enhance your [Sanity](https://www.sanity.io/) project with the Iconify plugin, w
|
|
|
41
41
|
|
|
42
42
|
## 🚀 Getting Started
|
|
43
43
|
|
|
44
|
+
> **Requires Sanity Studio v5.** For Sanity Studio v3/v4, use [v2.x](https://github.com/waspeer/sanity-plugin-iconify/tree/v2).
|
|
45
|
+
|
|
44
46
|
### Installation
|
|
45
47
|
|
|
46
48
|
Install the plugin:
|
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 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, memo } from 'react';\n\ninterface SearchInputProps extends React.HTMLAttributes<HTMLInputElement> {\n selectedIcon: string | null;\n suffix?: React.ReactNode;\n}\n\nexport const SearchInput = memo(\n 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);\n\nSearchInput.displayName = 'SearchInput';\n","import { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\nimport type { UseComboboxGetItemPropsOptions, UseComboboxGetItemPropsReturnValue } from 'downshift';\nimport { forwardRef, memo } 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 = memo(\n 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\n {...rest}\n ref={ref}\n data-testid=\"iconify-results\"\n style={{ opacity: state === 'stale' ? 0.5 : 1 }}\n >\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);\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\n data-testid=\"iconify-unset\"\n icon={<TrashIcon />}\n onClick={onUnset}\n mode=\"bleed\"\n fontSize={1}\n padding={2}\n />\n </Card>\n );\n}\n","import { Popover, useToast } from '@sanity/ui';\nimport { useCombobox } from 'downshift';\nimport { memo, useCallback, useEffect, useId, useRef } from 'react';\nimport type { ObjectInputProps } from 'sanity';\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 studioElementProps?: ObjectInputProps['elementProps'];\n fieldFocused?: boolean;\n}\n\nexport const IconifyCombobox = memo(function IconifyCombobox(props: IconifyComboboxProps) {\n const {\n selectedIcon,\n onSelect: pushSelection,\n collections,\n studioElementProps,\n fieldFocused,\n } = props;\n\n const id = useId();\n const toast = useToast();\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Compose our inputRef (used by the Popover for positioning) with Studio's focusRef.\n // Standard Sanity inputs spread all of elementProps onto the native element, which\n // lets Studio programmatically re-focus the field and track focus via onPathFocus/onPathBlur.\n const composedInputRef = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node;\n if (studioElementProps?.ref) {\n (studioElementProps.ref as React.RefObject<HTMLInputElement | null>).current = node;\n }\n },\n [studioElementProps?.ref],\n );\n\n // Studio steals focus to its field-actions-trigger immediately after field activation, then\n // re-focuses the actual input — all within the same macrotask as the original focus event.\n // We suppress the onPathBlur for this activation blur so Studio's focused state stays accurate.\n // The flag is reset via setTimeout so any blur in a later macrotask (real user navigation) is\n // forwarded normally.\n const suppressNextBlur = useRef(false);\n\n const handleFocus = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n suppressNextBlur.current = true;\n setTimeout(() => {\n suppressNextBlur.current = false;\n }, 0);\n studioElementProps?.onFocus?.(event as unknown as React.FocusEvent<HTMLDivElement>);\n },\n [studioElementProps],\n );\n\n const handleBlur = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n if (suppressNextBlur.current) {\n suppressNextBlur.current = false;\n return;\n }\n studioElementProps?.onBlur?.(event as unknown as React.FocusEvent<HTMLDivElement>);\n },\n [studioElementProps],\n );\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 closeMenu,\n } = useCombobox({\n items: data ?? [],\n inputValue: term,\n onInputValueChange({ inputValue, selectedItem }) {\n if (inputValue !== selectedItem) {\n setTerm(inputValue);\n }\n },\n onSelectedItemChange({ selectedItem }) {\n if (selectedItem) {\n pushSelection(selectedItem);\n setTerm('', true);\n setInputValue('');\n }\n },\n });\n\n // Close the menu when Studio considers the field unfocused. This is the state→UI equivalent\n // of the old stateReducer: instead of intercepting downshift's blur handling imperatively,\n // we let Studio's focused state drive whether the menu should be open.\n useEffect(() => {\n if (!fieldFocused) closeMenu();\n }, [fieldFocused, closeMenu]);\n\n const handleUnset = useCallback(() => {\n pushSelection('');\n setTerm('', true);\n selectItem('');\n }, [pushSelection, setTerm, selectItem]);\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 // Destructure onBlur out so downshift's InputBlur doesn't close the menu —\n // menu lifecycle is now driven by fieldFocused via the effect above.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { onBlur: _downshiftOnBlur, ...inputProps } = getInputProps({\n ref: composedInputRef,\n id: studioElementProps?.id,\n 'aria-describedby': studioElementProps?.['aria-describedby'],\n onFocus: handleFocus,\n });\n\n return (\n <div>\n {/* @ts-expect-error wrong typings */}\n <SearchInput\n {...inputProps}\n onBlur={handleBlur}\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 { memo, 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\nconst theme = buildTheme();\n\ninterface IconifyInputProps extends ObjectInputProps {\n config: IconifyPluginConfig;\n}\n\nexport const IconifyInput = memo(function IconifyInput(props: IconifyInputProps) {\n const { config, value, onChange: pushChange, schemaType, elementProps, focused } = 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={theme}>\n <Stack space={2}>\n <IconifyCombobox\n selectedIcon={selectedIcon}\n onSelect={handleSelect}\n collections={collections}\n studioElementProps={elementProps}\n fieldFocused={focused}\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 { memo } from 'react';\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 const IconifyPreview = memo(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","memo","forwardRef","TextInput","Icon","jsxs","Fragment","Button","TrashIcon","useId","useToast","useRef","useCombobox","useEffect","Popover","match","QueryClient","ReactQueryClientProvider","useMemo","stringToIcon","sentenceCase","buildTheme","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, memo } from 'react';\n\ninterface SearchInputProps extends React.HTMLAttributes<HTMLInputElement> {\n selectedIcon: string | null;\n suffix?: React.ReactNode;\n}\n\nexport const SearchInput = memo(\n 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);\n\nSearchInput.displayName = 'SearchInput';\n","import { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\nimport type { UseComboboxGetItemPropsOptions, UseComboboxGetItemPropsReturnValue } from 'downshift';\nimport { forwardRef, memo } 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 = memo(\n 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\n {...rest}\n ref={ref}\n data-testid=\"iconify-results\"\n style={{ opacity: state === 'stale' ? 0.5 : 1 }}\n >\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);\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\n data-testid=\"iconify-unset\"\n icon={<TrashIcon />}\n onClick={onUnset}\n mode=\"bleed\"\n fontSize={1}\n padding={2}\n />\n </Card>\n );\n}\n","import { Popover, useToast } from '@sanity/ui';\nimport { useCombobox } from 'downshift';\nimport { memo, useCallback, useEffect, useId, useRef } from 'react';\nimport type { ObjectInputProps } from 'sanity';\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 studioElementProps?: ObjectInputProps['elementProps'];\n fieldFocused?: boolean;\n}\n\nexport const IconifyCombobox = memo(function IconifyCombobox(props: IconifyComboboxProps) {\n const {\n selectedIcon,\n onSelect: pushSelection,\n collections,\n studioElementProps,\n fieldFocused,\n } = props;\n\n const id = useId();\n const toast = useToast();\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Compose our inputRef (used by the Popover for positioning) with Studio's focusRef.\n // Standard Sanity inputs spread all of elementProps onto the native element, which\n // lets Studio programmatically re-focus the field and track focus via onPathFocus/onPathBlur.\n const composedInputRef = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node;\n if (studioElementProps?.ref) {\n (studioElementProps.ref as React.RefObject<HTMLInputElement | null>).current = node;\n }\n },\n [studioElementProps?.ref],\n );\n\n // Studio steals focus to its field-actions-trigger immediately after field activation, then\n // re-focuses the actual input — all within the same macrotask as the original focus event.\n // We suppress the onPathBlur for this activation blur so Studio's focused state stays accurate.\n // The flag is reset via setTimeout so any blur in a later macrotask (real user navigation) is\n // forwarded normally.\n const suppressNextBlur = useRef(false);\n\n const handleFocus = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n suppressNextBlur.current = true;\n setTimeout(() => {\n suppressNextBlur.current = false;\n }, 0);\n studioElementProps?.onFocus?.(event as unknown as React.FocusEvent<HTMLDivElement>);\n },\n [studioElementProps],\n );\n\n const handleBlur = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n if (suppressNextBlur.current) {\n suppressNextBlur.current = false;\n return;\n }\n studioElementProps?.onBlur?.(event as unknown as React.FocusEvent<HTMLDivElement>);\n },\n [studioElementProps],\n );\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 closeMenu,\n } = useCombobox({\n items: data ?? [],\n inputValue: term,\n onInputValueChange({ inputValue, selectedItem }) {\n if (inputValue !== selectedItem) {\n setTerm(inputValue);\n }\n },\n onSelectedItemChange({ selectedItem }) {\n if (selectedItem) {\n pushSelection(selectedItem);\n setTerm('', true);\n setInputValue('');\n }\n },\n });\n\n // Close the menu when Studio considers the field unfocused. This is the state→UI equivalent\n // of the old stateReducer: instead of intercepting downshift's blur handling imperatively,\n // we let Studio's focused state drive whether the menu should be open.\n useEffect(() => {\n if (!fieldFocused) closeMenu();\n }, [fieldFocused, closeMenu]);\n\n const handleUnset = useCallback(() => {\n pushSelection('');\n setTerm('', true);\n selectItem('');\n }, [pushSelection, setTerm, selectItem]);\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 // Destructure onBlur out so downshift's InputBlur doesn't close the menu —\n // menu lifecycle is now driven by fieldFocused via the effect above.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { onBlur: _downshiftOnBlur, ...inputProps } = getInputProps({\n ref: composedInputRef,\n id: studioElementProps?.id,\n 'aria-describedby': studioElementProps?.['aria-describedby'],\n onFocus: handleFocus,\n });\n\n return (\n <div>\n <SearchInput\n {...inputProps}\n onBlur={handleBlur}\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 { memo, 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\nconst theme = buildTheme();\n\ninterface IconifyInputProps extends ObjectInputProps {\n config: IconifyPluginConfig;\n}\n\nexport const IconifyInput = memo(function IconifyInput(props: IconifyInputProps) {\n const { config, value, onChange: pushChange, schemaType, elementProps, focused } = 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={theme}>\n <Stack space={2}>\n <IconifyCombobox\n selectedIcon={selectedIcon}\n onSelect={handleSelect}\n collections={collections}\n studioElementProps={elementProps}\n fieldFocused={focused}\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 { memo } from 'react';\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 const IconifyPreview = memo(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","memo","forwardRef","TextInput","Icon","jsxs","Fragment","Button","TrashIcon","useId","useToast","useRef","useCombobox","useEffect","Popover","match","QueryClient","ReactQueryClientProvider","useMemo","stringToIcon","sentenceCase","buildTheme","unset","set","ThemeProvider","Stack","Flex","definePlugin"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -129,6 +129,7 @@ export declare type IconPrefix =
|
|
|
129
129
|
| 'line-md'
|
|
130
130
|
| 'solar'
|
|
131
131
|
| 'tabler'
|
|
132
|
+
| 'boxicons'
|
|
132
133
|
| 'mingcute'
|
|
133
134
|
| 'ri'
|
|
134
135
|
| 'mynaui'
|
|
@@ -139,8 +140,6 @@ export declare type IconPrefix =
|
|
|
139
140
|
| 'uil'
|
|
140
141
|
| 'tdesign'
|
|
141
142
|
| 'si'
|
|
142
|
-
| 'bx'
|
|
143
|
-
| 'bxs'
|
|
144
143
|
| 'majesticons'
|
|
145
144
|
| 'gg'
|
|
146
145
|
| 'flowbite'
|
|
@@ -175,6 +174,7 @@ export declare type IconPrefix =
|
|
|
175
174
|
| 'mage'
|
|
176
175
|
| 'stash'
|
|
177
176
|
| 'lineicons'
|
|
177
|
+
| 'wordpress'
|
|
178
178
|
| 'icon-park-outline'
|
|
179
179
|
| 'icon-park-solid'
|
|
180
180
|
| 'icon-park-twotone'
|
|
@@ -201,6 +201,8 @@ export declare type IconPrefix =
|
|
|
201
201
|
| 'formkit'
|
|
202
202
|
| 'fluent'
|
|
203
203
|
| 'ph'
|
|
204
|
+
| 'glyphs'
|
|
205
|
+
| 'glyphs-poly'
|
|
204
206
|
| 'teenyicons'
|
|
205
207
|
| 'clarity'
|
|
206
208
|
| 'streamline-freehand'
|
|
@@ -307,6 +309,8 @@ export declare type IconPrefix =
|
|
|
307
309
|
| 'gala'
|
|
308
310
|
| 'heroicons-outline'
|
|
309
311
|
| 'heroicons-solid'
|
|
312
|
+
| 'bx'
|
|
313
|
+
| 'bxs'
|
|
310
314
|
| 'fa6-solid'
|
|
311
315
|
| 'fa6-regular'
|
|
312
316
|
| 'fa6-brands'
|
package/dist/index.d.ts
CHANGED
|
@@ -129,6 +129,7 @@ export declare type IconPrefix =
|
|
|
129
129
|
| 'line-md'
|
|
130
130
|
| 'solar'
|
|
131
131
|
| 'tabler'
|
|
132
|
+
| 'boxicons'
|
|
132
133
|
| 'mingcute'
|
|
133
134
|
| 'ri'
|
|
134
135
|
| 'mynaui'
|
|
@@ -139,8 +140,6 @@ export declare type IconPrefix =
|
|
|
139
140
|
| 'uil'
|
|
140
141
|
| 'tdesign'
|
|
141
142
|
| 'si'
|
|
142
|
-
| 'bx'
|
|
143
|
-
| 'bxs'
|
|
144
143
|
| 'majesticons'
|
|
145
144
|
| 'gg'
|
|
146
145
|
| 'flowbite'
|
|
@@ -175,6 +174,7 @@ export declare type IconPrefix =
|
|
|
175
174
|
| 'mage'
|
|
176
175
|
| 'stash'
|
|
177
176
|
| 'lineicons'
|
|
177
|
+
| 'wordpress'
|
|
178
178
|
| 'icon-park-outline'
|
|
179
179
|
| 'icon-park-solid'
|
|
180
180
|
| 'icon-park-twotone'
|
|
@@ -201,6 +201,8 @@ export declare type IconPrefix =
|
|
|
201
201
|
| 'formkit'
|
|
202
202
|
| 'fluent'
|
|
203
203
|
| 'ph'
|
|
204
|
+
| 'glyphs'
|
|
205
|
+
| 'glyphs-poly'
|
|
204
206
|
| 'teenyicons'
|
|
205
207
|
| 'clarity'
|
|
206
208
|
| 'streamline-freehand'
|
|
@@ -307,6 +309,8 @@ export declare type IconPrefix =
|
|
|
307
309
|
| 'gala'
|
|
308
310
|
| 'heroicons-outline'
|
|
309
311
|
| 'heroicons-solid'
|
|
312
|
+
| 'bx'
|
|
313
|
+
| 'bxs'
|
|
310
314
|
| 'fa6-solid'
|
|
311
315
|
| 'fa6-regular'
|
|
312
316
|
| 'fa6-brands'
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/lib/api.ts","../src/combobox/iconify-combobox.styles.tsx","../src/combobox/search-input.tsx","../src/combobox/search-result.tsx","../src/combobox/unset-button.tsx","../src/combobox/iconify-combobox.tsx","../src/lib/query-client.tsx","../src/lib/use-pretty-icon-name.ts","../src/iconify-input.tsx","../src/iconify-preview.tsx","../src/iconify-plugin.tsx"],"sourcesContent":["import type { IconifyInfo } from '@iconify/types';\nimport { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useCallback, useState } from 'react';\nimport { useDebounce } from 'use-debounce';\nimport type { IconifySearchResult } from './types';\n\nconst BASE_API_URL = 'https://api.iconify.design';\n\nfunction fetchJson<T>({ url, signal }: { url: string | URL; signal?: AbortSignal }): Promise<T> {\n return fetch(url, { signal })\n .then((response) => {\n if (!response.ok) {\n throw new Error(`Network error: status ${response.status}`);\n }\n\n return response.json();\n })\n .then(\n (result) => result as T,\n (error) => {\n if (error instanceof Error) {\n throw error;\n } else {\n console.error(`Unknown error: ${error}`);\n throw new Error('Something went wrong');\n }\n },\n );\n}\n\nexport function useSearch({ collections }: { collections: string[] | null }) {\n const queryClient = useQueryClient();\n const [term, setTerm] = useState('');\n const [debouncedTerm, setDebouncedTerm] = useDebounce(term, 500);\n\n const updateTerm = useCallback(\n (newTerm: string, updateImmediately = false) => {\n setTerm(newTerm);\n\n if (updateImmediately) {\n setDebouncedTerm(newTerm);\n }\n },\n [setDebouncedTerm],\n );\n\n const { isLoading, isError, error, data, isPlaceholderData } = useQuery<string[], Error>({\n queryKey: ['search', collections, debouncedTerm],\n queryFn: async ({ signal }) => {\n const url = new URL(`/search`, BASE_API_URL);\n\n url.searchParams.append('query', debouncedTerm);\n url.searchParams.append('limit', '60');\n\n if (collections) {\n url.searchParams.append('prefixes', collections.join(','));\n }\n\n const result = debouncedTerm ? await fetchJson<IconifySearchResult>({ url, signal }) : null;\n\n if (result) {\n // Cache the info for each collection\n Object.entries(result.collections).forEach(([prefix, info]) => {\n queryClient.setQueryData<IconifyInfo>(['iconSetInfo', prefix], info);\n });\n }\n\n return result?.icons ?? [];\n },\n enabled: debouncedTerm.length > 0,\n placeholderData: keepPreviousData,\n staleTime: 5 * 60 * 1000, // 5 minutes\n });\n\n return {\n term,\n setTerm: updateTerm,\n debouncedTerm,\n isLoading,\n isError,\n error,\n data,\n isPreviousData: isPlaceholderData,\n };\n}\n\nexport function useIconSetInfo({ prefix }: { prefix?: string | null }) {\n return useQuery<IconifyInfo | null, Error>({\n queryKey: ['iconSetInfo', prefix],\n queryFn: async ({ signal }) => {\n if (!prefix) return null;\n\n const url = new URL('/collection', BASE_API_URL);\n\n url.searchParams.append('prefix', prefix);\n url.searchParams.append('info', 'true');\n\n const result = await fetchJson<{ info: IconifyInfo }>({ url, signal });\n\n return result?.info ?? null;\n },\n staleTime: Infinity,\n });\n}\n","import { Box, Card, Grid, Text } from '@sanity/ui';\nimport type { ReactNode } from 'react';\nimport styled from 'styled-components';\n\nexport const ComboboxWrapper = styled(Grid)`\n grid-template-columns: 1fr min-content;\n position: relative;\n`;\n\nexport const OptionsWrapper = styled(Box)`\n box-sizing: border-box;\n padding: 0.5rem;\n\n & [role='listbox'] {\n display: 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, memo } from 'react';\n\ninterface SearchInputProps extends React.HTMLAttributes<HTMLInputElement> {\n selectedIcon: string | null;\n suffix?: React.ReactNode;\n}\n\nexport const SearchInput = memo(\n 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);\n\nSearchInput.displayName = 'SearchInput';\n","import { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\nimport type { UseComboboxGetItemPropsOptions, UseComboboxGetItemPropsReturnValue } from 'downshift';\nimport { forwardRef, memo } 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 = memo(\n 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\n {...rest}\n ref={ref}\n data-testid=\"iconify-results\"\n style={{ opacity: state === 'stale' ? 0.5 : 1 }}\n >\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);\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\n data-testid=\"iconify-unset\"\n icon={<TrashIcon />}\n onClick={onUnset}\n mode=\"bleed\"\n fontSize={1}\n padding={2}\n />\n </Card>\n );\n}\n","import { Popover, useToast } from '@sanity/ui';\nimport { useCombobox } from 'downshift';\nimport { memo, useCallback, useEffect, useId, useRef } from 'react';\nimport type { ObjectInputProps } from 'sanity';\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 studioElementProps?: ObjectInputProps['elementProps'];\n fieldFocused?: boolean;\n}\n\nexport const IconifyCombobox = memo(function IconifyCombobox(props: IconifyComboboxProps) {\n const {\n selectedIcon,\n onSelect: pushSelection,\n collections,\n studioElementProps,\n fieldFocused,\n } = props;\n\n const id = useId();\n const toast = useToast();\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Compose our inputRef (used by the Popover for positioning) with Studio's focusRef.\n // Standard Sanity inputs spread all of elementProps onto the native element, which\n // lets Studio programmatically re-focus the field and track focus via onPathFocus/onPathBlur.\n const composedInputRef = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node;\n if (studioElementProps?.ref) {\n (studioElementProps.ref as React.RefObject<HTMLInputElement | null>).current = node;\n }\n },\n [studioElementProps?.ref],\n );\n\n // Studio steals focus to its field-actions-trigger immediately after field activation, then\n // re-focuses the actual input — all within the same macrotask as the original focus event.\n // We suppress the onPathBlur for this activation blur so Studio's focused state stays accurate.\n // The flag is reset via setTimeout so any blur in a later macrotask (real user navigation) is\n // forwarded normally.\n const suppressNextBlur = useRef(false);\n\n const handleFocus = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n suppressNextBlur.current = true;\n setTimeout(() => {\n suppressNextBlur.current = false;\n }, 0);\n studioElementProps?.onFocus?.(event as unknown as React.FocusEvent<HTMLDivElement>);\n },\n [studioElementProps],\n );\n\n const handleBlur = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n if (suppressNextBlur.current) {\n suppressNextBlur.current = false;\n return;\n }\n studioElementProps?.onBlur?.(event as unknown as React.FocusEvent<HTMLDivElement>);\n },\n [studioElementProps],\n );\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 closeMenu,\n } = useCombobox({\n items: data ?? [],\n inputValue: term,\n onInputValueChange({ inputValue, selectedItem }) {\n if (inputValue !== selectedItem) {\n setTerm(inputValue);\n }\n },\n onSelectedItemChange({ selectedItem }) {\n if (selectedItem) {\n pushSelection(selectedItem);\n setTerm('', true);\n setInputValue('');\n }\n },\n });\n\n // Close the menu when Studio considers the field unfocused. This is the state→UI equivalent\n // of the old stateReducer: instead of intercepting downshift's blur handling imperatively,\n // we let Studio's focused state drive whether the menu should be open.\n useEffect(() => {\n if (!fieldFocused) closeMenu();\n }, [fieldFocused, closeMenu]);\n\n const handleUnset = useCallback(() => {\n pushSelection('');\n setTerm('', true);\n selectItem('');\n }, [pushSelection, setTerm, selectItem]);\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 // Destructure onBlur out so downshift's InputBlur doesn't close the menu —\n // menu lifecycle is now driven by fieldFocused via the effect above.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { onBlur: _downshiftOnBlur, ...inputProps } = getInputProps({\n ref: composedInputRef,\n id: studioElementProps?.id,\n 'aria-describedby': studioElementProps?.['aria-describedby'],\n onFocus: handleFocus,\n });\n\n return (\n <div>\n {/* @ts-expect-error wrong typings */}\n <SearchInput\n {...inputProps}\n onBlur={handleBlur}\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 { memo, 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\nconst theme = buildTheme();\n\ninterface IconifyInputProps extends ObjectInputProps {\n config: IconifyPluginConfig;\n}\n\nexport const IconifyInput = memo(function IconifyInput(props: IconifyInputProps) {\n const { config, value, onChange: pushChange, schemaType, elementProps, focused } = 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={theme}>\n <Stack space={2}>\n <IconifyCombobox\n selectedIcon={selectedIcon}\n onSelect={handleSelect}\n collections={collections}\n studioElementProps={elementProps}\n fieldFocused={focused}\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 { memo } from 'react';\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 const IconifyPreview = memo(function IconifyPreview(props: PreviewProps) {\n const { title } = props;\n const iconName = typeof props.title === 'string' ? stringToIcon(props.title) : null;\n\n // We check this double to avoid the TS error\n if (typeof title === 'string' && iconName) {\n return (\n <QueryClientProvider>\n <IconifyPreviewInner {...props} iconName={title} iconMeta={iconName} />\n </QueryClientProvider>\n );\n }\n\n return props.renderDefault(props);\n});\n\n// --------------------- //\n// ICONIFY PREVIEW INNER //\n// --------------------- //\n\ninterface IconifyPreviewInnerProps extends PreviewProps {\n iconName: string;\n iconMeta: IconifyIconName;\n}\n\nfunction IconifyPreviewInner(props: IconifyPreviewInnerProps) {\n const { iconMeta, iconName, ...previewProps } = props;\n const prettyName = usePrettyIconName({ iconMeta });\n\n return props.renderDefault({\n ...previewProps,\n media: <Icon icon={iconName} />,\n title: prettyName?.name ?? iconName,\n subtitle: prettyName?.collection,\n });\n}\n","import type { FieldProps, ObjectInputProps } from 'sanity';\nimport { definePlugin } from 'sanity';\nimport { IconifyInput } from './iconify-input';\nimport { IconifyPreview } from './iconify-preview';\nimport type { IconifyPluginConfig } from './lib/types';\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import { defineConfig } from 'sanity'\n * import { iconify } from 'sanity-plugin-iconify'\n *\n * export default defineConfig({\n * // ...\n * plugins: [iconify()],\n * })\n * ```\n */\nexport const iconify = definePlugin<IconifyPluginConfig | void>((config = {}) => {\n return {\n name: 'sanity-plugin-iconify',\n schema: {\n types: [\n {\n name: 'icon',\n title: 'Icon',\n type: 'object',\n fields: [\n {\n name: 'name',\n title: 'Name',\n type: 'string',\n },\n ],\n components: {\n input: (props: ObjectInputProps) => <IconifyInput {...props} config={config!} />,\n preview: IconifyPreview,\n\n // This makes sure the input component is not indented\n field: (props: FieldProps) => props.renderDefault({ ...props, level: 0 }),\n },\n },\n ],\n },\n };\n});\n"],"names":["queryClient","ReactQueryClientProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/lib/api.ts","../src/combobox/iconify-combobox.styles.tsx","../src/combobox/search-input.tsx","../src/combobox/search-result.tsx","../src/combobox/unset-button.tsx","../src/combobox/iconify-combobox.tsx","../src/lib/query-client.tsx","../src/lib/use-pretty-icon-name.ts","../src/iconify-input.tsx","../src/iconify-preview.tsx","../src/iconify-plugin.tsx"],"sourcesContent":["import type { IconifyInfo } from '@iconify/types';\nimport { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useCallback, useState } from 'react';\nimport { useDebounce } from 'use-debounce';\nimport type { IconifySearchResult } from './types';\n\nconst BASE_API_URL = 'https://api.iconify.design';\n\nfunction fetchJson<T>({ url, signal }: { url: string | URL; signal?: AbortSignal }): Promise<T> {\n return fetch(url, { signal })\n .then((response) => {\n if (!response.ok) {\n throw new Error(`Network error: status ${response.status}`);\n }\n\n return response.json();\n })\n .then(\n (result) => result as T,\n (error) => {\n if (error instanceof Error) {\n throw error;\n } else {\n console.error(`Unknown error: ${error}`);\n throw new Error('Something went wrong');\n }\n },\n );\n}\n\nexport function useSearch({ collections }: { collections: string[] | null }) {\n const queryClient = useQueryClient();\n const [term, setTerm] = useState('');\n const [debouncedTerm, setDebouncedTerm] = useDebounce(term, 500);\n\n const updateTerm = useCallback(\n (newTerm: string, updateImmediately = false) => {\n setTerm(newTerm);\n\n if (updateImmediately) {\n setDebouncedTerm(newTerm);\n }\n },\n [setDebouncedTerm],\n );\n\n const { isLoading, isError, error, data, isPlaceholderData } = useQuery<string[], Error>({\n queryKey: ['search', collections, debouncedTerm],\n queryFn: async ({ signal }) => {\n const url = new URL(`/search`, BASE_API_URL);\n\n url.searchParams.append('query', debouncedTerm);\n url.searchParams.append('limit', '60');\n\n if (collections) {\n url.searchParams.append('prefixes', collections.join(','));\n }\n\n const result = debouncedTerm ? await fetchJson<IconifySearchResult>({ url, signal }) : null;\n\n if (result) {\n // Cache the info for each collection\n Object.entries(result.collections).forEach(([prefix, info]) => {\n queryClient.setQueryData<IconifyInfo>(['iconSetInfo', prefix], info);\n });\n }\n\n return result?.icons ?? [];\n },\n enabled: debouncedTerm.length > 0,\n placeholderData: keepPreviousData,\n staleTime: 5 * 60 * 1000, // 5 minutes\n });\n\n return {\n term,\n setTerm: updateTerm,\n debouncedTerm,\n isLoading,\n isError,\n error,\n data,\n isPreviousData: isPlaceholderData,\n };\n}\n\nexport function useIconSetInfo({ prefix }: { prefix?: string | null }) {\n return useQuery<IconifyInfo | null, Error>({\n queryKey: ['iconSetInfo', prefix],\n queryFn: async ({ signal }) => {\n if (!prefix) return null;\n\n const url = new URL('/collection', BASE_API_URL);\n\n url.searchParams.append('prefix', prefix);\n url.searchParams.append('info', 'true');\n\n const result = await fetchJson<{ info: IconifyInfo }>({ url, signal });\n\n return result?.info ?? null;\n },\n staleTime: Infinity,\n });\n}\n","import { Box, Card, Grid, Text } from '@sanity/ui';\nimport type { ReactNode } from 'react';\nimport styled from 'styled-components';\n\nexport const ComboboxWrapper = styled(Grid)`\n grid-template-columns: 1fr min-content;\n position: relative;\n`;\n\nexport const OptionsWrapper = styled(Box)`\n box-sizing: border-box;\n padding: 0.5rem;\n\n & [role='listbox'] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n & [role='option'] {\n display: grid;\n place-items: center;\n width: clamp(3rem, 10vw, 4rem);\n\n & button {\n cursor: pointer;\n width: 100%;\n\n & > [data-ui='Box'] {\n display: flex;\n }\n\n & svg {\n aspect-ratio: 1;\n }\n }\n }\n`;\n\nexport function MessageWrapper({ children }: { children: ReactNode }) {\n return (\n <Card padding={4}>\n <Text align=\"center\" muted>\n {children}\n </Text>\n </Card>\n );\n}\n","import { Icon } from '@iconify/react';\nimport { TextInput } from '@sanity/ui';\nimport { forwardRef, memo } from 'react';\n\ninterface SearchInputProps extends React.HTMLAttributes<HTMLInputElement> {\n selectedIcon: string | null;\n suffix?: React.ReactNode;\n}\n\nexport const SearchInput = memo(\n 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);\n\nSearchInput.displayName = 'SearchInput';\n","import { Icon } from '@iconify/react';\nimport { Button } from '@sanity/ui';\nimport type { UseComboboxGetItemPropsOptions, UseComboboxGetItemPropsReturnValue } from 'downshift';\nimport { forwardRef, memo } 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 = memo(\n 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\n {...rest}\n ref={ref}\n data-testid=\"iconify-results\"\n style={{ opacity: state === 'stale' ? 0.5 : 1 }}\n >\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);\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\n data-testid=\"iconify-unset\"\n icon={<TrashIcon />}\n onClick={onUnset}\n mode=\"bleed\"\n fontSize={1}\n padding={2}\n />\n </Card>\n );\n}\n","import { Popover, useToast } from '@sanity/ui';\nimport { useCombobox } from 'downshift';\nimport { memo, useCallback, useEffect, useId, useRef } from 'react';\nimport type { ObjectInputProps } from 'sanity';\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 studioElementProps?: ObjectInputProps['elementProps'];\n fieldFocused?: boolean;\n}\n\nexport const IconifyCombobox = memo(function IconifyCombobox(props: IconifyComboboxProps) {\n const {\n selectedIcon,\n onSelect: pushSelection,\n collections,\n studioElementProps,\n fieldFocused,\n } = props;\n\n const id = useId();\n const toast = useToast();\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Compose our inputRef (used by the Popover for positioning) with Studio's focusRef.\n // Standard Sanity inputs spread all of elementProps onto the native element, which\n // lets Studio programmatically re-focus the field and track focus via onPathFocus/onPathBlur.\n const composedInputRef = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node;\n if (studioElementProps?.ref) {\n (studioElementProps.ref as React.RefObject<HTMLInputElement | null>).current = node;\n }\n },\n [studioElementProps?.ref],\n );\n\n // Studio steals focus to its field-actions-trigger immediately after field activation, then\n // re-focuses the actual input — all within the same macrotask as the original focus event.\n // We suppress the onPathBlur for this activation blur so Studio's focused state stays accurate.\n // The flag is reset via setTimeout so any blur in a later macrotask (real user navigation) is\n // forwarded normally.\n const suppressNextBlur = useRef(false);\n\n const handleFocus = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n suppressNextBlur.current = true;\n setTimeout(() => {\n suppressNextBlur.current = false;\n }, 0);\n studioElementProps?.onFocus?.(event as unknown as React.FocusEvent<HTMLDivElement>);\n },\n [studioElementProps],\n );\n\n const handleBlur = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n if (suppressNextBlur.current) {\n suppressNextBlur.current = false;\n return;\n }\n studioElementProps?.onBlur?.(event as unknown as React.FocusEvent<HTMLDivElement>);\n },\n [studioElementProps],\n );\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 closeMenu,\n } = useCombobox({\n items: data ?? [],\n inputValue: term,\n onInputValueChange({ inputValue, selectedItem }) {\n if (inputValue !== selectedItem) {\n setTerm(inputValue);\n }\n },\n onSelectedItemChange({ selectedItem }) {\n if (selectedItem) {\n pushSelection(selectedItem);\n setTerm('', true);\n setInputValue('');\n }\n },\n });\n\n // Close the menu when Studio considers the field unfocused. This is the state→UI equivalent\n // of the old stateReducer: instead of intercepting downshift's blur handling imperatively,\n // we let Studio's focused state drive whether the menu should be open.\n useEffect(() => {\n if (!fieldFocused) closeMenu();\n }, [fieldFocused, closeMenu]);\n\n const handleUnset = useCallback(() => {\n pushSelection('');\n setTerm('', true);\n selectItem('');\n }, [pushSelection, setTerm, selectItem]);\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 // Destructure onBlur out so downshift's InputBlur doesn't close the menu —\n // menu lifecycle is now driven by fieldFocused via the effect above.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { onBlur: _downshiftOnBlur, ...inputProps } = getInputProps({\n ref: composedInputRef,\n id: studioElementProps?.id,\n 'aria-describedby': studioElementProps?.['aria-describedby'],\n onFocus: handleFocus,\n });\n\n return (\n <div>\n <SearchInput\n {...inputProps}\n onBlur={handleBlur}\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 { memo, 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\nconst theme = buildTheme();\n\ninterface IconifyInputProps extends ObjectInputProps {\n config: IconifyPluginConfig;\n}\n\nexport const IconifyInput = memo(function IconifyInput(props: IconifyInputProps) {\n const { config, value, onChange: pushChange, schemaType, elementProps, focused } = 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={theme}>\n <Stack space={2}>\n <IconifyCombobox\n selectedIcon={selectedIcon}\n onSelect={handleSelect}\n collections={collections}\n studioElementProps={elementProps}\n fieldFocused={focused}\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 { memo } from 'react';\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 const IconifyPreview = memo(function IconifyPreview(props: PreviewProps) {\n const { title } = props;\n const iconName = typeof props.title === 'string' ? stringToIcon(props.title) : null;\n\n // We check this double to avoid the TS error\n if (typeof title === 'string' && iconName) {\n return (\n <QueryClientProvider>\n <IconifyPreviewInner {...props} iconName={title} iconMeta={iconName} />\n </QueryClientProvider>\n );\n }\n\n return props.renderDefault(props);\n});\n\n// --------------------- //\n// ICONIFY PREVIEW INNER //\n// --------------------- //\n\ninterface IconifyPreviewInnerProps extends PreviewProps {\n iconName: string;\n iconMeta: IconifyIconName;\n}\n\nfunction IconifyPreviewInner(props: IconifyPreviewInnerProps) {\n const { iconMeta, iconName, ...previewProps } = props;\n const prettyName = usePrettyIconName({ iconMeta });\n\n return props.renderDefault({\n ...previewProps,\n media: <Icon icon={iconName} />,\n title: prettyName?.name ?? iconName,\n subtitle: prettyName?.collection,\n });\n}\n","import type { FieldProps, ObjectInputProps } from 'sanity';\nimport { definePlugin } from 'sanity';\nimport { IconifyInput } from './iconify-input';\nimport { IconifyPreview } from './iconify-preview';\nimport type { IconifyPluginConfig } from './lib/types';\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import { defineConfig } from 'sanity'\n * import { iconify } from 'sanity-plugin-iconify'\n *\n * export default defineConfig({\n * // ...\n * plugins: [iconify()],\n * })\n * ```\n */\nexport const iconify = definePlugin<IconifyPluginConfig | void>((config = {}) => {\n return {\n name: 'sanity-plugin-iconify',\n schema: {\n types: [\n {\n name: 'icon',\n title: 'Icon',\n type: 'object',\n fields: [\n {\n name: 'name',\n title: 'Name',\n type: 'string',\n },\n ],\n components: {\n input: (props: ObjectInputProps) => <IconifyInput {...props} config={config!} />,\n preview: IconifyPreview,\n\n // This makes sure the input component is not indented\n field: (props: FieldProps) => props.renderDefault({ ...props, level: 0 }),\n },\n },\n ],\n },\n };\n});\n"],"names":["queryClient","ReactQueryClientProvider"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-iconify",
|
|
3
|
-
"version": "3.0.0
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Icon picker based on Iconify",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"@vitejs/plugin-react": "^5.1.2",
|
|
85
85
|
"@vitest/ui": "^4.1.0",
|
|
86
86
|
"@waspeer/config": "^2.4.5",
|
|
87
|
-
"eslint": "
|
|
87
|
+
"eslint": "9.39.2",
|
|
88
88
|
"lefthook": "^2.0.12",
|
|
89
89
|
"npm-run-all2": "^8.0.4",
|
|
90
90
|
"prettier": "^3.7.4",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type IconPrefix = 'material-symbols' | 'material-symbols-light' | 'ic' | 'mdi' | 'mdi-light' | 'line-md' | 'solar' | 'tabler' | 'mingcute' | 'ri' | 'mynaui' | 'iconamoon' | 'iconoir' | 'lucide' | 'lucide-lab' | 'uil' | 'tdesign' | 'si' | '
|
|
1
|
+
export type IconPrefix = 'material-symbols' | 'material-symbols-light' | 'ic' | 'mdi' | 'mdi-light' | 'line-md' | 'solar' | 'tabler' | 'boxicons' | 'mingcute' | 'ri' | 'mynaui' | 'iconamoon' | 'iconoir' | 'lucide' | 'lucide-lab' | 'uil' | 'tdesign' | 'si' | 'majesticons' | 'gg' | 'flowbite' | 'basil' | 'pixelarticons' | 'pixel' | 'akar-icons' | 'ci' | 'proicons' | 'typcn' | 'meteor-icons' | 'prime' | 'circum' | 'fe' | 'eos-icons' | 'bitcoin-icons' | 'humbleicons' | 'uim' | 'uit' | 'uis' | 'gridicons' | 'mi' | 'cuida' | 'weui' | 'duo-icons' | 'svg-spinners' | 'hugeicons' | 'lets-icons' | 'streamline-ultimate' | 'streamline-plump' | 'streamline-sharp' | 'mage' | 'stash' | 'lineicons' | 'wordpress' | 'icon-park-outline' | 'icon-park-solid' | 'icon-park-twotone' | 'jam' | 'streamline-cyber' | 'guidance' | 'carbon' | 'ion' | 'famicons' | 'ant-design' | 'lsicon' | 'gravity-ui' | 'cil' | 'roentgen' | 'ep' | 'charm' | 'quill' | 'bytesize' | 'bi' | 'streamline-pixel' | 'streamline-block' | 'rivet-icons' | 'nimbus' | 'formkit' | 'fluent' | 'ph' | 'glyphs' | 'glyphs-poly' | 'teenyicons' | 'clarity' | 'streamline-freehand' | 'ix' | 'octicon' | 'memory' | 'system-uicons' | 'radix-icons' | 'zondicons' | 'uiw' | 'codex' | 'ei' | 'heroicons' | 'sidekickicons' | 'pepicons-pop' | 'pepicons-print' | 'pepicons-pencil' | 'f7' | 'pajamas' | 'garden' | 'streamline' | 'streamline-flex' | 'fa7-solid' | 'fa7-regular' | 'picon' | 'ooui' | 'maki' | 'temaki' | 'oui' | 'nrk' | 'dinkie-icons' | 'qlementine-icons' | 'streamline-ultimate-color' | 'streamline-plump-color' | 'streamline-freehand-color' | 'streamline-kameleon-color' | 'streamline-stickies-color' | 'fluent-color' | 'streamline-color' | 'streamline-flex-color' | 'streamline-sharp-color' | 'streamline-cyber-color' | 'icon-park' | 'marketeq' | 'vscode-icons' | 'codicon' | 'material-icon-theme' | 'file-icons' | 'devicon' | 'devicon-plain' | 'catppuccin' | 'skill-icons' | 'unjs' | 'simple-icons' | 'logos' | 'streamline-logos' | 'cib' | 'fa7-brands' | 'bxl' | 'nonicons' | 'arcticons' | 'cbi' | 'brandico' | 'entypo-social' | 'token' | 'token-branded' | 'cryptocurrency' | 'cryptocurrency-color' | 'openmoji' | 'twemoji' | 'noto' | 'fluent-emoji-flat' | 'fluent-emoji-high-contrast' | 'noto-v1' | 'emojione' | 'emojione-monotone' | 'emojione-v1' | 'fxemoji' | 'streamline-emojis' | 'circle-flags' | 'flag' | 'flagpack' | 'cif' | 'gis' | 'map' | 'geo' | 'game-icons' | 'fad' | 'academicons' | 'wi' | 'meteocons' | 'healthicons' | 'medical-icon' | 'covid' | 'la' | 'eva' | 'dashicons' | 'flat-color-icons' | 'entypo' | 'foundation' | 'raphael' | 'icons8' | 'iwwa' | 'gala' | 'heroicons-outline' | 'heroicons-solid' | 'bx' | 'bxs' | 'fa6-solid' | 'fa6-regular' | 'fa6-brands' | 'fa-solid' | 'fa-regular' | 'fa-brands' | 'fa' | 'fluent-mdl2' | 'fontisto' | 'icomoon-free' | 'subway' | 'oi' | 'wpf' | 'simple-line-icons' | 'et' | 'el' | 'vaadin' | 'grommet-icons' | 'whh' | 'si-glyph' | 'zmdi' | 'ls' | 'bpmn' | 'flat-ui' | 'vs' | 'topcoat' | 'il' | 'websymbol' | 'fontelico' | 'ps' | 'feather' | 'mono-icons' | 'pepicons' | 'fluent-emoji';
|
package/src/lib/types.test.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { defineField } from 'sanity';
|
|
2
|
+
import type { IntrinsicDefinitions } from 'sanity';
|
|
2
3
|
import { describe, expectTypeOf, it } from 'vitest';
|
|
3
|
-
import type { IconValue } from './types';
|
|
4
|
+
import type { IconDefinition, IconValue } from './types';
|
|
4
5
|
|
|
5
6
|
// These are type-level tests: they fail at compile time if types are wrong,
|
|
6
7
|
// not at runtime. Credit: danilo-arioli (PR #13).
|
|
7
8
|
|
|
8
9
|
describe('IconDefinition type safety', () => {
|
|
10
|
+
it('registers icon in IntrinsicDefinitions (module augmentation)', () => {
|
|
11
|
+
// If this fails, the declare module 'sanity' augmentation is broken and
|
|
12
|
+
// Sanity won't recognise 'icon' as a valid type string in defineField/defineType.
|
|
13
|
+
expectTypeOf<IntrinsicDefinitions['icon']>().toMatchTypeOf<IconDefinition>();
|
|
14
|
+
});
|
|
15
|
+
|
|
9
16
|
it('types value as IconValue in validation callbacks', () => {
|
|
10
17
|
defineField({
|
|
11
18
|
name: 'icon',
|
|
@@ -43,6 +50,17 @@ describe('IconDefinition type safety', () => {
|
|
|
43
50
|
});
|
|
44
51
|
});
|
|
45
52
|
|
|
53
|
+
it('types value as IconValue in initialValue callbacks', () => {
|
|
54
|
+
defineField({
|
|
55
|
+
name: 'icon',
|
|
56
|
+
type: 'icon',
|
|
57
|
+
initialValue: (params, context) => {
|
|
58
|
+
expectTypeOf(context.currentUser).toMatchTypeOf<{ id: string } | null>();
|
|
59
|
+
return { name: 'mdi:home' } satisfies IconValue;
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
46
64
|
it('accepts collapsible and collapsed options', () => {
|
|
47
65
|
defineField({
|
|
48
66
|
name: 'icon',
|
|
@@ -51,7 +69,17 @@ describe('IconDefinition type safety', () => {
|
|
|
51
69
|
collapsible: true,
|
|
52
70
|
collapsed: false,
|
|
53
71
|
collections: ['mdi'],
|
|
72
|
+
showName: true,
|
|
54
73
|
},
|
|
55
74
|
});
|
|
56
75
|
});
|
|
76
|
+
|
|
77
|
+
it('rejects unknown options', () => {
|
|
78
|
+
defineField({
|
|
79
|
+
name: 'icon',
|
|
80
|
+
type: 'icon',
|
|
81
|
+
// @ts-expect-error unknown option should not be accepted
|
|
82
|
+
options: { unknownOption: true },
|
|
83
|
+
});
|
|
84
|
+
});
|
|
57
85
|
});
|