@arqel-dev/ui 0.18.0 → 0.19.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/dist/ArqelCreatePage-SUQTG7LF.js +9 -0
- package/dist/{ArqelCreatePage-UZAHV4DK.js.map → ArqelCreatePage-SUQTG7LF.js.map} +1 -1
- package/dist/ArqelEditPage-TC6CY66H.js +13 -0
- package/dist/{ArqelEditPage-7OFWPULE.js.map → ArqelEditPage-TC6CY66H.js.map} +1 -1
- package/dist/ArqelIndexPage-3DPWRK2Q.js +15 -0
- package/dist/{ArqelIndexPage-ZAVCCM6V.js.map → ArqelIndexPage-3DPWRK2Q.js.map} +1 -1
- package/dist/ArqelNotificationsPage-VCNRIN6A.js +7 -0
- package/dist/{ArqelNotificationsPage-MBJBYFHW.js.map → ArqelNotificationsPage-VCNRIN6A.js.map} +1 -1
- package/dist/action.js +5 -4
- package/dist/{chunk-7NGUPQON.js → chunk-4XV35QZA.js} +5 -5
- package/dist/{chunk-7NGUPQON.js.map → chunk-4XV35QZA.js.map} +1 -1
- package/dist/{chunk-GJ2FKAOM.js → chunk-5ETNGNVM.js} +17 -4
- package/dist/chunk-5ETNGNVM.js.map +1 -0
- package/dist/chunk-CZUV5WCY.js +3 -0
- package/dist/chunk-CZUV5WCY.js.map +1 -0
- package/dist/{chunk-DO3PRGVV.js → chunk-FVKM6FDW.js} +3 -3
- package/dist/{chunk-DO3PRGVV.js.map → chunk-FVKM6FDW.js.map} +1 -1
- package/dist/{chunk-KGAY2AZH.js → chunk-HOJEO5LX.js} +3 -3
- package/dist/{chunk-KGAY2AZH.js.map → chunk-HOJEO5LX.js.map} +1 -1
- package/dist/{chunk-CH7YLELO.js → chunk-NFP2EB7Y.js} +3 -3
- package/dist/{chunk-CH7YLELO.js.map → chunk-NFP2EB7Y.js.map} +1 -1
- package/dist/{chunk-DOQUHQND.js → chunk-P64TZA7T.js} +4 -4
- package/dist/{chunk-DOQUHQND.js.map → chunk-P64TZA7T.js.map} +1 -1
- package/dist/{chunk-WKIYS2FQ.js → chunk-RKWHRD75.js} +53 -10
- package/dist/chunk-RKWHRD75.js.map +1 -0
- package/dist/{chunk-MZMYV43C.js → chunk-SVCWLDZ4.js} +3 -3
- package/dist/{chunk-MZMYV43C.js.map → chunk-SVCWLDZ4.js.map} +1 -1
- package/dist/{chunk-YEPQWAD6.js → chunk-TBDWW6L5.js} +3 -3
- package/dist/{chunk-YEPQWAD6.js.map → chunk-TBDWW6L5.js.map} +1 -1
- package/dist/{chunk-3E66JNQO.js → chunk-VO5KYIHC.js} +3 -30
- package/dist/chunk-VO5KYIHC.js.map +1 -0
- package/dist/{chunk-IO6RMVUF.js → chunk-WXPBHB7R.js} +3 -3
- package/dist/{chunk-IO6RMVUF.js.map → chunk-WXPBHB7R.js.map} +1 -1
- package/dist/{chunk-EXA6DWLB.js → chunk-YDUL7HFU.js} +7 -3
- package/dist/chunk-YDUL7HFU.js.map +1 -0
- package/dist/{chunk-H23VX3RR.js → chunk-YF2RINPG.js} +2 -2
- package/dist/{chunk-H23VX3RR.js.map → chunk-YF2RINPG.js.map} +1 -1
- package/dist/{chunk-53J74IYR.js → chunk-ZZKWQO3W.js} +30 -3
- package/dist/chunk-ZZKWQO3W.js.map +1 -0
- package/dist/flash.d.ts +2 -1
- package/dist/flash.js +2 -1
- package/dist/form.js +3 -2
- package/dist/index.js +11 -10
- package/dist/pages.js +16 -15
- package/dist/pages.js.map +1 -1
- package/dist/resource.js +4 -3
- package/dist/shell.js +4 -2
- package/dist/shell.js.map +1 -1
- package/dist/table.js +3 -2
- package/dist/utility.js +2 -2
- package/package.json +6 -6
- package/dist/ArqelCreatePage-UZAHV4DK.js +0 -8
- package/dist/ArqelEditPage-7OFWPULE.js +0 -12
- package/dist/ArqelIndexPage-ZAVCCM6V.js +0 -14
- package/dist/ArqelNotificationsPage-MBJBYFHW.js +0 -6
- package/dist/chunk-3E66JNQO.js.map +0 -1
- package/dist/chunk-53J74IYR.js.map +0 -1
- package/dist/chunk-EXA6DWLB.js.map +0 -1
- package/dist/chunk-GJ2FKAOM.js.map +0 -1
- package/dist/chunk-WKIYS2FQ.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pages/ArqelIndexPage.tsx"],"names":[],"mappings":"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","file":"chunk-DOQUHQND.js","sourcesContent":["/**\n * Default Inertia page for `arqel::index`.\n *\n * Pulls every prop the server emits via `InertiaDataBuilder::\n * buildIndexData` / `buildTableIndexData` and forwards them to\n * `<ResourceIndex>`. Apps can override per-resource by registering\n * their own page component at `Pages/Arqel/{Slug}/Index.tsx` (the\n * lookup falls through to user pages first inside `createArqelApp`).\n *\n * Wires the standard table interactions — search / filter / sort /\n * pagination — into Inertia partial `router.get` visits so the\n * server can re-run TableQueryBuilder with the new query string.\n *\n * Query-string contract (matches `Arqel\\Table\\TableQueryBuilder`):\n * - `?search=foo` global search\n * - `?sort=column&direction=asc|desc`\n * - `?page=N&per_page=M`\n * - `?filter[name]=value` one entry per filter\n *\n * `search` is debounced (300ms) so typing doesn't hammer the\n * backend; the rest fire immediately.\n */\n\nimport type { ActionSchema } from '@arqel-dev/types/actions';\nimport type { RecordType, ResourceIndexProps } from '@arqel-dev/types/resources';\nimport type { SortDirection } from '@arqel-dev/types/tables';\nimport { router, usePage } from '@inertiajs/react';\nimport { type JSX, useEffect, useMemo, useRef, useState } from 'react';\nimport { ActionButton } from '../action/ActionButton.js';\nimport { ActionMenu } from '../action/ActionMenu.js';\nimport { ResourceIndex } from '../resource/ResourceIndex.js';\n\ntype FilterValue = unknown;\n\nfunction pruneEmptyFilters(values: Record<string, FilterValue>): Record<string, FilterValue> {\n const out: Record<string, FilterValue> = {};\n for (const [k, v] of Object.entries(values)) {\n if (v === undefined || v === null || v === '') continue;\n if (Array.isArray(v) && v.length === 0) continue;\n out[k] = v;\n }\n return out;\n}\n\ninterface VisitParams {\n filters: Record<string, FilterValue>;\n search: string;\n sort?: { column: string | null; direction: string | null } | null;\n page?: number | undefined;\n perPage?: number | undefined;\n}\n\nfunction invokeAction(\n action: ActionSchema,\n record: { id: string | number } | null,\n formValues?: Record<string, unknown>,\n): void {\n const recordId = record?.id;\n // Every dispatchable action ships a server-emitted `url` (stock verbs,\n // bulk, and custom callback actions all resolve through core's authorised\n // routes — see `Action::resolveStockUrl()`, #48/#231). An absent `url`\n // signals a misconfiguration; we must NOT fall back to the dead\n // `/arqel-dev/actions/{name}` route removed in #174. Surface it clearly\n // instead of masking it as a 404.\n if (!action.url) {\n throw new Error(\n `Arqel: action \"${action.name}\" has no url to dispatch to. Declare it on ` +\n `the Resource's actions()/headerActions()/toolbarActions() so the server ` +\n `emits its endpoint URL, or give it an explicit ->url().`,\n );\n }\n const url = action.url.replace('{id}', String(recordId ?? ''));\n const method = action.method.toLowerCase() as 'get' | 'post' | 'put' | 'patch' | 'delete';\n const data: Record<string, unknown> = { ...(formValues ?? {}) };\n if (recordId !== undefined) data['record_id'] = recordId;\n\n router.visit(url, {\n method: method as never,\n data: data as never,\n preserveScroll: true,\n });\n}\n\n/**\n * Resolve the row-action list for a single record (#140).\n *\n * Row actions are defined once at table level (label / icon / color /\n * confirmation / form), but `url(Closure)` and `disabled(Closure)`\n * actions depend on the row. The server emits those resolved values\n * per record under `record.arqel.actionOverrides`; here we merge them\n * onto the shared definitions so each row links to its own URL and\n * carries its own disabled state.\n *\n * When the server also emits `record.arqel.actions` (the visible +\n * executable action names) we filter the list against it so per-row\n * authorization/visibility is honoured.\n */\nfunction resolveRecordActions(\n tableActions: ActionSchema[],\n record: {\n arqel?: {\n actions?: string[];\n actionOverrides?: Record<string, { url?: string; disabled?: true }>;\n };\n },\n): ActionSchema[] {\n const visibleNames = record.arqel?.actions;\n const overrides = record.arqel?.actionOverrides ?? {};\n\n return tableActions\n .filter((action) => (visibleNames ? visibleNames.includes(action.name) : true))\n .map((action) => {\n const override = overrides[action.name];\n if (override === undefined) return action;\n return {\n ...action,\n ...(override.url !== undefined ? { url: override.url } : {}),\n ...(override.disabled === true ? { disabled: true as const } : {}),\n };\n });\n}\n\nfunction buildQuery(params: VisitParams): Record<string, unknown> {\n const data: Record<string, unknown> = {};\n const filters = pruneEmptyFilters(params.filters);\n if (Object.keys(filters).length > 0) data['filter'] = filters;\n if (params.search !== undefined) data['search'] = params.search;\n if (params.sort?.column) {\n data['sort'] = params.sort.column;\n if (params.sort.direction) data['direction'] = params.sort.direction;\n }\n if (params.page && params.page > 1) data['page'] = params.page;\n if (params.perPage) data['per_page'] = params.perPage;\n return data;\n}\n\nexport default function ArqelIndexPage<TRecord extends RecordType = RecordType>(): JSX.Element {\n const page = usePage();\n const props = page.props as unknown as ResourceIndexProps<TRecord>;\n\n const initialFilters = useMemo(() => {\n if (typeof window === 'undefined') return {};\n const sp = new URLSearchParams(window.location.search);\n const fromUrl: Record<string, FilterValue> = {};\n for (const [key, value] of sp.entries()) {\n const m = key.match(/^filter\\[([^\\]]+)\\]$/);\n if (m?.[1]) fromUrl[m[1]] = value;\n }\n return fromUrl;\n }, []);\n\n const [filterValues, setFilterValues] = useState<Record<string, FilterValue>>(initialFilters);\n const [searchValue, setSearchValue] = useState<string>(props.search ?? '');\n const [perPage, setPerPage] = useState<number | undefined>(props.pagination?.perPage);\n const [selectedIds, setSelectedIds] = useState<ReadonlyArray<string | number>>([]);\n const searchDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const visit = (data: Record<string, unknown>): void => {\n const url = typeof window !== 'undefined' ? window.location.pathname : page.url.split('?')[0];\n router.get(url ?? '/', data as Record<string, string | number | boolean | undefined>, {\n preserveState: true,\n preserveScroll: true,\n replace: true,\n });\n };\n\n const currentSort = props.sort ?? null;\n\n const handleFilterChange = (name: string, value: FilterValue): void => {\n const nextFilters = { ...filterValues };\n if (value === undefined || value === null || value === '') {\n delete nextFilters[name];\n } else {\n nextFilters[name] = value;\n }\n setFilterValues(nextFilters);\n visit(buildQuery({ filters: nextFilters, search: searchValue, sort: currentSort, perPage }));\n };\n\n const handleClearFilters = (): void => {\n setFilterValues({});\n visit(buildQuery({ filters: {}, search: searchValue, sort: currentSort, perPage }));\n };\n\n const handleSearchChange = (value: string): void => {\n setSearchValue(value);\n if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current);\n searchDebounceRef.current = setTimeout(() => {\n visit(buildQuery({ filters: filterValues, search: value, sort: currentSort, perPage }));\n }, 300);\n };\n\n useEffect(\n () => () => {\n if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current);\n },\n [],\n );\n\n const handleSortChange = (column: string, direction: SortDirection): void => {\n visit(\n buildQuery({\n filters: filterValues,\n search: searchValue,\n sort: { column, direction },\n perPage,\n }),\n );\n };\n\n const handlePageChange = (pageNum: number): void => {\n visit(\n buildQuery({\n filters: filterValues,\n search: searchValue,\n sort: currentSort,\n page: pageNum,\n perPage,\n }),\n );\n };\n\n const handlePerPageChange = (newPerPage: number): void => {\n setPerPage(newPerPage);\n visit(\n buildQuery({\n filters: filterValues,\n search: searchValue,\n sort: currentSort,\n perPage: newPerPage,\n }),\n );\n };\n\n const dispatchBulkAction = (action: ActionSchema): void => {\n // Every bulk action carries a stock url (core resolves\n // /admin/{slug}/bulk/{name} for any bulk action without an\n // explicit url), so there is no client-side fallback route.\n const url = action.url;\n if (url === undefined) {\n return;\n }\n const method = action.method.toLowerCase() as 'get' | 'post' | 'put' | 'patch' | 'delete';\n router.visit(url, {\n method: method as never,\n data: { record_ids: selectedIds as readonly (string | number)[] } as never,\n preserveScroll: true,\n onSuccess: () => setSelectedIds([]),\n });\n };\n\n const bulkActionsList = props.actions?.bulk ?? [];\n const bulkActions =\n bulkActionsList.length > 0 && selectedIds.length > 0 ? (\n <div className=\"flex items-center gap-2\">\n {bulkActionsList.map((action) => (\n // Route through ActionButton so destructive bulk actions that set\n // requiresConfirmation open the ConfirmDialog before dispatching,\n // matching row-action behaviour. Non-confirming actions fire\n // immediately. The visit payload is unchanged.\n <ActionButton\n key={action.name}\n action={action}\n onInvoke={() => dispatchBulkAction(action)}\n size=\"sm\"\n // 44px touch target on mobile (WCAG 2.5.5); dense 32px on >=md.\n className=\"h-11 md:h-8\"\n />\n ))}\n </div>\n ) : undefined;\n\n const rowActionsList = props.actions?.row ?? [];\n const rowActions =\n rowActionsList.length > 0\n ? (record: TRecord) => (\n <ActionMenu\n // Resolve actions against this row so closure-URL /\n // closure-disabled actions get their per-record values\n // (#140) instead of the table-level placeholder.\n actions={resolveRecordActions(rowActionsList, record)}\n onInvoke={(action, formValues) =>\n invokeAction(action, record as { id: string | number }, formValues)\n }\n />\n )\n : undefined;\n\n return (\n <ResourceIndex<TRecord>\n {...props}\n filterValues={filterValues}\n onFilterChange={handleFilterChange}\n onClearFilters={handleClearFilters}\n onSearchChange={handleSearchChange}\n onSortChange={handleSortChange}\n onPageChange={handlePageChange}\n onPerPageChange={handlePerPageChange}\n search={searchValue}\n selectedIds={selectedIds}\n onSelectionChange={(ids) => setSelectedIds(ids)}\n {...(rowActions ? { rowActions } : {})}\n {...(bulkActions ? { bulkActions } : {})}\n />\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/pages/ArqelIndexPage.tsx"],"names":[],"mappings":"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","file":"chunk-P64TZA7T.js","sourcesContent":["/**\n * Default Inertia page for `arqel::index`.\n *\n * Pulls every prop the server emits via `InertiaDataBuilder::\n * buildIndexData` / `buildTableIndexData` and forwards them to\n * `<ResourceIndex>`. Apps can override per-resource by registering\n * their own page component at `Pages/Arqel/{Slug}/Index.tsx` (the\n * lookup falls through to user pages first inside `createArqelApp`).\n *\n * Wires the standard table interactions — search / filter / sort /\n * pagination — into Inertia partial `router.get` visits so the\n * server can re-run TableQueryBuilder with the new query string.\n *\n * Query-string contract (matches `Arqel\\Table\\TableQueryBuilder`):\n * - `?search=foo` global search\n * - `?sort=column&direction=asc|desc`\n * - `?page=N&per_page=M`\n * - `?filter[name]=value` one entry per filter\n *\n * `search` is debounced (300ms) so typing doesn't hammer the\n * backend; the rest fire immediately.\n */\n\nimport type { ActionSchema } from '@arqel-dev/types/actions';\nimport type { RecordType, ResourceIndexProps } from '@arqel-dev/types/resources';\nimport type { SortDirection } from '@arqel-dev/types/tables';\nimport { router, usePage } from '@inertiajs/react';\nimport { type JSX, useEffect, useMemo, useRef, useState } from 'react';\nimport { ActionButton } from '../action/ActionButton.js';\nimport { ActionMenu } from '../action/ActionMenu.js';\nimport { ResourceIndex } from '../resource/ResourceIndex.js';\n\ntype FilterValue = unknown;\n\nfunction pruneEmptyFilters(values: Record<string, FilterValue>): Record<string, FilterValue> {\n const out: Record<string, FilterValue> = {};\n for (const [k, v] of Object.entries(values)) {\n if (v === undefined || v === null || v === '') continue;\n if (Array.isArray(v) && v.length === 0) continue;\n out[k] = v;\n }\n return out;\n}\n\ninterface VisitParams {\n filters: Record<string, FilterValue>;\n search: string;\n sort?: { column: string | null; direction: string | null } | null;\n page?: number | undefined;\n perPage?: number | undefined;\n}\n\nfunction invokeAction(\n action: ActionSchema,\n record: { id: string | number } | null,\n formValues?: Record<string, unknown>,\n): void {\n const recordId = record?.id;\n // Every dispatchable action ships a server-emitted `url` (stock verbs,\n // bulk, and custom callback actions all resolve through core's authorised\n // routes — see `Action::resolveStockUrl()`, #48/#231). An absent `url`\n // signals a misconfiguration; we must NOT fall back to the dead\n // `/arqel-dev/actions/{name}` route removed in #174. Surface it clearly\n // instead of masking it as a 404.\n if (!action.url) {\n throw new Error(\n `Arqel: action \"${action.name}\" has no url to dispatch to. Declare it on ` +\n `the Resource's actions()/headerActions()/toolbarActions() so the server ` +\n `emits its endpoint URL, or give it an explicit ->url().`,\n );\n }\n const url = action.url.replace('{id}', String(recordId ?? ''));\n const method = action.method.toLowerCase() as 'get' | 'post' | 'put' | 'patch' | 'delete';\n const data: Record<string, unknown> = { ...(formValues ?? {}) };\n if (recordId !== undefined) data['record_id'] = recordId;\n\n router.visit(url, {\n method: method as never,\n data: data as never,\n preserveScroll: true,\n });\n}\n\n/**\n * Resolve the row-action list for a single record (#140).\n *\n * Row actions are defined once at table level (label / icon / color /\n * confirmation / form), but `url(Closure)` and `disabled(Closure)`\n * actions depend on the row. The server emits those resolved values\n * per record under `record.arqel.actionOverrides`; here we merge them\n * onto the shared definitions so each row links to its own URL and\n * carries its own disabled state.\n *\n * When the server also emits `record.arqel.actions` (the visible +\n * executable action names) we filter the list against it so per-row\n * authorization/visibility is honoured.\n */\nfunction resolveRecordActions(\n tableActions: ActionSchema[],\n record: {\n arqel?: {\n actions?: string[];\n actionOverrides?: Record<string, { url?: string; disabled?: true }>;\n };\n },\n): ActionSchema[] {\n const visibleNames = record.arqel?.actions;\n const overrides = record.arqel?.actionOverrides ?? {};\n\n return tableActions\n .filter((action) => (visibleNames ? visibleNames.includes(action.name) : true))\n .map((action) => {\n const override = overrides[action.name];\n if (override === undefined) return action;\n return {\n ...action,\n ...(override.url !== undefined ? { url: override.url } : {}),\n ...(override.disabled === true ? { disabled: true as const } : {}),\n };\n });\n}\n\nfunction buildQuery(params: VisitParams): Record<string, unknown> {\n const data: Record<string, unknown> = {};\n const filters = pruneEmptyFilters(params.filters);\n if (Object.keys(filters).length > 0) data['filter'] = filters;\n if (params.search !== undefined) data['search'] = params.search;\n if (params.sort?.column) {\n data['sort'] = params.sort.column;\n if (params.sort.direction) data['direction'] = params.sort.direction;\n }\n if (params.page && params.page > 1) data['page'] = params.page;\n if (params.perPage) data['per_page'] = params.perPage;\n return data;\n}\n\nexport default function ArqelIndexPage<TRecord extends RecordType = RecordType>(): JSX.Element {\n const page = usePage();\n const props = page.props as unknown as ResourceIndexProps<TRecord>;\n\n const initialFilters = useMemo(() => {\n if (typeof window === 'undefined') return {};\n const sp = new URLSearchParams(window.location.search);\n const fromUrl: Record<string, FilterValue> = {};\n for (const [key, value] of sp.entries()) {\n const m = key.match(/^filter\\[([^\\]]+)\\]$/);\n if (m?.[1]) fromUrl[m[1]] = value;\n }\n return fromUrl;\n }, []);\n\n const [filterValues, setFilterValues] = useState<Record<string, FilterValue>>(initialFilters);\n const [searchValue, setSearchValue] = useState<string>(props.search ?? '');\n const [perPage, setPerPage] = useState<number | undefined>(props.pagination?.perPage);\n const [selectedIds, setSelectedIds] = useState<ReadonlyArray<string | number>>([]);\n const searchDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const visit = (data: Record<string, unknown>): void => {\n const url = typeof window !== 'undefined' ? window.location.pathname : page.url.split('?')[0];\n router.get(url ?? '/', data as Record<string, string | number | boolean | undefined>, {\n preserveState: true,\n preserveScroll: true,\n replace: true,\n });\n };\n\n const currentSort = props.sort ?? null;\n\n const handleFilterChange = (name: string, value: FilterValue): void => {\n const nextFilters = { ...filterValues };\n if (value === undefined || value === null || value === '') {\n delete nextFilters[name];\n } else {\n nextFilters[name] = value;\n }\n setFilterValues(nextFilters);\n visit(buildQuery({ filters: nextFilters, search: searchValue, sort: currentSort, perPage }));\n };\n\n const handleClearFilters = (): void => {\n setFilterValues({});\n visit(buildQuery({ filters: {}, search: searchValue, sort: currentSort, perPage }));\n };\n\n const handleSearchChange = (value: string): void => {\n setSearchValue(value);\n if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current);\n searchDebounceRef.current = setTimeout(() => {\n visit(buildQuery({ filters: filterValues, search: value, sort: currentSort, perPage }));\n }, 300);\n };\n\n useEffect(\n () => () => {\n if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current);\n },\n [],\n );\n\n const handleSortChange = (column: string, direction: SortDirection): void => {\n visit(\n buildQuery({\n filters: filterValues,\n search: searchValue,\n sort: { column, direction },\n perPage,\n }),\n );\n };\n\n const handlePageChange = (pageNum: number): void => {\n visit(\n buildQuery({\n filters: filterValues,\n search: searchValue,\n sort: currentSort,\n page: pageNum,\n perPage,\n }),\n );\n };\n\n const handlePerPageChange = (newPerPage: number): void => {\n setPerPage(newPerPage);\n visit(\n buildQuery({\n filters: filterValues,\n search: searchValue,\n sort: currentSort,\n perPage: newPerPage,\n }),\n );\n };\n\n const dispatchBulkAction = (action: ActionSchema): void => {\n // Every bulk action carries a stock url (core resolves\n // /admin/{slug}/bulk/{name} for any bulk action without an\n // explicit url), so there is no client-side fallback route.\n const url = action.url;\n if (url === undefined) {\n return;\n }\n const method = action.method.toLowerCase() as 'get' | 'post' | 'put' | 'patch' | 'delete';\n router.visit(url, {\n method: method as never,\n data: { record_ids: selectedIds as readonly (string | number)[] } as never,\n preserveScroll: true,\n onSuccess: () => setSelectedIds([]),\n });\n };\n\n const bulkActionsList = props.actions?.bulk ?? [];\n const bulkActions =\n bulkActionsList.length > 0 && selectedIds.length > 0 ? (\n <div className=\"flex items-center gap-2\">\n {bulkActionsList.map((action) => (\n // Route through ActionButton so destructive bulk actions that set\n // requiresConfirmation open the ConfirmDialog before dispatching,\n // matching row-action behaviour. Non-confirming actions fire\n // immediately. The visit payload is unchanged.\n <ActionButton\n key={action.name}\n action={action}\n onInvoke={() => dispatchBulkAction(action)}\n size=\"sm\"\n // 44px touch target on mobile (WCAG 2.5.5); dense 32px on >=md.\n className=\"h-11 md:h-8\"\n />\n ))}\n </div>\n ) : undefined;\n\n const rowActionsList = props.actions?.row ?? [];\n const rowActions =\n rowActionsList.length > 0\n ? (record: TRecord) => (\n <ActionMenu\n // Resolve actions against this row so closure-URL /\n // closure-disabled actions get their per-record values\n // (#140) instead of the table-level placeholder.\n actions={resolveRecordActions(rowActionsList, record)}\n onInvoke={(action, formValues) =>\n invokeAction(action, record as { id: string | number }, formValues)\n }\n />\n )\n : undefined;\n\n return (\n <ResourceIndex<TRecord>\n {...props}\n filterValues={filterValues}\n onFilterChange={handleFilterChange}\n onClearFilters={handleClearFilters}\n onSearchChange={handleSearchChange}\n onSortChange={handleSortChange}\n onPageChange={handlePageChange}\n onPerPageChange={handlePerPageChange}\n search={searchValue}\n selectedIds={selectedIds}\n onSelectionChange={(ids) => setSelectedIds(ids)}\n {...(rowActions ? { rowActions } : {})}\n {...(bulkActions ? { bulkActions } : {})}\n />\n );\n}\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ErrorState } from './chunk-
|
|
1
|
+
import { ErrorState, LoadingSkeleton } from './chunk-ZZKWQO3W.js';
|
|
2
2
|
import { PageHeader } from './chunk-MXUXMHOK.js';
|
|
3
3
|
import { DataTable } from './chunk-JKD6SE75.js';
|
|
4
|
-
import { ConfirmDialog, Dialog, DialogContent, DialogHeader, DialogTitle } from './chunk-
|
|
5
|
-
import { FormActions } from './chunk-
|
|
4
|
+
import { ConfirmDialog, Dialog, DialogContent, DialogHeader, DialogTitle } from './chunk-FVKM6FDW.js';
|
|
5
|
+
import { FormActions } from './chunk-SVCWLDZ4.js';
|
|
6
6
|
import { FormRenderer } from './chunk-CMNZLA32.js';
|
|
7
|
-
import { Button } from './chunk-
|
|
7
|
+
import { Button } from './chunk-YF2RINPG.js';
|
|
8
8
|
import { cn } from './chunk-B7ULUJVO.js';
|
|
9
9
|
import { useArqelForm } from '@arqel-dev/hooks';
|
|
10
10
|
import { useArqelTranslations } from '@arqel-dev/react/utils';
|
|
@@ -154,13 +154,47 @@ function RelationFormModal({
|
|
|
154
154
|
parentId,
|
|
155
155
|
basePath = "/admin",
|
|
156
156
|
recordId,
|
|
157
|
-
initialValues
|
|
157
|
+
initialValues,
|
|
158
158
|
onSuccess
|
|
159
159
|
}) {
|
|
160
160
|
const t = useArqelTranslations();
|
|
161
|
-
const [values, setValues] = useState(initialValues);
|
|
161
|
+
const [values, setValues] = useState(initialValues ?? {});
|
|
162
162
|
const [errors, setErrors] = useState({});
|
|
163
163
|
const [processing, setProcessing] = useState(false);
|
|
164
|
+
const needsFetch = recordId !== void 0 && initialValues === void 0;
|
|
165
|
+
const [loadingRecord, setLoadingRecord] = useState(needsFetch);
|
|
166
|
+
const [loadError, setLoadError] = useState(false);
|
|
167
|
+
const base = `${basePath}/${parentSlug}/${parentId}/relations/${relation.slug}`;
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
if (!open || !needsFetch) return;
|
|
170
|
+
let cancelled = false;
|
|
171
|
+
const editUrl = `${base}/${recordId}/edit`;
|
|
172
|
+
const doFetch = async () => {
|
|
173
|
+
setLoadingRecord(true);
|
|
174
|
+
setLoadError(false);
|
|
175
|
+
try {
|
|
176
|
+
const response = await fetch(editUrl, {
|
|
177
|
+
headers: { Accept: "application/json", "X-Requested-With": "XMLHttpRequest" },
|
|
178
|
+
credentials: "same-origin"
|
|
179
|
+
});
|
|
180
|
+
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
|
|
181
|
+
const body = await response.json();
|
|
182
|
+
if (!cancelled && body.record) {
|
|
183
|
+
setValues(body.record);
|
|
184
|
+
} else if (!cancelled) {
|
|
185
|
+
throw new Error("Response did not include a record");
|
|
186
|
+
}
|
|
187
|
+
} catch {
|
|
188
|
+
if (!cancelled) setLoadError(true);
|
|
189
|
+
} finally {
|
|
190
|
+
if (!cancelled) setLoadingRecord(false);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
void doFetch();
|
|
194
|
+
return () => {
|
|
195
|
+
cancelled = true;
|
|
196
|
+
};
|
|
197
|
+
}, [open, needsFetch, base, recordId]);
|
|
164
198
|
const fields = relation.fields;
|
|
165
199
|
const schema = useMemo(
|
|
166
200
|
() => ({
|
|
@@ -177,10 +211,11 @@ function RelationFormModal({
|
|
|
177
211
|
[fields]
|
|
178
212
|
);
|
|
179
213
|
if (!open) return null;
|
|
180
|
-
const base = `${basePath}/${parentSlug}/${parentId}/relations/${relation.slug}`;
|
|
181
214
|
const url = recordId ? `${base}/${recordId}` : base;
|
|
182
215
|
const method = recordId ? "put" : "post";
|
|
216
|
+
const blockedByRecordLoad = needsFetch && (loadingRecord || loadError);
|
|
183
217
|
const submit = () => {
|
|
218
|
+
if (blockedByRecordLoad) return;
|
|
184
219
|
setProcessing(true);
|
|
185
220
|
router[method](url, values, {
|
|
186
221
|
preserveScroll: true,
|
|
@@ -203,11 +238,18 @@ function RelationFormModal({
|
|
|
203
238
|
values,
|
|
204
239
|
errors,
|
|
205
240
|
onChange: (name, value) => setValues((prev) => ({ ...prev, [name]: value })),
|
|
206
|
-
disabled: processing,
|
|
241
|
+
disabled: processing || blockedByRecordLoad,
|
|
207
242
|
onSubmit: submit
|
|
208
243
|
};
|
|
209
244
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (next) => !next && onClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "overflow-auto sm:max-w-[32rem]", children: [
|
|
210
245
|
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: relation.label }) }),
|
|
246
|
+
needsFetch && loadingRecord ? /* @__PURE__ */ jsx(LoadingSkeleton, { variant: "block", count: 3 }) : needsFetch && loadError ? /* @__PURE__ */ jsx(
|
|
247
|
+
ErrorState,
|
|
248
|
+
{
|
|
249
|
+
title: t("relations.form.loadError", "Couldn't load this record"),
|
|
250
|
+
description: t("relations.form.loadErrorDescription", "Please try again.")
|
|
251
|
+
}
|
|
252
|
+
) : null,
|
|
211
253
|
/* @__PURE__ */ jsxs(
|
|
212
254
|
"form",
|
|
213
255
|
{
|
|
@@ -222,6 +264,7 @@ function RelationFormModal({
|
|
|
222
264
|
FormActions,
|
|
223
265
|
{
|
|
224
266
|
processing,
|
|
267
|
+
disabled: blockedByRecordLoad,
|
|
225
268
|
submitLabel: t("form.save", "Save"),
|
|
226
269
|
onCancel: onClose
|
|
227
270
|
}
|
|
@@ -505,5 +548,5 @@ function ArqelEditPage() {
|
|
|
505
548
|
}
|
|
506
549
|
|
|
507
550
|
export { ArqelEditPage };
|
|
508
|
-
//# sourceMappingURL=chunk-
|
|
509
|
-
//# sourceMappingURL=chunk-
|
|
551
|
+
//# sourceMappingURL=chunk-RKWHRD75.js.map
|
|
552
|
+
//# sourceMappingURL=chunk-RKWHRD75.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shadcn/ui/tabs.tsx","../src/relations/AttachModal.tsx","../src/relations/RelationFormModal.tsx","../src/relations/RelationManagerPanel.tsx","../src/relations/ResourceEditTabs.tsx","../src/pages/ArqelEditPage.tsx"],"names":["TabsPrimitive","jsx","useArqelTranslations","useState","router","jsxs","useEffect","Fragment"],"mappings":"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","file":"chunk-RKWHRD75.js","sourcesContent":["import * as React from \"react\"\nimport { Tabs as TabsPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/utils/cn\"\n\nfunction Tabs({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n return (\n <TabsPrimitive.Root\n data-slot=\"tabs\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n />\n )\n}\n\nfunction TabsList({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.List>) {\n return (\n <TabsPrimitive.List\n data-slot=\"tabs-list\"\n className={cn(\n \"inline-flex h-9 w-fit items-center justify-center rounded-lg bg-muted p-[3px] text-muted-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction TabsTrigger({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n return (\n <TabsPrimitive.Trigger\n data-slot=\"tabs-trigger\"\n className={cn(\n \"inline-flex flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:shadow-sm dark:text-muted-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction TabsContent({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Content>) {\n return (\n <TabsPrimitive.Content\n data-slot=\"tabs-content\"\n className={cn(\"flex-1 outline-none\", className)}\n {...props}\n />\n )\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent }\n","/**\n * `<AttachModal>` — attach an existing record to a `belongsToMany`\n * relation from a `RelationManagerPanel` tab.\n *\n * Phase 1 ships a plain id-entry picker rather than reusing\n * `@arqel-dev/fields`' `BelongsToInput`: that component lives in\n * `arqel-dev/fields`, which depends on `@arqel-dev/ui` (registers into its\n * `FieldRegistry`) — importing it back here would be a circular package\n * dependency. `RelationManager::toArray()` also doesn't yet emit a search\n * route for the attach picker (only `RelationController::attach()`'s\n * `{ related, pivot }` contract), so there's nothing to debounce-search\n * against yet. A follow-up ticket can upgrade this to a search combobox\n * once the server side emits `relation.attachSearchRoute` (or similar).\n *\n * On success the modal closes and calls `onSuccess` (if given) so the\n * caller can refresh the relation's table — see `RelationFormModal`'s\n * docblock for why a partial Inertia reload no longer applies (Task 13a).\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { RelationManagerProps } from '@arqel-dev/types/relations';\nimport { router } from '@inertiajs/react';\nimport { useId, useState } from 'react';\nimport { FormActions } from '../form/FormActions.js';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../shadcn/ui/dialog.js';\n\nexport interface AttachModalProps {\n open: boolean;\n onClose(): void;\n relation: RelationManagerProps;\n parentSlug: string;\n parentId: string | number;\n basePath?: string;\n onSuccess?: () => void;\n}\n\nexport function AttachModal({\n open,\n onClose,\n relation,\n parentSlug,\n parentId,\n basePath = '/admin',\n onSuccess,\n}: AttachModalProps) {\n const t = useArqelTranslations();\n const inputId = useId();\n const [related, setRelated] = useState('');\n const [processing, setProcessing] = useState(false);\n const [errors, setErrors] = useState<Record<string, string>>({});\n\n if (!open) return null;\n\n const url = `${basePath}/${parentSlug}/${parentId}/relations/${relation.slug}/attach`;\n\n const submit = () => {\n setProcessing(true);\n router.post(\n url,\n { related, pivot: {} },\n {\n preserveScroll: true,\n onSuccess: () => {\n setProcessing(false);\n onSuccess?.();\n onClose();\n },\n onError: (formErrors: Record<string, string>) => {\n setProcessing(false);\n setErrors(formErrors);\n },\n },\n );\n };\n\n return (\n <Dialog open={open} onOpenChange={(next) => !next && onClose()}>\n <DialogContent className=\"overflow-auto sm:max-w-[28rem]\">\n <DialogHeader>\n <DialogTitle>\n {t('arqel.relations.attach', 'Attach :label', { label: relation.label })}\n </DialogTitle>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-4\"\n onSubmit={(e) => {\n e.preventDefault();\n submit();\n }}\n >\n <div className=\"flex flex-col gap-1\">\n <label htmlFor={inputId} className=\"text-sm font-medium\">\n {relation.label}\n </label>\n <input\n id={inputId}\n type=\"text\"\n className=\"rounded-sm border border-border bg-background px-3 py-1.5 text-sm\"\n value={related}\n disabled={processing}\n aria-invalid={errors['related'] !== undefined || undefined}\n onChange={(e) => setRelated(e.target.value)}\n />\n {errors['related'] && <p className=\"text-sm text-destructive\">{errors['related']}</p>}\n </div>\n <FormActions\n processing={processing}\n submitLabel={t('arqel.relations.attach_action', 'Attach')}\n onCancel={onClose}\n />\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n","/**\n * `<RelationFormModal>` — create/edit a related record from within a\n * `RelationManagerPanel` tab. Reuses `<FormRenderer>` for the field list\n * (a flat schema built from `relation.fields`, mirroring how\n * `<ActionFormModal>` derives a `FormSchema` from a flat `ActionFormField[]`)\n * and submits via Inertia `router.post`/`router.put`.\n *\n * On success the modal closes and calls `onSuccess` (if given) so the\n * caller can refresh the relation's table — records now come from\n * `RelationManagerPanel`'s own `fetch()` to `RelationController::index()`\n * (Task 13a), not from an Inertia `relations` prop, so a partial reload\n * would no longer do anything useful here; `ResourceEditTabs` uses\n * `onSuccess` to bump that panel's `refreshKey`.\n *\n * **Edit-mode data loading (data-loss fix)**: when `recordId` is given and\n * the caller doesn't pass an explicit `initialValues`, the form used to\n * mount empty and `submit()` would `PUT` those empty values, silently\n * wiping out every untouched column server-side. To prevent that, this\n * component now fetches the current record from\n * `RelationController::edit()` (`GET {base}/{recordId}/edit`, a plain JSON\n * endpoint returning `{ fields, record }`) on mount, mirroring the\n * `fetch()`-on-mount pattern `RelationManagerPanel` already uses against\n * `RelationController::index()`. While that fetch is in flight, or if it\n * fails, submit stays disabled so the modal can never PUT an empty/partial\n * `values` object — the safe default when we don't yet know the real data.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { FieldSchema } from '@arqel-dev/types/fields';\nimport type { FormSchema } from '@arqel-dev/types/forms';\nimport type { RelationManagerProps } from '@arqel-dev/types/relations';\nimport { router } from '@inertiajs/react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { FormActions } from '../form/FormActions.js';\nimport { FormRenderer, type FormRendererProps } from '../form/FormRenderer.js';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../shadcn/ui/dialog.js';\nimport { ErrorState } from '../utility/ErrorState.js';\nimport { LoadingSkeleton } from '../utility/LoadingSkeleton.js';\n\nexport interface RelationFormModalProps {\n open: boolean;\n onClose(): void;\n relation: RelationManagerProps;\n parentSlug: string;\n parentId: string | number;\n basePath?: string;\n recordId?: string | number;\n initialValues?: Record<string, unknown>;\n onSuccess?: () => void;\n}\n\nexport function RelationFormModal({\n open,\n onClose,\n relation,\n parentSlug,\n parentId,\n basePath = '/admin',\n recordId,\n initialValues,\n onSuccess,\n}: RelationFormModalProps) {\n const t = useArqelTranslations();\n // When editing without an explicit `initialValues`, the record isn't\n // known yet — start empty but keep the form gated (see `canSubmit` below)\n // until the fetch below resolves.\n const [values, setValues] = useState<Record<string, unknown>>(initialValues ?? {});\n const [errors, setErrors] = useState<Record<string, string[]>>({});\n const [processing, setProcessing] = useState(false);\n\n const needsFetch = recordId !== undefined && initialValues === undefined;\n const [loadingRecord, setLoadingRecord] = useState(needsFetch);\n const [loadError, setLoadError] = useState(false);\n\n const base = `${basePath}/${parentSlug}/${parentId}/relations/${relation.slug}`;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `open` is a deliberate re-fetch trigger (refetch each time the modal is reopened for a given record), not a value the effect reads.\n useEffect(() => {\n if (!open || !needsFetch) return;\n let cancelled = false;\n const editUrl = `${base}/${recordId}/edit`;\n\n const doFetch = async () => {\n setLoadingRecord(true);\n setLoadError(false);\n try {\n const response = await fetch(editUrl, {\n headers: { Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest' },\n credentials: 'same-origin',\n });\n if (!response.ok) throw new Error(`Request failed with status ${response.status}`);\n const body = (await response.json()) as { record?: Record<string, unknown> };\n if (!cancelled && body.record) {\n setValues(body.record);\n } else if (!cancelled) {\n throw new Error('Response did not include a record');\n }\n } catch {\n // Leave `values` empty and keep the form gated — never let a failed\n // fetch fall through to a submit that would PUT empty data.\n if (!cancelled) setLoadError(true);\n } finally {\n if (!cancelled) setLoadingRecord(false);\n }\n };\n\n void doFetch();\n\n return () => {\n cancelled = true;\n };\n }, [open, needsFetch, base, recordId]);\n\n const fields = relation.fields as FieldSchema[];\n\n const schema: FormSchema = useMemo(\n () => ({\n schema: fields.map((field) => ({\n kind: 'field' as const,\n name: field.name,\n type: field.type,\n })),\n columns: 1,\n model: null,\n inline: false,\n disabled: false,\n }),\n [fields],\n );\n\n if (!open) return null;\n\n const url = recordId ? `${base}/${recordId}` : base;\n const method = recordId ? 'put' : 'post';\n\n // Never allow a submit while the current record's data is still loading\n // or failed to load — that's exactly the empty-`values` PUT that caused\n // the data-loss bug this component now guards against.\n const blockedByRecordLoad = needsFetch && (loadingRecord || loadError);\n\n const submit = () => {\n if (blockedByRecordLoad) return;\n setProcessing(true);\n router[method](url, values as Record<string, never>, {\n preserveScroll: true,\n onSuccess: () => {\n setProcessing(false);\n onSuccess?.();\n onClose();\n },\n onError: (formErrors: Record<string, string>) => {\n setProcessing(false);\n setErrors(\n Object.fromEntries(Object.entries(formErrors).map(([key, message]) => [key, [message]])),\n );\n },\n });\n };\n\n // `FormRenderer` itself is submit-agnostic (state lives in the caller);\n // the wrapping `<form onSubmit>` below drives real submission, mirroring\n // `ArqelEditPage`/`ActionFormModal`. The stray `onSubmit` in this typed\n // props bag is inert for the real component but lets a test double\n // (which renders a plain submit button) exercise the same `submit`.\n const formRendererProps: FormRendererProps & { onSubmit: () => void } = {\n schema,\n fields,\n values,\n errors,\n onChange: (name, value) => setValues((prev) => ({ ...prev, [name]: value })),\n disabled: processing || blockedByRecordLoad,\n onSubmit: submit,\n };\n\n return (\n <Dialog open={open} onOpenChange={(next) => !next && onClose()}>\n <DialogContent className=\"overflow-auto sm:max-w-[32rem]\">\n <DialogHeader>\n <DialogTitle>{relation.label}</DialogTitle>\n </DialogHeader>\n {needsFetch && loadingRecord ? (\n <LoadingSkeleton variant=\"block\" count={3} />\n ) : needsFetch && loadError ? (\n <ErrorState\n title={t('relations.form.loadError', \"Couldn't load this record\")}\n description={t('relations.form.loadErrorDescription', 'Please try again.')}\n />\n ) : null}\n <form\n className=\"flex flex-col gap-4\"\n onSubmit={(e) => {\n e.preventDefault();\n submit();\n }}\n >\n <FormRenderer {...formRendererProps} />\n <FormActions\n processing={processing}\n disabled={blockedByRecordLoad}\n submitLabel={t('form.save', 'Save')}\n onCancel={onClose}\n />\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n","/**\n * `<RelationManagerPanel>` — one relation-manager tab on a parent's edit\n * page: a `DataTable` of related records with ability-gated toolbar (New /\n * Attach) and per-row Edit/Delete/Detach actions. Create/attach/edit\n * mutations are delegated to the parent page via the callbacks; Delete and\n * Detach are owned by this component directly (Task 13c) since they need\n * no form — just a confirmation and an Inertia `router.delete()` call,\n * mirroring how `ArqelIndexPage`'s row actions confirm via `ConfirmDialog`\n * before dispatching.\n *\n * Delete targets `hasMany`/`morphMany` relations (`abilities.delete`);\n * Detach targets `belongsToMany` (`abilities.detach`) and only removes the\n * pivot row — the related record survives (guaranteed server-side by\n * `RelationController::detach()`). The two are mutually exclusive by\n * `relation.type`, matching the existing New/Attach toolbar gating.\n *\n * `relation.table` is the PHP `Table::toArray()` payload (untyped on the\n * wire per `RelationManagerProps`'s docblock); the column list lives at\n * `relation.table.columns`, mirroring how `ArqelIndexPage`/`ResourceIndex`\n * feed `DataTable` from `ResourceIndexProps.columns`.\n *\n * **Records loading**: `RelationManager::toArray()` deliberately does NOT\n * include the related records (see `RelationManagerProps`'s docblock) — the\n * actual rows live behind `RelationController::index()`\n * (`GET {basePath}/{parentSlug}/{parentId}/relations/{slug}`), a plain JSON\n * endpoint (`{ records, table, abilities }`, not an Inertia partial). This\n * panel is therefore self-fetching: it mirrors `WidgetRenderer`'s\n * `useEffect` + native `fetch()` pattern (see that component's docblock) —\n * fetch on mount, `Accept: application/json`, swallow failures so a bad\n * request just leaves the previous records on screen instead of crashing\n * the tab. The `records` prop is kept as the *initial* seed (SSR-friendly,\n * and it's what the existing unit tests assert against) — the fetch result\n * replaces it once it resolves. `refreshKey` lets a caller force a refetch\n * (e.g. after a successful create/edit/attach/detach mutation) by bumping a\n * counter/string, since those mutations no longer flow through an Inertia\n * partial reload of a `relations` prop.\n */\n\nimport type { RelationManagerProps } from '@arqel-dev/types/relations';\nimport type { ColumnSchema } from '@arqel-dev/types/tables';\nimport { router } from '@inertiajs/react';\nimport { useEffect, useState } from 'react';\nimport { Button } from '../action/Button.js';\nimport { ConfirmDialog } from '../action/ConfirmDialog.js';\nimport { DataTable, type DataTableRecord } from '../table/DataTable.js';\nimport { ErrorState } from '../utility/ErrorState.js';\n\nexport interface RelationManagerPanelProps {\n relation: RelationManagerProps;\n parentSlug: string;\n parentId: string | number;\n records: unknown[];\n basePath?: string;\n /** Bump this (e.g. increment a counter) to force a refetch after a mutation. */\n refreshKey?: string | number;\n /** Test/DI seam — defaults to the native `fetch` API, mirroring `WidgetRenderer`. */\n fetcher?: ((url: string) => Promise<unknown>) | undefined;\n onEdit(id: string | number): void;\n onCreate(): void;\n onAttach(): void;\n /** Called after a Delete or Detach `router.delete()` succeeds, so the caller can bump `refreshKey`. */\n onMutated?: () => void;\n}\n\nfunction relationColumns(table: unknown): ColumnSchema[] {\n if (\n table &&\n typeof table === 'object' &&\n Array.isArray((table as { columns?: unknown }).columns)\n ) {\n return (table as { columns: ColumnSchema[] }).columns;\n }\n return [];\n}\n\nexport function RelationManagerPanel({\n relation,\n parentSlug,\n parentId,\n records: initialRecords,\n basePath = '/admin',\n refreshKey,\n fetcher,\n onEdit,\n onCreate,\n onAttach,\n onMutated,\n}: RelationManagerPanelProps) {\n const { abilities, type, slug } = relation;\n const columns = relationColumns(relation.table);\n\n const [records, setRecords] = useState<unknown[]>(initialRecords);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(false);\n const [pendingAction, setPendingAction] = useState<{\n kind: 'delete' | 'detach';\n id: string | number;\n } | null>(null);\n const [mutating, setMutating] = useState(false);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: refreshKey is a deliberate re-fetch trigger (bumped by the caller post-mutation), not a value the effect reads.\n useEffect(() => {\n let cancelled = false;\n const url = `${basePath}/${parentSlug}/${parentId}/relations/${slug}`;\n\n const doFetch = async () => {\n setLoading(true);\n try {\n const body = fetcher\n ? await fetcher(url)\n : await fetch(url, { headers: { Accept: 'application/json' } }).then((r) => r.json());\n const fetched =\n body && typeof body === 'object' && Array.isArray((body as { records?: unknown }).records)\n ? (body as { records: unknown[] }).records\n : undefined;\n if (!cancelled && fetched) {\n setRecords(fetched);\n setError(false);\n }\n } catch {\n // Swallow — the previous records (initial seed or last successful\n // fetch) stay on screen rather than blanking the tab.\n if (!cancelled) setError(true);\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n\n void doFetch();\n\n return () => {\n cancelled = true;\n };\n }, [basePath, parentSlug, parentId, slug, refreshKey, fetcher]);\n\n const canDelete = type !== 'belongsToMany' && abilities.delete;\n const canDetach = type === 'belongsToMany' && abilities.detach;\n\n const mutationUrl = (id: string | number, kind: 'delete' | 'detach'): string => {\n const base = `${basePath}/${parentSlug}/${parentId}/relations/${slug}/${id}`;\n return kind === 'detach' ? `${base}/detach` : base;\n };\n\n const confirmMutation = () => {\n if (!pendingAction) return;\n const { kind, id } = pendingAction;\n setMutating(true);\n router.delete(mutationUrl(id, kind), {\n preserveScroll: true,\n onSuccess: () => {\n setMutating(false);\n setPendingAction(null);\n onMutated?.();\n },\n onError: () => {\n setMutating(false);\n },\n });\n };\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-end gap-2\">\n {abilities.create && (\n <Button type=\"button\" size=\"sm\" onClick={onCreate}>\n New\n </Button>\n )}\n {type === 'belongsToMany' && abilities.attach && (\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" onClick={onAttach}>\n Attach\n </Button>\n )}\n </div>\n {error && records.length === 0 ? (\n <ErrorState title=\"Couldn't load records\" description=\"Please try again.\" />\n ) : (\n <DataTable<DataTableRecord>\n columns={columns}\n records={records as DataTableRecord[]}\n loading={loading}\n rowActions={\n abilities.update || canDelete || canDetach\n ? (record) => (\n <>\n {abilities.update && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => onEdit(record.id)}\n >\n Edit\n </Button>\n )}\n {canDelete && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => setPendingAction({ kind: 'delete', id: record.id })}\n >\n Delete\n </Button>\n )}\n {canDetach && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => setPendingAction({ kind: 'detach', id: record.id })}\n >\n Detach\n </Button>\n )}\n </>\n )\n : undefined\n }\n />\n )}\n <ConfirmDialog\n open={pendingAction !== null}\n onOpenChange={(next) => {\n if (!next) setPendingAction(null);\n }}\n onConfirm={confirmMutation}\n processing={mutating}\n config={\n pendingAction?.kind === 'detach'\n ? {\n heading: 'Detach this record?',\n color: 'destructive',\n submitLabel: 'Detach',\n }\n : {\n heading: 'Are you sure?',\n color: 'destructive',\n submitLabel: 'Delete',\n }\n }\n />\n </div>\n );\n}\n","/**\n * `<ResourceEditTabs>` — page-level tabs wrapping an edit page: a \"Data\"\n * tab (the existing form, passed as `children`) plus one tab per declared\n * `RelationManager`. Zero regression is the hard requirement: when\n * `relations` is empty (the overwhelming majority of Resources, which\n * declare no relation managers), this renders `children` directly with no\n * `Tabs` wrapper at all — so `ArqelEditPage`'s existing DOM/behavior is\n * byte-for-byte unchanged for every Resource that hasn't opted in.\n *\n * The active tab is deep-linked via `?tab=slug` (read once on mount from\n * `window.location.search`) so a reload / shared link lands back on the\n * same relation tab; navigating tabs updates the query string in place\n * (no Inertia visit — this is pure client-side tab state, not a page nav).\n *\n * Records source: `RelationManager::toArray()` (the server payload backing\n * each entry in `relations`) deliberately does NOT include the related\n * records — only `slug`/`label`/`type`/`table`/`fields`/`abilities`\n * (see `arqel-dev/types`' `RelationManagerProps` docblock). The actual rows\n * live behind `RelationController::index()`\n * (`GET {resource}/{parent}/relations/{relation}`), a plain JSON endpoint\n * (not an Inertia partial reload — it returns `{ records, table, abilities\n * }` directly), so each `RelationManagerPanel` is self-fetching (mirrors\n * `WidgetRenderer`'s `useEffect` + native `fetch()` pattern — see that\n * panel's own docblock). This keeps `ResourceEditTabs` from needing to own\n * a records cache itself; it only tracks a per-relation `refreshKey`\n * counter, bumped after a modal's mutation succeeds, so the panel's effect\n * re-runs and reloads the table without a full Inertia visit.\n *\n * Labels are a literal English fallback (\"Data\") rather than routed\n * through `useArqelTranslations`: that hook resolves its dictionary via\n * `usePage()`, and this component (like `RelationManagerPanel`, see its\n * docblock) is exercised directly in unit tests without a full Inertia\n * page context. `ArqelEditPage` itself already sits inside that context\n * and can localize its own strings; the tab-shell chrome added here\n * stays framework-agnostic.\n */\n\nimport type { RelationManagerProps } from '@arqel-dev/types/relations';\nimport { type ReactNode, useState } from 'react';\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '../shadcn/ui/tabs.js';\nimport { AttachModal } from './AttachModal.js';\nimport { RelationFormModal } from './RelationFormModal.js';\nimport { RelationManagerPanel } from './RelationManagerPanel.js';\n\nexport interface ResourceEditTabsProps {\n relations: RelationManagerProps[];\n parentSlug: string;\n parentId: string | number;\n basePath?: string;\n children: ReactNode;\n}\n\nfunction initialTab(relations: RelationManagerProps[]): string {\n const fromQuery = new URLSearchParams(window.location.search).get('tab');\n if (fromQuery && (fromQuery === 'data' || relations.some((r) => r.slug === fromQuery))) {\n return fromQuery;\n }\n return 'data';\n}\n\nexport function ResourceEditTabs({\n relations,\n parentSlug,\n parentId,\n basePath = '/admin',\n children,\n}: ResourceEditTabsProps) {\n // Hooks below only ever run when `relations` is non-empty in practice,\n // but React requires them unconditionally — cheap for the empty case.\n const [tab, setTab] = useState(() => initialTab(relations));\n const [modal, setModal] = useState<{ slug: string; recordId?: string | number } | null>(null);\n const [attachSlug, setAttachSlug] = useState<string | null>(null);\n // Bumped per-slug after a create/edit/attach mutation succeeds, so the\n // matching `RelationManagerPanel`'s fetch effect re-runs (see that\n // component's docblock — records no longer arrive via an Inertia\n // `relations` prop, so there is nothing left for a partial reload to\n // refresh).\n const [refreshKeys, setRefreshKeys] = useState<Record<string, number>>({});\n const bumpRefresh = (slug: string) =>\n setRefreshKeys((prev) => ({ ...prev, [slug]: (prev[slug] ?? 0) + 1 }));\n\n if (relations.length === 0) return <>{children}</>;\n\n const setActiveTab = (next: string) => {\n setTab(next);\n const url = new URL(window.location.href);\n if (next === 'data') {\n url.searchParams.delete('tab');\n } else {\n url.searchParams.set('tab', next);\n }\n window.history.replaceState(window.history.state, '', url);\n };\n\n const activeRelation = relations.find((r) => r.slug === modal?.slug);\n const attachRelation = relations.find((r) => r.slug === attachSlug);\n\n return (\n <Tabs value={tab} onValueChange={setActiveTab}>\n <TabsList>\n <TabsTrigger value=\"data\">Data</TabsTrigger>\n {relations.map((relation) => (\n <TabsTrigger key={relation.slug} value={relation.slug}>\n {relation.label}\n </TabsTrigger>\n ))}\n </TabsList>\n <TabsContent value=\"data\">{children}</TabsContent>\n {relations.map((relation) => (\n <TabsContent key={relation.slug} value={relation.slug}>\n <RelationManagerPanel\n relation={relation}\n parentSlug={parentSlug}\n parentId={parentId}\n basePath={basePath}\n records={[]}\n refreshKey={refreshKeys[relation.slug] ?? 0}\n onCreate={() => setModal({ slug: relation.slug })}\n onEdit={(id) => setModal({ slug: relation.slug, recordId: id })}\n onAttach={() => setAttachSlug(relation.slug)}\n onMutated={() => bumpRefresh(relation.slug)}\n />\n </TabsContent>\n ))}\n {modal && activeRelation && (\n <RelationFormModal\n open\n onClose={() => setModal(null)}\n relation={activeRelation}\n parentSlug={parentSlug}\n parentId={parentId}\n basePath={basePath}\n onSuccess={() => bumpRefresh(activeRelation.slug)}\n {...(modal.recordId !== undefined ? { recordId: modal.recordId } : {})}\n />\n )}\n {attachSlug && attachRelation && (\n <AttachModal\n open\n onClose={() => setAttachSlug(null)}\n relation={attachRelation}\n parentSlug={parentSlug}\n parentId={parentId}\n basePath={basePath}\n onSuccess={() => bumpRefresh(attachRelation.slug)}\n />\n )}\n </Tabs>\n );\n}\n","/**\n * Default Inertia page for `arqel::edit`.\n *\n * Same shape as `ArqelCreatePage` but seeds the form with the\n * server-emitted `record`. Submission posts to PUT `/{slug}/{id}`.\n */\n\nimport { useArqelForm } from '@arqel-dev/hooks';\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { FieldSchema } from '@arqel-dev/types/fields';\nimport type { FormSchema } from '@arqel-dev/types/forms';\nimport type { RelationManagerProps } from '@arqel-dev/types/relations';\nimport type { RecordType, ResourceEditProps } from '@arqel-dev/types/resources';\nimport { router, usePage } from '@inertiajs/react';\nimport type { FormEvent, JSX } from 'react';\nimport { FormActions } from '../form/FormActions.js';\nimport { FormRenderer } from '../form/FormRenderer.js';\nimport { ResourceEditTabs } from '../relations/ResourceEditTabs.js';\nimport { PageHeader } from '../utility/PageHeader.js';\n\nconst FALLBACK_SCHEMA: FormSchema = {\n schema: [],\n columns: 1,\n model: null,\n inline: false,\n disabled: false,\n};\n\ninterface ArqelFormShape {\n data: Record<string, unknown>;\n setData: (name: string, value: unknown) => void;\n errors: Record<string, string[]>;\n processing: boolean;\n}\n\nexport default function ArqelEditPage<TRecord extends RecordType = RecordType>(): JSX.Element {\n const page = usePage();\n const t = useArqelTranslations();\n const props = page.props as unknown as ResourceEditProps<TRecord>;\n const fields = (props.fields ?? []) as FieldSchema[];\n const record = props.record;\n const schema = (props as unknown as { form?: FormSchema }).form ?? FALLBACK_SCHEMA;\n const relations = (props.relations ?? []) as RelationManagerProps[];\n\n const form = useArqelForm({ fields, record }) as unknown as ArqelFormShape;\n\n const submit = (e: FormEvent): void => {\n e.preventDefault();\n const id = String((record as { id?: string | number } | undefined)?.id ?? '');\n const slug = props.resource?.slug ?? '';\n const basePath = props.resource?.panelPath ?? '/admin';\n router.put(`${basePath}/${slug}/${id}`, form.data as Record<string, never>, {\n preserveScroll: true,\n });\n };\n\n // Pre-interpolate the label into the English fallback so the title stays\n // correct even when the `arqel.pages.edit` key is absent from the shared\n // dictionary (the hook does not re-interpolate a raw fallback).\n const label = props.resource?.label ?? t('arqel.pages.fallback', 'record');\n const editTitle = props.recordTitle ?? t('arqel.pages.edit', `Edit ${label}`, { label });\n\n const formContent = (\n <form onSubmit={submit} className=\"space-y-6\">\n <FormRenderer\n schema={schema}\n fields={fields}\n values={form.data}\n onChange={(name, value) => form.setData(name, value)}\n errors={form.errors}\n />\n <FormActions processing={form.processing} onCancel={() => window.history.back()} />\n </form>\n );\n\n return (\n <div className=\"space-y-6\">\n <PageHeader title={editTitle} description={props.recordSubtitle ?? null} />\n <ResourceEditTabs\n relations={relations}\n parentSlug={props.resource?.slug ?? ''}\n parentId={(record as { id?: string | number } | undefined)?.id ?? ''}\n basePath={props.resource?.panelPath ?? '/admin'}\n >\n {formContent}\n </ResourceEditTabs>\n </div>\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button } from './chunk-
|
|
1
|
+
import { Button } from './chunk-YF2RINPG.js';
|
|
2
2
|
import { cn } from './chunk-B7ULUJVO.js';
|
|
3
3
|
import { useArqelTranslations } from '@arqel-dev/react/utils';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -32,5 +32,5 @@ function FormActions({
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export { FormActions };
|
|
35
|
-
//# sourceMappingURL=chunk-
|
|
36
|
-
//# sourceMappingURL=chunk-
|
|
35
|
+
//# sourceMappingURL=chunk-SVCWLDZ4.js.map
|
|
36
|
+
//# sourceMappingURL=chunk-SVCWLDZ4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/form/FormActions.tsx"],"names":[],"mappings":";;;;;AAuBO,SAAS,WAAA,CAAY;AAAA,EAC1B,WAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA,GAAa,KAAA;AAAA,EACb,QAAA,GAAW,KAAA;AAAA,EACX,KAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAE/B,EAAA,MAAM,MAAA,GAAS,WAAA,IAAe,CAAA,CAAE,WAAA,EAAa,MAAM,CAAA;AACnD,EAAA,MAAM,MAAA,GAAS,WAAA,IAAe,CAAA,CAAE,aAAA,EAAe,QAAQ,CAAA;AACvD,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,2EAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,KAAA,oBAAS,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,SAAA,EAAW,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,QACzC,QAAA,oBACC,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAQ,OAAA,EAAQ,OAAA,EAAS,QAAA,EAAU,QAAA,EAAU,UAAA,EAChE,QAAA,EAAA,MAAA,EACH,CAAA;AAAA,wBAEF,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,QAAA,EAAU,UAAA,IAAc,QAAA,EAC3C,QAAA,EAAA,UAAA,GAAa,CAAA,CAAE,aAAA,EAAe,cAAS,CAAA,GAAI,MAAA,EAC9C;AAAA;AAAA;AAAA,GACF;AAEJ","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/form/FormActions.tsx"],"names":[],"mappings":";;;;;AAuBO,SAAS,WAAA,CAAY;AAAA,EAC1B,WAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA,GAAa,KAAA;AAAA,EACb,QAAA,GAAW,KAAA;AAAA,EACX,KAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAE/B,EAAA,MAAM,MAAA,GAAS,WAAA,IAAe,CAAA,CAAE,WAAA,EAAa,MAAM,CAAA;AACnD,EAAA,MAAM,MAAA,GAAS,WAAA,IAAe,CAAA,CAAE,aAAA,EAAe,QAAQ,CAAA;AACvD,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,2EAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,KAAA,oBAAS,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,SAAA,EAAW,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,QACzC,QAAA,oBACC,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAQ,OAAA,EAAQ,OAAA,EAAS,QAAA,EAAU,QAAA,EAAU,UAAA,EAChE,QAAA,EAAA,MAAA,EACH,CAAA;AAAA,wBAEF,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,QAAA,EAAU,UAAA,IAAc,QAAA,EAC3C,QAAA,EAAA,UAAA,GAAa,CAAA,CAAE,aAAA,EAAe,cAAS,CAAA,GAAI,MAAA,EAC9C;AAAA;AAAA;AAAA,GACF;AAEJ","file":"chunk-SVCWLDZ4.js","sourcesContent":["/**\n * `<FormActions>` — submit + cancel + extra slots.\n *\n * Sits at the bottom of a form. The submit button is `type=\"submit\"`\n * so wrapping a `<form>` around `<FormRenderer>` + `<FormActions>`\n * triggers the form's onSubmit naturally.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { ReactNode } from 'react';\nimport { Button } from '../action/Button.js';\nimport { cn } from '../utils/cn.js';\n\nexport interface FormActionsProps {\n submitLabel?: string;\n cancelLabel?: string;\n onCancel?: () => void;\n processing?: boolean;\n disabled?: boolean;\n extra?: ReactNode;\n className?: string;\n}\n\nexport function FormActions({\n submitLabel,\n cancelLabel,\n onCancel,\n processing = false,\n disabled = false,\n extra,\n className,\n}: FormActionsProps) {\n const t = useArqelTranslations();\n // Precedence: explicit prop > shared translation > English fallback.\n const submit = submitLabel ?? t('form.save', 'Save');\n const cancel = cancelLabel ?? t('form.cancel', 'Cancel');\n return (\n <div\n className={cn(\n 'flex flex-wrap items-center justify-end gap-2 border-t border-border pt-4',\n className,\n )}\n >\n {extra && <div className=\"mr-auto\">{extra}</div>}\n {onCancel && (\n <Button type=\"button\" variant=\"ghost\" onClick={onCancel} disabled={processing}>\n {cancel}\n </Button>\n )}\n <Button type=\"submit\" disabled={processing || disabled}>\n {processing ? t('form.saving', 'Saving…') : submit}\n </Button>\n </div>\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button } from './chunk-
|
|
1
|
+
import { Button } from './chunk-YF2RINPG.js';
|
|
2
2
|
import { cn } from './chunk-B7ULUJVO.js';
|
|
3
3
|
import { useArqelTranslations, useArqelLocale } from '@arqel-dev/react/utils';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -271,5 +271,5 @@ function TableToolbar({
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
export { TableFilters, TablePagination, TableToolbar };
|
|
274
|
-
//# sourceMappingURL=chunk-
|
|
275
|
-
//# sourceMappingURL=chunk-
|
|
274
|
+
//# sourceMappingURL=chunk-TBDWW6L5.js.map
|
|
275
|
+
//# sourceMappingURL=chunk-TBDWW6L5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/table/TableFilters.tsx","../src/table/TablePagination.tsx","../src/table/TableToolbar.tsx"],"names":["useArqelTranslations","jsxs","jsx"],"mappings":"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","file":"chunk-YEPQWAD6.js","sourcesContent":["/**\n * `<TableFilters>` — renders one input per `FilterSchema` and emits\n * a single `onChange(name, value)` callback. Active values render as\n * dismissible chips so users can read state without re-opening menus.\n *\n * Phase 1 covers the four most-used filter types (select, multiSelect,\n * text, ternary). dateRange / scope land alongside FieldRenderer in\n * UI-004, where the date primitives ship.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type {\n FilterSchema,\n MultiSelectFilterSchema,\n SelectFilterSchema,\n TernaryFilterSchema,\n TextFilterSchema,\n} from '@arqel-dev/types/tables';\nimport { Button } from '../action/Button.js';\nimport { cn } from '../utils/cn.js';\n\nexport interface TableFiltersProps {\n filters: FilterSchema[];\n values: Record<string, unknown>;\n onChange: (name: string, value: unknown) => void;\n onClearAll?: (() => void) | undefined;\n className?: string | undefined;\n}\n\nexport function TableFilters({\n filters,\n values,\n onChange,\n onClearAll,\n className,\n}: TableFiltersProps) {\n const t = useArqelTranslations();\n if (filters.length === 0) return null;\n\n const activeCount = filters.reduce((acc, f) => {\n const v = values[f.name];\n return v !== undefined && v !== null && v !== '' ? acc + 1 : acc;\n }, 0);\n\n return (\n <fieldset className={cn('flex flex-wrap items-end gap-2 border-0 p-0', className)}>\n <legend className=\"sr-only\">{t('table.filters.legend', 'Filters')}</legend>\n {filters.map((filter) => (\n <FilterControl\n key={filter.name}\n filter={filter}\n value={values[filter.name]}\n onChange={(v) => onChange(filter.name, v)}\n />\n ))}\n {activeCount > 0 && onClearAll && (\n <Button variant=\"ghost\" size=\"sm\" onClick={onClearAll}>\n {t('table.filters.clear', `Clear filters (${activeCount})`, { count: activeCount })}\n </Button>\n )}\n </fieldset>\n );\n}\n\nfunction FilterControl({\n filter,\n value,\n onChange,\n}: {\n filter: FilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n switch (filter.type) {\n case 'select':\n return <SelectFilter filter={filter} value={value} onChange={onChange} />;\n case 'multiSelect':\n return <MultiSelectFilter filter={filter} value={value} onChange={onChange} />;\n case 'text':\n return <TextFilter filter={filter} value={value} onChange={onChange} />;\n case 'ternary':\n return <TernaryFilter filter={filter} value={value} onChange={onChange} />;\n case 'dateRange':\n case 'scope':\n return null;\n }\n}\n\nfunction controlClasses() {\n return cn(\n // 44px touch target on mobile (WCAG 2.5.5); dense 36px on >=md.\n 'h-11 rounded-sm border border-[var(--input)] md:h-9',\n 'bg-background px-3 text-sm',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n );\n}\n\nfunction SelectFilter({\n filter,\n value,\n onChange,\n}: {\n filter: SelectFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const t = useArqelTranslations();\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n className={controlClasses()}\n value={value === undefined || value === null ? '' : String(value)}\n onChange={(e) => onChange(e.target.value === '' ? null : e.target.value)}\n >\n <option value=\"\">{t('table.filters.all', 'All')}</option>\n {filter.props.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nfunction MultiSelectFilter({\n filter,\n value,\n onChange,\n}: {\n filter: MultiSelectFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const arr = Array.isArray(value) ? (value as Array<string | number>) : [];\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n multiple\n className={cn(controlClasses(), 'h-auto min-h-11 py-1 md:min-h-[2.25rem]')}\n value={arr.map(String)}\n onChange={(e) => {\n const next = Array.from(e.target.selectedOptions, (o) => o.value);\n onChange(next.length === 0 ? null : next);\n }}\n >\n {filter.props.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nfunction TextFilter({\n filter,\n value,\n onChange,\n}: {\n filter: TextFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <input\n type=\"text\"\n className={controlClasses()}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value === '' ? null : e.target.value)}\n />\n </label>\n );\n}\n\nfunction TernaryFilter({\n filter,\n value,\n onChange,\n}: {\n filter: TernaryFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const t = useArqelTranslations();\n const current = value === undefined || value === null ? 'all' : String(value);\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n className={controlClasses()}\n value={current}\n onChange={(e) => {\n const v = e.target.value;\n onChange(v === 'all' ? null : v);\n }}\n >\n <option value=\"all\">{filter.props.allLabel ?? t('table.filters.all', 'All')}</option>\n <option value=\"true\">{filter.props.trueLabel ?? t('table.filters.yes', 'Yes')}</option>\n <option value=\"false\">{filter.props.falseLabel ?? t('table.filters.no', 'No')}</option>\n </select>\n </label>\n );\n}\n","/**\n * `<TablePagination>` — prev/next + range + per-page picker.\n *\n * Stateless: parent owns `currentPage` / `perPage` and handles transitions\n * (typically via Inertia `router.get` with `preserveState: true`).\n */\n\nimport { useArqelLocale, useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { PaginationMeta } from '@arqel-dev/types/resources';\nimport { useMemo } from 'react';\nimport { Button } from '../action/Button.js';\nimport { cn } from '../utils/cn.js';\n\nexport interface TablePaginationProps {\n meta: PaginationMeta;\n onPageChange: (page: number) => void;\n onPerPageChange?: ((perPage: number) => void) | undefined;\n perPageOptions?: number[];\n className?: string;\n}\n\nexport function TablePagination({\n meta,\n onPageChange,\n onPerPageChange,\n perPageOptions = [10, 25, 50, 100],\n className,\n}: TablePaginationProps) {\n const t = useArqelTranslations();\n const locale = useArqelLocale();\n const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);\n const fromRaw = (meta.currentPage - 1) * meta.perPage + 1;\n const toRaw = Math.min(meta.currentPage * meta.perPage, meta.total);\n // Interpolated counts are locale number-grouped (12,345 / 12.345) before they\n // reach the translator, whose applyReplacements does plain String() substitution.\n const from = numberFormatter.format(fromRaw);\n const to = numberFormatter.format(toRaw);\n const total = numberFormatter.format(meta.total);\n const isFirst = meta.currentPage <= 1;\n const isLast = meta.currentPage >= meta.lastPage;\n\n return (\n <nav\n className={cn(\n 'flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2 text-sm',\n className,\n )}\n aria-label={t('table.pagination.label', 'Pagination')}\n >\n <span className=\"text-muted-foreground\">\n {meta.total === 0\n ? t('table.empty', 'No records found.')\n : t(\n 'table.pagination.showing',\n // Fallback is rendered verbatim when the key is missing, so it must\n // already carry the interpolated values (the replacements map only\n // applies to a resolved dictionary string).\n `Showing ${from} to ${to} of ${total} results`,\n { from, to, total },\n )}\n </span>\n <div className=\"flex items-center gap-2\">\n {onPerPageChange && (\n <label className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {t('table.per_page', 'Per page')}\n {/* 44px touch target on mobile (WCAG 2.5.5); dense 32px on >=md. */}\n <select\n className=\"h-11 rounded-sm border border-[var(--input)] bg-background px-2 md:h-8\"\n value={meta.perPage}\n onChange={(e) => onPerPageChange(Number(e.target.value))}\n >\n {perPageOptions.map((n) => (\n <option key={n} value={n}>\n {n}\n </option>\n ))}\n </select>\n </label>\n )}\n {/* Buttons use size=\"sm\" (h-8) for the dense desktop bar; the responsive\n h-11 override lifts them to a 44px touch target below md. */}\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-8\"\n disabled={isFirst}\n onClick={() => onPageChange(meta.currentPage - 1)}\n aria-label={t('table.pagination.previous_page', 'Previous page')}\n >\n {t('table.pagination.previous', 'Prev')}\n </Button>\n <span className=\"text-xs text-muted-foreground\">\n {numberFormatter.format(meta.currentPage)} / {numberFormatter.format(meta.lastPage)}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-8\"\n disabled={isLast}\n onClick={() => onPageChange(meta.currentPage + 1)}\n aria-label={t('table.pagination.next_page', 'Next page')}\n >\n {t('table.pagination.next', 'Next')}\n </Button>\n </div>\n </nav>\n );\n}\n","/**\n * `<TableToolbar>` — search input + filters + bulk-action bar slot.\n *\n * The bulk-action bar appears only when `selectedCount > 0`. ResourceIndex\n * passes `bulkActions` rendered as a row of buttons; the toolbar just\n * positions them.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { ReactNode } from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport interface TableToolbarProps {\n search?: ReactNode;\n filters?: ReactNode;\n selectedCount?: number;\n bulkActions?: ReactNode;\n onClearSelection?: (() => void) | undefined;\n className?: string;\n}\n\nexport function TableToolbar({\n search,\n filters,\n selectedCount = 0,\n bulkActions,\n onClearSelection,\n className,\n}: TableToolbarProps) {\n const t = useArqelTranslations();\n return (\n <div className={cn('flex flex-col gap-3 px-3 py-3', className)}>\n <div className=\"flex flex-wrap items-end gap-2\">\n {search}\n {filters}\n </div>\n {selectedCount > 0 && (\n <section\n className=\"flex flex-wrap items-center gap-2 rounded-sm border border-border bg-muted px-3 py-2\"\n aria-label={t('table.bulk.label', 'Bulk actions')}\n >\n <span className=\"text-sm font-medium\">\n {t('table.bulk.selected', '{one} :count selected|{other} :count selected', {\n count: selectedCount,\n })}\n </span>\n <div className=\"ml-auto flex flex-wrap items-center gap-2\">\n {bulkActions}\n {onClearSelection && (\n <button\n type=\"button\"\n className=\"text-sm text-muted-foreground hover:underline\"\n onClick={onClearSelection}\n >\n {t('table.bulk.clear', 'Clear')}\n </button>\n )}\n </div>\n </section>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/table/TableFilters.tsx","../src/table/TablePagination.tsx","../src/table/TableToolbar.tsx"],"names":["useArqelTranslations","jsxs","jsx"],"mappings":"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","file":"chunk-TBDWW6L5.js","sourcesContent":["/**\n * `<TableFilters>` — renders one input per `FilterSchema` and emits\n * a single `onChange(name, value)` callback. Active values render as\n * dismissible chips so users can read state without re-opening menus.\n *\n * Phase 1 covers the four most-used filter types (select, multiSelect,\n * text, ternary). dateRange / scope land alongside FieldRenderer in\n * UI-004, where the date primitives ship.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type {\n FilterSchema,\n MultiSelectFilterSchema,\n SelectFilterSchema,\n TernaryFilterSchema,\n TextFilterSchema,\n} from '@arqel-dev/types/tables';\nimport { Button } from '../action/Button.js';\nimport { cn } from '../utils/cn.js';\n\nexport interface TableFiltersProps {\n filters: FilterSchema[];\n values: Record<string, unknown>;\n onChange: (name: string, value: unknown) => void;\n onClearAll?: (() => void) | undefined;\n className?: string | undefined;\n}\n\nexport function TableFilters({\n filters,\n values,\n onChange,\n onClearAll,\n className,\n}: TableFiltersProps) {\n const t = useArqelTranslations();\n if (filters.length === 0) return null;\n\n const activeCount = filters.reduce((acc, f) => {\n const v = values[f.name];\n return v !== undefined && v !== null && v !== '' ? acc + 1 : acc;\n }, 0);\n\n return (\n <fieldset className={cn('flex flex-wrap items-end gap-2 border-0 p-0', className)}>\n <legend className=\"sr-only\">{t('table.filters.legend', 'Filters')}</legend>\n {filters.map((filter) => (\n <FilterControl\n key={filter.name}\n filter={filter}\n value={values[filter.name]}\n onChange={(v) => onChange(filter.name, v)}\n />\n ))}\n {activeCount > 0 && onClearAll && (\n <Button variant=\"ghost\" size=\"sm\" onClick={onClearAll}>\n {t('table.filters.clear', `Clear filters (${activeCount})`, { count: activeCount })}\n </Button>\n )}\n </fieldset>\n );\n}\n\nfunction FilterControl({\n filter,\n value,\n onChange,\n}: {\n filter: FilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n switch (filter.type) {\n case 'select':\n return <SelectFilter filter={filter} value={value} onChange={onChange} />;\n case 'multiSelect':\n return <MultiSelectFilter filter={filter} value={value} onChange={onChange} />;\n case 'text':\n return <TextFilter filter={filter} value={value} onChange={onChange} />;\n case 'ternary':\n return <TernaryFilter filter={filter} value={value} onChange={onChange} />;\n case 'dateRange':\n case 'scope':\n return null;\n }\n}\n\nfunction controlClasses() {\n return cn(\n // 44px touch target on mobile (WCAG 2.5.5); dense 36px on >=md.\n 'h-11 rounded-sm border border-[var(--input)] md:h-9',\n 'bg-background px-3 text-sm',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n );\n}\n\nfunction SelectFilter({\n filter,\n value,\n onChange,\n}: {\n filter: SelectFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const t = useArqelTranslations();\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n className={controlClasses()}\n value={value === undefined || value === null ? '' : String(value)}\n onChange={(e) => onChange(e.target.value === '' ? null : e.target.value)}\n >\n <option value=\"\">{t('table.filters.all', 'All')}</option>\n {filter.props.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nfunction MultiSelectFilter({\n filter,\n value,\n onChange,\n}: {\n filter: MultiSelectFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const arr = Array.isArray(value) ? (value as Array<string | number>) : [];\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n multiple\n className={cn(controlClasses(), 'h-auto min-h-11 py-1 md:min-h-[2.25rem]')}\n value={arr.map(String)}\n onChange={(e) => {\n const next = Array.from(e.target.selectedOptions, (o) => o.value);\n onChange(next.length === 0 ? null : next);\n }}\n >\n {filter.props.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nfunction TextFilter({\n filter,\n value,\n onChange,\n}: {\n filter: TextFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <input\n type=\"text\"\n className={controlClasses()}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value === '' ? null : e.target.value)}\n />\n </label>\n );\n}\n\nfunction TernaryFilter({\n filter,\n value,\n onChange,\n}: {\n filter: TernaryFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const t = useArqelTranslations();\n const current = value === undefined || value === null ? 'all' : String(value);\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n className={controlClasses()}\n value={current}\n onChange={(e) => {\n const v = e.target.value;\n onChange(v === 'all' ? null : v);\n }}\n >\n <option value=\"all\">{filter.props.allLabel ?? t('table.filters.all', 'All')}</option>\n <option value=\"true\">{filter.props.trueLabel ?? t('table.filters.yes', 'Yes')}</option>\n <option value=\"false\">{filter.props.falseLabel ?? t('table.filters.no', 'No')}</option>\n </select>\n </label>\n );\n}\n","/**\n * `<TablePagination>` — prev/next + range + per-page picker.\n *\n * Stateless: parent owns `currentPage` / `perPage` and handles transitions\n * (typically via Inertia `router.get` with `preserveState: true`).\n */\n\nimport { useArqelLocale, useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { PaginationMeta } from '@arqel-dev/types/resources';\nimport { useMemo } from 'react';\nimport { Button } from '../action/Button.js';\nimport { cn } from '../utils/cn.js';\n\nexport interface TablePaginationProps {\n meta: PaginationMeta;\n onPageChange: (page: number) => void;\n onPerPageChange?: ((perPage: number) => void) | undefined;\n perPageOptions?: number[];\n className?: string;\n}\n\nexport function TablePagination({\n meta,\n onPageChange,\n onPerPageChange,\n perPageOptions = [10, 25, 50, 100],\n className,\n}: TablePaginationProps) {\n const t = useArqelTranslations();\n const locale = useArqelLocale();\n const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);\n const fromRaw = (meta.currentPage - 1) * meta.perPage + 1;\n const toRaw = Math.min(meta.currentPage * meta.perPage, meta.total);\n // Interpolated counts are locale number-grouped (12,345 / 12.345) before they\n // reach the translator, whose applyReplacements does plain String() substitution.\n const from = numberFormatter.format(fromRaw);\n const to = numberFormatter.format(toRaw);\n const total = numberFormatter.format(meta.total);\n const isFirst = meta.currentPage <= 1;\n const isLast = meta.currentPage >= meta.lastPage;\n\n return (\n <nav\n className={cn(\n 'flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2 text-sm',\n className,\n )}\n aria-label={t('table.pagination.label', 'Pagination')}\n >\n <span className=\"text-muted-foreground\">\n {meta.total === 0\n ? t('table.empty', 'No records found.')\n : t(\n 'table.pagination.showing',\n // Fallback is rendered verbatim when the key is missing, so it must\n // already carry the interpolated values (the replacements map only\n // applies to a resolved dictionary string).\n `Showing ${from} to ${to} of ${total} results`,\n { from, to, total },\n )}\n </span>\n <div className=\"flex items-center gap-2\">\n {onPerPageChange && (\n <label className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {t('table.per_page', 'Per page')}\n {/* 44px touch target on mobile (WCAG 2.5.5); dense 32px on >=md. */}\n <select\n className=\"h-11 rounded-sm border border-[var(--input)] bg-background px-2 md:h-8\"\n value={meta.perPage}\n onChange={(e) => onPerPageChange(Number(e.target.value))}\n >\n {perPageOptions.map((n) => (\n <option key={n} value={n}>\n {n}\n </option>\n ))}\n </select>\n </label>\n )}\n {/* Buttons use size=\"sm\" (h-8) for the dense desktop bar; the responsive\n h-11 override lifts them to a 44px touch target below md. */}\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-8\"\n disabled={isFirst}\n onClick={() => onPageChange(meta.currentPage - 1)}\n aria-label={t('table.pagination.previous_page', 'Previous page')}\n >\n {t('table.pagination.previous', 'Prev')}\n </Button>\n <span className=\"text-xs text-muted-foreground\">\n {numberFormatter.format(meta.currentPage)} / {numberFormatter.format(meta.lastPage)}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-8\"\n disabled={isLast}\n onClick={() => onPageChange(meta.currentPage + 1)}\n aria-label={t('table.pagination.next_page', 'Next page')}\n >\n {t('table.pagination.next', 'Next')}\n </Button>\n </div>\n </nav>\n );\n}\n","/**\n * `<TableToolbar>` — search input + filters + bulk-action bar slot.\n *\n * The bulk-action bar appears only when `selectedCount > 0`. ResourceIndex\n * passes `bulkActions` rendered as a row of buttons; the toolbar just\n * positions them.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { ReactNode } from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport interface TableToolbarProps {\n search?: ReactNode;\n filters?: ReactNode;\n selectedCount?: number;\n bulkActions?: ReactNode;\n onClearSelection?: (() => void) | undefined;\n className?: string;\n}\n\nexport function TableToolbar({\n search,\n filters,\n selectedCount = 0,\n bulkActions,\n onClearSelection,\n className,\n}: TableToolbarProps) {\n const t = useArqelTranslations();\n return (\n <div className={cn('flex flex-col gap-3 px-3 py-3', className)}>\n <div className=\"flex flex-wrap items-end gap-2\">\n {search}\n {filters}\n </div>\n {selectedCount > 0 && (\n <section\n className=\"flex flex-wrap items-center gap-2 rounded-sm border border-border bg-muted px-3 py-2\"\n aria-label={t('table.bulk.label', 'Bulk actions')}\n >\n <span className=\"text-sm font-medium\">\n {t('table.bulk.selected', '{one} :count selected|{other} :count selected', {\n count: selectedCount,\n })}\n </span>\n <div className=\"ml-auto flex flex-wrap items-center gap-2\">\n {bulkActions}\n {onClearSelection && (\n <button\n type=\"button\"\n className=\"text-sm text-muted-foreground hover:underline\"\n onClick={onClearSelection}\n >\n {t('table.bulk.clear', 'Clear')}\n </button>\n )}\n </div>\n </section>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -46,34 +46,7 @@ function EmptyState({ title, description, icon, action, className }) {
|
|
|
46
46
|
}
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
-
var VARIANT_CLASSES = {
|
|
50
|
-
line: "h-4 w-full",
|
|
51
|
-
block: "h-24 w-full",
|
|
52
|
-
circle: "h-10 w-10 rounded-full"
|
|
53
|
-
};
|
|
54
|
-
function LoadingSkeleton({
|
|
55
|
-
variant = "line",
|
|
56
|
-
width,
|
|
57
|
-
height,
|
|
58
|
-
count = 1,
|
|
59
|
-
className
|
|
60
|
-
}) {
|
|
61
|
-
const items = Array.from({ length: count }, (_, i) => i);
|
|
62
|
-
return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", "aria-hidden": "true", children: items.map((i) => /* @__PURE__ */ jsx(
|
|
63
|
-
"div",
|
|
64
|
-
{
|
|
65
|
-
style: { width, height },
|
|
66
|
-
className: cn(
|
|
67
|
-
"animate-pulse bg-muted",
|
|
68
|
-
variant !== "circle" && "rounded-sm",
|
|
69
|
-
VARIANT_CLASSES[variant],
|
|
70
|
-
className
|
|
71
|
-
)
|
|
72
|
-
},
|
|
73
|
-
i
|
|
74
|
-
)) });
|
|
75
|
-
}
|
|
76
49
|
|
|
77
|
-
export { Breadcrumbs, EmptyState
|
|
78
|
-
//# sourceMappingURL=chunk-
|
|
79
|
-
//# sourceMappingURL=chunk-
|
|
50
|
+
export { Breadcrumbs, EmptyState };
|
|
51
|
+
//# sourceMappingURL=chunk-VO5KYIHC.js.map
|
|
52
|
+
//# sourceMappingURL=chunk-VO5KYIHC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utility/Breadcrumbs.tsx","../src/utility/EmptyState.tsx"],"names":["jsxs","jsx"],"mappings":";;;;;AAiCO,SAAS,YAAY,KAAA,EAAyB;AACnD,EAAA,IAAI,KAAA,CAAM,UAAU,MAAA,EAAW;AAC7B,IAAA,uBAAO,GAAA,CAAC,iBAAA,EAAA,EAAmB,GAAG,KAAA,EAAO,CAAA;AAAA,EACvC;AACA,EAAA,2BAAQ,eAAA,EAAA,EAAiB,GAAG,KAAA,EAAO,KAAA,EAAO,MAAM,KAAA,EAAO,CAAA;AACzD;AAEA,SAAS,kBAAkB,KAAA,EAAyB;AAClD,EAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,EAAA,MAAM,KAAA,GAAS,IAAA,CAAK,KAAA,CAAqC,KAAA,EAAO,eAAe,EAAC;AAChF,EAAA,uBAAO,GAAA,CAAC,eAAA,EAAA,EAAiB,GAAG,KAAA,EAAO,KAAA,EAAc,CAAA;AACnD;AAEA,SAAS,eAAA,CAAgB;AAAA,EACvB,KAAA;AAAA,EACA,SAAA,mBAAY,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAY,QAAO,QAAA,EAAA,GAAA,EAAC,CAAA;AAAA,EACtC;AACF,CAAA,EAAmD;AACjD,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAC/B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAE/B,EAAA,uBACE,GAAA,CAAC,SAAI,YAAA,EAAY,CAAA,CAAE,yBAAyB,YAAY,CAAA,EAAG,WAAW,EAAA,CAAG,SAAA,EAAW,SAAS,CAAA,EAC3F,QAAA,kBAAA,GAAA,CAAC,QAAG,SAAA,EAAU,yDAAA,EACX,gBAAM,GAAA,CAAI,CAAC,MAAM,KAAA,KAAU;AAC1B,IAAA,MAAM,MAAA,GAAS,KAAA,KAAU,KAAA,CAAM,MAAA,GAAS,CAAA;AACxC,IAAA,uBACE,IAAA,CAAC,IAAA,EAAA,EAA+C,SAAA,EAAU,yBAAA,EACvD,QAAA,EAAA;AAAA,MAAA,MAAA,IAAU,CAAC,KAAK,GAAA,mBACf,GAAA,CAAC,UAAK,cAAA,EAAc,MAAA,GAAS,MAAA,GAAS,MAAA,EAAW,SAAA,EAAU,iBAAA,EACxD,eAAK,KAAA,EACR,CAAA,uBAEC,GAAA,EAAA,EAAE,IAAA,EAAM,KAAK,GAAA,EAAK,SAAA,EAAU,iBAAA,EAC1B,QAAA,EAAA,IAAA,CAAK,KAAA,EACR,CAAA;AAAA,MAED,CAAC,MAAA,IAAU;AAAA,KAAA,EAAA,EAVL,GAAG,IAAA,CAAK,KAAK,IAAI,IAAA,CAAK,GAAA,IAAO,MAAM,CAAA,CAW5C,CAAA;AAAA,EAEJ,CAAC,GACH,CAAA,EACF,CAAA;AAEJ;AC3DO,SAAS,WAAW,EAAE,KAAA,EAAO,aAAa,IAAA,EAAM,MAAA,EAAQ,WAAU,EAAoB;AAC3F,EAAA,uBACEA,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,+EAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,IAAA,oBAAQC,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,YAAY,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,wBACzCA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,2CAA2C,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,QAC9D,+BAAeA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oBAAoB,QAAA,EAAA,WAAA,EAAY,CAAA;AAAA,QAC5D,0BAAUA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,QAAQ,QAAA,EAAA,MAAA,EAAO;AAAA;AAAA;AAAA,GAC3C;AAEJ","file":"chunk-VO5KYIHC.js","sourcesContent":["/**\n * `<Breadcrumbs>` — renders the panel's breadcrumb trail.\n *\n * Items can be passed explicitly, or auto-resolved from Inertia shared\n * props (`panel.breadcrumbs`, populated server-side by\n * `Arqel\\Nav\\BreadcrumbsBuilder`). Each item is a link unless it's the\n * last entry, which is rendered as plain text and marked\n * `aria-current=\"page\"`.\n *\n * `usePage()` is only invoked when `items` is omitted — explicit-items\n * usage works outside Inertia (e.g. dashboard widgets, tests).\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport { usePage } from '@inertiajs/react';\nimport type { ReactNode } from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport interface BreadcrumbItem {\n label: string;\n url?: string | null;\n}\n\nexport interface BreadcrumbsProps {\n items?: BreadcrumbItem[];\n separator?: ReactNode;\n className?: string;\n}\n\ninterface PanelWithCrumbs {\n panel?: { breadcrumbs?: BreadcrumbItem[] } | null;\n}\n\nexport function Breadcrumbs(props: BreadcrumbsProps) {\n if (props.items === undefined) {\n return <SharedBreadcrumbs {...props} />;\n }\n return <BreadcrumbsList {...props} items={props.items} />;\n}\n\nfunction SharedBreadcrumbs(props: BreadcrumbsProps) {\n const page = usePage();\n const items = (page.props as unknown as PanelWithCrumbs).panel?.breadcrumbs ?? [];\n return <BreadcrumbsList {...props} items={items} />;\n}\n\nfunction BreadcrumbsList({\n items,\n separator = <span aria-hidden=\"true\">/</span>,\n className,\n}: BreadcrumbsProps & { items: BreadcrumbItem[] }) {\n const t = useArqelTranslations();\n if (items.length === 0) return null;\n\n return (\n <nav aria-label={t('arqel.aria.breadcrumb', 'Breadcrumb')} className={cn('text-sm', className)}>\n <ol className=\"flex flex-wrap items-center gap-2 text-muted-foreground\">\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n return (\n <li key={`${item.label}-${item.url ?? 'leaf'}`} className=\"flex items-center gap-2\">\n {isLast || !item.url ? (\n <span aria-current={isLast ? 'page' : undefined} className=\"text-foreground\">\n {item.label}\n </span>\n ) : (\n <a href={item.url} className=\"hover:underline\">\n {item.label}\n </a>\n )}\n {!isLast && separator}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n","/**\n * `<EmptyState>` — standardised empty-state block.\n *\n * Used by DataTable's empty slot and as a stand-alone fallback when\n * a resource collection has zero records.\n */\n\nimport type { ReactNode } from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport interface EmptyStateProps {\n title: ReactNode;\n description?: ReactNode;\n icon?: ReactNode;\n action?: ReactNode;\n className?: string;\n}\n\nexport function EmptyState({ title, description, icon, action, className }: EmptyStateProps) {\n return (\n <div\n className={cn(\n 'flex flex-col items-center gap-3 px-4 py-12 text-center text-muted-foreground',\n className,\n )}\n >\n {icon && <div className=\"text-3xl\">{icon}</div>}\n <h2 className=\"text-base font-semibold text-foreground\">{title}</h2>\n {description && <p className=\"max-w-md text-sm\">{description}</p>}\n {action && <div className=\"mt-2\">{action}</div>}\n </div>\n );\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PageHeader } from './chunk-MXUXMHOK.js';
|
|
2
|
-
import { FormActions } from './chunk-
|
|
2
|
+
import { FormActions } from './chunk-SVCWLDZ4.js';
|
|
3
3
|
import { FormRenderer } from './chunk-CMNZLA32.js';
|
|
4
4
|
import { useArqelForm } from '@arqel-dev/hooks';
|
|
5
5
|
import { useArqelTranslations } from '@arqel-dev/react/utils';
|
|
@@ -49,5 +49,5 @@ function ArqelCreatePage() {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export { ArqelCreatePage };
|
|
52
|
-
//# sourceMappingURL=chunk-
|
|
53
|
-
//# sourceMappingURL=chunk-
|
|
52
|
+
//# sourceMappingURL=chunk-WXPBHB7R.js.map
|
|
53
|
+
//# sourceMappingURL=chunk-WXPBHB7R.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pages/ArqelCreatePage.tsx"],"names":[],"mappings":";;;;;;;;AAoBA,IAAM,eAAA,GAA8B;AAAA,EAClC,QAAQ,EAAC;AAAA,EACT,OAAA,EAAS,CAAA;AAAA,EACT,KAAA,EAAO,IAAA;AAAA,EACP,MAAA,EAAQ,KAAA;AAAA,EACR,QAAA,EAAU;AACZ,CAAA;AASe,SAAR,eAAA,GAAgD;AACrD,EAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAC/B,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,EAAA,MAAM,MAAA,GAAU,KAAA,CAAM,MAAA,IAAU,EAAC;AACjC,EAAA,MAAM,MAAA,GAAU,MAA2C,IAAA,IAAQ,eAAA;AAEnE,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,EAAE,MAAA,EAAQ,CAAA;AAEpC,EAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAuB;AACrC,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,QAAA,EAAU,IAAA,IAAQ,EAAA;AACrC,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,EAAU,SAAA,IAAa,QAAA;AAC9C,IAAA,MAAA,CAAO,KAAK,CAAA,EAAG,QAAQ,IAAI,IAAI,CAAA,CAAA,EAAI,KAAK,IAAA,EAA+B;AAAA,MACrE,cAAA,EAAgB;AAAA,KACjB,CAAA;AAAA,EACH,CAAA;AAKA,EAAA,MAAM,QAAQ,KAAA,CAAM,QAAA,EAAU,KAAA,IAAS,CAAA,CAAE,wBAAwB,QAAQ,CAAA;AACzE,EAAA,MAAM,WAAA,GAAc,EAAE,oBAAA,EAAsB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA,EAAI,EAAE,OAAO,CAAA;AAExE,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,KAAA,EAAO,WAAA,EAAa,WAAA,EAAa,IAAA,EAAM,CAAA;AAAA,oBACnD,IAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAU,MAAA,EAAQ,WAAU,WAAA,EAChC,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,MAAA;AAAA,UACA,MAAA;AAAA,UACA,QAAQ,IAAA,CAAK,IAAA;AAAA,UACb,UAAU,CAAC,IAAA,EAAM,UAAU,IAAA,CAAK,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,UACnD,QAAQ,IAAA,CAAK;AAAA;AAAA,OACf;AAAA,sBACA,GAAA,CAAC,WAAA,EAAA,EAAY,UAAA,EAAY,IAAA,CAAK,UAAA,EAAY,UAAU,MAAM,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAK,EAAG;AAAA,KAAA,EACnF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/pages/ArqelCreatePage.tsx"],"names":[],"mappings":";;;;;;;;AAoBA,IAAM,eAAA,GAA8B;AAAA,EAClC,QAAQ,EAAC;AAAA,EACT,OAAA,EAAS,CAAA;AAAA,EACT,KAAA,EAAO,IAAA;AAAA,EACP,MAAA,EAAQ,KAAA;AAAA,EACR,QAAA,EAAU;AACZ,CAAA;AASe,SAAR,eAAA,GAAgD;AACrD,EAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAC/B,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,EAAA,MAAM,MAAA,GAAU,KAAA,CAAM,MAAA,IAAU,EAAC;AACjC,EAAA,MAAM,MAAA,GAAU,MAA2C,IAAA,IAAQ,eAAA;AAEnE,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,EAAE,MAAA,EAAQ,CAAA;AAEpC,EAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAuB;AACrC,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,QAAA,EAAU,IAAA,IAAQ,EAAA;AACrC,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,EAAU,SAAA,IAAa,QAAA;AAC9C,IAAA,MAAA,CAAO,KAAK,CAAA,EAAG,QAAQ,IAAI,IAAI,CAAA,CAAA,EAAI,KAAK,IAAA,EAA+B;AAAA,MACrE,cAAA,EAAgB;AAAA,KACjB,CAAA;AAAA,EACH,CAAA;AAKA,EAAA,MAAM,QAAQ,KAAA,CAAM,QAAA,EAAU,KAAA,IAAS,CAAA,CAAE,wBAAwB,QAAQ,CAAA;AACzE,EAAA,MAAM,WAAA,GAAc,EAAE,oBAAA,EAAsB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA,EAAI,EAAE,OAAO,CAAA;AAExE,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,KAAA,EAAO,WAAA,EAAa,WAAA,EAAa,IAAA,EAAM,CAAA;AAAA,oBACnD,IAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAU,MAAA,EAAQ,WAAU,WAAA,EAChC,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,MAAA;AAAA,UACA,MAAA;AAAA,UACA,QAAQ,IAAA,CAAK,IAAA;AAAA,UACb,UAAU,CAAC,IAAA,EAAM,UAAU,IAAA,CAAK,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,UACnD,QAAQ,IAAA,CAAK;AAAA;AAAA,OACf;AAAA,sBACA,GAAA,CAAC,WAAA,EAAA,EAAY,UAAA,EAAY,IAAA,CAAK,UAAA,EAAY,UAAU,MAAM,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAK,EAAG;AAAA,KAAA,EACnF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"chunk-WXPBHB7R.js","sourcesContent":["/**\n * Default Inertia page for `arqel::create`.\n *\n * Renders a `<FormRenderer>` over the schema/fields the server\n * emits (with `record: null`). Submission goes through Inertia's\n * `useForm` via `useArqelForm` from `@arqel-dev/hooks` — this page is\n * just the layout shell.\n */\n\nimport { useArqelForm } from '@arqel-dev/hooks';\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { FieldSchema } from '@arqel-dev/types/fields';\nimport type { FormSchema } from '@arqel-dev/types/forms';\nimport type { ResourceCreateProps } from '@arqel-dev/types/resources';\nimport { router, usePage } from '@inertiajs/react';\nimport type { FormEvent, JSX } from 'react';\nimport { FormActions } from '../form/FormActions.js';\nimport { FormRenderer } from '../form/FormRenderer.js';\nimport { PageHeader } from '../utility/PageHeader.js';\n\nconst FALLBACK_SCHEMA: FormSchema = {\n schema: [],\n columns: 1,\n model: null,\n inline: false,\n disabled: false,\n};\n\ninterface ArqelFormShape {\n data: Record<string, unknown>;\n setData: (name: string, value: unknown) => void;\n errors: Record<string, string[]>;\n processing: boolean;\n}\n\nexport default function ArqelCreatePage(): JSX.Element {\n const page = usePage();\n const t = useArqelTranslations();\n const props = page.props as unknown as ResourceCreateProps;\n const fields = (props.fields ?? []) as FieldSchema[];\n const schema = (props as unknown as { form?: FormSchema }).form ?? FALLBACK_SCHEMA;\n\n const form = useArqelForm({ fields }) as unknown as ArqelFormShape;\n\n const submit = (e: FormEvent): void => {\n e.preventDefault();\n const slug = props.resource?.slug ?? '';\n const basePath = props.resource?.panelPath ?? '/admin';\n router.post(`${basePath}/${slug}`, form.data as Record<string, never>, {\n preserveScroll: true,\n });\n };\n\n // Pre-interpolate the label into the English fallback so the title stays\n // correct even when the `arqel.pages.create` key is absent from the shared\n // dictionary (the hook does not re-interpolate a raw fallback).\n const label = props.resource?.label ?? t('arqel.pages.fallback', 'record');\n const createTitle = t('arqel.pages.create', `Create ${label}`, { label });\n\n return (\n <div className=\"space-y-6\">\n <PageHeader title={createTitle} description={null} />\n <form onSubmit={submit} className=\"space-y-6\">\n <FormRenderer\n schema={schema}\n fields={fields}\n values={form.data}\n onChange={(name, value) => form.setData(name, value)}\n errors={form.errors}\n />\n <FormActions processing={form.processing} onCancel={() => window.history.back()} />\n </form>\n </div>\n );\n}\n"]}
|