UNPKG

@sanity/preview-kit

Version:

General purpose utils for live content and visual editing

1 lines 6.58 kB
{"version":3,"file":"client-component.cjs","sources":["../../src/live-query/client-component/useLiveQuery.ts","../../src/live-query/client-component/LiveQueryClientComponent.tsx"],"sourcesContent":["// This is a smaller version of `useLiveQuery`, as `LiveQuery` doesn't\n// need the more advanced features `useLiveQuery`, like the `isEqual` option or the `loading` state\n\nimport type {QueryParams as ClientQueryParams} from '@sanity/client'\nimport type {QueryEnabled} from '@sanity/preview-kit'\nimport {useCallback, useContext, useMemo, useState, useSyncExternalStore} from 'react'\n\nimport {defineStoreContext} from '../../context'\nimport {useQueryParams} from '../../hooks'\n\n/** @internal */\nexport function useLiveQuery<\n QueryResult,\n QueryParams extends ClientQueryParams = ClientQueryParams,\n>(\n initialData: QueryResult,\n query: string,\n queryParams2?: QueryParams,\n): [QueryResult, QueryEnabled] {\n const defineStore = useContext(defineStoreContext)\n const queryParams = useQueryParams(queryParams2)\n const store = useMemo(\n () => defineStore?.<QueryResult>(initialData, query, queryParams),\n [defineStore, initialData, queryParams, query],\n )\n // initialSnapshot might change before hydration is done, so deep cloning it on the first hook call\n // helps ensure that we don't get a mismatch between the server and client snapshots\n const [serverSnapshot] = useState(() => {\n if (initialData === undefined) {\n throw new Error(\n `initialSnapshot can't be undefined, if you don't want an initial value use null instead`,\n )\n }\n try {\n return JSON.parse(JSON.stringify(initialData))\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Failed to deep clone initialSnapshot, this is likely an error and an indication that the snapshot isn't JSON serializable\",\n {initialSnapshot: initialData, error},\n )\n return initialData\n }\n })\n const getServerSnapshot = useCallback(() => serverSnapshot, [serverSnapshot])\n\n return [\n useSyncExternalStore(\n store?.subscribe || noop,\n store?.getSnapshot || getServerSnapshot,\n getServerSnapshot,\n ),\n defineStore !== null,\n ]\n}\n\nfunction noop() {\n return () => {}\n}\n","import type {QueryParams as ClientQueryParams} from '@sanity/client'\nimport {Children, cloneElement, isValidElement} from 'react'\n\nimport {useLiveQuery} from './useLiveQuery'\n\n/** @public */\nexport interface LiveQueryClientComponentProps<QueryResult, QueryParams> {\n children?: React.ReactNode | undefined\n /**\n * If a parent <LiveQueryProvider> is missing, then an error is thrown.\n * If you want to disable this behavior, set this prop to false.\n * @defaultValue true\n */\n throwOnMissingProvider?: boolean\n initialData: QueryResult\n query: string\n params?: QueryParams | undefined\n}\n\n/**\n * Browser-only preview component, overwrites the data prop with live data on-demand\n * @public\n */\nexport default function LiveQueryClientComponent<\n QueryResult,\n QueryParams extends ClientQueryParams = ClientQueryParams,\n>(props: LiveQueryClientComponentProps<QueryResult, QueryParams>): React.ReactNode {\n const {initialData, query, params, children, throwOnMissingProvider = true} = props\n const [data, enabled] = useLiveQuery<QueryResult, QueryParams>(initialData, query, params)\n // This hook is only used by `LiveQuery` when its `enabled` prop is true,\n // so we can reliably assume that if a parent provider is missing then that's an error\n if (throwOnMissingProvider && !enabled) {\n // Throw and let them know a parent <LiveQueryProvider> is missing\n throw new Error(\n `<LiveQuery> require you to wrap them in a parent <LiveQueryProvider> when its 'enabled' prop is true, or set the 'throwOnMissingProvider' prop to 'false' to ignore this error`,\n )\n }\n\n /**\n * The original source for the rest of this component is `Slot` from `@radix-ui/react-slot`: https://github.com/radix-ui/primitives/blob/3e0642e40038386d58da9fb1d812c2fbfe9f67c1/packages/react/slot/src/Slot.tsx\n * It's copied and modified here as the original doesn't override the props on children, which would require us to use this pattern:\n * ```<LiveQuery initialData={data}><Posts /></LiveQuery>```\n * However, we want to use this pattern as it preserves the same type safety as before live queries are added:\n * ```<LiveQuery initialData={data}><Posts data={data} /></LiveQuery>```\n *\n * It also made sense to modify the original as our use case is smaller than radix, for example we don't have to worry about merging `style` props\n */\n if (isValidElement(children)) {\n return cloneElement(children, {\n // eslint-disable-next-line no-warning-comments\n // @ts-expect-error -- @todo fix the typings\n ...children.props,\n // all child props should override, except for `data`\n data,\n // eslint-disable-next-line no-warning-comments\n // @ts-expect-error -- @todo fix the typings\n ref: children.ref,\n })\n }\n\n return Children.count(children) > 1 ? Children.only(null) : null\n}\nLiveQueryClientComponent.displayName = 'LiveQueryClientComponent'\n\n/** @public */\nexport type {LiveQueryClientComponent}\n"],"names":["useContext","defineStoreContext","useQueryParams","useMemo","useState","useCallback","useSyncExternalStore","isValidElement","cloneElement","Children"],"mappings":";;;AAWgB,SAAA,aAId,aACA,OACA,cAC6B;AACvB,QAAA,cAAcA,iBAAWC,wBAAkB,GAC3C,cAAcC,qBAAe,YAAY,GACzC,QAAQC,MAAA;AAAA,IACZ,MAAM,cAA2B,aAAa,OAAO,WAAW;AAAA,IAChE,CAAC,aAAa,aAAa,aAAa,KAAK;AAAA,EAAA,GAIzC,CAAC,cAAc,IAAIC,MAAAA,SAAS,MAAM;AACtC,QAAI,gBAAgB;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAEE,QAAA;AACF,aAAO,KAAK,MAAM,KAAK,UAAU,WAAW,CAAC;AAAA,aACtC,OAAO;AAEN,aAAA,QAAA;AAAA,QACN;AAAA,QACA,EAAC,iBAAiB,aAAa,MAAK;AAAA,MAAA,GAE/B;AAAA,IAAA;AAAA,EACT,CACD,GACK,oBAAoBC,MAAA,YAAY,MAAM,gBAAgB,CAAC,cAAc,CAAC;AAErE,SAAA;AAAA,IACLC,MAAA;AAAA,MACE,OAAO,aAAa;AAAA,MACpB,OAAO,eAAe;AAAA,MACtB;AAAA,IACF;AAAA,IACA,gBAAgB;AAAA,EAClB;AACF;AAEA,SAAS,OAAO;AACd,SAAO,MAAM;AAAA,EAAC;AAChB;ACnCA,SAAwB,yBAGtB,OAAiF;AACjF,QAAM,EAAC,aAAa,OAAO,QAAQ,UAAU,yBAAyB,GAAI,IAAI,OACxE,CAAC,MAAM,OAAO,IAAI,aAAuC,aAAa,OAAO,MAAM;AAGzF,MAAI,0BAA0B,CAAC;AAE7B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAYF,SAAIC,qBAAe,QAAQ,IAClBC,MAAAA,aAAa,UAAU;AAAA;AAAA;AAAA,IAG5B,GAAG,SAAS;AAAA;AAAA,IAEZ;AAAA;AAAA;AAAA,IAGA,KAAK,SAAS;AAAA,EAAA,CACf,IAGIC,MAAAA,SAAS,MAAM,QAAQ,IAAI,IAAIA,eAAS,KAAK,IAAI,IAAI;AAC9D;AACA,yBAAyB,cAAc;;"}