@marktiderman/genesis-ui 2.10.1 → 2.12.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/SKILL.md +59 -1
- package/dist/AppShell-DpQdcLE-.d.ts +347 -0
- package/dist/{chunk-C7PQ54JI.js → chunk-3TWCZYZY.js} +43 -13
- package/dist/chunk-3TWCZYZY.js.map +1 -0
- package/dist/{chunk-WGMEVX3Y.js → chunk-KC43CNMA.js} +2 -2
- package/dist/{chunk-WGMEVX3Y.js.map → chunk-KC43CNMA.js.map} +1 -1
- package/dist/{chunk-UYI3GLFJ.js → chunk-SZMXNC5Q.js} +722 -159
- package/dist/chunk-SZMXNC5Q.js.map +1 -0
- package/dist/{chunk-OITWCIG2.js → chunk-XGG5RUDE.js} +3 -3
- package/dist/{chunk-OITWCIG2.js.map → chunk-XGG5RUDE.js.map} +1 -1
- package/dist/components/data/index.d.ts +5 -5
- package/dist/components/data/index.js +32 -6
- package/dist/components/data/index.js.map +1 -1
- package/dist/components/layout/index.d.ts +2 -2
- package/dist/components/layout/index.js +3 -2
- package/dist/components/rich-text/rich-text-editor.js +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +3 -3
- package/dist/hooks/use-data-filters.d.ts +1 -1
- package/dist/hooks/use-data-filters.js +2 -2
- package/dist/hooks/use-resource-url-state.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/{navigation-Bha0R3Fu.d.ts → navigation-By1DrzaM.d.ts} +24 -0
- package/dist/router/react-router.d.ts +1 -1
- package/dist/router/tanstack-router.d.ts +1 -1
- package/dist/router/tanstack-router.js +1 -1
- package/dist/{use-resource-table-DCVf_lEG.d.ts → use-resource-table-DrTkD5O1.d.ts} +32 -3
- package/package.json +4 -3
- package/dist/AppShell-BVr4V0UK.d.ts +0 -174
- package/dist/chunk-C7PQ54JI.js.map +0 -1
- package/dist/chunk-UYI3GLFJ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/data/undo-toast.ts","../src/components/data/use-resource-table.ts"],"names":[],"mappings":"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","file":"chunk-3TWCZYZY.js","sourcesContent":["import type { MutationMode, UndoableWrite } from \"@marktiderman/genesis-core/hooks\";\nimport { toast } from \"../ui/sonner\";\n\nconst DONE: Record<UndoableWrite[\"kind\"], string> = {\n create: \"Created.\",\n update: \"Saved.\",\n delete: \"Deleted.\",\n};\n\n/**\n * The undo toast for an `undoable` write (core's `onUndoable`): a sonner\n * toast with an Undo button, shown for as long as the undo is offered.\n * Needs a mounted `<Toaster />`.\n */\nexport function showUndoToast(write: UndoableWrite): void {\n toast(DONE[write.kind], {\n duration: write.delayMs,\n action: {\n label: \"Undo\",\n onClick: () => {\n void write.undo().then((undone) => {\n // Sonner pauses on hover, so the button can outlive the window.\n if (!undone && write.strategy === \"delay\") {\n toast(\"Already saved. It can no longer be undone.\");\n }\n });\n },\n },\n });\n}\n\n/** The default error report for writes that fail after the form has closed. */\nexport function showWriteErrorToast(error: Error): void {\n toast.error(error.message || \"The change could not be saved.\");\n}\n\n/**\n * ResourcePage's write-mode options for its `useResource`: the page's\n * `mutationMode` unless `resourceOptions` sets one, the undo toast, and an\n * error toast for a write that fails after it was shown as done.\n */\nexport function writeModeOptions(\n resourceOptions: { mutationMode?: MutationMode; onUndoable?: (write: UndoableWrite) => void; onError?: (error: Error) => void } | undefined,\n mutationMode: MutationMode | undefined,\n): { mutationMode: MutationMode; onUndoable: (write: UndoableWrite) => void; onError?: (error: Error) => void } {\n const mode = resourceOptions?.mutationMode ?? mutationMode ?? \"pessimistic\";\n return {\n mutationMode: mode,\n onUndoable: resourceOptions?.onUndoable ?? showUndoToast,\n onError: resourceOptions?.onError ?? (mode === \"pessimistic\" ? undefined : showWriteErrorToast),\n };\n}\n","\"use client\";\n\n/**\n * `useResourceTable`: ResourcePage's behaviour without its markup. Lives\n * apart from ResourcePage.tsx so importing the hook (e.g. from `/hooks`)\n * does not pull in the page's components and icons.\n */\nimport { useMemo, useState, useCallback, useEffect, useRef } from \"react\";\nimport type { DataTableColumn, DataTableSort } from \"./DataTable\";\nimport type {\n ResourceAction,\n ResourceDeleteConfirmCopy,\n ResourcePageProps,\n} from \"./ResourcePage\";\nimport { useViewSettings } from \"../../hooks/use-view-settings\";\nimport { useKeyboardNavigation } from \"../../hooks/use-keyboard-navigation\";\nimport { useResourceUrlState } from \"../../hooks/use-resource-url-state\";\nimport {\n useResourcePage,\n type ResourceActions,\n} from \"../../hooks/use-resource-page\";\nimport {\n useCapabilities,\n useInfiniteResource,\n useOne,\n useResource,\n} from \"@marktiderman/genesis-core/hooks\";\nimport type {\n BaseRecord,\n Identifier,\n} from \"@marktiderman/genesis-core/provider\";\nimport { writeModeOptions } from \"./undo-toast\";\nimport { toast } from \"../ui/sonner\";\nimport { defaultNavigate } from \"../../navigation\";\n\n/**\n * Everything ResourcePage's markup reads. Internal: its names may change in\n * any release. Apps use {@link useResourceTable}.\n *\n * @internal\n */\nexport function useResourceTableModel<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(props: ResourcePageProps<T>) {\n const {\n resource: resourceName,\n data: dataProp,\n total: totalProp,\n pagination = \"client\",\n clientRowLimit = 1000,\n title,\n subtitle,\n icon,\n columns: columnsProp,\n getKey: getKeyProp,\n detail = \"panel\",\n detailWidth = \"md\",\n titleField: titleFieldProp,\n subtitleField: subtitleFieldProp,\n getTitle,\n getSubtitle,\n renderDetail: renderDetailProp,\n detailFields,\n statusFilter,\n searchFields,\n searchPlaceholder,\n initialFilters,\n onFiltersChange,\n filters: filtersProp,\n page: pageProp,\n perPage: perPageProp,\n onPageChange,\n onPerPageChange,\n onSortChange,\n onSearchChange,\n loading: loadingProp,\n error: errorProp,\n errorMessage,\n onRetry: onRetryProp,\n savedViews,\n onLoadView,\n onSaveView,\n onDeleteView,\n canSaveViews,\n columnVisibility,\n columnVisibilityKey,\n resizableColumns,\n resizeKey,\n stickyHeader,\n stickyFirstColumn,\n pageSizeOptions,\n onCreate,\n onEdit,\n onDelete,\n can,\n canEditItem,\n createLabel = \"New\",\n canEdit,\n canDelete,\n allowDelete,\n confirmDelete,\n onDeleted,\n secondaryActions,\n allowCreate,\n allowEdit,\n formFields,\n renderForm: renderFormProp,\n formMode,\n formSteps,\n formLayout: formLayoutProp,\n mutationMode: mutationModeProp,\n bulkActions,\n renderCard: renderCardProp,\n openOnCardClick = false,\n renderTable: renderTableProp,\n gridCols: gridColsProp,\n keyboardNavigation = true,\n capabilities,\n toolbar,\n emptyState,\n emptyIcon,\n emptyMessage,\n emptyDescription,\n header: headerMode = \"page\",\n resourceOptions,\n live,\n urlState: urlStateProp,\n defaultView = \"table\",\n onNavigate = defaultNavigate,\n viewSettingsKey: viewSettingsKeyProp,\n slots,\n slotProps,\n className,\n } = props;\n\n // ── Determine mode ──\n const isClientMode = !!resourceName;\n\n /**\n * Server-controlled mode is entered by supplying ANY of the controlled\n * props — presence is the switch, so a caller that only pages (no server\n * search) still gets its `data` left alone.\n */\n // `resource` mode paging through the provider: ResourcePage owns both the\n // fetch and the page state, and reuses the server-controlled path below\n // (no client-side transform, the pager under the list) with useResource's\n // setters standing in for the caller's callbacks.\n const resourceServerPaging = isClientMode && pagination === \"server\";\n // `pagination=\"cursor\"`: pages load by cursor and append (\"Load more\").\n const resourceCursorPaging = isClientMode && pagination === \"cursor\";\n\n // ── URL state (`urlState`): the open record, search, sort and page ──\n // An adapter has `setSearchParams`; the options object wraps one.\n const url = useResourceUrlState(\n urlStateProp\n ? \"setSearchParams\" in urlStateProp\n ? { searchParams: urlStateProp }\n : urlStateProp\n : undefined,\n );\n // Read once: the URL seeds the list when it mounts, then follows it.\n const [urlSeed] = useState(() => {\n if (!url) return null;\n // A URL sort only counts when it names a sortable column: a hand-edited\n // or stale link must not send an arbitrary field to the provider.\n const sortable =\n !url.sort || !columnsProp\n ? true\n : columnsProp.some((col) =>\n typeof col === \"string\"\n ? col === url.sort!.field\n : col.key === url.sort!.field && col.sortable !== false,\n );\n return { q: url.q, sort: sortable ? url.sort : null, page: url.page };\n });\n // The URL names the open record only where there is a peek to open.\n const urlPeek = detail === \"panel\" || detail === \"modal\" ? url : undefined;\n const urlSortKey = urlSeed?.sort\n ? `${urlSeed.sort.field}:${urlSeed.sort.order}`\n : \"\";\n\n const isServerControlled =\n resourceServerPaging ||\n pageProp !== undefined ||\n perPageProp !== undefined ||\n onPageChange !== undefined ||\n onPerPageChange !== undefined ||\n onSortChange !== undefined ||\n onSearchChange !== undefined;\n\n const viewSettingsKey =\n viewSettingsKeyProp ??\n resourceName ??\n title.toLowerCase().replace(/\\s+/g, \"-\");\n const { settings, updateSetting } = useViewSettings(viewSettingsKey);\n\n // Server search needs the columns to match. Without them the provider\n // would get a query it ignores, so the search box hides instead of lying.\n const serverSearchFields = resourceOptions?.searchFields ?? searchFields;\n\n // ── Client-side mode: call useResource (hook is always called for rules-of-hooks) ──\n // Core's useResource constrains its row type to BaseRecord (rows carry an\n // `id`), which is stricter than ResourcePage's public `T extends\n // Record<string, unknown>`. Intersect at the call site so the public\n // ResourcePageProps<T> generic stays unchanged while satisfying the hook.\n const resourceHook = useResource<T & BaseRecord>(\n resourceName ?? \"__noop__\",\n isClientMode\n ? {\n ...resourceOptions,\n // Client paging fetches everything it can in one request; server\n // paging starts at the user's stored page size. An explicit\n // `defaultPerPage` wins over both.\n defaultPerPage:\n resourceOptions?.defaultPerPage ??\n (resourceServerPaging\n ? (perPageProp ?? settings.pageSize)\n : clientRowLimit),\n searchFields: resourceServerPaging\n ? serverSearchFields\n : resourceOptions?.searchFields,\n // Paging, searching and sorting change the query key; keep the\n // current page on screen while the next one loads.\n keepPreviousData:\n resourceOptions?.keepPreviousData ?? resourceServerPaging,\n // Start where the URL says, so restoring a link doesn't push a\n // search or sort that resets the page to 1.\n ...(resourceServerPaging && urlSeed\n ? {\n defaultSearch: urlSeed.q,\n ...(urlSeed.page ? { defaultPage: urlSeed.page } : {}),\n ...(urlSeed.sort ? { defaultSort: urlSeed.sort } : {}),\n }\n : {}),\n ...writeModeOptions(resourceOptions, mutationModeProp),\n // Cursor paging reads through useInfiniteResource below; this hook\n // only writes.\n ...(resourceCursorPaging ? { enabled: false } : {}),\n live: resourceOptions?.live ?? live,\n }\n : { enabled: false },\n );\n const infinite = useInfiniteResource<T & BaseRecord>(resourceName ?? \"__noop__\", {\n enabled: resourceCursorPaging && (resourceOptions?.enabled ?? true),\n perPage: resourceOptions?.defaultPerPage ?? perPageProp ?? settings.pageSize,\n defaultSort: resourceOptions?.defaultSort,\n defaultFilters: resourceOptions?.defaultFilters,\n select: resourceOptions?.select,\n live: resourceOptions?.live ?? live,\n });\n\n /** Explicit prop beats the per-user stored preference. */\n const effectivePageSize = resourceServerPaging\n ? (resourceHook.params.pagination?.perPage ?? settings.pageSize)\n : (perPageProp ?? settings.pageSize);\n\n // ── Resolve display data ──\n const displayData: T[] = resourceCursorPaging\n ? infinite.rows\n : isClientMode\n ? (resourceHook.list.data?.data ?? [])\n : (dataProp ?? []);\n const displayTotal: number = resourceCursorPaging\n ? (infinite.total ?? infinite.rows.length)\n : isClientMode\n ? (resourceHook.list.data?.total ?? 0)\n : (totalProp ?? 0);\n // Client-side mode reads the hook it owns; server-data mode reads the\n // caller's `loading` / `error` props, defaulting to false so a page that\n // supplies neither renders exactly as it did before they existed.\n const isLoading = resourceCursorPaging\n ? infinite.query.isLoading\n : isClientMode\n ? resourceHook.list.isLoading\n : (loadingProp ?? false);\n const hasError = resourceCursorPaging\n ? infinite.query.isError\n : isClientMode\n ? resourceHook.list.isError\n : (errorProp ?? false);\n\n // ── Call useResourcePage ──\n const page = useResourcePage<T>({\n resource: resourceName,\n data: displayData,\n total: displayTotal,\n columns: columnsProp,\n statusFilter,\n searchFields,\n initialFilters:\n initialFilters ??\n (urlSeed && (urlSeed.q || urlSeed.sort)\n ? [\n ...(urlSeed.q\n ? [{ field: \"__search__\", operator: \"contains\" as const, value: urlSeed.q }]\n : []),\n ...(urlSeed.sort\n ? [{ field: \"__sort__\", operator: \"eq\" as const, value: urlSortKey }]\n : []),\n ]\n : undefined),\n onFiltersChange,\n defaultView,\n // Each page remembers its own table/cards choice, under the same key as\n // its density and page size — not one key shared by every data page.\n viewKey: viewSettingsKey,\n detail,\n titleField: titleFieldProp,\n subtitleField: subtitleFieldProp,\n controlled: isServerControlled,\n });\n\n // ── `pagination=\"server\"`: push the filter row's state into useResource ──\n // Effects rather than the change handlers, so `initialFilters` and \"Clear\n // all\" reach the provider by the same path as a keystroke. Each push is\n // skipped while its value still equals what the hook already has, so the\n // first render does not reset `defaultSort` or refetch for nothing.\n const {\n setSearch: setResourceSearch,\n setSort: setResourceSort,\n setFilters: setResourceFilters,\n } = resourceHook;\n // Seeded from the URL, which useResource already starts on (see above).\n const pushedSearchRef = useRef(resourceServerPaging ? (urlSeed?.q ?? \"\") : \"\");\n const searchEffectRanRef = useRef(false);\n useEffect(() => {\n if (!resourceServerPaging) return;\n const firstRun = !searchEffectRanRef.current;\n searchEffectRanRef.current = true;\n if (page.search === pushedSearchRef.current) return;\n const push = () => {\n pushedSearchRef.current = page.search;\n setResourceSearch(page.search);\n };\n // One request per pause in typing, not per keystroke — but an\n // `initialFilters` search (first run) or a cleared box (\"Clear all\")\n // goes out at once, landing with the sort / status pushes instead of\n // 300ms behind them.\n if (firstRun || page.search === \"\") {\n push();\n return;\n }\n const timer = setTimeout(push, 300);\n return () => clearTimeout(timer);\n }, [resourceServerPaging, page.search, setResourceSearch]);\n\n const defaultSort = resourceOptions?.defaultSort;\n const pushedSortRef = useRef<string>(resourceServerPaging ? urlSortKey : \"\");\n useEffect(() => {\n if (!resourceServerPaging) return;\n const key = page.sort ? `${page.sort.field}:${page.sort.order}` : \"\";\n if (key === pushedSortRef.current) return;\n pushedSortRef.current = key;\n // Clearing the sort returns to the resource's default order, not to\n // whatever order the provider happens to use.\n setResourceSort(page.sort ?? defaultSort);\n }, [resourceServerPaging, page.sort, defaultSort, setResourceSort]);\n\n const statusField = statusFilter\n ? typeof statusFilter === \"string\"\n ? statusFilter\n : statusFilter.field\n : undefined;\n const defaultFilters = resourceOptions?.defaultFilters;\n const pushedStatusRef = useRef<string>(\"\");\n useEffect(() => {\n if (!resourceServerPaging || !statusField) return;\n // `defaultFilters` is part of the key: useResource re-syncs its filters\n // to a changed `defaultFilters` (dropping the status filter), so a\n // change there must re-push even when the chips did not move.\n const key = JSON.stringify([page.statusValue, defaultFilters ?? null]);\n if (key === pushedStatusRef.current) return;\n pushedStatusRef.current = key;\n setResourceFilters([\n ...(defaultFilters ?? []),\n ...(page.statusValue.length > 0\n ? [{ field: statusField, operator: \"in\" as const, value: page.statusValue }]\n : []),\n ]);\n }, [\n resourceServerPaging,\n statusField,\n page.statusValue,\n defaultFilters,\n setResourceFilters,\n ]);\n\n // ── `pagination=\"client\"`: say so when the resource outgrew the fetch ──\n const clientTruncated =\n isClientMode &&\n !resourceServerPaging &&\n !resourceCursorPaging &&\n !isLoading &&\n !hasError &&\n displayTotal > displayData.length;\n const warnedTruncatedRef = useRef(false);\n useEffect(() => {\n if (!clientTruncated || warnedTruncatedRef.current) return;\n warnedTruncatedRef.current = true;\n console.warn(\n `ResourcePage: \"${resourceName}\" has ${displayTotal} rows but only ${displayData.length} were fetched. ` +\n `Pass \\`pagination=\"server\"\\` to page through all of them, or raise \\`clientRowLimit\\` ` +\n `(no higher than the provider's \\`maxPerPage\\`, which refuses a larger page).`,\n );\n }, [clientTruncated, resourceName, displayTotal, displayData.length]);\n // ── Build ResourceActions for column render functions ──\n // `refetch` is stable; the query results around it are new each render.\n const refetchList = resourceHook.list.refetch;\n const refetchInfinite = infinite.query.refetch;\n const actions: ResourceActions<T> = useMemo(() => {\n if (isClientMode) {\n return {\n update: resourceHook.update as ResourceActions<T>[\"update\"],\n remove: resourceHook.remove,\n refetch: () => (resourceCursorPaging ? refetchInfinite() : refetchList()),\n };\n }\n return {\n update: async () => {\n throw new Error(\n \"ResourceActions.update not available in server-data mode\",\n );\n },\n remove: async () => {\n throw new Error(\n \"ResourceActions.remove not available in server-data mode\",\n );\n },\n refetch: () => {\n /* no-op in server-data mode */\n },\n };\n }, [\n isClientMode,\n resourceHook.update,\n resourceHook.remove,\n refetchList,\n resourceCursorPaging,\n refetchInfinite,\n ]);\n\n // ── Row identity ──\n const keyOf = useCallback(\n (item: T): string =>\n getKeyProp ? getKeyProp(item) : String((item as Record<string, unknown>).id ?? \"\"),\n [getKeyProp],\n );\n\n // ── The peek's row, kept live ──\n // `page.selectedItem` is a snapshot taken at click time. Re-resolving it by\n // key against the current rows means a save (which refetches) shows its\n // new values in the open peek instead of the pre-edit copy. A row missing\n // from the current rows keeps the snapshot: paging, sorting, search and\n // filters all drop rows that still exist. A confirmed delete closes the\n // peek itself (`performDelete`).\n // An empty key (rows with no `id` and no `getKey`) identifies nothing, so\n // it keeps the snapshot rather than matching the first keyless row.\n // With `urlState` the URL names the open record (`?id=`): a link opens it,\n // and Back closes it. The click-time snapshot still covers a record that\n // isn't in the current rows.\n const snapshotKey = page.selectedItem ? keyOf(page.selectedItem) : null;\n const selectedKey = urlPeek ? urlPeek.detailId : snapshotKey;\n const snapshot =\n page.selectedItem && snapshotKey === selectedKey ? page.selectedItem : null;\n const rowOrSnapshot: T | null = !selectedKey\n ? snapshot\n : (displayData.find((row) => keyOf(row) === selectedKey) ?? snapshot);\n // A linked record that isn't in the loaded rows (another page, outside the\n // search) is fetched on its own; one that can't be read shows as missing.\n const linkedId = urlPeek && selectedKey && !rowOrSnapshot ? selectedKey : null;\n const linked = useOne<T & BaseRecord>(resourceName ?? \"__noop__\", linkedId, {\n enabled: isClientMode && !!linkedId,\n });\n const selectedItem: T | null =\n rowOrSnapshot ?? (linkedId && linked.data ? (linked.data as T) : null);\n // Missing only when that is known: the fetch failed (resource mode), or\n // `data` is the whole set (data mode without server paging). A record\n // absent from one server-controlled page may be on another.\n const linkMissing =\n !!linkedId &&\n !selectedItem &&\n !isLoading &&\n (isClientMode ? linked.isError : !isServerControlled);\n const detailOpen = urlPeek ? selectedItem !== null || linkMissing : page.detailOpen;\n\n // ── Bulk selection ──\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n\n const handleToggleSelect = useCallback((id: string) => {\n setSelectedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }, []);\n\n const handleToggleAll = useCallback(() => {\n setSelectedIds((prev) => {\n if (prev.size === page.data.length) return new Set();\n return new Set(page.data.map(keyOf));\n });\n }, [page.data, keyOf]);\n\n const handleClearSelection = useCallback(() => {\n setSelectedIds(new Set());\n }, []);\n\n // ── Built-in form state ──\n const [formOpen, setFormOpen] = useState(false);\n const [formAction, setFormAction] = useState<\"create\" | \"edit\">(\"create\");\n const [formItem, setFormItem] = useState<T | null>(null);\n\n // Determine if built-in form should handle create/edit\n const useBuiltInCreate = allowCreate && !onCreate && isClientMode;\n const useBuiltInEdit = allowEdit && !onEdit && isClientMode;\n\n const handleCreate = useCallback(() => {\n if (useBuiltInCreate) {\n setFormAction(\"create\");\n setFormItem(null);\n setFormOpen(true);\n } else if (onCreate) {\n onCreate();\n }\n }, [useBuiltInCreate, onCreate]);\n\n // One permission check: `can`, then the deprecated per-row predicates.\n const allows = useCallback(\n (action: ResourceAction, item?: T): boolean => {\n if (can && !can(action, item)) return false;\n if (!item) return true;\n if (canEditItem && !canEditItem(item)) return false;\n if (action === \"edit\" && canEdit && !canEdit(item)) return false;\n if (action === \"delete\" && canDelete && !canDelete(item)) return false;\n return true;\n },\n [can, canEditItem, canEdit, canDelete],\n );\n\n const handleEdit = useCallback(\n (item: T) => {\n if (!allows(\"edit\", item)) return;\n if (useBuiltInEdit) {\n setFormAction(\"edit\");\n setFormItem(item);\n setFormOpen(true);\n } else if (onEdit) {\n onEdit(item);\n }\n },\n [useBuiltInEdit, onEdit, allows],\n );\n\n const closeDetail = useCallback(() => {\n page.setDetailOpen(false);\n page.setSelectedItem(null);\n urlPeek?.setDetailId(null);\n }, [page, urlPeek]);\n\n // ── Delete: built-in, confirmed, or the caller's as-is ──\n const useBuiltInDelete = !!allowDelete && !onDelete && isClientMode;\n const deleteConfirmed =\n confirmDelete === undefined ? useBuiltInDelete : !!confirmDelete;\n const deleteCopy =\n typeof confirmDelete === \"object\" ? confirmDelete : undefined;\n // The row being confirmed, kept after the dialog closes so its copy does\n // not flip to the defaults during the exit animation; `deleteOpen` is what\n // actually opens and closes it.\n const [pendingDelete, setPendingDelete] = useState<T | null>(null);\n const [deleteOpen, setDeleteOpen] = useState(false);\n const { remove: removeRecord } = resourceHook;\n // A recycle-bin resource says so in the confirm step instead of \"can't be undone\".\n const { data: providerCaps } = useCapabilities(resourceName, {\n enabled: useBuiltInDelete && deleteConfirmed,\n });\n const deleteKind: \"recycle\" | \"permanent\" = providerCaps?.softDelete ? \"recycle\" : \"permanent\";\n\n const performDelete = useCallback(\n async (item: T) => {\n if (useBuiltInDelete) {\n // A caller-supplied `getKey` (e.g. `encodeRecordKey` for a composite\n // key) is the row's identity to the provider too; otherwise `id`.\n await removeRecord(\n (getKeyProp\n ? keyOf(item)\n : (item as Record<string, unknown>).id) as Identifier,\n );\n } else if (onDelete) {\n await onDelete(item);\n }\n closeDetail();\n onDeleted?.(item);\n },\n [\n useBuiltInDelete,\n removeRecord,\n getKeyProp,\n keyOf,\n onDelete,\n closeDetail,\n onDeleted,\n ],\n );\n\n const deleteHandler: ((item: T) => void) | undefined = !(\n useBuiltInDelete || onDelete\n )\n ? undefined\n : deleteConfirmed\n ? (item: T) => {\n setPendingDelete(item);\n setDeleteOpen(true);\n }\n : useBuiltInDelete\n ? (item: T) => {\n performDelete(item).catch((err: unknown) => {\n // useResource has already handed the failure to\n // `resourceOptions.onError`; without one, the user is told.\n if (!resourceOptions?.onError) {\n toast.error(err instanceof Error ? err.message : \"The delete failed.\");\n }\n });\n }\n : // Unconfirmed `onDelete` keeps its original contract exactly:\n // called straight from the peek, nothing closed for it.\n (item: T) => {\n // A throw or a rejected promise is reported, never left unhandled,\n // even when `onError` itself throws (the toast is the fallback).\n const report = (err: unknown) => {\n const error = err instanceof Error ? err : new Error(String(err));\n if (resourceOptions?.onError) {\n try {\n resourceOptions.onError(error);\n return;\n } catch {\n // fall through to the toast\n }\n }\n toast.error(error.message || \"The delete failed.\");\n };\n // Called right away, as before; a throw or a rejection is reported.\n try {\n Promise.resolve(onDelete?.(item)).catch(report);\n } catch (err) {\n report(err);\n }\n };\n\n // Per-row rights, evaluated against the row the peek is showing.\n const selectedEditable = !!selectedItem && allows(\"edit\", selectedItem);\n const selectedDeletable = !!selectedItem && allows(\"delete\", selectedItem);\n\n // ── Patch tableColumns to use real actions (client-side mode) ──\n const tableColumns = useMemo(() => {\n const base = isClientMode\n ? page.columns.map((col) => ({\n key: col.key,\n header: col.header ?? col.key,\n sortable: col.sortable ?? true,\n hideBelow: col.hideBelow,\n width: col.width,\n minWidth: col.minWidth,\n defaultVisible: col.defaultVisible,\n editable: col.editable,\n accessor: col.accessor,\n render: col.render\n ? (item: T, value: unknown) => col.render!(item, value, actions)\n : undefined,\n }))\n : page.tableColumns;\n if (!isServerControlled) return base;\n // The server owns the ordering. DataTable's header sort is client-side\n // and would only reorder the rows of the current page — a visibly wrong\n // answer presented as a sort — so the affordance is withdrawn rather\n // than left to lie. The DataFilters sort control drives `onSortChange`.\n return base.map((col) => ({ ...col, sortable: false }));\n }, [\n isClientMode,\n isServerControlled,\n page.columns,\n page.tableColumns,\n actions,\n ]);\n\n // ── Client mode: DataTable's header sort is `page.sort` ──\n // The primary header sort is the page's sort (and so the URL's); Shift-\n // click tie-breakers are kept here while that primary still matches, and\n // dropped when the sort changes elsewhere (the sort select, the URL).\n const [tableTieBreaks, setTableTieBreaks] = useState<{\n primary: string;\n rest: DataTableSort[];\n } | null>(null);\n const pageSort = page.sort;\n const setPageSort = page.setSort;\n const tableSort = useMemo<DataTableSort[]>(() => {\n if (!pageSort) return [];\n const primary: DataTableSort = { key: pageSort.field, dir: pageSort.order };\n const rest =\n tableTieBreaks && tableTieBreaks.primary === `${primary.key}:${primary.dir}`\n ? tableTieBreaks.rest\n : [];\n // Only the table's own columns: a sort-select option or a URL sort on a\n // field the table doesn't show still orders the rows (page.sort), but is\n // not a header sort.\n return [primary, ...rest].filter((s) => tableColumns.some((c) => c.key === s.key));\n }, [pageSort, tableTieBreaks, tableColumns]);\n const handleTableSort = useCallback(\n (next: DataTableSort[]) => {\n const [primary, ...rest] = next;\n setTableTieBreaks(primary ? { primary: `${primary.key}:${primary.dir}`, rest } : null);\n setPageSort(primary ? { field: primary.key, order: primary.dir } : null);\n },\n [setPageSort],\n );\n\n // ── Server-driven pager state, needed above for handleSearchChange's\n // already-on-page-1 check. ──\n // The pager's inputs: the caller's controlled props, or — for\n // `pagination=\"server\"` — useResource's own page state.\n const pagerPage = resourceServerPaging\n ? (resourceHook.params.pagination?.page ?? 1)\n : pageProp;\n const pagerPerPage = resourceServerPaging\n ? resourceHook.params.pagination?.perPage\n : perPageProp;\n const pagerTotal = resourceServerPaging ? displayTotal : totalProp;\n const pagerOnPageChange = resourceServerPaging\n ? resourceHook.setPage\n : onPageChange;\n const currentPage = pagerPage ?? 1;\n\n // ── `urlState`: write search, sort and (server paging) page back ──\n // Replace-only, so Back steps through opened records rather than every\n // keystroke; an unchanged URL is not rewritten.\n const writeUrl = url?.write;\n useEffect(() => {\n writeUrl?.({\n q: page.search,\n sort: page.sort,\n ...(resourceServerPaging ? { page: currentPage } : {}),\n });\n }, [writeUrl, page.search, page.sort, currentPage, resourceServerPaging]);\n\n // ── Filter changes: keep the controlled UI state, and tell the server ──\n // In client-side mode these are exactly the hook's own setters; in\n // server-controlled mode they additionally notify the caller and reset to\n // page 1, since the previous page number is meaningless against a new\n // query. The reset is skipped when already on page 1 — nothing changed,\n // so there is nothing for the caller to do.\n const handleSearchChange = useCallback(\n (value: string) => {\n page.filterConfig.onSearchChange(value);\n if (!isServerControlled) return;\n onSearchChange?.(value);\n // `pagination=\"server\"`: useResource's setSearch resets the page\n // itself once the debounce settles; resetting here too would fetch\n // page 1 of the OLD query first.\n if (currentPage !== 1 && !resourceServerPaging) onPageChange?.(1);\n },\n [\n page.filterConfig,\n isServerControlled,\n onSearchChange,\n onPageChange,\n resourceServerPaging,\n currentPage,\n ],\n );\n\n const handleSortSelect = useCallback(\n (value: string) => {\n page.filterConfig.onSortChange(value);\n if (!isServerControlled) return;\n const [field, order] = value.split(\":\");\n onSortChange?.(\n field && (order === \"asc\" || order === \"desc\")\n ? { field, order }\n : null,\n );\n // See handleSearchChange: useResource's setSort resets the page.\n if (!resourceServerPaging) onPageChange?.(1);\n },\n [\n page.filterConfig,\n isServerControlled,\n onSortChange,\n onPageChange,\n resourceServerPaging,\n ],\n );\n\n const handleClearFilters = useCallback(() => {\n page.clearFilters();\n if (!isServerControlled) return;\n // Clearing has to reach the server too — otherwise \"Clear all\" empties\n // the controls and leaves the same rows on screen.\n onSearchChange?.(\"\");\n onSortChange?.(null);\n if (!resourceServerPaging) onPageChange?.(1);\n }, [\n page,\n isServerControlled,\n onSearchChange,\n onSortChange,\n onPageChange,\n resourceServerPaging,\n ]);\n\n // ── Status-chip changes: same page-1 reset as search/sort ──\n // In server-controlled mode `useResourcePage` skips client-side status\n // filtering, so a status change only reaches the caller through\n // `onFiltersChange`. Nothing else calls `onPageChange(1)` for it, so\n // selecting a more restrictive status while on page 3 could otherwise\n // fetch page 3 of the new result set and render an empty page while the\n // matching rows sit on page 1. Guarded the same way as\n // `handleSearchChange`, and not reachable from `handleClearFilters`\n // (which already does its own single reset).\n const handleStatusChange = useCallback(\n (values: string[]) => {\n page.filterConfig.statusChips?.onChange(values);\n if (!isServerControlled) return;\n if (currentPage !== 1 && !resourceServerPaging) onPageChange?.(1);\n },\n [\n page.filterConfig,\n isServerControlled,\n onPageChange,\n resourceServerPaging,\n currentPage,\n ],\n );\n\n const statusChipsConfig = useMemo(() => {\n const base = page.filterConfig.statusChips;\n if (!base) return undefined;\n return { ...base, onChange: handleStatusChange };\n }, [page.filterConfig.statusChips, handleStatusChange]);\n\n const handlePageSizeChange = useCallback(\n (size: number) => {\n updateSetting(\"pageSize\", size);\n onPerPageChange?.(size);\n // useResource's setPerPage resets to page 1 itself.\n if (resourceServerPaging) resourceHook.setPerPage(size);\n else if (isServerControlled) onPageChange?.(1);\n },\n [\n updateSetting,\n onPerPageChange,\n resourceServerPaging,\n resourceHook.setPerPage,\n isServerControlled,\n onPageChange,\n ],\n );\n\n // ── Pagination-config error ──\n // `perPage` AND `total` are both required whenever `onPageChange` is\n // supplied. Neither can be derived from the other, and neither can be\n // derived from the rows:\n // - `perPage`: see the prop doc on `perPage`. A short final page has\n // fewer rows than the page size, so the row count of a page cannot\n // stand in for the page size.\n // - `total`: `displayTotal` falls back to `0` (Line 453). With `total`\n // omitted the range span reads \"No records\" and `Next` stays\n // disabled, while `page.data` renders rows directly below it. A\n // surface that says \"no records\" above visible records is a lie, not\n // a degraded view.\n // Rather than silently guess either one, the pager below refuses to\n // render and shows the error instead. Logged once per mount (not on\n // every render) so it's visible in a console without spamming it.\n const missingPerPage =\n isServerControlled && !!pagerOnPageChange && pagerPerPage === undefined;\n const missingTotal =\n isServerControlled && !!pagerOnPageChange && pagerTotal === undefined;\n const pagerMisconfigured = missingPerPage || missingTotal;\n const missingPagerProps = [\n ...(missingPerPage ? [\"perPage\"] : []),\n ...(missingTotal ? [\"total\"] : []),\n ];\n const loggedMissingPerPageRef = useRef(false);\n useEffect(() => {\n if (!pagerMisconfigured) return;\n if (loggedMissingPerPageRef.current) return;\n loggedMissingPerPageRef.current = true;\n console.error(\n `ResourcePage: ${missingPagerProps\n .map((name) => `\\`${name}\\``)\n .join(\" and \")} ${\n missingPagerProps.length > 1 ? \"are\" : \"is\"\n } required when \\`onPageChange\\` is supplied.`,\n );\n // `missingPagerProps` is derived from `pagerMisconfigured`'s own inputs\n // and the ref makes this run at most once, so it is not a dependency.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pagerMisconfigured]);\n\n // ── Server-driven pager math ──\n // By the time the pager renders, `pagerMisconfigured` has already gated\n // it off, so `perPageProp` and `totalProp` are both present here.\n const pagerPageSize = pagerPerPage ?? effectivePageSize;\n const totalPages = Math.max(\n 1,\n Math.ceil(displayTotal / Math.max(1, pagerPageSize)),\n );\n const rangeFrom =\n page.data.length === 0 ? 0 : (currentPage - 1) * pagerPageSize + 1;\n const rangeTo = rangeFrom === 0 ? 0 : rangeFrom + page.data.length - 1;\n\n // ── `pagination=\"server\"`: never strand the user past the last page ──\n // Deleting the last row of the last page (or any shrink in `total`) would\n // otherwise leave `page` beyond the end: the list comes back empty, the\n // shell swaps in its empty state — pager included — and there is no way\n // back. Step back to the real last page instead.\n const { setPage: setResourcePage } = resourceHook;\n const settledPage =\n !isLoading && !hasError && !resourceHook.list.isPlaceholderData;\n useEffect(() => {\n if (!resourceServerPaging || !settledPage) return;\n if (currentPage > totalPages) setResourcePage(totalPages);\n }, [resourceServerPaging, settledPage, currentPage, totalPages, setResourcePage]);\n\n // ── Detail title/subtitle values ──\n const titleOf = (item: T): string =>\n getTitle\n ? getTitle(item)\n : String((item as Record<string, unknown>)[page.titleField] ?? \"\");\n const detailTitle = selectedItem ? titleOf(selectedItem) : \"\";\n const detailSubtitle = !selectedItem\n ? undefined\n : getSubtitle\n ? getSubtitle(selectedItem)\n : page.subtitleField\n ? String(\n (selectedItem as Record<string, unknown>)[page.subtitleField] ?? \"\",\n )\n : undefined;\n\n // ── Row click handler (route mode navigates) ──\n const handleRowClick = (item: T) => {\n if (detail === \"route\") {\n // Navigate to /{resource}/{id}\n const id = (item as Record<string, unknown>).id;\n if (resourceName && id) {\n onNavigate(`/${resourceName}/${id}`);\n }\n return;\n }\n page.handleRowClick(item);\n urlPeek?.setDetailId(keyOf(item));\n };\n\n // ── Keyboard navigation (j/k, Enter, Backspace, x) ──\n // Only engaged for grid/list views: table view runs its own independent\n // client-side sort + pagination (DataTable), so a flat index into\n // `page.data` can't reliably be mapped back onto its currently-visible,\n // possibly differently-ordered rows.\n const hasBulkSelect = !!bulkActions && bulkActions.length > 0;\n // A detail panel/modal or the built-in form is covering the list. Cursor\n // keys suspend (they'd otherwise drive the list behind the overlay, and\n // Enter would re-open the row instead of activating the focused control);\n // ⌫ stays live so it can dismiss the overlay.\n const overlayOpen = detailOpen || formOpen || deleteOpen;\n const keyboardNav = useKeyboardNavigation({\n itemCount: page.data.length,\n enabled: keyboardNavigation && page.viewMode !== \"table\",\n overlayOpen,\n onOpen: (index) => {\n const item = page.data[index];\n if (item) handleRowClick(item);\n },\n onToggleSelect: hasBulkSelect\n ? (index) => {\n const item = page.data[index];\n if (item) {\n handleToggleSelect(keyOf(item));\n }\n }\n : undefined,\n // Supplied only while there is an open detail to close — the hook\n // suppresses Backspace's default whenever this is present, so leaving it\n // wired up permanently would swallow the browser/app's Backspace on\n // every grid/list page (including detail=\"none\" and detail=\"route\",\n // which never open one). `detailOpen` is only ever true for the panel\n // and modal modes, so it is the precise precondition here.\n onBack: detailOpen ? closeDetail : undefined,\n });\n\n // `pagination=\"cursor\"`: the \"Load more\" footer's state.\n const infinitePages = infinite.query.data?.pages;\n const loadMore = resourceCursorPaging\n ? {\n hasMore: infinite.hasNextPage,\n loading: infinite.isFetchingNextPage,\n load: infinite.fetchNextPage,\n loaded: infinite.rows.length,\n // Rows the latest \"Load more\" added; 0 before the first one.\n lastLoaded:\n infinitePages && infinitePages.length > 1\n ? infinitePages[infinitePages.length - 1]!.data.length\n : 0,\n }\n : undefined;\n\n // ── Create button ──\n\n return {\n actions,\n allows,\n clientTruncated,\n loadMore,\n closeDetail,\n currentPage,\n deleteConfirmed,\n deleteCopy,\n deleteHandler,\n deleteKind,\n deleteOpen,\n detailOpen,\n detailSubtitle,\n detailTitle,\n displayData,\n displayTotal,\n effectivePageSize,\n formAction,\n formItem,\n formOpen,\n handleClearFilters,\n handleClearSelection,\n handleCreate,\n handleEdit,\n handlePageSizeChange,\n handleRowClick,\n handleSearchChange,\n handleSortSelect,\n handleTableSort,\n handleToggleAll,\n handleToggleSelect,\n hasError,\n isClientMode,\n isLoading,\n isServerControlled,\n keyOf,\n keyboardNav,\n linkMissing,\n linked,\n missingPagerProps,\n page,\n pagerMisconfigured,\n pagerOnPageChange,\n pendingDelete,\n performDelete,\n rangeFrom,\n rangeTo,\n resourceHook,\n resourceServerPaging,\n selectedDeletable,\n selectedEditable,\n selectedIds,\n selectedItem,\n serverSearchFields,\n setDeleteOpen,\n setFormOpen,\n settings,\n statusChipsConfig,\n tableColumns,\n tableSort,\n titleOf,\n totalPages,\n updateSetting,\n useBuiltInCreate,\n useBuiltInDelete,\n useBuiltInEdit,\n };\n}\n\n/**\n * What {@link useResourceTable} returns: the list's rows and the handlers a\n * custom layout wires to its controls.\n *\n * @stability Beta\n */\nexport interface ResourceTableState<\n T extends Record<string, unknown> = Record<string, unknown>,\n> {\n // ── Rows ──\n /**\n * The rows to show: filtered and sorted. With `pagination=\"client\"` this\n * is every matching row (page it yourself); with server paging it is the\n * current page.\n */\n rows: T[];\n /**\n * How many rows match, across all pages. With `pagination=\"cursor\"` it is\n * the server's count while no search or status filter is active; with one,\n * only loaded rows are filtered, so it counts the loaded rows that match.\n */\n total: number;\n loading: boolean;\n /** The read failed. */\n error: boolean;\n /** True when more than `clientRowLimit` rows exist and only that many were loaded. */\n truncated: boolean;\n /**\n * `pagination=\"cursor\"`: whether more rows can be loaded, whether a page\n * is loading, and `load()` to append the next page. Undefined otherwise.\n */\n loadMore?: {\n hasMore: boolean;\n loading: boolean;\n load: () => void;\n /** Rows loaded so far. */\n loaded: number;\n /** Rows the latest load added (0 before the first \"Load more\"). */\n lastLoaded: number;\n };\n /** The columns, resolved to DataTable's format. */\n columns: DataTableColumn<T>[];\n /** Write actions for cell renderers (update, remove, …). */\n actions: ResourceActions<T>;\n /** A row's identity: `getKey`, else its `id`. */\n getKey: (item: T) => string;\n /** A row's title: `getTitle`, else its title field. */\n getTitle: (item: T) => string;\n /** The page's permission check (`can`, then the deprecated per-row predicates). */\n can: (action: ResourceAction, item?: T) => boolean;\n\n // ── Search, sort and filters ──\n search: string;\n setSearch: (value: string) => void;\n /** Sort keys, primary first. */\n sort: DataTableSort[];\n setSort: (sort: DataTableSort[]) => void;\n /** The status filter's choices, its selected values and its setter, when the list has one. */\n statusFilter:\n | { options: string[]; selected: string[]; onChange: (values: string[]) => void }\n | undefined;\n hasActiveFilters: boolean;\n clearFilters: () => void;\n\n // ── Paging (server or caller-controlled paging) ──\n /** The current page, from 1. */\n page: number;\n pageCount: number;\n pageSize: number;\n setPageSize: (size: number) => void;\n /** Go to a page; undefined when the page is not controlled (client paging). */\n setPage: ((page: number) => void) | undefined;\n /** The 1-based range of the rows shown, for \"21–40 of 95\"; 0 when empty. */\n rangeFrom: number;\n rangeTo: number;\n\n // ── Selection ──\n selectedIds: Set<string>;\n toggleSelected: (id: string) => void;\n toggleAll: () => void;\n clearSelection: () => void;\n\n // ── The open record ──\n /** The open row, kept current as the data changes. */\n openItem: T | null;\n detailOpen: boolean;\n /** What clicking a row does: opens the peek, modal or route. */\n openRow: (item: T) => void;\n closeDetail: () => void;\n /** A record linked by URL that does not exist (or was deleted). */\n openItemMissing: boolean;\n\n // ── Create and edit ──\n /** Undefined when the page cannot create. */\n create: (() => void) | undefined;\n edit: (item: T) => void;\n /** The built-in form's state, for rendering your own form. */\n form: {\n open: boolean;\n setOpen: (open: boolean) => void;\n action: \"create\" | \"edit\";\n /** The row being edited; null when creating. */\n item: T | null;\n };\n\n // ── Delete ──\n /** Delete a row: asks first when the delete is confirmed. Undefined when the page cannot delete. */\n remove: ((item: T) => void) | undefined;\n /** The confirm step's state, when `remove` asks first. */\n deleteConfirm: {\n open: boolean;\n setOpen: (open: boolean) => void;\n /** The row being confirmed (kept through the close animation). */\n item: T | null;\n /** Run the delete; rejects with the failure. */\n confirm: () => Promise<void>;\n /** \"recycle\" when the provider soft-deletes, so the copy can say it can be restored. */\n kind: \"recycle\" | \"permanent\";\n copy: ResourceDeleteConfirmCopy<T> | undefined;\n };\n}\n\n/**\n * The list behind {@link ResourcePage}, without any markup: where the rows\n * come from (a `resource` through the data provider, or `data` you pass),\n * search, sort, status filter and paging, selection, the open record (and\n * its URL state), the built-in create/edit form and confirmed delete, and\n * the row handlers. Takes the same options as `ResourcePage`.\n *\n * Use it to build a different layout over the same behaviour; `ResourcePage`\n * itself is this behaviour plus Genesis's markup.\n *\n * @stability Beta\n */\nexport function useResourceTable<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(props: ResourcePageProps<T>): ResourceTableState<T> {\n const m = useResourceTableModel<T>(props);\n const { pendingDelete, performDelete } = m;\n const confirm = useCallback(\n () => (pendingDelete ? performDelete(pendingDelete) : Promise.resolve()),\n [pendingDelete, performDelete],\n );\n return {\n rows: m.page.data,\n total:\n m.loadMore && m.page.search === \"\" && m.page.statusValue.length === 0\n ? m.displayTotal\n : m.page.total,\n loading: m.isLoading,\n error: m.hasError,\n truncated: m.clientTruncated,\n // Present only with `pagination=\"cursor\"`.\n ...(m.loadMore ? { loadMore: m.loadMore } : {}),\n columns: m.tableColumns,\n actions: m.actions,\n getKey: m.keyOf,\n getTitle: m.titleOf,\n can: m.allows,\n search: m.page.search,\n setSearch: m.handleSearchChange,\n sort: m.tableSort,\n setSort: m.handleTableSort,\n statusFilter: m.statusChipsConfig,\n hasActiveFilters: m.page.hasActiveFilters,\n clearFilters: m.handleClearFilters,\n page: m.currentPage,\n pageCount: m.totalPages,\n pageSize: m.effectivePageSize,\n setPageSize: m.handlePageSizeChange,\n setPage: m.pagerOnPageChange,\n rangeFrom: m.rangeFrom,\n rangeTo: m.rangeTo,\n selectedIds: m.selectedIds,\n toggleSelected: m.handleToggleSelect,\n toggleAll: m.handleToggleAll,\n clearSelection: m.handleClearSelection,\n openItem: m.selectedItem,\n detailOpen: m.detailOpen,\n openRow: m.handleRowClick,\n closeDetail: m.closeDetail,\n openItemMissing: m.linkMissing,\n create: m.useBuiltInCreate || props.onCreate ? m.handleCreate : undefined,\n edit: m.handleEdit,\n form: {\n open: m.formOpen,\n setOpen: m.setFormOpen,\n action: m.formAction,\n item: m.formItem,\n },\n remove: m.deleteHandler,\n deleteConfirm: {\n open: m.deleteOpen,\n setOpen: m.setDeleteOpen,\n item: pendingDelete,\n confirm,\n kind: m.deleteKind,\n copy: m.deleteCopy,\n },\n };\n}\n"]}
|
|
@@ -137,5 +137,5 @@ function useBrowserSearchParams() {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
export { DefaultLink, defaultNavigate, isPathActive, resolveNavigation, useBrowserSearchParams };
|
|
140
|
-
//# sourceMappingURL=chunk-
|
|
141
|
-
//# sourceMappingURL=chunk-
|
|
140
|
+
//# sourceMappingURL=chunk-KC43CNMA.js.map
|
|
141
|
+
//# sourceMappingURL=chunk-KC43CNMA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/navigation.tsx"],"names":["trail"],"mappings":"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","file":"chunk-WGMEVX3Y.js","sourcesContent":["\"use client\";\n\n/**\n * Router-agnostic navigation primitives.\n *\n * genesis-ui does NOT depend on any router. Components that need to render a\n * link or navigate imperatively accept an injectable abstraction defined here,\n * and default to plain browser behavior (`<a>` / `window.location`). Consumers\n * on a router inject an adapter that maps these props to their own `<Link>` /\n * router. Ready-made ones ship on their own subpaths, each with its router as\n * an optional peer: `@marktiderman/genesis-ui/router/react-router` and\n * `@marktiderman/genesis-ui/router/tanstack-router`. Next.js passes\n * `next/link` directly.\n */\nimport {\n useCallback,\n useEffect,\n useState,\n type AnchorHTMLAttributes,\n type ComponentType,\n type ReactNode,\n} from \"react\";\n\n// ---------------------------------------------------------------------------\n// Link abstraction\n// ---------------------------------------------------------------------------\n\n/**\n * Props passed to an injectable link component. The contract is a plain anchor\n * (`href`), so the default works with NO router. A React Router consumer maps\n * `href` → `to`; a Next.js consumer passes `next/link` directly (it already\n * accepts `href`, `className`, `children`).\n *\n * @stability Beta\n */\nexport interface GenesisLinkProps {\n /** Destination path or URL. */\n href: string;\n className?: string;\n onClick?: () => void;\n children?: ReactNode;\n /** Set to \"page\" when the link points at the active route. */\n \"aria-current\"?: AnchorHTMLAttributes<HTMLAnchorElement>[\"aria-current\"];\n /** Accessible name — useful when the visible label is hidden (icon rail). */\n \"aria-label\"?: string;\n /** Native tooltip / title attribute. */\n title?: string;\n /**\n * Stable test/automation selector. {@link DefaultLink} renders it as\n * `data-testid`; injected router adapters (`next/link`, RR `Link`) forward it\n * to the underlying `<a>` too.\n */\n testID?: string;\n}\n\n/**\n * A component that renders a navigable link from {@link GenesisLinkProps}.\n *\n * @stability Beta\n */\nexport type LinkComponent = ComponentType<GenesisLinkProps>;\n\n/**\n * Default link — a plain `<a>`. No router required.\n *\n * @stability Beta\n */\nexport const DefaultLink: LinkComponent = ({\n href,\n children,\n testID,\n ...rest\n}) => (\n <a href={href} data-testid={testID} {...rest}>\n {children}\n </a>\n);\n\n/**\n * Split a href into its path (trailing slash dropped, except for `/`), query\n * (no `?`) and hash (no `#`).\n */\nfunction splitHref(href: string): { path: string; search: string; hash: string } {\n const hashAt = href.indexOf(\"#\");\n const hash = hashAt === -1 ? \"\" : href.slice(hashAt + 1);\n const beforeHash = hashAt === -1 ? href : href.slice(0, hashAt);\n const searchAt = beforeHash.indexOf(\"?\");\n const rawPath = searchAt === -1 ? beforeHash : beforeHash.slice(0, searchAt);\n return {\n path: rawPath.length > 1 ? rawPath.replace(/\\/+$/, \"\") || \"/\" : rawPath,\n search: searchAt === -1 ? \"\" : beforeHash.slice(searchAt + 1),\n hash,\n };\n}\n\n/**\n * Options for {@link isPathActive}.\n *\n * @stability Beta\n */\nexport interface IsPathActiveOptions {\n /** Require an exact path match instead of a prefix match (like `NavLink end`). */\n end?: boolean;\n}\n\n/**\n * Default active-path matcher, mirroring React Router's `NavLink` (prefix\n * match, with `/` treated as exact). Consumers can override via an `isActive`\n * prop where components accept one.\n *\n * `activePath` may carry a query and hash (`pathname + search + hash`). An\n * item whose `to` has neither compares against the path part only, exactly as\n * before. An item that opts in by putting a query or hash in its `to`\n * (`/admin?tab=users`, `/settings#profile`) is active only when the path\n * matches exactly AND every query param it names has the same value in\n * `activePath` (extra params such as `&page=2` are ignored) AND, if it names a\n * hash, the hash is equal.\n *\n * @stability Beta\n */\nexport function isPathActive(\n to: string,\n activePath?: string,\n options?: IsPathActiveOptions,\n): boolean {\n if (activePath == null) return false;\n if (to === activePath) return true;\n const target = splitHref(to);\n const current = splitHref(activePath);\n\n if (!target.search && !target.hash) {\n if (target.path === current.path) return true;\n if (options?.end) return false;\n return target.path !== \"/\" && current.path.startsWith(target.path + \"/\");\n }\n\n if (target.path !== current.path) return false;\n if (target.hash && target.hash !== current.hash) return false;\n if (target.search) {\n const want = new URLSearchParams(target.search);\n const have = new URLSearchParams(current.search);\n for (const key of new Set(want.keys())) {\n const wanted = want.getAll(key);\n const had = have.getAll(key);\n if (!wanted.every((value) => had.includes(value))) return false;\n }\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Hierarchical navigation resolver\n// ---------------------------------------------------------------------------\n\n/**\n * One node of a logical navigation hierarchy. `path` is a route pattern whose\n * segments are either static (`clients`) or named params (`$clientId`). A\n * node's place in the tree is its LOGICAL parent, which need not share its URL\n * prefix — `/clients/$clientId` can sit under `/dashboard`.\n *\n * @stability Beta\n */\nexport interface NavigationNode<T> {\n id: string;\n path: string;\n label: string;\n /** Contextual nav items to show while this node is current. */\n items: T[];\n children?: NavigationNode<T>[];\n}\n\n/**\n * Result of {@link resolveNavigation}. `current`, `parent` and every `trail`\n * entry are shallow copies of their tree nodes with `path` interpolated from\n * `params` (a param the URL did not supply stays as `$name`).\n *\n * @stability Beta\n */\nexport interface ResolvedNavigation<T> {\n /** The best-matching node — the root when nothing else matches. */\n current: NavigationNode<T>;\n /** `current`'s logical parent, for an \"up\" / back-to-parent link. */\n parent?: NavigationNode<T>;\n /** `current.items`. */\n items: T[];\n /** Root → `current`, inclusive. */\n trail: NavigationNode<T>[];\n /** Params captured by `current.path`, URL-decoded. */\n params: Record<string, string>;\n}\n\nfunction pathSegments(path: string): string[] {\n return splitHref(path).path.split(\"/\").filter(Boolean);\n}\n\nfunction decodeSegment(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\n/**\n * Resolve where `pathname` sits in a logical navigation tree. Pure: it never\n * reads browser history or `window`.\n *\n * A node matches when its pattern matches a leading run of WHOLE path\n * segments (`/my` matches `/my/tasks`, never `/my-other`). Among matches the\n * winner is decided by positional specificity: at the first position where\n * one pattern is static and the other a `$param`, the static one wins (so\n * `/clients/new` beats `/clients/$clientId` whatever the sibling order, and\n * `/my` beats `/$space/tasks` for `/my/tasks`). Otherwise the pattern matching\n * more segments wins, then the deeper tree node.\n * Non-matching nodes are still searched, so a match keeps its logical\n * ancestors even when their URLs differ.\n *\n * @stability Beta\n */\nexport function resolveNavigation<T>(\n tree: NavigationNode<T>,\n pathname: string,\n): ResolvedNavigation<T> {\n // Compare decoded forms on both sides, so `/caf%C3%A9` matches a `/café`\n // node (and an encoded pattern matches a decoded pathname).\n const segments = pathSegments(pathname).map(decodeSegment);\n\n type Match = { trail: NavigationNode<T>[]; pattern: string[] };\n const matches = (pattern: string[]) =>\n pattern.length <= segments.length &&\n pattern.every(\n (part, i) => part.startsWith(\"$\") || decodeSegment(part) === segments[i],\n );\n\n // > 0 when `a` should win over `b`.\n // Positional specificity, as TanStack Router and React Router rank routes:\n // walking left to right, the first position where one pattern is static and\n // the other a `$param` decides. Only then does the longer match win.\n const compare = (a: Match, b: Match): number => {\n const shared = Math.min(a.pattern.length, b.pattern.length);\n for (let i = 0; i < shared; i++) {\n const aParam = a.pattern[i]!.startsWith(\"$\");\n const bParam = b.pattern[i]!.startsWith(\"$\");\n if (aParam !== bParam) return aParam ? -1 : 1;\n }\n if (a.pattern.length !== b.pattern.length) {\n return a.pattern.length - b.pattern.length;\n }\n return a.trail.length - b.trail.length;\n };\n\n let best: Match | undefined;\n const visit = (node: NavigationNode<T>, ancestors: NavigationNode<T>[]) => {\n const trail = [...ancestors, node];\n const pattern = pathSegments(node.path);\n if (matches(pattern)) {\n const candidate = { trail, pattern };\n if (!best || compare(candidate, best) > 0) best = candidate;\n }\n for (const child of node.children ?? []) visit(child, trail);\n };\n visit(tree, []);\n\n const winner: Match = best ?? { trail: [tree], pattern: [] };\n const params: Record<string, string> = {};\n winner.pattern.forEach((part, i) => {\n if (part.startsWith(\"$\")) params[part.slice(1)] = segments[i]!;\n });\n\n const interpolate = (node: NavigationNode<T>): NavigationNode<T> => ({\n ...node,\n path: node.path\n .split(\"/\")\n .map((part) => {\n if (!part.startsWith(\"$\")) return part;\n const value = params[part.slice(1)];\n return value == null ? part : encodeURIComponent(value);\n })\n .join(\"/\"),\n });\n\n const trail = winner.trail.map(interpolate);\n const current = trail[trail.length - 1]!;\n return {\n current,\n parent: trail.length > 1 ? trail[trail.length - 2] : undefined,\n items: current.items,\n trail,\n params,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Imperative navigation abstraction\n// ---------------------------------------------------------------------------\n\n/**\n * Injectable imperative navigation callback.\n *\n * @stability Beta\n */\nexport type NavigateFn = (path: string) => void;\n\n/**\n * Default navigate — a full-page navigation. No router required.\n *\n * @stability Beta\n */\nexport const defaultNavigate: NavigateFn = (path) => {\n if (typeof window !== \"undefined\") window.location.assign(path);\n};\n\n// ---------------------------------------------------------------------------\n// Search-params abstraction (for URL-synced hooks)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal, router-agnostic replacement for React Router's `useSearchParams`\n * return shape. Consumers may inject their router's implementation for full\n * SPA integration; otherwise the browser History API is used.\n *\n * @stability Beta\n */\nexport interface SearchParamsAdapter {\n searchParams: URLSearchParams;\n setSearchParams: (\n next: URLSearchParams,\n options?: { replace?: boolean },\n ) => void;\n}\n\n/**\n * Browser-native {@link SearchParamsAdapter} built on the History API. Reads\n * the current query string and writes updates via `pushState`/`replaceState`,\n * staying reactive to `popstate` events. No router required.\n *\n * @stability Beta\n */\nexport function useBrowserSearchParams(): SearchParamsAdapter {\n const read = () =>\n new URLSearchParams(\n typeof window !== \"undefined\" ? window.location.search : \"\",\n );\n\n const [searchParams, setLocal] = useState<URLSearchParams>(read);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const onPop = () => setLocal(read());\n window.addEventListener(\"popstate\", onPop);\n return () => window.removeEventListener(\"popstate\", onPop);\n }, []);\n\n const setSearchParams = useCallback<SearchParamsAdapter[\"setSearchParams\"]>(\n (next, options) => {\n if (typeof window === \"undefined\") return;\n const qs = next.toString();\n const url =\n window.location.pathname + (qs ? `?${qs}` : \"\") + window.location.hash;\n if (options?.replace) {\n window.history.replaceState(window.history.state, \"\", url);\n } else {\n window.history.pushState(window.history.state, \"\", url);\n }\n setLocal(new URLSearchParams(next));\n },\n [],\n );\n\n return { searchParams, setSearchParams };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/navigation.tsx"],"names":["trail"],"mappings":"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","file":"chunk-KC43CNMA.js","sourcesContent":["\"use client\";\n\n/**\n * Router-agnostic navigation primitives.\n *\n * genesis-ui does NOT depend on any router. Components that need to render a\n * link or navigate imperatively accept an injectable abstraction defined here,\n * and default to plain browser behavior (`<a>` / `window.location`). Consumers\n * on a router inject an adapter that maps these props to their own `<Link>` /\n * router. Ready-made ones ship on their own subpaths, each with its router as\n * an optional peer: `@marktiderman/genesis-ui/router/react-router` and\n * `@marktiderman/genesis-ui/router/tanstack-router`. Next.js passes\n * `next/link` directly.\n */\nimport {\n useCallback,\n useEffect,\n useState,\n type AnchorHTMLAttributes,\n type ComponentType,\n type ReactNode,\n} from \"react\";\n\n// ---------------------------------------------------------------------------\n// Link abstraction\n// ---------------------------------------------------------------------------\n\n/**\n * Props passed to an injectable link component. The contract is a plain anchor\n * (`href`), so the default works with NO router. A React Router consumer maps\n * `href` → `to`; a Next.js consumer passes `next/link` directly (it already\n * accepts `href`, `className`, `children`).\n *\n * @stability Beta\n */\nexport interface GenesisLinkProps {\n /** Destination path or URL. */\n href: string;\n className?: string;\n onClick?: () => void;\n children?: ReactNode;\n /** Set to \"page\" when the link points at the active route. */\n \"aria-current\"?: AnchorHTMLAttributes<HTMLAnchorElement>[\"aria-current\"];\n /** Accessible name — useful when the visible label is hidden (icon rail). */\n \"aria-label\"?: string;\n /** Native tooltip / title attribute. */\n title?: string;\n /**\n * Stable test/automation selector. {@link DefaultLink} renders it as\n * `data-testid`; injected router adapters (`next/link`, RR `Link`) forward it\n * to the underlying `<a>` too.\n */\n testID?: string;\n}\n\n/**\n * A component that renders a navigable link from {@link GenesisLinkProps}.\n *\n * @stability Beta\n */\nexport type LinkComponent = ComponentType<GenesisLinkProps>;\n\n/**\n * Default link — a plain `<a>`. No router required.\n *\n * @stability Beta\n */\nexport const DefaultLink: LinkComponent = ({\n href,\n children,\n testID,\n ...rest\n}) => (\n <a href={href} data-testid={testID} {...rest}>\n {children}\n </a>\n);\n\n/**\n * Split a href into its path (trailing slash dropped, except for `/`), query\n * (no `?`) and hash (no `#`).\n */\nfunction splitHref(href: string): { path: string; search: string; hash: string } {\n const hashAt = href.indexOf(\"#\");\n const hash = hashAt === -1 ? \"\" : href.slice(hashAt + 1);\n const beforeHash = hashAt === -1 ? href : href.slice(0, hashAt);\n const searchAt = beforeHash.indexOf(\"?\");\n const rawPath = searchAt === -1 ? beforeHash : beforeHash.slice(0, searchAt);\n return {\n path: rawPath.length > 1 ? rawPath.replace(/\\/+$/, \"\") || \"/\" : rawPath,\n search: searchAt === -1 ? \"\" : beforeHash.slice(searchAt + 1),\n hash,\n };\n}\n\n/**\n * Options for {@link isPathActive}.\n *\n * @stability Beta\n */\nexport interface IsPathActiveOptions {\n /** Require an exact path match instead of a prefix match (like `NavLink end`). */\n end?: boolean;\n}\n\n/**\n * Default active-path matcher, mirroring React Router's `NavLink` (prefix\n * match, with `/` treated as exact). Consumers can override via an `isActive`\n * prop where components accept one.\n *\n * `activePath` may carry a query and hash (`pathname + search + hash`). An\n * item whose `to` has neither compares against the path part only, exactly as\n * before. An item that opts in by putting a query or hash in its `to`\n * (`/admin?tab=users`, `/settings#profile`) is active only when the path\n * matches exactly AND every query param it names has the same value in\n * `activePath` (extra params such as `&page=2` are ignored) AND, if it names a\n * hash, the hash is equal.\n *\n * @stability Beta\n */\nexport function isPathActive(\n to: string,\n activePath?: string,\n options?: IsPathActiveOptions,\n): boolean {\n if (activePath == null) return false;\n if (to === activePath) return true;\n const target = splitHref(to);\n const current = splitHref(activePath);\n\n if (!target.search && !target.hash) {\n if (target.path === current.path) return true;\n if (options?.end) return false;\n return target.path !== \"/\" && current.path.startsWith(target.path + \"/\");\n }\n\n if (target.path !== current.path) return false;\n if (target.hash && target.hash !== current.hash) return false;\n if (target.search) {\n const want = new URLSearchParams(target.search);\n const have = new URLSearchParams(current.search);\n for (const key of new Set(want.keys())) {\n const wanted = want.getAll(key);\n const had = have.getAll(key);\n if (!wanted.every((value) => had.includes(value))) return false;\n }\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Hierarchical navigation resolver\n// ---------------------------------------------------------------------------\n\n/**\n * One node of a logical navigation hierarchy. `path` is a route pattern whose\n * segments are either static (`clients`) or named params (`$clientId`). A\n * node's place in the tree is its LOGICAL parent, which need not share its URL\n * prefix — `/clients/$clientId` can sit under `/dashboard`.\n *\n * @stability Beta\n */\nexport interface NavigationNode<T> {\n id: string;\n path: string;\n label: string;\n /** Contextual nav items to show while this node is current. */\n items: T[];\n children?: NavigationNode<T>[];\n /**\n * Ask the app shell to open its desktop sidebar collapsed (icon rail) while\n * this node, or a descendant that doesn't set its own value, is current.\n * The nearest node in the resolved trail that sets it wins, so\n * `defaultCollapsed: false` on a child re-opens it under a collapsed\n * parent. Only a default: once the user has toggled the sidebar, their\n * choice wins everywhere. `AppShell` reads it; `resolveNavigation` copies\n * it through untouched.\n *\n * @stability Beta\n */\n defaultCollapsed?: boolean;\n /**\n * How the app shell shows this node's `items` (its child pages, e.g. a\n * form's Questions / Logic / Responses / Settings). `\"tabs\"` (across the\n * top of the content) or `\"sidebar\"` (nested under the active item) turn\n * shell sub-navigation on, which also gives phones a back item plus the\n * children in the bottom bar. `\"section\"` is the legacy rendering (the\n * shell's default) and `\"off\"` hides them. The nearest node in the trail\n * that sets it wins over the shell's `options.subNav`.\n *\n * @stability Beta\n */\n subNav?: \"section\" | \"tabs\" | \"sidebar\" | \"off\";\n}\n\n/**\n * Result of {@link resolveNavigation}. `current`, `parent` and every `trail`\n * entry are shallow copies of their tree nodes with `path` interpolated from\n * `params` (a param the URL did not supply stays as `$name`).\n *\n * @stability Beta\n */\nexport interface ResolvedNavigation<T> {\n /** The best-matching node — the root when nothing else matches. */\n current: NavigationNode<T>;\n /** `current`'s logical parent, for an \"up\" / back-to-parent link. */\n parent?: NavigationNode<T>;\n /** `current.items`. */\n items: T[];\n /** Root → `current`, inclusive. */\n trail: NavigationNode<T>[];\n /** Params captured by `current.path`, URL-decoded. */\n params: Record<string, string>;\n}\n\nfunction pathSegments(path: string): string[] {\n return splitHref(path).path.split(\"/\").filter(Boolean);\n}\n\nfunction decodeSegment(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\n/**\n * Resolve where `pathname` sits in a logical navigation tree. Pure: it never\n * reads browser history or `window`.\n *\n * A node matches when its pattern matches a leading run of WHOLE path\n * segments (`/my` matches `/my/tasks`, never `/my-other`). Among matches the\n * winner is decided by positional specificity: at the first position where\n * one pattern is static and the other a `$param`, the static one wins (so\n * `/clients/new` beats `/clients/$clientId` whatever the sibling order, and\n * `/my` beats `/$space/tasks` for `/my/tasks`). Otherwise the pattern matching\n * more segments wins, then the deeper tree node.\n * Non-matching nodes are still searched, so a match keeps its logical\n * ancestors even when their URLs differ.\n *\n * @stability Beta\n */\nexport function resolveNavigation<T>(\n tree: NavigationNode<T>,\n pathname: string,\n): ResolvedNavigation<T> {\n // Compare decoded forms on both sides, so `/caf%C3%A9` matches a `/café`\n // node (and an encoded pattern matches a decoded pathname).\n const segments = pathSegments(pathname).map(decodeSegment);\n\n type Match = { trail: NavigationNode<T>[]; pattern: string[] };\n const matches = (pattern: string[]) =>\n pattern.length <= segments.length &&\n pattern.every(\n (part, i) => part.startsWith(\"$\") || decodeSegment(part) === segments[i],\n );\n\n // > 0 when `a` should win over `b`.\n // Positional specificity, as TanStack Router and React Router rank routes:\n // walking left to right, the first position where one pattern is static and\n // the other a `$param` decides. Only then does the longer match win.\n const compare = (a: Match, b: Match): number => {\n const shared = Math.min(a.pattern.length, b.pattern.length);\n for (let i = 0; i < shared; i++) {\n const aParam = a.pattern[i]!.startsWith(\"$\");\n const bParam = b.pattern[i]!.startsWith(\"$\");\n if (aParam !== bParam) return aParam ? -1 : 1;\n }\n if (a.pattern.length !== b.pattern.length) {\n return a.pattern.length - b.pattern.length;\n }\n return a.trail.length - b.trail.length;\n };\n\n let best: Match | undefined;\n const visit = (node: NavigationNode<T>, ancestors: NavigationNode<T>[]) => {\n const trail = [...ancestors, node];\n const pattern = pathSegments(node.path);\n if (matches(pattern)) {\n const candidate = { trail, pattern };\n if (!best || compare(candidate, best) > 0) best = candidate;\n }\n for (const child of node.children ?? []) visit(child, trail);\n };\n visit(tree, []);\n\n const winner: Match = best ?? { trail: [tree], pattern: [] };\n const params: Record<string, string> = {};\n winner.pattern.forEach((part, i) => {\n if (part.startsWith(\"$\")) params[part.slice(1)] = segments[i]!;\n });\n\n const interpolate = (node: NavigationNode<T>): NavigationNode<T> => ({\n ...node,\n path: node.path\n .split(\"/\")\n .map((part) => {\n if (!part.startsWith(\"$\")) return part;\n const value = params[part.slice(1)];\n return value == null ? part : encodeURIComponent(value);\n })\n .join(\"/\"),\n });\n\n const trail = winner.trail.map(interpolate);\n const current = trail[trail.length - 1]!;\n return {\n current,\n parent: trail.length > 1 ? trail[trail.length - 2] : undefined,\n items: current.items,\n trail,\n params,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Imperative navigation abstraction\n// ---------------------------------------------------------------------------\n\n/**\n * Injectable imperative navigation callback.\n *\n * @stability Beta\n */\nexport type NavigateFn = (path: string) => void;\n\n/**\n * Default navigate — a full-page navigation. No router required.\n *\n * @stability Beta\n */\nexport const defaultNavigate: NavigateFn = (path) => {\n if (typeof window !== \"undefined\") window.location.assign(path);\n};\n\n// ---------------------------------------------------------------------------\n// Search-params abstraction (for URL-synced hooks)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal, router-agnostic replacement for React Router's `useSearchParams`\n * return shape. Consumers may inject their router's implementation for full\n * SPA integration; otherwise the browser History API is used.\n *\n * @stability Beta\n */\nexport interface SearchParamsAdapter {\n searchParams: URLSearchParams;\n setSearchParams: (\n next: URLSearchParams,\n options?: { replace?: boolean },\n ) => void;\n}\n\n/**\n * Browser-native {@link SearchParamsAdapter} built on the History API. Reads\n * the current query string and writes updates via `pushState`/`replaceState`,\n * staying reactive to `popstate` events. No router required.\n *\n * @stability Beta\n */\nexport function useBrowserSearchParams(): SearchParamsAdapter {\n const read = () =>\n new URLSearchParams(\n typeof window !== \"undefined\" ? window.location.search : \"\",\n );\n\n const [searchParams, setLocal] = useState<URLSearchParams>(read);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const onPop = () => setLocal(read());\n window.addEventListener(\"popstate\", onPop);\n return () => window.removeEventListener(\"popstate\", onPop);\n }, []);\n\n const setSearchParams = useCallback<SearchParamsAdapter[\"setSearchParams\"]>(\n (next, options) => {\n if (typeof window === \"undefined\") return;\n const qs = next.toString();\n const url =\n window.location.pathname + (qs ? `?${qs}` : \"\") + window.location.hash;\n if (options?.replace) {\n window.history.replaceState(window.history.state, \"\", url);\n } else {\n window.history.pushState(window.history.state, \"\", url);\n }\n setLocal(new URLSearchParams(next));\n },\n [],\n );\n\n return { searchParams, setSearchParams };\n}\n"]}
|