@carto/ps-react-ui 6.0.0 → 6.1.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/actions-BWlS5tpP.js +1150 -0
- package/dist/actions-BWlS5tpP.js.map +1 -0
- package/dist/category-alzjKzvQ.js +839 -0
- package/dist/category-alzjKzvQ.js.map +1 -0
- package/dist/{download-Vlzn2jzb.js → download-B4sykOFm.js} +94 -83
- package/dist/download-B4sykOFm.js.map +1 -0
- package/dist/{echart-DjcbtKgi.js → echart-CV8F50gn.js} +6 -5
- package/dist/echart-CV8F50gn.js.map +1 -0
- package/dist/{formula-CdHWtepq.js → formula-DJS-JLpk.js} +10 -16
- package/dist/{formula-CdHWtepq.js.map → formula-DJS-JLpk.js.map} +1 -1
- package/dist/legend.js +34 -21
- package/dist/legend.js.map +1 -1
- package/dist/{markdown-CY-67NRE.js → markdown-Bn2nKCbn.js} +12 -18
- package/dist/{markdown-CY-67NRE.js.map → markdown-Bn2nKCbn.js.map} +1 -1
- package/dist/{range-DHQSsl2_.js → range-BpU2zBmq.js} +2 -2
- package/dist/{range-DHQSsl2_.js.map → range-BpU2zBmq.js.map} +1 -1
- package/dist/{spread-DuM5oTI1.js → spread-CQwFIwuz.js} +10 -16
- package/dist/{spread-DuM5oTI1.js.map → spread-CQwFIwuz.js.map} +1 -1
- package/dist/{stores-B8CHbgw-.js → stores-DcBOZlU3.js} +30 -24
- package/dist/stores-DcBOZlU3.js.map +1 -0
- package/dist/{table-BE4uO9pp.js → table-DEdW_fDj.js} +7 -13
- package/dist/{table-BE4uO9pp.js.map → table-DEdW_fDj.js.map} +1 -1
- package/dist/types/legend/stores/types.d.ts +4 -2
- package/dist/types/widgets/actions/download/csv-item.d.ts +3 -3
- package/dist/types/widgets/actions/download/index.d.ts +2 -1
- package/dist/types/widgets/actions/download/png-item.d.ts +2 -2
- package/dist/types/widgets/actions/download/types.d.ts +12 -1
- package/dist/types/widgets/actions/download/widget-download.d.ts +26 -0
- package/dist/types/widgets/actions/fullscreen/fullscreen.d.ts +20 -13
- package/dist/types/widgets/actions/index.d.ts +1 -1
- package/dist/types/widgets/actions/searcher/filter.d.ts +3 -2
- package/dist/types/widgets/actions/searcher/searcher-toggle.d.ts +3 -0
- package/dist/types/widgets/bar/download.d.ts +6 -20
- package/dist/types/widgets/category/category-ui.d.ts +9 -1
- package/dist/types/widgets/category/download.d.ts +5 -10
- package/dist/types/widgets/category/helpers.d.ts +10 -0
- package/dist/types/widgets/echart/style.d.ts +1 -0
- package/dist/types/widgets/formula/download.d.ts +5 -15
- package/dist/types/widgets/histogram/download.d.ts +3 -8
- package/dist/types/widgets/index.d.ts +1 -1
- package/dist/types/widgets/markdown/download.d.ts +5 -11
- package/dist/types/widgets/pie/download.d.ts +3 -8
- package/dist/types/widgets/scatterplot/download.d.ts +6 -11
- package/dist/types/widgets/spread/download.d.ts +6 -12
- package/dist/types/widgets/stores/index.d.ts +1 -1
- package/dist/types/widgets/stores/widget-store-registry.d.ts +14 -0
- package/dist/types/widgets/table/download.d.ts +7 -13
- package/dist/types/widgets/timeseries/download.d.ts +7 -12
- package/dist/types/widgets/toolbox/toolbox.d.ts +1 -1
- package/dist/{utils-BStJWhZN.js → utils-C-eWwOhE.js} +2 -2
- package/dist/{utils-BStJWhZN.js.map → utils-C-eWwOhE.js.map} +1 -1
- package/dist/widgets/actions.js +4 -4
- package/dist/widgets/bar.js +11 -17
- package/dist/widgets/bar.js.map +1 -1
- package/dist/widgets/category.js +1 -1
- package/dist/widgets/echart.js +1 -1
- package/dist/widgets/formula.js +1 -1
- package/dist/widgets/histogram.js +14 -20
- package/dist/widgets/histogram.js.map +1 -1
- package/dist/widgets/markdown.js +1 -1
- package/dist/widgets/pie.js +13 -19
- package/dist/widgets/pie.js.map +1 -1
- package/dist/widgets/range.js +1 -1
- package/dist/widgets/scatterplot.js +13 -19
- package/dist/widgets/scatterplot.js.map +1 -1
- package/dist/widgets/spread.js +1 -1
- package/dist/widgets/stores.js +2 -2
- package/dist/widgets/table.js +1 -1
- package/dist/widgets/timeseries.js +16 -22
- package/dist/widgets/timeseries.js.map +1 -1
- package/dist/widgets/utils.js +1 -1
- package/dist/widgets.js +274 -333
- package/dist/widgets.js.map +1 -1
- package/dist/{zoom-toggle-D_VuA01l.js → zoom-toggle-MmLjMTEw.js} +2 -2
- package/dist/{zoom-toggle-D_VuA01l.js.map → zoom-toggle-MmLjMTEw.js.map} +1 -1
- package/package.json +1 -1
- package/src/legend/components/legend-item/legend-item-ui.test.tsx +22 -1
- package/src/legend/components/legend-ramp/legend-ramp-ui.tsx +22 -6
- package/src/legend/stores/types.ts +4 -2
- package/src/widgets/actions/download/csv-item.test.tsx +3 -3
- package/src/widgets/actions/download/csv-item.tsx +6 -6
- package/src/widgets/actions/download/download.tsx +5 -3
- package/src/widgets/actions/download/index.ts +2 -1
- package/src/widgets/actions/download/png-item.test.tsx +5 -3
- package/src/widgets/actions/download/png-item.tsx +4 -4
- package/src/widgets/actions/download/types.ts +15 -1
- package/src/widgets/actions/download/widget-download.test.ts +30 -0
- package/src/widgets/actions/download/widget-download.ts +41 -0
- package/src/widgets/actions/fullscreen/fullscreen-store.test.tsx +155 -0
- package/src/widgets/actions/fullscreen/fullscreen.test.tsx +39 -41
- package/src/widgets/actions/fullscreen/fullscreen.tsx +198 -96
- package/src/widgets/actions/index.ts +3 -0
- package/src/widgets/actions/searcher/filter.test.ts +28 -0
- package/src/widgets/actions/searcher/filter.ts +22 -4
- package/src/widgets/actions/searcher/searcher-toggle.tsx +16 -8
- package/src/widgets/actions/searcher/searcher.test.tsx +22 -0
- package/src/widgets/actions/searcher/searcher.tsx +17 -7
- package/src/widgets/bar/download.test.tsx +5 -3
- package/src/widgets/bar/download.tsx +11 -35
- package/src/widgets/category/category-ui.tsx +26 -14
- package/src/widgets/category/category.tsx +37 -2
- package/src/widgets/category/components/category-legend.tsx +1 -2
- package/src/widgets/category/download.test.ts +4 -2
- package/src/widgets/category/download.ts +14 -27
- package/src/widgets/category/helpers.test.ts +17 -0
- package/src/widgets/category/helpers.ts +16 -0
- package/src/widgets/echart/style.ts +6 -0
- package/src/widgets/formula/download.test.tsx +3 -1
- package/src/widgets/formula/download.tsx +10 -30
- package/src/widgets/histogram/download.test.ts +6 -4
- package/src/widgets/histogram/download.ts +13 -26
- package/src/widgets/index.ts +1 -0
- package/src/widgets/markdown/download.test.ts +2 -2
- package/src/widgets/markdown/download.tsx +11 -26
- package/src/widgets/pie/download.test.ts +7 -3
- package/src/widgets/pie/download.ts +12 -25
- package/src/widgets/scatterplot/download.test.ts +4 -2
- package/src/widgets/scatterplot/download.ts +15 -28
- package/src/widgets/spread/download.test.ts +3 -1
- package/src/widgets/spread/download.ts +13 -27
- package/src/widgets/stores/index.ts +2 -0
- package/src/widgets/stores/widget-store-registry.test.ts +25 -0
- package/src/widgets/stores/widget-store-registry.ts +22 -0
- package/src/widgets/table/download.test.ts +5 -3
- package/src/widgets/table/download.ts +15 -29
- package/src/widgets/timeseries/download.test.ts +6 -4
- package/src/widgets/timeseries/download.ts +16 -29
- package/src/widgets/toolbox/toolbox.tsx +1 -1
- package/dist/actions-KsX1xdDM.js +0 -1024
- package/dist/actions-KsX1xdDM.js.map +0 -1
- package/dist/category-CsdDqDzo.js +0 -833
- package/dist/category-CsdDqDzo.js.map +0 -1
- package/dist/download-Vlzn2jzb.js.map +0 -1
- package/dist/echart-DjcbtKgi.js.map +0 -1
- package/dist/stores-B8CHbgw-.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stores-DcBOZlU3.js","names":["getWidgetStore(id)","(cb) => subscribeEchartInstance(id, cb)","() => getEchartInstance(id)","getWidgetStore(id)","(s) => s.transformStates[primaryId]?.enabled","() => {\n if (typeof persisted === 'boolean') return\n store.setState((s: WidgetState) => ({\n transformStates: {\n ...s.transformStates,\n [primaryId]: {\n ...s.transformStates[primaryId],\n enabled: initialEnabled,\n },\n },\n }))\n }","[store, primaryId, persisted, initialEnabled]","s","(next) => {\n store.setState((s: WidgetState) => {\n const current = s.transformStates[primaryId]?.enabled ?? initialEnabled\n const value =\n typeof next === 'function'\n ? (next as (v: boolean) => boolean)(current)\n : next\n if (value === current) return {}\n return {\n transformStates: {\n ...s.transformStates,\n [primaryId]: {\n ...s.transformStates[primaryId],\n enabled: value,\n },\n },\n }\n })\n }","useCallback<Dispatch<SetStateAction<boolean>>>(\n (next) => {\n store.setState((s: WidgetState) => {\n const current = s.transformStates[primaryId]?.enabled ?? initialEnabled\n const value =\n typeof next === 'function'\n ? (next as (v: boolean) => boolean)(current)\n : next\n if (value === current) return {}\n return {\n transformStates: {\n ...s.transformStates,\n [primaryId]: {\n ...s.transformStates[primaryId],\n enabled: value,\n },\n },\n }\n })\n },\n [store, primaryId, initialEnabled],\n )","[]","() => {\n const next: Registration[] = []\n for (const { descriptor, fn } of pairs) {\n const key: RegistrationKey =\n descriptor.type === 'data' ? 'dataTransforms' : 'configTransforms'\n const transform: Transform = { ...descriptor, fn, enabled }\n store.setState(\n (s: WidgetState) =>\n ({\n [key]: upsertTransform(s[key], transform),\n }) as Partial<WidgetState>,\n )\n next.push({ key, id: descriptor.id })\n }\n registeredRef.current = next\n }","[store, pairs, enabled]","next","() => {\n return () => {\n for (const { key, id: descriptorId } of registeredRef.current) {\n store.setState(\n (s: WidgetState) =>\n ({\n [key]: removeTransform(s[key], descriptorId),\n }) as Partial<WidgetState>,\n )\n }\n registeredRef.current = []\n }\n }","[store]","key","() => setEnabled((v) => !v)","(v) => !v","useCallback(() => setEnabled((v) => !v), [setEnabled])","{ enabled, setEnabled, toggle }","[{ descriptor, fn }]","useMemo<readonly TransformPair[]>(\n () => [{ descriptor, fn }],\n [descriptor, fn],\n )","(s: WidgetState) => s.transformStates?.[transformId]?.enabled === true"],"sources":["../src/widgets/stores/transforms.ts","../src/widgets/stores/pipeline-middleware.ts","../src/widgets/stores/widget-context.ts","../src/widgets/stores/widget-store-registry.ts","../src/widgets/stores/use-echart-instance.ts","../src/widgets/stores/use-transform.ts","../src/widgets/stores/use-transform-enabled.ts"],"sourcesContent":["import type { Transform } from './types'\n\nexport function applyTransforms(\n input: unknown,\n transforms: readonly Transform[],\n onError?: (id: string, error: Error) => void,\n): unknown {\n const disabledIds = new Set<string>()\n for (const t of transforms) {\n if (t.enabled && t.disables?.length) {\n for (const id of t.disables) disabledIds.add(id)\n }\n }\n let acc: unknown = input\n for (const t of transforms) {\n if (!t.enabled) continue\n if (disabledIds.has(t.id)) continue\n try {\n acc = t.fn(acc)\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e))\n // eslint-disable-next-line no-console\n console.warn(`[widgets] Transform \"${t.id}\" failed:`, err)\n onError?.(t.id, err)\n }\n }\n return acc\n}\n\nexport function upsertTransform(\n transforms: readonly Transform[],\n next: Transform,\n): readonly Transform[] {\n const existing = transforms.find((t) => t.id === next.id)\n if (\n existing?.order === next.order &&\n existing?.enabled === next.enabled &&\n existing?.fn === next.fn &&\n existing?.type === next.type &&\n sameStringArray(existing?.disables, next.disables) &&\n sameStringArray(existing?.replaceMergeKeys, next.replaceMergeKeys)\n ) {\n return transforms\n }\n const filtered = transforms.filter((t) => t.id !== next.id)\n const idx = filtered.findIndex((t) => t.order > next.order)\n const out = filtered.slice()\n out.splice(idx === -1 ? out.length : idx, 0, next)\n return out\n}\n\nexport function removeTransform(\n transforms: readonly Transform[],\n id: string,\n): readonly Transform[] {\n if (!transforms.some((t) => t.id === id)) return transforms\n return transforms.filter((t) => t.id !== id)\n}\n\nfunction sameStringArray(\n a?: readonly string[],\n b?: readonly string[],\n): boolean {\n if (a === b) return true\n if (!a) return !b?.length\n if (!b) return !a.length\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false\n return true\n}\n","import type { StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand'\nimport type { Transform, WidgetState } from './types'\nimport { applyTransforms } from './transforms'\n\ntype PipelineMiddleware = <\n T extends WidgetState,\n Mps extends [StoreMutatorIdentifier, unknown][] = [],\n Mcs extends [StoreMutatorIdentifier, unknown][] = [],\n>(\n config: StateCreator<T, Mps, Mcs>,\n) => StateCreator<T, Mps, Mcs>\n\ntype SetFn<T> = StoreApi<T>['setState']\n\n// Per-store flag: true iff the current `state.error` was authored by the\n// pipeline (a transform threw) rather than by the consumer (Provider's\n// `error` prop or a direct setState). Lets the middleware clear stale\n// pipeline errors on a subsequent clean run without clobbering errors a\n// consumer set out-of-band.\nconst pipelineOwnedError = new WeakSet<StoreApi<WidgetState>>()\n\nexport const pipelineMiddleware: PipelineMiddleware = ((config) =>\n (set, get, api) => {\n const origSetState = api.setState as SetFn<WidgetState>\n const typedApi = api as StoreApi<WidgetState>\n\n const wrap = (delegate: SetFn<WidgetState>): SetFn<WidgetState> =>\n ((partial, replace) => {\n const current = (api.getState as () => WidgetState)()\n const incoming =\n typeof partial === 'function'\n ? (partial as (s: WidgetState) => Partial<WidgetState>)(current)\n : (partial as Partial<WidgetState>)\n\n const has = (key: keyof WidgetState) =>\n Object.prototype.hasOwnProperty.call(incoming, key)\n\n const rawDataChanged =\n has('rawData') && !Object.is(incoming.rawData, current.rawData)\n const dataXfChanged =\n has('dataTransforms') &&\n incoming.dataTransforms !== current.dataTransforms\n\n if (!rawDataChanged && !dataXfChanged) {\n // Consumer-authored writes that don't trigger the pipeline. If the\n // consumer is explicitly touching `error`, the next pipeline run is\n // no longer responsible for it — drop the pipeline-owned marker.\n if (has('error')) pipelineOwnedError.delete(typedApi)\n return delegate(incoming, replace as false)\n }\n\n const augmented: Partial<WidgetState> = { ...incoming }\n let firstError: unknown = undefined\n const onError = (_id: string, err: Error) => {\n if (firstError === undefined) firstError = err\n }\n\n const nextRaw = rawDataChanged ? incoming.rawData : current.rawData\n const nextXf: readonly Transform[] = dataXfChanged\n ? incoming.dataTransforms!\n : current.dataTransforms\n augmented.data = applyTransforms(nextRaw, nextXf, onError)\n\n // Reconcile `error` based on who authored the previous value:\n // - pipeline throw → stamp the new error, mark pipeline-owned.\n // - clean run AND previous error was pipeline-owned → clear it.\n // - clean run AND previous error was consumer-set → leave it.\n // Consumer-authored `error` in `incoming` also wins over the marker\n // (and resets the marker via the early-return branch above).\n if (firstError !== undefined) {\n augmented.error = firstError\n pipelineOwnedError.add(typedApi)\n } else if (pipelineOwnedError.has(typedApi) && !has('error')) {\n augmented.error = undefined\n pipelineOwnedError.delete(typedApi)\n } else if (has('error')) {\n // Consumer set error in the same call that ran the pipeline — honor\n // their write and surrender ownership.\n pipelineOwnedError.delete(typedApi)\n }\n\n return delegate(augmented, replace as false)\n }) as SetFn<WidgetState>\n\n // Wrap both the public setState (used by store.setState() callers) and\n // the inner set passed into the state creator (used by actions inside config).\n api.setState = wrap(origSetState) as typeof api.setState\n const wrappedInnerSet = wrap(set as SetFn<WidgetState>)\n\n return config(wrappedInnerSet as typeof set, get, api)\n }) as PipelineMiddleware\n","import { createContext, useContext } from 'react'\n\nexport const WidgetContext = createContext<string | null>(null)\n\nexport function useWidgetId(): string {\n const id = useContext(WidgetContext)\n if (id == null) {\n throw new Error(\n 'useWidgetId() must be called inside <Widget.Provider>. ' +\n 'If you are calling from outside the Provider tree, use the hooks ' +\n '(useWidget, useWidgetShallow, useTransform) directly with an explicit id.',\n )\n }\n return id\n}\n","import type { ECharts } from 'echarts'\nimport { useStore, type StoreApi } from 'zustand'\nimport { createStore } from 'zustand/vanilla'\nimport { devtools } from 'zustand/middleware'\nimport { useShallow } from 'zustand/react/shallow'\nimport { isDev } from '@carto/ps-utils'\nimport { pipelineMiddleware } from './pipeline-middleware'\nimport type { WidgetInit, WidgetState, WidgetStoreApi } from './types'\nimport type { DownloadContext } from '../actions/download/types'\n\nconst widgetStores = new Map<string, WidgetStoreApi>()\n\nconst widgetMountCounts = new Map<string, number>()\nconst warnedDuplicates = new Set<string>()\n\n// Per-widget capture-element registry. Held outside the reactive store so\n// publishing the element doesn't trigger any consumer re-renders — these\n// handles are read imperatively by per-widget download configs at click time\n// only. `Widget.State` writes its success-path content wrapper here on mount\n// (auto-cleared on unmount via callback ref), and `create*DownloadConfig`\n// looks it up to feed `html2canvas` for PNG export.\nconst captureEls = new Map<string, HTMLElement>()\n\n// Per-widget live ECharts instance registry. Same imperative-only contract\n// as `captureEls`: published by the `Widget.Echart` bridge on mount /\n// dispose, read at click time by actions that need to dispatch on the live\n// chart (e.g. `ZoomToggle`'s disable handler issuing\n// `setOption({}, { replaceMerge: ['dataZoom'] })` to clear the slider).\n// Held outside the reactive store so publishing never triggers consumer\n// re-renders.\nconst echartInstances = new Map<string, ECharts>()\n\n// Per-id subscribers notified whenever `setEchartInstance` writes a new\n// value. Powers `useEchartInstance(id)` (a `useSyncExternalStore` wrapper)\n// so actions like `BrushToggle` can react when the chart becomes available\n// — required for lifecycle effects that need the instance on mount but\n// arrive in the tree before the `Widget.Echart` bridge has run its init\n// `useEffect`.\ntype EchartInstanceListener = (chart: ECharts | null) => void\nconst echartInstanceSubscribers = new Map<string, Set<EchartInstanceListener>>()\n\nexport function getWidgetStore(id: string): WidgetStoreApi {\n const store = widgetStores.get(id)\n if (!store) throw new Error(`[widgets] Widget store \"${id}\" not found.`)\n return store\n}\n\nexport function hasWidgetStore(id: string): boolean {\n return widgetStores.has(id)\n}\n\nexport function deleteWidgetStore(id: string): void {\n widgetStores.delete(id)\n}\n\nexport function resetWidgetStore(id: string): void {\n const store = widgetStores.get(id)\n if (store) store.setState({ transformStates: {} })\n}\n\nexport function clearAllWidgetStores(): void {\n widgetStores.clear()\n widgetMountCounts.clear()\n warnedDuplicates.clear()\n captureEls.clear()\n echartInstances.clear()\n echartInstanceSubscribers.clear()\n}\n\n/**\n * Register or clear the capture element for a widget. Pass `null` to clear.\n * Called by `Widget.State` via a callback ref on its success-path content\n * wrapper. The element is read by per-widget download configs at click time\n * to feed `html2canvas` for PNG export.\n */\nexport function setCaptureEl(id: string, el: HTMLElement | null): void {\n if (el == null) captureEls.delete(id)\n else captureEls.set(id, el)\n}\n\n/**\n * Read the currently registered capture element for a widget. Returns `null`\n * when no `Widget.State` is on its success path (loading / error / empty)\n * or when the widget hasn't mounted.\n */\nexport function getCaptureEl(id: string): HTMLElement | null {\n return captureEls.get(id) ?? null\n}\n\n/**\n * `getData` for a `create*DownloadConfig`: the `data` of the store the\n * download menu was opened from (`ctx.id` — the fullscreen dialog's own\n * while it's open), or of widget `id` when the menu sits outside a\n * `<Widget.Provider>`.\n */\nexport function widgetStoreData<T>(id: string): (ctx: DownloadContext) => T {\n return (ctx) => getWidgetStore(ctx.id ?? id).getState().data as T\n}\n\n/**\n * `getCaptureEl` for a `create*DownloadConfig`: the capture element of the\n * store the download menu was opened from (`ctx.id`), or of widget `id`\n * outside a `<Widget.Provider>`.\n */\nexport function widgetCaptureEl(\n id: string,\n): (ctx: DownloadContext) => HTMLElement | null {\n return (ctx) => getCaptureEl(ctx.id ?? id)\n}\n\n/** @internal — exposed for tests and debugging only. */\nexport function clearAllCaptureEls(): void {\n captureEls.clear()\n}\n\n/**\n * Register or clear the live ECharts instance for a widget. Pass `null`\n * to clear. Called by the `Widget.Echart` bridge on mount / dispose.\n * Read by actions (e.g. `ZoomToggle`'s disable handler) that need to\n * dispatch on the live chart without going through the pipeline.\n *\n * Notifies subscribers registered via {@link subscribeEchartInstance}\n * after the map mutation, so reactive consumers (the\n * `useEchartInstance` hook) re-render with the new value.\n */\nexport function setEchartInstance(id: string, chart: ECharts | null): void {\n if (chart == null) echartInstances.delete(id)\n else echartInstances.set(id, chart)\n echartInstanceSubscribers.get(id)?.forEach((fn) => fn(chart))\n}\n\n/**\n * Read the currently registered ECharts instance for a widget. Returns\n * `null` when no `Widget.Echart` is mounted, or before the bridge has\n * created the instance.\n */\nexport function getEchartInstance(id: string): ECharts | null {\n return echartInstances.get(id) ?? null\n}\n\n/**\n * Subscribe to changes of the registered ECharts instance for a widget.\n * The listener is called *after* every {@link setEchartInstance} (with\n * the new chart, or `null` when cleared). Returns an unsubscribe\n * function. Used by the `useEchartInstance` hook to drive React effects\n * that need to react to instance arrival / departure (e.g.\n * `BrushToggle`'s `'finished'` re-dispatch loop).\n */\nexport function subscribeEchartInstance(\n id: string,\n listener: EchartInstanceListener,\n): () => void {\n let listeners = echartInstanceSubscribers.get(id)\n if (!listeners) {\n listeners = new Set()\n echartInstanceSubscribers.set(id, listeners)\n }\n listeners.add(listener)\n return () => {\n const set = echartInstanceSubscribers.get(id)\n if (!set) return\n set.delete(listener)\n if (set.size === 0) echartInstanceSubscribers.delete(id)\n }\n}\n\n/** @internal — exposed for tests and debugging only. */\nexport function clearAllEchartInstances(): void {\n echartInstances.clear()\n echartInstanceSubscribers.clear()\n}\n\n/** @internal — exposed for tests and debugging only. */\nexport function __debugListWidgetStores(): string[] {\n return Array.from(widgetStores.keys())\n}\n\n/**\n * Insert or replace a store entry in the registry without refcounting or\n * duplicate-id detection. Used by Provider's lazy `useState` init so the\n * store is reachable from `useWidget(id)` calls in children that render\n * before the Provider's mount effect runs. Refcounting and dev warns happen\n * in {@link registerWidgetStore} during the mount effect.\n *\n * @internal\n */\nexport function setWidgetStoreEntry(id: string, store: WidgetStoreApi): void {\n widgetStores.set(id, store)\n}\n\n/** @internal — used by Provider; not part of the public API. */\nexport function createWidgetStore(\n id: string,\n init: WidgetInit,\n): WidgetStoreApi {\n const builder = pipelineMiddleware<WidgetState>(() => ({\n rawData: init.data,\n data: init.data,\n dataTransforms: [],\n configTransforms: [],\n transformStates: {},\n isLoading: init.isLoading ?? false,\n isFetching: init.isFetching ?? false,\n error: init.error,\n rawFormatter: init.formatter,\n formatter: init.formatter,\n labelFormatter: init.labelFormatter,\n }))\n\n const store = createStore<WidgetState>()(\n devtools(builder, { name: `widget-${id}`, enabled: isDev() }),\n ) as unknown as WidgetStoreApi\n\n return store\n}\n\n/** @internal — registers a Provider mount and tracks/warns on duplicate ids in dev. */\nexport function registerWidgetStore(id: string, store: WidgetStoreApi): void {\n widgetStores.set(id, store)\n const count = (widgetMountCounts.get(id) ?? 0) + 1\n widgetMountCounts.set(id, count)\n if (count > 1 && isDev() && !warnedDuplicates.has(id)) {\n // eslint-disable-next-line no-console\n console.warn(\n `[widgets] Duplicate <Widget.Provider id=\"${id}\"> detected. ` +\n `Multiple providers sharing an id will race on prop sync and corrupt the store. ` +\n `Use unique ids per widget instance.`,\n )\n warnedDuplicates.add(id)\n }\n}\n\n/** @internal — Provider unmount counterpart; on last unmount removes the refcount entry. */\nexport function unregisterWidgetStore(\n id: string,\n options: { keepAlive: boolean },\n): void {\n const count = (widgetMountCounts.get(id) ?? 1) - 1\n if (count <= 0) {\n widgetMountCounts.delete(id)\n if (!options.keepAlive) widgetStores.delete(id)\n } else {\n widgetMountCounts.set(id, count)\n }\n}\n\nexport function useWidget<T, S extends WidgetState = WidgetState>(\n id: string,\n selector: (state: S) => T,\n): T {\n const store = getWidgetStore(id) as unknown as StoreApi<S>\n return useStore(store, selector)\n}\n\nexport function useWidgetShallow<T, S extends WidgetState = WidgetState>(\n id: string,\n selector: (state: S) => T,\n): T {\n const store = getWidgetStore(id) as unknown as StoreApi<S>\n return useStore(store, useShallow(selector))\n}\n","import { useSyncExternalStore } from 'react'\nimport type { ECharts } from 'echarts'\nimport {\n getEchartInstance,\n subscribeEchartInstance,\n} from './widget-store-registry'\n\nconst SSR_SNAPSHOT = (): ECharts | null => null\n\n/**\n * Reactive read of the live ECharts instance for a widget. Returns\n * `null` before the `Widget.Echart` bridge has mounted (or after it's\n * disposed); the consumer re-renders when the instance arrives /\n * departs / changes.\n *\n * Wraps {@link subscribeEchartInstance} via `useSyncExternalStore`, so\n * actions can use it inside an effect's deps array to react to chart\n * lifecycle events without polling. Required for actions like\n * `BrushToggle` whose effect needs to dispatch `takeGlobalCursor` the\n * moment the chart exists, then re-dispatch on every `'finished'`\n * event.\n */\nexport function useEchartInstance(id: string): ECharts | null {\n return useSyncExternalStore(\n (cb) => subscribeEchartInstance(id, cb),\n () => getEchartInstance(id),\n SSR_SNAPSHOT,\n )\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n type Dispatch,\n type SetStateAction,\n} from 'react'\nimport { useStore } from 'zustand'\nimport { getWidgetStore } from './widget-store-registry'\nimport { removeTransform, upsertTransform } from './transforms'\nimport type {\n Transform,\n TransformDescriptor,\n TransformFn,\n TransformPair,\n WidgetState,\n} from './types'\n\nexport interface UseTransformOptions {\n initialEnabled?: boolean\n}\n\nexport interface TransformControls {\n enabled: boolean\n setEnabled: Dispatch<SetStateAction<boolean>>\n toggle: () => void\n}\n\ntype RegistrationKey = 'dataTransforms' | 'configTransforms'\n\ninterface Registration {\n key: RegistrationKey\n id: string\n}\n\nexport function useTransform(\n id: string,\n pairs: readonly TransformPair[],\n options?: UseTransformOptions,\n): TransformControls {\n if (pairs.length === 0) {\n throw new Error('[widgets] useTransform requires at least one pair.')\n }\n\n const store = getWidgetStore(id)\n const primaryId = pairs[0]!.descriptor.id\n const initialEnabled = options?.initialEnabled ?? true\n\n // Read `enabled` reactively from the store. Multiple mounts of the same\n // descriptor (e.g., Toolbox renders ZoomToggle both in the inline preview\n // and inside its overflow Paper) stay in sync because they share the\n // `transformStates[primaryId].enabled` slot.\n const persisted = useStore(\n store,\n (s) => s.transformStates[primaryId]?.enabled,\n )\n const enabled = typeof persisted === 'boolean' ? persisted : initialEnabled\n\n // Seed the store's `transformStates[primaryId].enabled` on first mount so\n // subsequent reads (and a rehydration after `keepAlive` remounts) have a\n // canonical value to read from. Idempotent: skip when already set.\n useEffect(() => {\n if (typeof persisted === 'boolean') return\n store.setState((s: WidgetState) => ({\n transformStates: {\n ...s.transformStates,\n [primaryId]: {\n ...s.transformStates[primaryId],\n enabled: initialEnabled,\n },\n },\n }))\n }, [store, primaryId, persisted, initialEnabled])\n\n const setEnabled = useCallback<Dispatch<SetStateAction<boolean>>>(\n (next) => {\n store.setState((s: WidgetState) => {\n const current = s.transformStates[primaryId]?.enabled ?? initialEnabled\n const value =\n typeof next === 'function'\n ? (next as (v: boolean) => boolean)(current)\n : next\n if (value === current) return {}\n return {\n transformStates: {\n ...s.transformStates,\n [primaryId]: {\n ...s.transformStates[primaryId],\n enabled: value,\n },\n },\n }\n })\n },\n [store, primaryId, initialEnabled],\n )\n\n // Track the latest registrations so the unmount cleanup knows what to remove.\n // Updated inside the register effect (post-render), never during render.\n const registeredRef = useRef<Registration[]>([])\n\n // Register / re-register when `pairs` reference or `enabled` changes.\n // upsertTransform is identity-stable: re-registering with an unchanged\n // descriptor + fn returns the same array reference, and the middleware\n // bypasses the pipeline for unchanged refs. Consumers should memoize\n // `pairs` (useSingleTransform does this internally; multi-pair consumers\n // should wrap the pairs array in useMemo).\n useEffect(() => {\n const next: Registration[] = []\n for (const { descriptor, fn } of pairs) {\n const key: RegistrationKey =\n descriptor.type === 'data' ? 'dataTransforms' : 'configTransforms'\n const transform: Transform = { ...descriptor, fn, enabled }\n store.setState(\n (s: WidgetState) =>\n ({\n [key]: upsertTransform(s[key], transform),\n }) as Partial<WidgetState>,\n )\n next.push({ key, id: descriptor.id })\n }\n registeredRef.current = next\n }, [store, pairs, enabled])\n\n // Unmount cleanup — remove every currently-registered descriptor. Reads from\n // the ref so we always remove the latest registrations, not a stale snapshot.\n useEffect(() => {\n return () => {\n for (const { key, id: descriptorId } of registeredRef.current) {\n store.setState(\n (s: WidgetState) =>\n ({\n [key]: removeTransform(s[key], descriptorId),\n }) as Partial<WidgetState>,\n )\n }\n registeredRef.current = []\n }\n }, [store])\n\n const toggle = useCallback(() => setEnabled((v) => !v), [setEnabled])\n\n return { enabled, setEnabled, toggle }\n}\n\nexport function useSingleTransform(\n id: string,\n descriptor: TransformDescriptor,\n fn: TransformFn,\n options?: UseTransformOptions,\n): TransformControls {\n const pairs = useMemo<readonly TransformPair[]>(\n () => [{ descriptor, fn }],\n [descriptor, fn],\n )\n return useTransform(id, pairs, options)\n}\n","import { useWidgetShallow } from './widget-store-registry'\nimport type { WidgetState } from './types'\n\n/**\n * Reactive read of a single transform's `enabled` flag from the\n * per-widget store. Returns `false` if the transform hasn't been\n * registered yet (i.e., the action component hasn't mounted) — safe\n * default for \"the feature is off\".\n *\n * Used by widget composers that want to react to an action's on/off\n * cycle without having the widget primitive import the action. For\n * example, the `CategoryWidget` storybook composer wires the\n * SearcherToggle's open state into `<Widget.Category searcherOpen=…>`\n * so the library primitive stays renderer-agnostic.\n *\n * Magic-string `transformId` is intentional — it lives at the composer\n * layer where the action is already imported by JSX, so the string\n * appears alongside the same name in the toolbox.\n */\nexport function useTransformEnabled(id: string, transformId: string): boolean {\n return useWidgetShallow(\n id,\n (s: WidgetState) => s.transformStates?.[transformId]?.enabled === true,\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as e,
|
|
2
|
-
import {
|
|
1
|
+
import { C as e, D as t, S as n, p as r } from "./stores-DcBOZlU3.js";
|
|
2
|
+
import { f as i, n as a, t as o } from "./download-B4sykOFm.js";
|
|
3
3
|
import { c as ee } from "react/compiler-runtime";
|
|
4
4
|
import { Box as s, Checkbox as c, IconButton as l, Skeleton as u, Table as d, TableBody as f, TableCell as p, TableContainer as m, TableHead as h, TablePagination as g, TableRow as _, TableSortLabel as v } from "@mui/material";
|
|
5
5
|
import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
@@ -294,7 +294,7 @@ function z(e) {
|
|
|
294
294
|
function B(i) {
|
|
295
295
|
let a = ee(59), o, s, c, l, u, d, f, p, m, h, g, _, v;
|
|
296
296
|
a[0] === i ? (o = a[1], s = a[2], c = a[3], l = a[4], u = a[5], d = a[6], f = a[7], p = a[8], m = a[9], h = a[10], g = a[11], _ = a[12], v = a[13]) : ({columns: o, visibleColumns: v, initialPageSize: h, selection: m, onSelectionChange: d, onRowClick: l, onRowHover: u, remote: g, total: p, onSortChange: f, onPageChange: s, onPageSizeChange: c, ..._} = i, a[0] = i, a[1] = o, a[2] = s, a[3] = c, a[4] = l, a[5] = u, a[6] = d, a[7] = f, a[8] = p, a[9] = m, a[10] = h, a[11] = g, a[12] = _, a[13] = v);
|
|
297
|
-
let y = h === void 0 ? 10 : h, x = g !== void 0 && g, S =
|
|
297
|
+
let y = h === void 0 ? 10 : h, x = g !== void 0 && g, S = t(), C = n(S, re), w;
|
|
298
298
|
a[14] === y ? w = a[15] : (w = (e) => ({
|
|
299
299
|
sort: e.sort,
|
|
300
300
|
page: e.page ?? 0,
|
|
@@ -412,16 +412,10 @@ function ae(e, t) {
|
|
|
412
412
|
//#endregion
|
|
413
413
|
//#region src/widgets/table/download.ts
|
|
414
414
|
function V(e) {
|
|
415
|
-
|
|
416
|
-
return e.getCaptureEl && t.push(a({
|
|
415
|
+
return o(e, a({
|
|
417
416
|
filename: e.filename,
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
backgroundColor: e.pngBackgroundColor
|
|
421
|
-
})), t.push(o({
|
|
422
|
-
filename: e.filename,
|
|
423
|
-
getCsv: () => L(e.getData(), e.columns)
|
|
424
|
-
})), t;
|
|
417
|
+
getCsv: (t) => L(e.getData(t), e.columns)
|
|
418
|
+
}));
|
|
425
419
|
}
|
|
426
420
|
//#endregion
|
|
427
421
|
//#region src/widgets/table/transforms.ts
|
|
@@ -437,4 +431,4 @@ function oe(e, t, n = "id") {
|
|
|
437
431
|
//#endregion
|
|
438
432
|
export { M as a, F as c, j as d, O as f, B as i, N as l, D as m, V as n, I as o, k as p, ie as r, P as s, oe as t, L as u };
|
|
439
433
|
|
|
440
|
-
//# sourceMappingURL=table-
|
|
434
|
+
//# sourceMappingURL=table-DEdW_fDj.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-BE4uO9pp.js","names":["{\n columns,\n rows,\n total,\n page,\n pageSize,\n pageSizeOptions = DEFAULT_TABLE_PAGE_SIZE_OPTIONS,\n sort,\n keyColumn = 'id',\n selection,\n selectable = false,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n onSelectionChange,\n onRowClick,\n onRowHover,\n labels,\n emptyContent,\n size,\n}: TableUIProps<T>","pageSizeOptions = DEFAULT_TABLE_PAGE_SIZE_OPTIONS","keyColumn = 'id'","selectable = false","{ ...DEFAULT_TABLE_LABELS, ...labels }","useMemo(\n () => ({ ...DEFAULT_TABLE_LABELS, ...labels }),\n [labels],\n )","makePaginationActions(_labels)","useMemo(\n () => makePaginationActions(_labels),\n [_labels],\n )","selection ?? []","new Set<string | number>(selection ?? [])","useMemo(\n () => new Set<string | number>(selection ?? []),\n [selection],\n )","(row: T, index: number): string | number =>\n (row[keyColumn] ?? index) as string | number","useCallback(\n (row: T, index: number): string | number =>\n (row[keyColumn] ?? index) as string | number,\n [keyColumn],\n )","rows.map(resolveRowId)","useMemo(() => rows.map(resolveRowId), [rows, resolveRowId])","pageRowIds.length > 0 && pageRowIds.every((id) => selectionSet.has(id))","pageRowIds.length","!allOnPageSelected && pageRowIds.some((id) => selectionSet.has(id))","id","(columnId: string) => {\n if (!onSortChange) return\n const sameCol = sort?.columnId === columnId\n const nextDir: TableSortDirection =\n sameCol && sort?.direction === 'asc' ? 'desc' : 'asc'\n onSortChange({ columnId, direction: nextDir })\n }","columnId","direction","() => {\n if (!onSelectionChange) return\n if (allOnPageSelected) {\n onSelectionChange(\n (selection ?? []).filter((id) => !pageRowIds.includes(id)),\n )\n } else {\n const merged = new Set<string | number>(selection ?? [])\n for (const id of pageRowIds) merged.add(id)\n onSelectionChange([...merged])\n }\n }","(rowId: string | number) => {\n if (!onSelectionChange) return\n const next = new Set<string | number>(selection ?? [])\n if (next.has(rowId)) next.delete(rowId)\n else next.add(rowId)\n onSelectionChange([...next])\n }","selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null","_labels.selectAll","columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })","(column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n }","<TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>","rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )","columns.length","rows.length","rowId","row","index","column","<TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>","<TableContainer>\n <MuiTable stickyHeader size={size} sx={styles.table}>\n <TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>\n </MuiTable>\n </TableContainer>","showPagination ? (\n <TablePagination\n component='div'\n count={total}\n page={page}\n rowsPerPage={pageSize}\n rowsPerPageOptions={[...pageSizeOptions]}\n onPageChange={(_, next) => onPageChange?.(next)}\n onRowsPerPageChange={(e) => {\n const next = parseInt(e.target.value, 10)\n onPageSizeChange?.(next)\n }}\n labelRowsPerPage={_labels.rowsPerPage}\n labelDisplayedRows={({ from, to, count }) =>\n _labels.paginationOf(from, to, count)\n }\n sx={styles.pagination}\n ActionsComponent={PaginationActions}\n />\n ) : null","next","e","{ from, to, count }","<Box sx={styles.container}>\n <TableContainer>\n <MuiTable stickyHeader size={size} sx={styles.table}>\n <TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>\n </MuiTable>\n </TableContainer>\n {showPagination ? (\n <TablePagination\n component='div'\n count={total}\n page={page}\n rowsPerPage={pageSize}\n rowsPerPageOptions={[...pageSizeOptions]}\n onPageChange={(_, next) => onPageChange?.(next)}\n onRowsPerPageChange={(e) => {\n const next = parseInt(e.target.value, 10)\n onPageSizeChange?.(next)\n }}\n labelRowsPerPage={_labels.rowsPerPage}\n labelDisplayedRows={({ from, to, count }) =>\n _labels.paginationOf(from, to, count)\n }\n sx={styles.pagination}\n ActionsComponent={PaginationActions}\n />\n ) : null}\n </Box>","initialPageSize = DEFAULT_TABLE_PAGE_SIZE","remote = false","{\n columns,\n visibleColumns,\n initialPageSize = DEFAULT_TABLE_PAGE_SIZE,\n selection,\n onSelectionChange,\n onRowClick,\n onRowHover,\n remote = false,\n total: remoteTotal,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n ...uiProps\n}: TableProps<T>","(s) => s.data as readonly T[] | undefined","(s) => ({\n sort: s.sort,\n page: s.page ?? 0,\n pageSize: s.pageSize ?? initialPageSize,\n columnOrder: s.columnOrder,\n })","s","visibleColumns == null\n ? reordered\n : reordered.slice(0, visibleColumns)","columnOrder","useMemo(() => {\n const reordered = resolveColumns(columns, ui.columnOrder)\n return visibleColumns == null\n ? reordered\n : reordered.slice(0, visibleColumns)\n }, [columns, ui.columnOrder, visibleColumns])","useMemo(() => {\n if (remote) {\n return {\n rows: data ?? [],\n totalRows: remoteTotal ?? 0,\n }\n }\n const { sorted, visible } = deriveVisibleRows(data ?? [], {\n sort: ui.sort,\n page: ui.page,\n pageSize: ui.pageSize,\n })\n return { rows: visible, totalRows: sorted.length }\n }, [remote, data, remoteTotal, ui.sort, ui.page, ui.pageSize])","data ?? []","{\n rows: data ?? [],\n totalRows: remoteTotal ?? 0,\n }","remoteTotal ?? 0","deriveVisibleRows(data ?? [], {\n sort: ui.sort,\n page: ui.page,\n pageSize: ui.pageSize,\n })","page","pageSize","sort","{ rows: visible, totalRows: sorted.length }","length","(next: TableSortState) => {\n getWidgetStore(id).setState({\n sort: next,\n page: 0,\n } as Partial<TableWidgetState>)\n onSortChange?.(next)\n }","useCallback(\n (next: TableSortState) => {\n getWidgetStore(id).setState({\n sort: next,\n page: 0,\n } as Partial<TableWidgetState>)\n onSortChange?.(next)\n },\n [id, onSortChange],\n )","(page: number) => {\n getWidgetStore(id).setState({ page } as Partial<TableWidgetState>)\n onPageChange?.(page)\n }","useCallback(\n (page: number) => {\n getWidgetStore(id).setState({ page } as Partial<TableWidgetState>)\n onPageChange?.(page)\n },\n [id, onPageChange],\n )","(pageSize: number) => {\n getWidgetStore(id).setState({\n pageSize,\n page: 0,\n } as Partial<TableWidgetState>)\n onPageSizeChange?.(pageSize)\n }","useCallback(\n (pageSize: number) => {\n getWidgetStore(id).setState({\n pageSize,\n page: 0,\n } as Partial<TableWidgetState>)\n onPageSizeChange?.(pageSize)\n },\n [id, onPageSizeChange],\n )","<TableUI\n {...uiProps}\n columns={orderedColumns}\n rows={rows}\n total={totalRows}\n page={ui.page}\n pageSize={ui.pageSize}\n sort={ui.sort}\n selection={selection}\n onSortChange={handleSortChange}\n onPageChange={handlePageChange}\n onPageSizeChange={handlePageSizeChange}\n onSelectionChange={onSelectionChange}\n onRowClick={onRowClick}\n onRowHover={onRowHover}\n />","{\n rows = 5,\n columns = 4,\n size,\n}: TableSkeletonProps","rows = 5","columns = 4","<TableHead>\n <MuiTableRow>\n {Array.from({ length: columns }).map((_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n ))}\n </MuiTableRow>\n </TableHead>","(_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n )","Array.from({ length: rows })","<TableBody>\n {Array.from({ length: rows }).map((_, r) => (\n <MuiTableRow key={`row-${r}`} sx={styles.row}>\n {Array.from({ length: columns }).map((__, c) => (\n <TableCell key={`cell-${r}-${c}`}>\n <Skeleton variant='text' width='70%' height={20} />\n </TableCell>\n ))}\n </MuiTableRow>\n ))}\n </TableBody>","c","<Box sx={styles.container} aria-label='Table skeleton'>\n <MuiTable size={size} sx={styles.table} stickyHeader>\n <TableHead>\n <MuiTableRow>\n {Array.from({ length: columns }).map((_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n ))}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {Array.from({ length: rows }).map((_, r) => (\n <MuiTableRow key={`row-${r}`} sx={styles.row}>\n {Array.from({ length: columns }).map((__, c) => (\n <TableCell key={`cell-${r}-${c}`}>\n <Skeleton variant='text' width='70%' height={20} />\n </TableCell>\n ))}\n </MuiTableRow>\n ))}\n </TableBody>\n </MuiTable>\n </Box>"],"sources":["../src/widgets/table/labels.tsx","../src/widgets/table/types.ts","../src/widgets/table/style.ts","../src/widgets/table/table-ui.tsx","../src/widgets/table/helpers.ts","../src/widgets/table/table.tsx","../src/widgets/table/skeleton.tsx","../src/widgets/table/download.ts","../src/widgets/table/transforms.ts"],"sourcesContent":["import { Box, type SxProps, type Theme } from '@mui/material'\nimport type { ReactNode } from 'react'\n\nexport interface TableLabels {\n selectAll: string\n selectRow: (rowId: string | number) => string\n rowsPerPage: string\n /**\n * Renders the displayed-rows summary in the pagination footer. Returns\n * a `ReactNode` so the default can emphasise the active range\n * (`from-to`) with a bolder weight while keeping the trailing\n * ` of total` muted. Override to localise wording or restyle.\n */\n paginationOf: (from: number, to: number, total: number) => ReactNode\n /** aria-label for the first-page pagination button. */\n firstPage: string\n /** aria-label for the previous-page pagination button. */\n previousPage: string\n /** aria-label for the next-page pagination button. */\n nextPage: string\n /** aria-label for the last-page pagination button. */\n lastPage: string\n}\n\nconst boldRange: SxProps<Theme> = { fontWeight: 600, color: 'text.primary' }\n\nexport const DEFAULT_TABLE_LABELS: TableLabels = {\n selectAll: 'Select all rows',\n selectRow: (id) => `Select row ${id}`,\n rowsPerPage: 'Rows per page:',\n paginationOf: (from, to, total) => (\n <>\n <Box component='span' sx={boldRange}>{`${from}–${to}`}</Box>\n {` of ${total}`}\n </>\n ),\n firstPage: 'First page',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n lastPage: 'Last page',\n}\n","import type { ReactNode } from 'react'\nimport type { WidgetState } from '../stores'\n\n/**\n * Single row of tabular data.\n *\n * The default row-identity column is `id`. Consumers that don't have a\n * literal `id` field can point `<Table>` / `<TableUI>` at a different\n * column via the `keyColumn` prop; the library reads `row[keyColumn]`\n * for selection lookup, React keys, and aria labels.\n */\nexport interface TableRow extends Record<string, unknown> {\n /**\n * Default row identity. Required when no `keyColumn` is configured.\n * Omit when wiring `keyColumn` to a different column.\n */\n id?: string | number\n}\n\nexport type TableWidgetData = readonly TableRow[]\n\nexport type TableSortDirection = 'asc' | 'desc'\n\nexport interface TableSortState {\n columnId: string | null\n direction: TableSortDirection\n}\n\nexport interface TableColumn {\n /** Unique column identifier; matches the field name on each row. */\n id: string\n /** Header label. */\n label: ReactNode\n align?: 'left' | 'center' | 'right'\n width?: number | string\n sortable?: boolean\n /** Custom cell renderer. Falls back to a string-cast of the raw value. */\n formatter?: (value: unknown, row: TableRow) => ReactNode\n}\n\n/**\n * State extension carrying Table-specific UI state on the per-widget store.\n * Per R12: widget-specific UI state lives in widget-specific extensions of\n * `WidgetState`, not on the base type.\n */\nexport interface TableWidgetState extends WidgetState {\n /** Optional reordered column list driven by ChangeColumn. Falls back to props. */\n columnOrder?: readonly string[]\n sort?: TableSortState\n page: number\n pageSize: number\n}\n\nexport const DEFAULT_TABLE_PAGE_SIZE = 10\nexport const DEFAULT_TABLE_PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const\n","import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n container: {\n width: '100%',\n overflowX: 'auto',\n },\n\n table: {\n minWidth: 0,\n },\n headerCell: {\n fontWeight: 600,\n backgroundColor: 'background.paper',\n },\n /**\n * Strip the bottom border from the last body row so the body flushes\n * against the pagination border instead of doubling it up. Mirrors v1.\n */\n row: {\n '&:last-child td, &:last-child th': {\n border: 0,\n },\n },\n rowClickable: {\n cursor: 'pointer',\n },\n pagination: {\n borderTop: '1px solid',\n borderColor: 'divider',\n },\n paginationActions: {\n display: 'flex',\n alignItems: 'center',\n gap: 0.25,\n ml: 1,\n },\n empty: {\n textAlign: 'center',\n color: 'text.secondary',\n py: 3,\n },\n} satisfies Record<string, SxProps<Theme>>\n","import { useCallback, useMemo } from 'react'\nimport {\n Box,\n Checkbox,\n IconButton,\n Table as MuiTable,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TablePagination,\n TableRow as MuiTableRow,\n TableSortLabel,\n type TableProps as MuiTableProps,\n} from '@mui/material'\nimport type { TablePaginationActionsProps } from '@mui/material/TablePaginationActions'\nimport { FirstPage as FirstPageIcon } from '@mui/icons-material'\nimport { KeyboardArrowLeft } from '@mui/icons-material'\nimport { KeyboardArrowRight } from '@mui/icons-material'\nimport { LastPage as LastPageIcon } from '@mui/icons-material'\nimport { DEFAULT_TABLE_LABELS, type TableLabels } from './labels'\nimport {\n DEFAULT_TABLE_PAGE_SIZE_OPTIONS,\n type TableColumn,\n type TableRow,\n type TableSortDirection,\n type TableSortState,\n} from './types'\nimport { styles } from './style'\n\nexport interface TableUIProps<T extends TableRow = TableRow> {\n columns: readonly TableColumn[]\n /** Already-paginated, already-sorted rows for the current view. */\n rows: readonly T[]\n /** Total row count (across all pages). Required for pagination footer. */\n total: number\n page: number\n pageSize: number\n pageSizeOptions?: readonly number[]\n sort?: TableSortState\n /**\n * Column name to use as the row identity. Drives selection lookup,\n * React keys, and aria labels. Defaults to `'id'` — point it at\n * another column when your rows don't carry an `id` field.\n */\n keyColumn?: string\n /** Selected row ids. Destination-owned. */\n selection?: readonly (string | number)[]\n selectable?: boolean\n onSortChange?: (next: TableSortState) => void\n onPageChange?: (page: number) => void\n onPageSizeChange?: (pageSize: number) => void\n onSelectionChange?: (next: readonly (string | number)[]) => void\n onRowClick?: (row: T) => void\n onRowHover?: (row: T | null) => void\n labels?: Partial<TableLabels>\n /** Row rendered when `rows` is empty for the current page. */\n emptyContent?: React.ReactNode\n /**\n * Forwarded to MUI's `<Table size>` — `'small'` for compact rows,\n * `'medium'` for the default density. Leave `undefined` (the default)\n * to let MUI's own default kick in.\n */\n size?: MuiTableProps['size']\n}\n\n/**\n * Pure renderer for a paginated, sortable, optionally-selectable table.\n * Has no widget-store coupling — `<Table>` (the bridge) reads from the store\n * and feeds this UI with already-projected data.\n */\nexport function TableUI<T extends TableRow = TableRow>({\n columns,\n rows,\n total,\n page,\n pageSize,\n pageSizeOptions = DEFAULT_TABLE_PAGE_SIZE_OPTIONS,\n sort,\n keyColumn = 'id',\n selection,\n selectable = false,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n onSelectionChange,\n onRowClick,\n onRowHover,\n labels,\n emptyContent,\n size,\n}: TableUIProps<T>) {\n if (process.env.NODE_ENV !== 'production') {\n // Dev-time guard: a nullish identity collapses every row into the\n // same selection-set entry, which manifests as \"click one → all\n // appear selected\". Surface it loudly instead of silently degrading.\n const missing = rows.some((r) => r[keyColumn] == null)\n if (missing) {\n // eslint-disable-next-line no-console\n console.error(\n `<TableUI>: rows are missing the identity column \\`${keyColumn}\\`. ` +\n 'Set the `keyColumn` prop to a column present on every row, or ' +\n 'add the column to the data.',\n )\n }\n }\n const _labels = useMemo(\n () => ({ ...DEFAULT_TABLE_LABELS, ...labels }),\n [labels],\n )\n // Auto-hide the pagination footer when every row already fits in the\n // smallest available page size — the Rows-per-page selector + prev /\n // next buttons would just be inert noise. Consumers force the footer\n // on by passing a smaller `pageSizeOptions[0]` than `total`.\n const minPageSize = Math.min(...pageSizeOptions)\n const showPagination = total > minPageSize\n // Own the `ActionsComponent` slot ourselves so the Meridian theme's\n // `theme.components.MuiTablePagination.defaultProps.ActionsComponent`\n // (which depends on `react-intl`) doesn't leak into the library. The\n // MUI / Meridian style overrides for `MuiIconButton` /\n // `MuiTablePagination` still apply.\n const PaginationActions = useMemo(\n () => makePaginationActions(_labels),\n [_labels],\n )\n const selectionSet = useMemo(\n () => new Set<string | number>(selection ?? []),\n [selection],\n )\n // Resolve each row's identity from `keyColumn`, falling back to the row's\n // index when the cell is nullish. The dev-time guard above surfaces the\n // misconfiguration loudly, but in production we must NOT collapse every\n // nullish-keyed row into the same selection-set entry (that's the\n // \"click one → all selected\" bug) — a per-index fallback keeps ids\n // distinct and React keys stable for a given page.\n const resolveRowId = useCallback(\n (row: T, index: number): string | number =>\n (row[keyColumn] ?? index) as string | number,\n [keyColumn],\n )\n const pageRowIds = useMemo(() => rows.map(resolveRowId), [rows, resolveRowId])\n const allOnPageSelected =\n pageRowIds.length > 0 && pageRowIds.every((id) => selectionSet.has(id))\n const someOnPageSelected =\n !allOnPageSelected && pageRowIds.some((id) => selectionSet.has(id))\n\n const handleSort = (columnId: string) => {\n if (!onSortChange) return\n const sameCol = sort?.columnId === columnId\n const nextDir: TableSortDirection =\n sameCol && sort?.direction === 'asc' ? 'desc' : 'asc'\n onSortChange({ columnId, direction: nextDir })\n }\n\n const handleSelectAllOnPage = () => {\n if (!onSelectionChange) return\n if (allOnPageSelected) {\n onSelectionChange(\n (selection ?? []).filter((id) => !pageRowIds.includes(id)),\n )\n } else {\n const merged = new Set<string | number>(selection ?? [])\n for (const id of pageRowIds) merged.add(id)\n onSelectionChange([...merged])\n }\n }\n\n const handleSelectRow = (rowId: string | number) => {\n if (!onSelectionChange) return\n const next = new Set<string | number>(selection ?? [])\n if (next.has(rowId)) next.delete(rowId)\n else next.add(rowId)\n onSelectionChange([...next])\n }\n\n return (\n <Box sx={styles.container}>\n <TableContainer>\n <MuiTable stickyHeader size={size} sx={styles.table}>\n <TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>\n </MuiTable>\n </TableContainer>\n {showPagination ? (\n <TablePagination\n component='div'\n count={total}\n page={page}\n rowsPerPage={pageSize}\n rowsPerPageOptions={[...pageSizeOptions]}\n onPageChange={(_, next) => onPageChange?.(next)}\n onRowsPerPageChange={(e) => {\n const next = parseInt(e.target.value, 10)\n onPageSizeChange?.(next)\n }}\n labelRowsPerPage={_labels.rowsPerPage}\n labelDisplayedRows={({ from, to, count }) =>\n _labels.paginationOf(from, to, count)\n }\n sx={styles.pagination}\n ActionsComponent={PaginationActions}\n />\n ) : null}\n </Box>\n )\n}\n\nfunction stringifyCell(value: unknown): React.ReactNode {\n if (value == null) return ''\n if (typeof value === 'string' || typeof value === 'number') return value\n if (typeof value === 'boolean') return String(value)\n if (Array.isArray(value) || typeof value === 'object') {\n return JSON.stringify(value)\n }\n return ''\n}\n\n/**\n * Build the `ActionsComponent` used by `<TablePagination>` — four MUI\n * `IconButton`s for first / previous / next / last. We provide this\n * ourselves so the Meridian theme's `defaultProps.ActionsComponent`\n * (which depends on `react-intl`) is bypassed at the call site without\n * disturbing the rest of the Meridian theme. The factory closes over\n * the merged label set so aria-labels stay consistent with the rest\n * of the table's i18n surface.\n */\nfunction makePaginationActions(labels: TableLabels) {\n return function PaginationActions({\n count,\n page,\n rowsPerPage,\n onPageChange,\n }: TablePaginationActionsProps) {\n const lastPage = Math.max(0, Math.ceil(count / rowsPerPage) - 1)\n return (\n <Box sx={styles.paginationActions}>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, 0)}\n disabled={page === 0}\n aria-label={labels.firstPage}\n >\n <FirstPageIcon fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, page - 1)}\n disabled={page === 0}\n aria-label={labels.previousPage}\n >\n <KeyboardArrowLeft fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, page + 1)}\n disabled={page >= lastPage}\n aria-label={labels.nextPage}\n >\n <KeyboardArrowRight fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, lastPage)}\n disabled={page >= lastPage}\n aria-label={labels.lastPage}\n >\n <LastPageIcon fontSize='small' />\n </IconButton>\n </Box>\n )\n }\n}\n","import { toCsvString } from '../actions/download'\nimport type {\n TableColumn,\n TableRow,\n TableSortDirection,\n TableWidgetData,\n} from './types'\n\n/**\n * Compares two values with a consistent ordering across primitive types.\n * Strings use locale comparison; numbers subtract; booleans rank false < true;\n * objects/arrays compare by JSON serialization. Null/undefined sort to the end\n * regardless of direction.\n */\nexport function compareValues(\n a: unknown,\n b: unknown,\n direction: TableSortDirection,\n): number {\n if (a == null && b == null) return 0\n if (a == null) return 1\n if (b == null) return -1\n let cmp = 0\n if (typeof a === 'string' && typeof b === 'string') {\n cmp = a.localeCompare(b)\n } else if (typeof a === 'number' && typeof b === 'number') {\n cmp = a - b\n } else if (typeof a === 'boolean' && typeof b === 'boolean') {\n cmp = a === b ? 0 : a ? 1 : -1\n } else if (typeof a === 'object' || typeof b === 'object') {\n cmp = JSON.stringify(a).localeCompare(JSON.stringify(b))\n }\n return direction === 'asc' ? cmp : -cmp\n}\n\n/** Returns a new array sorted by the named column. Does not mutate the input. */\nexport function sortRows<T extends TableRow>(\n rows: readonly T[],\n columnId: string,\n direction: TableSortDirection,\n): T[] {\n return [...rows].sort((a, b) =>\n compareValues(a[columnId], b[columnId], direction),\n )\n}\n\n/** Returns the slice for the requested page. Out-of-range pages return []. */\nexport function paginateRows<T>(\n rows: readonly T[],\n page: number,\n pageSize: number,\n): T[] {\n if (pageSize <= 0) return rows.slice()\n const start = page * pageSize\n return rows.slice(start, start + pageSize)\n}\n\n/**\n * Resolves the effective column list. When the widget store has a\n * `columnOrder` set (e.g. ChangeColumn was used), the column array is\n * reordered to match. Unknown ids in the order are skipped; columns not\n * present in the order keep their original relative position at the end.\n */\nexport function resolveColumns(\n columns: readonly TableColumn[],\n columnOrder: readonly string[] | undefined,\n): readonly TableColumn[] {\n if (!columnOrder || columnOrder.length === 0) return columns\n const byId = new Map(columns.map((c) => [c.id, c]))\n const ordered: TableColumn[] = []\n const seen = new Set<string>()\n for (const id of columnOrder) {\n const c = byId.get(id)\n if (c && !seen.has(id)) {\n ordered.push(c)\n seen.add(id)\n }\n }\n for (const c of columns) {\n if (!seen.has(c.id)) ordered.push(c)\n }\n return ordered\n}\n\n/** Applies sort and pagination to the input data. Pure. */\nexport function deriveVisibleRows<T extends TableRow>(\n rows: readonly T[],\n options: {\n sort?: { columnId: string | null; direction: TableSortDirection }\n page: number\n pageSize: number\n },\n): { sorted: readonly T[]; visible: T[] } {\n const sorted =\n options.sort?.columnId != null\n ? sortRows(rows, options.sort.columnId, options.sort.direction)\n : rows\n const visible = paginateRows(sorted, options.page, options.pageSize)\n return { sorted, visible }\n}\n\nexport function tableDataToCsv(\n data: TableWidgetData,\n columns: readonly TableColumn[],\n): string {\n // Pre-stringify with the table's own header/cell rules, then delegate the\n // CSV assembly (quoting + spreadsheet formula-injection guard) to the shared\n // `toCsvString` so escaping stays identical to every other widget's export.\n const rows: string[][] = [columns.map((c) => stringifyHeader(c.label))]\n for (const row of data) {\n rows.push(columns.map((c) => stringifyCell(row[c.id])))\n }\n return toCsvString(rows)\n}\n\nfunction stringifyHeader(label: unknown): string {\n if (typeof label === 'string') return label\n if (typeof label === 'number' || typeof label === 'boolean')\n return String(label)\n return ''\n}\n\nfunction stringifyCell(value: unknown): string {\n if (value == null) return ''\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value)\n if (Array.isArray(value) || typeof value === 'object')\n return JSON.stringify(value)\n return ''\n}\n","import { useCallback, useMemo } from 'react'\nimport {\n getWidgetStore,\n useWidget,\n useWidgetId,\n useWidgetShallow,\n} from '../stores'\nimport { TableUI, type TableUIProps } from './table-ui'\nimport {\n DEFAULT_TABLE_PAGE_SIZE,\n type TableColumn,\n type TableRow,\n type TableSortState,\n type TableWidgetState,\n} from './types'\nimport { deriveVisibleRows, resolveColumns } from './helpers'\n\nexport interface TableProps<T extends TableRow = TableRow> extends Pick<\n TableUIProps<T>,\n | 'pageSizeOptions'\n | 'selectable'\n | 'labels'\n | 'emptyContent'\n | 'size'\n | 'keyColumn'\n> {\n /**\n * Column definitions. Order can be overridden by ChangeColumn via the\n * `columnOrder` field on the extended widget state.\n */\n columns: readonly TableColumn[]\n /**\n * When set, render only the first `visibleColumns` entries **after**\n * applying the user's `columnOrder` from the store. Useful for showing\n * a compact projection while letting consumers (e.g. `Widget.ChangeColumn`)\n * see the full column list. When omitted, every column renders.\n */\n visibleColumns?: number\n /** Initial page size (only on first mount; afterwards lives on the store). */\n initialPageSize?: number\n /** Selected row ids (destination-owned). */\n selection?: readonly (string | number)[]\n onSelectionChange?: (next: readonly (string | number)[]) => void\n onRowClick?: (row: T) => void\n onRowHover?: (row: T | null) => void\n /**\n * When `true`, the bridge stops sorting and paginating locally and\n * renders `data` as-is — the consumer is then responsible for\n * refetching the slice that matches the active `page` / `pageSize` /\n * `sort` from the outbound callbacks below. `total` is required in\n * this mode (the server already knows the full row count; the\n * widget can't infer it from a partial page).\n */\n remote?: boolean\n /**\n * Server-reported total row count. Required when `remote === true`;\n * ignored in local mode (where the bridge derives total from the\n * sorted result of `deriveVisibleRows`).\n */\n total?: number\n /** Fires after the store-level sort write so the consumer can refetch. */\n onSortChange?: (next: TableSortState) => void\n /** Fires after the store-level page write so the consumer can refetch. */\n onPageChange?: (page: number) => void\n /** Fires after the store-level pageSize write so the consumer can refetch. */\n onPageSizeChange?: (pageSize: number) => void\n}\n\n/**\n * Bridge component — reads the widget store's `data`, applies sort + pagination\n * locally, and feeds `<TableUI />`. Sort, page, and pageSize live on the\n * extended widget state ({@link TableWidgetState}).\n */\nexport function Table<T extends TableRow = TableRow>({\n columns,\n visibleColumns,\n initialPageSize = DEFAULT_TABLE_PAGE_SIZE,\n selection,\n onSelectionChange,\n onRowClick,\n onRowHover,\n remote = false,\n total: remoteTotal,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n ...uiProps\n}: TableProps<T>) {\n const id = useWidgetId()\n const data = useWidget(id, (s) => s.data as readonly T[] | undefined)\n const ui = useWidgetShallow<\n {\n sort: TableSortState | undefined\n page: number\n pageSize: number\n columnOrder: readonly string[] | undefined\n },\n TableWidgetState\n >(id, (s) => ({\n sort: s.sort,\n page: s.page ?? 0,\n pageSize: s.pageSize ?? initialPageSize,\n columnOrder: s.columnOrder,\n }))\n\n const orderedColumns = useMemo(() => {\n const reordered = resolveColumns(columns, ui.columnOrder)\n return visibleColumns == null\n ? reordered\n : reordered.slice(0, visibleColumns)\n }, [columns, ui.columnOrder, visibleColumns])\n\n // In remote mode the consumer already paginated / sorted server-side,\n // so pass `data` and `total` straight through. Local mode keeps the\n // bridge-driven sort + slice via `deriveVisibleRows`.\n const { rows, totalRows } = useMemo(() => {\n if (remote) {\n return {\n rows: data ?? [],\n totalRows: remoteTotal ?? 0,\n }\n }\n const { sorted, visible } = deriveVisibleRows(data ?? [], {\n sort: ui.sort,\n page: ui.page,\n pageSize: ui.pageSize,\n })\n return { rows: visible, totalRows: sorted.length }\n }, [remote, data, remoteTotal, ui.sort, ui.page, ui.pageSize])\n\n const handleSortChange = useCallback(\n (next: TableSortState) => {\n getWidgetStore(id).setState({\n sort: next,\n page: 0,\n } as Partial<TableWidgetState>)\n onSortChange?.(next)\n },\n [id, onSortChange],\n )\n\n const handlePageChange = useCallback(\n (page: number) => {\n getWidgetStore(id).setState({ page } as Partial<TableWidgetState>)\n onPageChange?.(page)\n },\n [id, onPageChange],\n )\n\n const handlePageSizeChange = useCallback(\n (pageSize: number) => {\n getWidgetStore(id).setState({\n pageSize,\n page: 0,\n } as Partial<TableWidgetState>)\n onPageSizeChange?.(pageSize)\n },\n [id, onPageSizeChange],\n )\n\n return (\n <TableUI\n {...uiProps}\n columns={orderedColumns}\n rows={rows}\n total={totalRows}\n page={ui.page}\n pageSize={ui.pageSize}\n sort={ui.sort}\n selection={selection}\n onSortChange={handleSortChange}\n onPageChange={handlePageChange}\n onPageSizeChange={handlePageSizeChange}\n onSelectionChange={onSelectionChange}\n onRowClick={onRowClick}\n onRowHover={onRowHover}\n />\n )\n}\n","import {\n Box,\n Skeleton,\n Table as MuiTable,\n TableBody,\n TableCell,\n TableHead,\n TableRow as MuiTableRow,\n type TableProps as MuiTableProps,\n} from '@mui/material'\nimport { styles } from './style'\n\nexport interface TableSkeletonProps {\n /** Number of body rows to render. Defaults to `5` (matches v1). */\n rows?: number\n /** Number of columns to render. Defaults to `4` (matches v1). */\n columns?: number\n /**\n * Forwarded to MUI's `<Table size>` so the loading layout matches the\n * size you'll render in {@link TableUI}. Leave `undefined` (the\n * default) to use MUI's own default density.\n */\n size?: MuiTableProps['size']\n}\n\n/**\n * Loading placeholder for the Table widget. Renders the same MUI table\n * primitives that {@link TableUI} uses so the loading layout (column\n * widths, header band, row density) doesn't shift when data resolves.\n *\n * Mirrors the v1 widget's `<TableSkeleton>` structure with v2's themed\n * `styles.headerCell`.\n */\nexport function TableSkeleton({\n rows = 5,\n columns = 4,\n size,\n}: TableSkeletonProps) {\n return (\n <Box sx={styles.container} aria-label='Table skeleton'>\n <MuiTable size={size} sx={styles.table} stickyHeader>\n <TableHead>\n <MuiTableRow>\n {Array.from({ length: columns }).map((_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n ))}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {Array.from({ length: rows }).map((_, r) => (\n <MuiTableRow key={`row-${r}`} sx={styles.row}>\n {Array.from({ length: columns }).map((__, c) => (\n <TableCell key={`cell-${r}-${c}`}>\n <Skeleton variant='text' width='70%' height={20} />\n </TableCell>\n ))}\n </MuiTableRow>\n ))}\n </TableBody>\n </MuiTable>\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n buildPngDownloadItem,\n type DownloadItem,\n} from '../actions/download'\nimport { tableDataToCsv } from './helpers'\nimport type { TableColumn, TableWidgetData } from './types'\n\n/**\n * Download menu items for the Table widget. Always includes a CSV item\n * that pulls the latest data from the widget store via `getData()` (so\n * locked / sorted / filtered state is honored); headers come from\n * `column.label`, cells from `row[column.id]`. When `getCaptureEl` is\n * supplied, prepends a PNG item that rasterises the captured element via\n * `html2canvas`.\n */\nexport function createTableDownloadConfig(opts: {\n filename: string\n getData: () => TableWidgetData\n columns: readonly TableColumn[]\n getCaptureEl?: () => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (opts.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: opts.filename,\n getCaptureEl: opts.getCaptureEl,\n pixelRatio: opts.pngPixelRatio,\n backgroundColor: opts.pngBackgroundColor,\n }),\n )\n }\n items.push(\n buildCsvDownloadItem({\n filename: opts.filename,\n getCsv: () => tableDataToCsv(opts.getData(), opts.columns),\n }),\n )\n return items\n}\n","/**\n * `LockSelection` filter for Table. Data is a FLAT `TableRow[]` (unlike every\n * other widget's `X[][]` series shape) and row identity comes from\n * `row[keyColumn]` (default `'id'`), not `name` — so `filterByLockedItems`\n * doesn't apply here (its outer `.map` treats each row as a \"series\", and a\n * plain row object isn't an array, so it would silently pass everything\n * through unfiltered). Falls back to the row's index when the identity\n * column is nullish, mirroring `TableUI`'s own `resolveRowId`.\n *\n * `keyColumn` arrives as `LockSelection`'s `filterKey`, so pass this by\n * reference: `filterFn={filterTableByLockedRows} filterKey={keyColumn}`.\n * Don't close over it — `filterFn`'s identity is not a pipeline dependency,\n * so a captured key changes without re-running anything.\n */\nexport function filterTableByLockedRows(\n input: unknown,\n lockedItems: readonly (string | number)[],\n keyColumn: string | number = 'id',\n): unknown {\n if (lockedItems.length === 0) return input\n if (!Array.isArray(input)) return input\n const locked = new Set<string | number>(lockedItems)\n return input.filter((row: unknown, index: number): boolean => {\n if (row == null || typeof row !== 'object') return false\n const id = (row as Record<string, unknown>)[keyColumn] ?? index\n return (typeof id === 'string' || typeof id === 'number') && locked.has(id)\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table-DEdW_fDj.js","names":["{\n columns,\n rows,\n total,\n page,\n pageSize,\n pageSizeOptions = DEFAULT_TABLE_PAGE_SIZE_OPTIONS,\n sort,\n keyColumn = 'id',\n selection,\n selectable = false,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n onSelectionChange,\n onRowClick,\n onRowHover,\n labels,\n emptyContent,\n size,\n}: TableUIProps<T>","pageSizeOptions = DEFAULT_TABLE_PAGE_SIZE_OPTIONS","keyColumn = 'id'","selectable = false","{ ...DEFAULT_TABLE_LABELS, ...labels }","useMemo(\n () => ({ ...DEFAULT_TABLE_LABELS, ...labels }),\n [labels],\n )","makePaginationActions(_labels)","useMemo(\n () => makePaginationActions(_labels),\n [_labels],\n )","selection ?? []","new Set<string | number>(selection ?? [])","useMemo(\n () => new Set<string | number>(selection ?? []),\n [selection],\n )","(row: T, index: number): string | number =>\n (row[keyColumn] ?? index) as string | number","useCallback(\n (row: T, index: number): string | number =>\n (row[keyColumn] ?? index) as string | number,\n [keyColumn],\n )","rows.map(resolveRowId)","useMemo(() => rows.map(resolveRowId), [rows, resolveRowId])","pageRowIds.length > 0 && pageRowIds.every((id) => selectionSet.has(id))","pageRowIds.length","!allOnPageSelected && pageRowIds.some((id) => selectionSet.has(id))","id","(columnId: string) => {\n if (!onSortChange) return\n const sameCol = sort?.columnId === columnId\n const nextDir: TableSortDirection =\n sameCol && sort?.direction === 'asc' ? 'desc' : 'asc'\n onSortChange({ columnId, direction: nextDir })\n }","columnId","direction","() => {\n if (!onSelectionChange) return\n if (allOnPageSelected) {\n onSelectionChange(\n (selection ?? []).filter((id) => !pageRowIds.includes(id)),\n )\n } else {\n const merged = new Set<string | number>(selection ?? [])\n for (const id of pageRowIds) merged.add(id)\n onSelectionChange([...merged])\n }\n }","(rowId: string | number) => {\n if (!onSelectionChange) return\n const next = new Set<string | number>(selection ?? [])\n if (next.has(rowId)) next.delete(rowId)\n else next.add(rowId)\n onSelectionChange([...next])\n }","selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null","_labels.selectAll","columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })","(column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n }","<TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>","rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )","columns.length","rows.length","rowId","row","index","column","<TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>","<TableContainer>\n <MuiTable stickyHeader size={size} sx={styles.table}>\n <TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>\n </MuiTable>\n </TableContainer>","showPagination ? (\n <TablePagination\n component='div'\n count={total}\n page={page}\n rowsPerPage={pageSize}\n rowsPerPageOptions={[...pageSizeOptions]}\n onPageChange={(_, next) => onPageChange?.(next)}\n onRowsPerPageChange={(e) => {\n const next = parseInt(e.target.value, 10)\n onPageSizeChange?.(next)\n }}\n labelRowsPerPage={_labels.rowsPerPage}\n labelDisplayedRows={({ from, to, count }) =>\n _labels.paginationOf(from, to, count)\n }\n sx={styles.pagination}\n ActionsComponent={PaginationActions}\n />\n ) : null","next","e","{ from, to, count }","<Box sx={styles.container}>\n <TableContainer>\n <MuiTable stickyHeader size={size} sx={styles.table}>\n <TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>\n </MuiTable>\n </TableContainer>\n {showPagination ? (\n <TablePagination\n component='div'\n count={total}\n page={page}\n rowsPerPage={pageSize}\n rowsPerPageOptions={[...pageSizeOptions]}\n onPageChange={(_, next) => onPageChange?.(next)}\n onRowsPerPageChange={(e) => {\n const next = parseInt(e.target.value, 10)\n onPageSizeChange?.(next)\n }}\n labelRowsPerPage={_labels.rowsPerPage}\n labelDisplayedRows={({ from, to, count }) =>\n _labels.paginationOf(from, to, count)\n }\n sx={styles.pagination}\n ActionsComponent={PaginationActions}\n />\n ) : null}\n </Box>","initialPageSize = DEFAULT_TABLE_PAGE_SIZE","remote = false","{\n columns,\n visibleColumns,\n initialPageSize = DEFAULT_TABLE_PAGE_SIZE,\n selection,\n onSelectionChange,\n onRowClick,\n onRowHover,\n remote = false,\n total: remoteTotal,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n ...uiProps\n}: TableProps<T>","(s) => s.data as readonly T[] | undefined","(s) => ({\n sort: s.sort,\n page: s.page ?? 0,\n pageSize: s.pageSize ?? initialPageSize,\n columnOrder: s.columnOrder,\n })","s","visibleColumns == null\n ? reordered\n : reordered.slice(0, visibleColumns)","columnOrder","useMemo(() => {\n const reordered = resolveColumns(columns, ui.columnOrder)\n return visibleColumns == null\n ? reordered\n : reordered.slice(0, visibleColumns)\n }, [columns, ui.columnOrder, visibleColumns])","useMemo(() => {\n if (remote) {\n return {\n rows: data ?? [],\n totalRows: remoteTotal ?? 0,\n }\n }\n const { sorted, visible } = deriveVisibleRows(data ?? [], {\n sort: ui.sort,\n page: ui.page,\n pageSize: ui.pageSize,\n })\n return { rows: visible, totalRows: sorted.length }\n }, [remote, data, remoteTotal, ui.sort, ui.page, ui.pageSize])","data ?? []","{\n rows: data ?? [],\n totalRows: remoteTotal ?? 0,\n }","remoteTotal ?? 0","deriveVisibleRows(data ?? [], {\n sort: ui.sort,\n page: ui.page,\n pageSize: ui.pageSize,\n })","page","pageSize","sort","{ rows: visible, totalRows: sorted.length }","length","(next: TableSortState) => {\n getWidgetStore(id).setState({\n sort: next,\n page: 0,\n } as Partial<TableWidgetState>)\n onSortChange?.(next)\n }","useCallback(\n (next: TableSortState) => {\n getWidgetStore(id).setState({\n sort: next,\n page: 0,\n } as Partial<TableWidgetState>)\n onSortChange?.(next)\n },\n [id, onSortChange],\n )","(page: number) => {\n getWidgetStore(id).setState({ page } as Partial<TableWidgetState>)\n onPageChange?.(page)\n }","useCallback(\n (page: number) => {\n getWidgetStore(id).setState({ page } as Partial<TableWidgetState>)\n onPageChange?.(page)\n },\n [id, onPageChange],\n )","(pageSize: number) => {\n getWidgetStore(id).setState({\n pageSize,\n page: 0,\n } as Partial<TableWidgetState>)\n onPageSizeChange?.(pageSize)\n }","useCallback(\n (pageSize: number) => {\n getWidgetStore(id).setState({\n pageSize,\n page: 0,\n } as Partial<TableWidgetState>)\n onPageSizeChange?.(pageSize)\n },\n [id, onPageSizeChange],\n )","<TableUI\n {...uiProps}\n columns={orderedColumns}\n rows={rows}\n total={totalRows}\n page={ui.page}\n pageSize={ui.pageSize}\n sort={ui.sort}\n selection={selection}\n onSortChange={handleSortChange}\n onPageChange={handlePageChange}\n onPageSizeChange={handlePageSizeChange}\n onSelectionChange={onSelectionChange}\n onRowClick={onRowClick}\n onRowHover={onRowHover}\n />","{\n rows = 5,\n columns = 4,\n size,\n}: TableSkeletonProps","rows = 5","columns = 4","<TableHead>\n <MuiTableRow>\n {Array.from({ length: columns }).map((_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n ))}\n </MuiTableRow>\n </TableHead>","(_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n )","Array.from({ length: rows })","<TableBody>\n {Array.from({ length: rows }).map((_, r) => (\n <MuiTableRow key={`row-${r}`} sx={styles.row}>\n {Array.from({ length: columns }).map((__, c) => (\n <TableCell key={`cell-${r}-${c}`}>\n <Skeleton variant='text' width='70%' height={20} />\n </TableCell>\n ))}\n </MuiTableRow>\n ))}\n </TableBody>","c","<Box sx={styles.container} aria-label='Table skeleton'>\n <MuiTable size={size} sx={styles.table} stickyHeader>\n <TableHead>\n <MuiTableRow>\n {Array.from({ length: columns }).map((_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n ))}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {Array.from({ length: rows }).map((_, r) => (\n <MuiTableRow key={`row-${r}`} sx={styles.row}>\n {Array.from({ length: columns }).map((__, c) => (\n <TableCell key={`cell-${r}-${c}`}>\n <Skeleton variant='text' width='70%' height={20} />\n </TableCell>\n ))}\n </MuiTableRow>\n ))}\n </TableBody>\n </MuiTable>\n </Box>"],"sources":["../src/widgets/table/labels.tsx","../src/widgets/table/types.ts","../src/widgets/table/style.ts","../src/widgets/table/table-ui.tsx","../src/widgets/table/helpers.ts","../src/widgets/table/table.tsx","../src/widgets/table/skeleton.tsx","../src/widgets/table/download.ts","../src/widgets/table/transforms.ts"],"sourcesContent":["import { Box, type SxProps, type Theme } from '@mui/material'\nimport type { ReactNode } from 'react'\n\nexport interface TableLabels {\n selectAll: string\n selectRow: (rowId: string | number) => string\n rowsPerPage: string\n /**\n * Renders the displayed-rows summary in the pagination footer. Returns\n * a `ReactNode` so the default can emphasise the active range\n * (`from-to`) with a bolder weight while keeping the trailing\n * ` of total` muted. Override to localise wording or restyle.\n */\n paginationOf: (from: number, to: number, total: number) => ReactNode\n /** aria-label for the first-page pagination button. */\n firstPage: string\n /** aria-label for the previous-page pagination button. */\n previousPage: string\n /** aria-label for the next-page pagination button. */\n nextPage: string\n /** aria-label for the last-page pagination button. */\n lastPage: string\n}\n\nconst boldRange: SxProps<Theme> = { fontWeight: 600, color: 'text.primary' }\n\nexport const DEFAULT_TABLE_LABELS: TableLabels = {\n selectAll: 'Select all rows',\n selectRow: (id) => `Select row ${id}`,\n rowsPerPage: 'Rows per page:',\n paginationOf: (from, to, total) => (\n <>\n <Box component='span' sx={boldRange}>{`${from}–${to}`}</Box>\n {` of ${total}`}\n </>\n ),\n firstPage: 'First page',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n lastPage: 'Last page',\n}\n","import type { ReactNode } from 'react'\nimport type { WidgetState } from '../stores'\n\n/**\n * Single row of tabular data.\n *\n * The default row-identity column is `id`. Consumers that don't have a\n * literal `id` field can point `<Table>` / `<TableUI>` at a different\n * column via the `keyColumn` prop; the library reads `row[keyColumn]`\n * for selection lookup, React keys, and aria labels.\n */\nexport interface TableRow extends Record<string, unknown> {\n /**\n * Default row identity. Required when no `keyColumn` is configured.\n * Omit when wiring `keyColumn` to a different column.\n */\n id?: string | number\n}\n\nexport type TableWidgetData = readonly TableRow[]\n\nexport type TableSortDirection = 'asc' | 'desc'\n\nexport interface TableSortState {\n columnId: string | null\n direction: TableSortDirection\n}\n\nexport interface TableColumn {\n /** Unique column identifier; matches the field name on each row. */\n id: string\n /** Header label. */\n label: ReactNode\n align?: 'left' | 'center' | 'right'\n width?: number | string\n sortable?: boolean\n /** Custom cell renderer. Falls back to a string-cast of the raw value. */\n formatter?: (value: unknown, row: TableRow) => ReactNode\n}\n\n/**\n * State extension carrying Table-specific UI state on the per-widget store.\n * Per R12: widget-specific UI state lives in widget-specific extensions of\n * `WidgetState`, not on the base type.\n */\nexport interface TableWidgetState extends WidgetState {\n /** Optional reordered column list driven by ChangeColumn. Falls back to props. */\n columnOrder?: readonly string[]\n sort?: TableSortState\n page: number\n pageSize: number\n}\n\nexport const DEFAULT_TABLE_PAGE_SIZE = 10\nexport const DEFAULT_TABLE_PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const\n","import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n container: {\n width: '100%',\n overflowX: 'auto',\n },\n\n table: {\n minWidth: 0,\n },\n headerCell: {\n fontWeight: 600,\n backgroundColor: 'background.paper',\n },\n /**\n * Strip the bottom border from the last body row so the body flushes\n * against the pagination border instead of doubling it up. Mirrors v1.\n */\n row: {\n '&:last-child td, &:last-child th': {\n border: 0,\n },\n },\n rowClickable: {\n cursor: 'pointer',\n },\n pagination: {\n borderTop: '1px solid',\n borderColor: 'divider',\n },\n paginationActions: {\n display: 'flex',\n alignItems: 'center',\n gap: 0.25,\n ml: 1,\n },\n empty: {\n textAlign: 'center',\n color: 'text.secondary',\n py: 3,\n },\n} satisfies Record<string, SxProps<Theme>>\n","import { useCallback, useMemo } from 'react'\nimport {\n Box,\n Checkbox,\n IconButton,\n Table as MuiTable,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TablePagination,\n TableRow as MuiTableRow,\n TableSortLabel,\n type TableProps as MuiTableProps,\n} from '@mui/material'\nimport type { TablePaginationActionsProps } from '@mui/material/TablePaginationActions'\nimport { FirstPage as FirstPageIcon } from '@mui/icons-material'\nimport { KeyboardArrowLeft } from '@mui/icons-material'\nimport { KeyboardArrowRight } from '@mui/icons-material'\nimport { LastPage as LastPageIcon } from '@mui/icons-material'\nimport { DEFAULT_TABLE_LABELS, type TableLabels } from './labels'\nimport {\n DEFAULT_TABLE_PAGE_SIZE_OPTIONS,\n type TableColumn,\n type TableRow,\n type TableSortDirection,\n type TableSortState,\n} from './types'\nimport { styles } from './style'\n\nexport interface TableUIProps<T extends TableRow = TableRow> {\n columns: readonly TableColumn[]\n /** Already-paginated, already-sorted rows for the current view. */\n rows: readonly T[]\n /** Total row count (across all pages). Required for pagination footer. */\n total: number\n page: number\n pageSize: number\n pageSizeOptions?: readonly number[]\n sort?: TableSortState\n /**\n * Column name to use as the row identity. Drives selection lookup,\n * React keys, and aria labels. Defaults to `'id'` — point it at\n * another column when your rows don't carry an `id` field.\n */\n keyColumn?: string\n /** Selected row ids. Destination-owned. */\n selection?: readonly (string | number)[]\n selectable?: boolean\n onSortChange?: (next: TableSortState) => void\n onPageChange?: (page: number) => void\n onPageSizeChange?: (pageSize: number) => void\n onSelectionChange?: (next: readonly (string | number)[]) => void\n onRowClick?: (row: T) => void\n onRowHover?: (row: T | null) => void\n labels?: Partial<TableLabels>\n /** Row rendered when `rows` is empty for the current page. */\n emptyContent?: React.ReactNode\n /**\n * Forwarded to MUI's `<Table size>` — `'small'` for compact rows,\n * `'medium'` for the default density. Leave `undefined` (the default)\n * to let MUI's own default kick in.\n */\n size?: MuiTableProps['size']\n}\n\n/**\n * Pure renderer for a paginated, sortable, optionally-selectable table.\n * Has no widget-store coupling — `<Table>` (the bridge) reads from the store\n * and feeds this UI with already-projected data.\n */\nexport function TableUI<T extends TableRow = TableRow>({\n columns,\n rows,\n total,\n page,\n pageSize,\n pageSizeOptions = DEFAULT_TABLE_PAGE_SIZE_OPTIONS,\n sort,\n keyColumn = 'id',\n selection,\n selectable = false,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n onSelectionChange,\n onRowClick,\n onRowHover,\n labels,\n emptyContent,\n size,\n}: TableUIProps<T>) {\n if (process.env.NODE_ENV !== 'production') {\n // Dev-time guard: a nullish identity collapses every row into the\n // same selection-set entry, which manifests as \"click one → all\n // appear selected\". Surface it loudly instead of silently degrading.\n const missing = rows.some((r) => r[keyColumn] == null)\n if (missing) {\n // eslint-disable-next-line no-console\n console.error(\n `<TableUI>: rows are missing the identity column \\`${keyColumn}\\`. ` +\n 'Set the `keyColumn` prop to a column present on every row, or ' +\n 'add the column to the data.',\n )\n }\n }\n const _labels = useMemo(\n () => ({ ...DEFAULT_TABLE_LABELS, ...labels }),\n [labels],\n )\n // Auto-hide the pagination footer when every row already fits in the\n // smallest available page size — the Rows-per-page selector + prev /\n // next buttons would just be inert noise. Consumers force the footer\n // on by passing a smaller `pageSizeOptions[0]` than `total`.\n const minPageSize = Math.min(...pageSizeOptions)\n const showPagination = total > minPageSize\n // Own the `ActionsComponent` slot ourselves so the Meridian theme's\n // `theme.components.MuiTablePagination.defaultProps.ActionsComponent`\n // (which depends on `react-intl`) doesn't leak into the library. The\n // MUI / Meridian style overrides for `MuiIconButton` /\n // `MuiTablePagination` still apply.\n const PaginationActions = useMemo(\n () => makePaginationActions(_labels),\n [_labels],\n )\n const selectionSet = useMemo(\n () => new Set<string | number>(selection ?? []),\n [selection],\n )\n // Resolve each row's identity from `keyColumn`, falling back to the row's\n // index when the cell is nullish. The dev-time guard above surfaces the\n // misconfiguration loudly, but in production we must NOT collapse every\n // nullish-keyed row into the same selection-set entry (that's the\n // \"click one → all selected\" bug) — a per-index fallback keeps ids\n // distinct and React keys stable for a given page.\n const resolveRowId = useCallback(\n (row: T, index: number): string | number =>\n (row[keyColumn] ?? index) as string | number,\n [keyColumn],\n )\n const pageRowIds = useMemo(() => rows.map(resolveRowId), [rows, resolveRowId])\n const allOnPageSelected =\n pageRowIds.length > 0 && pageRowIds.every((id) => selectionSet.has(id))\n const someOnPageSelected =\n !allOnPageSelected && pageRowIds.some((id) => selectionSet.has(id))\n\n const handleSort = (columnId: string) => {\n if (!onSortChange) return\n const sameCol = sort?.columnId === columnId\n const nextDir: TableSortDirection =\n sameCol && sort?.direction === 'asc' ? 'desc' : 'asc'\n onSortChange({ columnId, direction: nextDir })\n }\n\n const handleSelectAllOnPage = () => {\n if (!onSelectionChange) return\n if (allOnPageSelected) {\n onSelectionChange(\n (selection ?? []).filter((id) => !pageRowIds.includes(id)),\n )\n } else {\n const merged = new Set<string | number>(selection ?? [])\n for (const id of pageRowIds) merged.add(id)\n onSelectionChange([...merged])\n }\n }\n\n const handleSelectRow = (rowId: string | number) => {\n if (!onSelectionChange) return\n const next = new Set<string | number>(selection ?? [])\n if (next.has(rowId)) next.delete(rowId)\n else next.add(rowId)\n onSelectionChange([...next])\n }\n\n return (\n <Box sx={styles.container}>\n <TableContainer>\n <MuiTable stickyHeader size={size} sx={styles.table}>\n <TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n slotProps={{\n input: { 'aria-label': _labels.selectAll },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n slotProps={{\n input: {\n 'aria-label': _labels.selectRow(rowId),\n },\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>\n </MuiTable>\n </TableContainer>\n {showPagination ? (\n <TablePagination\n component='div'\n count={total}\n page={page}\n rowsPerPage={pageSize}\n rowsPerPageOptions={[...pageSizeOptions]}\n onPageChange={(_, next) => onPageChange?.(next)}\n onRowsPerPageChange={(e) => {\n const next = parseInt(e.target.value, 10)\n onPageSizeChange?.(next)\n }}\n labelRowsPerPage={_labels.rowsPerPage}\n labelDisplayedRows={({ from, to, count }) =>\n _labels.paginationOf(from, to, count)\n }\n sx={styles.pagination}\n ActionsComponent={PaginationActions}\n />\n ) : null}\n </Box>\n )\n}\n\nfunction stringifyCell(value: unknown): React.ReactNode {\n if (value == null) return ''\n if (typeof value === 'string' || typeof value === 'number') return value\n if (typeof value === 'boolean') return String(value)\n if (Array.isArray(value) || typeof value === 'object') {\n return JSON.stringify(value)\n }\n return ''\n}\n\n/**\n * Build the `ActionsComponent` used by `<TablePagination>` — four MUI\n * `IconButton`s for first / previous / next / last. We provide this\n * ourselves so the Meridian theme's `defaultProps.ActionsComponent`\n * (which depends on `react-intl`) is bypassed at the call site without\n * disturbing the rest of the Meridian theme. The factory closes over\n * the merged label set so aria-labels stay consistent with the rest\n * of the table's i18n surface.\n */\nfunction makePaginationActions(labels: TableLabels) {\n return function PaginationActions({\n count,\n page,\n rowsPerPage,\n onPageChange,\n }: TablePaginationActionsProps) {\n const lastPage = Math.max(0, Math.ceil(count / rowsPerPage) - 1)\n return (\n <Box sx={styles.paginationActions}>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, 0)}\n disabled={page === 0}\n aria-label={labels.firstPage}\n >\n <FirstPageIcon fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, page - 1)}\n disabled={page === 0}\n aria-label={labels.previousPage}\n >\n <KeyboardArrowLeft fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, page + 1)}\n disabled={page >= lastPage}\n aria-label={labels.nextPage}\n >\n <KeyboardArrowRight fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, lastPage)}\n disabled={page >= lastPage}\n aria-label={labels.lastPage}\n >\n <LastPageIcon fontSize='small' />\n </IconButton>\n </Box>\n )\n }\n}\n","import { toCsvString } from '../actions/download'\nimport type {\n TableColumn,\n TableRow,\n TableSortDirection,\n TableWidgetData,\n} from './types'\n\n/**\n * Compares two values with a consistent ordering across primitive types.\n * Strings use locale comparison; numbers subtract; booleans rank false < true;\n * objects/arrays compare by JSON serialization. Null/undefined sort to the end\n * regardless of direction.\n */\nexport function compareValues(\n a: unknown,\n b: unknown,\n direction: TableSortDirection,\n): number {\n if (a == null && b == null) return 0\n if (a == null) return 1\n if (b == null) return -1\n let cmp = 0\n if (typeof a === 'string' && typeof b === 'string') {\n cmp = a.localeCompare(b)\n } else if (typeof a === 'number' && typeof b === 'number') {\n cmp = a - b\n } else if (typeof a === 'boolean' && typeof b === 'boolean') {\n cmp = a === b ? 0 : a ? 1 : -1\n } else if (typeof a === 'object' || typeof b === 'object') {\n cmp = JSON.stringify(a).localeCompare(JSON.stringify(b))\n }\n return direction === 'asc' ? cmp : -cmp\n}\n\n/** Returns a new array sorted by the named column. Does not mutate the input. */\nexport function sortRows<T extends TableRow>(\n rows: readonly T[],\n columnId: string,\n direction: TableSortDirection,\n): T[] {\n return [...rows].sort((a, b) =>\n compareValues(a[columnId], b[columnId], direction),\n )\n}\n\n/** Returns the slice for the requested page. Out-of-range pages return []. */\nexport function paginateRows<T>(\n rows: readonly T[],\n page: number,\n pageSize: number,\n): T[] {\n if (pageSize <= 0) return rows.slice()\n const start = page * pageSize\n return rows.slice(start, start + pageSize)\n}\n\n/**\n * Resolves the effective column list. When the widget store has a\n * `columnOrder` set (e.g. ChangeColumn was used), the column array is\n * reordered to match. Unknown ids in the order are skipped; columns not\n * present in the order keep their original relative position at the end.\n */\nexport function resolveColumns(\n columns: readonly TableColumn[],\n columnOrder: readonly string[] | undefined,\n): readonly TableColumn[] {\n if (!columnOrder || columnOrder.length === 0) return columns\n const byId = new Map(columns.map((c) => [c.id, c]))\n const ordered: TableColumn[] = []\n const seen = new Set<string>()\n for (const id of columnOrder) {\n const c = byId.get(id)\n if (c && !seen.has(id)) {\n ordered.push(c)\n seen.add(id)\n }\n }\n for (const c of columns) {\n if (!seen.has(c.id)) ordered.push(c)\n }\n return ordered\n}\n\n/** Applies sort and pagination to the input data. Pure. */\nexport function deriveVisibleRows<T extends TableRow>(\n rows: readonly T[],\n options: {\n sort?: { columnId: string | null; direction: TableSortDirection }\n page: number\n pageSize: number\n },\n): { sorted: readonly T[]; visible: T[] } {\n const sorted =\n options.sort?.columnId != null\n ? sortRows(rows, options.sort.columnId, options.sort.direction)\n : rows\n const visible = paginateRows(sorted, options.page, options.pageSize)\n return { sorted, visible }\n}\n\nexport function tableDataToCsv(\n data: TableWidgetData,\n columns: readonly TableColumn[],\n): string {\n // Pre-stringify with the table's own header/cell rules, then delegate the\n // CSV assembly (quoting + spreadsheet formula-injection guard) to the shared\n // `toCsvString` so escaping stays identical to every other widget's export.\n const rows: string[][] = [columns.map((c) => stringifyHeader(c.label))]\n for (const row of data) {\n rows.push(columns.map((c) => stringifyCell(row[c.id])))\n }\n return toCsvString(rows)\n}\n\nfunction stringifyHeader(label: unknown): string {\n if (typeof label === 'string') return label\n if (typeof label === 'number' || typeof label === 'boolean')\n return String(label)\n return ''\n}\n\nfunction stringifyCell(value: unknown): string {\n if (value == null) return ''\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value)\n if (Array.isArray(value) || typeof value === 'object')\n return JSON.stringify(value)\n return ''\n}\n","import { useCallback, useMemo } from 'react'\nimport {\n getWidgetStore,\n useWidget,\n useWidgetId,\n useWidgetShallow,\n} from '../stores'\nimport { TableUI, type TableUIProps } from './table-ui'\nimport {\n DEFAULT_TABLE_PAGE_SIZE,\n type TableColumn,\n type TableRow,\n type TableSortState,\n type TableWidgetState,\n} from './types'\nimport { deriveVisibleRows, resolveColumns } from './helpers'\n\nexport interface TableProps<T extends TableRow = TableRow> extends Pick<\n TableUIProps<T>,\n | 'pageSizeOptions'\n | 'selectable'\n | 'labels'\n | 'emptyContent'\n | 'size'\n | 'keyColumn'\n> {\n /**\n * Column definitions. Order can be overridden by ChangeColumn via the\n * `columnOrder` field on the extended widget state.\n */\n columns: readonly TableColumn[]\n /**\n * When set, render only the first `visibleColumns` entries **after**\n * applying the user's `columnOrder` from the store. Useful for showing\n * a compact projection while letting consumers (e.g. `Widget.ChangeColumn`)\n * see the full column list. When omitted, every column renders.\n */\n visibleColumns?: number\n /** Initial page size (only on first mount; afterwards lives on the store). */\n initialPageSize?: number\n /** Selected row ids (destination-owned). */\n selection?: readonly (string | number)[]\n onSelectionChange?: (next: readonly (string | number)[]) => void\n onRowClick?: (row: T) => void\n onRowHover?: (row: T | null) => void\n /**\n * When `true`, the bridge stops sorting and paginating locally and\n * renders `data` as-is — the consumer is then responsible for\n * refetching the slice that matches the active `page` / `pageSize` /\n * `sort` from the outbound callbacks below. `total` is required in\n * this mode (the server already knows the full row count; the\n * widget can't infer it from a partial page).\n */\n remote?: boolean\n /**\n * Server-reported total row count. Required when `remote === true`;\n * ignored in local mode (where the bridge derives total from the\n * sorted result of `deriveVisibleRows`).\n */\n total?: number\n /** Fires after the store-level sort write so the consumer can refetch. */\n onSortChange?: (next: TableSortState) => void\n /** Fires after the store-level page write so the consumer can refetch. */\n onPageChange?: (page: number) => void\n /** Fires after the store-level pageSize write so the consumer can refetch. */\n onPageSizeChange?: (pageSize: number) => void\n}\n\n/**\n * Bridge component — reads the widget store's `data`, applies sort + pagination\n * locally, and feeds `<TableUI />`. Sort, page, and pageSize live on the\n * extended widget state ({@link TableWidgetState}).\n */\nexport function Table<T extends TableRow = TableRow>({\n columns,\n visibleColumns,\n initialPageSize = DEFAULT_TABLE_PAGE_SIZE,\n selection,\n onSelectionChange,\n onRowClick,\n onRowHover,\n remote = false,\n total: remoteTotal,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n ...uiProps\n}: TableProps<T>) {\n const id = useWidgetId()\n const data = useWidget(id, (s) => s.data as readonly T[] | undefined)\n const ui = useWidgetShallow<\n {\n sort: TableSortState | undefined\n page: number\n pageSize: number\n columnOrder: readonly string[] | undefined\n },\n TableWidgetState\n >(id, (s) => ({\n sort: s.sort,\n page: s.page ?? 0,\n pageSize: s.pageSize ?? initialPageSize,\n columnOrder: s.columnOrder,\n }))\n\n const orderedColumns = useMemo(() => {\n const reordered = resolveColumns(columns, ui.columnOrder)\n return visibleColumns == null\n ? reordered\n : reordered.slice(0, visibleColumns)\n }, [columns, ui.columnOrder, visibleColumns])\n\n // In remote mode the consumer already paginated / sorted server-side,\n // so pass `data` and `total` straight through. Local mode keeps the\n // bridge-driven sort + slice via `deriveVisibleRows`.\n const { rows, totalRows } = useMemo(() => {\n if (remote) {\n return {\n rows: data ?? [],\n totalRows: remoteTotal ?? 0,\n }\n }\n const { sorted, visible } = deriveVisibleRows(data ?? [], {\n sort: ui.sort,\n page: ui.page,\n pageSize: ui.pageSize,\n })\n return { rows: visible, totalRows: sorted.length }\n }, [remote, data, remoteTotal, ui.sort, ui.page, ui.pageSize])\n\n const handleSortChange = useCallback(\n (next: TableSortState) => {\n getWidgetStore(id).setState({\n sort: next,\n page: 0,\n } as Partial<TableWidgetState>)\n onSortChange?.(next)\n },\n [id, onSortChange],\n )\n\n const handlePageChange = useCallback(\n (page: number) => {\n getWidgetStore(id).setState({ page } as Partial<TableWidgetState>)\n onPageChange?.(page)\n },\n [id, onPageChange],\n )\n\n const handlePageSizeChange = useCallback(\n (pageSize: number) => {\n getWidgetStore(id).setState({\n pageSize,\n page: 0,\n } as Partial<TableWidgetState>)\n onPageSizeChange?.(pageSize)\n },\n [id, onPageSizeChange],\n )\n\n return (\n <TableUI\n {...uiProps}\n columns={orderedColumns}\n rows={rows}\n total={totalRows}\n page={ui.page}\n pageSize={ui.pageSize}\n sort={ui.sort}\n selection={selection}\n onSortChange={handleSortChange}\n onPageChange={handlePageChange}\n onPageSizeChange={handlePageSizeChange}\n onSelectionChange={onSelectionChange}\n onRowClick={onRowClick}\n onRowHover={onRowHover}\n />\n )\n}\n","import {\n Box,\n Skeleton,\n Table as MuiTable,\n TableBody,\n TableCell,\n TableHead,\n TableRow as MuiTableRow,\n type TableProps as MuiTableProps,\n} from '@mui/material'\nimport { styles } from './style'\n\nexport interface TableSkeletonProps {\n /** Number of body rows to render. Defaults to `5` (matches v1). */\n rows?: number\n /** Number of columns to render. Defaults to `4` (matches v1). */\n columns?: number\n /**\n * Forwarded to MUI's `<Table size>` so the loading layout matches the\n * size you'll render in {@link TableUI}. Leave `undefined` (the\n * default) to use MUI's own default density.\n */\n size?: MuiTableProps['size']\n}\n\n/**\n * Loading placeholder for the Table widget. Renders the same MUI table\n * primitives that {@link TableUI} uses so the loading layout (column\n * widths, header band, row density) doesn't shift when data resolves.\n *\n * Mirrors the v1 widget's `<TableSkeleton>` structure with v2's themed\n * `styles.headerCell`.\n */\nexport function TableSkeleton({\n rows = 5,\n columns = 4,\n size,\n}: TableSkeletonProps) {\n return (\n <Box sx={styles.container} aria-label='Table skeleton'>\n <MuiTable size={size} sx={styles.table} stickyHeader>\n <TableHead>\n <MuiTableRow>\n {Array.from({ length: columns }).map((_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n ))}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {Array.from({ length: rows }).map((_, r) => (\n <MuiTableRow key={`row-${r}`} sx={styles.row}>\n {Array.from({ length: columns }).map((__, c) => (\n <TableCell key={`cell-${r}-${c}`}>\n <Skeleton variant='text' width='70%' height={20} />\n </TableCell>\n ))}\n </MuiTableRow>\n ))}\n </TableBody>\n </MuiTable>\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n withPngItem,\n type DownloadItem,\n type WidgetDownloadArgs,\n} from '../actions/download'\nimport { tableDataToCsv } from './helpers'\nimport type { TableColumn, TableWidgetData } from './types'\n\n/**\n * Download menu items for the Table widget. Always includes a CSV item that\n * pulls the latest data from the widget store via `getData()` (so locked /\n * sorted / filtered state is honored); headers come from `column.label`,\n * cells from `row[column.id]`. When `getCaptureEl` is given, prepends a PNG\n * item that rasterises the captured element via `html2canvas`.\n */\nexport function createTableDownloadConfig(\n opts: WidgetDownloadArgs<TableWidgetData> & {\n columns: readonly TableColumn[]\n },\n): DownloadItem[] {\n return withPngItem(\n opts,\n buildCsvDownloadItem({\n filename: opts.filename,\n getCsv: (ctx) => tableDataToCsv(opts.getData(ctx), opts.columns),\n }),\n )\n}\n","/**\n * `LockSelection` filter for Table. Data is a FLAT `TableRow[]` (unlike every\n * other widget's `X[][]` series shape) and row identity comes from\n * `row[keyColumn]` (default `'id'`), not `name` — so `filterByLockedItems`\n * doesn't apply here (its outer `.map` treats each row as a \"series\", and a\n * plain row object isn't an array, so it would silently pass everything\n * through unfiltered). Falls back to the row's index when the identity\n * column is nullish, mirroring `TableUI`'s own `resolveRowId`.\n *\n * `keyColumn` arrives as `LockSelection`'s `filterKey`, so pass this by\n * reference: `filterFn={filterTableByLockedRows} filterKey={keyColumn}`.\n * Don't close over it — `filterFn`'s identity is not a pipeline dependency,\n * so a captured key changes without re-running anything.\n */\nexport function filterTableByLockedRows(\n input: unknown,\n lockedItems: readonly (string | number)[],\n keyColumn: string | number = 'id',\n): unknown {\n if (lockedItems.length === 0) return input\n if (!Array.isArray(input)) return input\n const locked = new Set<string | number>(lockedItems)\n return input.filter((row: unknown, index: number): boolean => {\n if (row == null || typeof row !== 'object') return false\n const id = (row as Record<string, unknown>)[keyColumn] ?? index\n return (typeof id === 'string' || typeof id === 'number') && locked.has(id)\n })\n}\n"],"mappings":"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"}
|
|
@@ -72,7 +72,8 @@ export interface LegendRampVariable {
|
|
|
72
72
|
* Ordered low→high stops. Discrete ramps **require `colors.length + 1`**
|
|
73
73
|
* stops — the boundaries between color steps, including both outer edges —
|
|
74
74
|
* and each label is centered on its boundary line (keep labels short, e.g.
|
|
75
|
-
* `20K`; there is no collision handling
|
|
75
|
+
* `20K`; there is no collision handling; pass `''` to hide one — each step's
|
|
76
|
+
* tooltip still shows its full range). A discrete ramp with any other
|
|
76
77
|
* stop count is incoherent and renders an inline error instead of the bar.
|
|
77
78
|
* Continuous ramps show only the first/last endpoints.
|
|
78
79
|
*/
|
|
@@ -86,7 +87,8 @@ export interface LegendRampVariable {
|
|
|
86
87
|
*/
|
|
87
88
|
avg?: number;
|
|
88
89
|
/**
|
|
89
|
-
* Formats `avg`
|
|
90
|
+
* Formats `avg` and, on discrete ramps, the stop values shown in each
|
|
91
|
+
* step's range tooltip. Default `String(value)` — pass e.g.
|
|
90
92
|
* `(v) => formatNumber(v, 'es-ES')` or `(v) => `${v}%``. Use a stable
|
|
91
93
|
* reference (same contract as the other variable fields).
|
|
92
94
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DownloadItem } from './types.js';
|
|
1
|
+
import { DownloadContext, DownloadItem } from './types.js';
|
|
2
2
|
interface BuildCsvDownloadItemBase {
|
|
3
3
|
/** Base filename (without extension). The item appends `.csv`. */
|
|
4
4
|
filename: string;
|
|
@@ -17,7 +17,7 @@ export type BuildCsvDownloadItemArgs = (BuildCsvDownloadItemBase & {
|
|
|
17
17
|
* through `toCsvString` so escaping (incl. the spreadsheet
|
|
18
18
|
* formula-injection guard) stays consistent across widgets.
|
|
19
19
|
*/
|
|
20
|
-
getRows: () => readonly (readonly unknown[])[];
|
|
20
|
+
getRows: (ctx: DownloadContext) => readonly (readonly unknown[])[];
|
|
21
21
|
getCsv?: never;
|
|
22
22
|
}) | (BuildCsvDownloadItemBase & {
|
|
23
23
|
/**
|
|
@@ -25,7 +25,7 @@ export type BuildCsvDownloadItemArgs = (BuildCsvDownloadItemBase & {
|
|
|
25
25
|
* (e.g. Table) that already serialise their own CSV with bespoke
|
|
26
26
|
* header/cell handling.
|
|
27
27
|
*/
|
|
28
|
-
getCsv: () => string;
|
|
28
|
+
getCsv: (ctx: DownloadContext) => string;
|
|
29
29
|
getRows?: never;
|
|
30
30
|
});
|
|
31
31
|
/**
|
|
@@ -3,6 +3,7 @@ export { downloadToCSV, downloadDOMToPNG, toCsvString, triggerLinkDownload, type
|
|
|
3
3
|
export { CSVIcon, PNGIcon, MarkdownIcon } from './icons.js';
|
|
4
4
|
export { buildPngDownloadItem, type BuildPngDownloadItemArgs } from './png-item.js';
|
|
5
5
|
export { buildCsvDownloadItem, type BuildCsvDownloadItemArgs } from './csv-item.js';
|
|
6
|
+
export { withPngItem, type WidgetDownloadArgs } from './widget-download.js';
|
|
6
7
|
export { DOWNLOAD_ITEM_IDS, type DownloadItemId } from './constants.js';
|
|
7
|
-
export type { DownloadItem } from './types.js';
|
|
8
|
+
export type { DownloadItem, DownloadContext } from './types.js';
|
|
8
9
|
export { DEFAULT_DOWNLOAD_LABELS, type DownloadLabels } from './labels.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DownloadItem } from './types.js';
|
|
1
|
+
import { DownloadContext, DownloadItem } from './types.js';
|
|
2
2
|
export interface BuildPngDownloadItemArgs {
|
|
3
3
|
/** Base filename (without extension). The item appends `.png`. */
|
|
4
4
|
filename: string;
|
|
@@ -7,7 +7,7 @@ export interface BuildPngDownloadItemArgs {
|
|
|
7
7
|
* download config doesn't capture a stale reference. Wire it to
|
|
8
8
|
* `() => getCaptureEl(id)` from `widgets/stores`.
|
|
9
9
|
*/
|
|
10
|
-
getCaptureEl: () => HTMLElement | null;
|
|
10
|
+
getCaptureEl: (ctx: DownloadContext) => HTMLElement | null;
|
|
11
11
|
/** html2canvas `scale`. Default 2. */
|
|
12
12
|
pixelRatio?: number;
|
|
13
13
|
/** html2canvas `backgroundColor`. Default transparent (`null`). */
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Passed to {@link DownloadItem.resolve} by `<Widget.Download>`.
|
|
4
|
+
*/
|
|
5
|
+
export interface DownloadContext {
|
|
6
|
+
/**
|
|
7
|
+
* Id of the widget store the menu was opened from — the dialog's own
|
|
8
|
+
* store when opened from `FullScreen.Slot`'s header, so an export matches
|
|
9
|
+
* what the user is looking at. `null` outside a `<Widget.Provider>`.
|
|
10
|
+
*/
|
|
11
|
+
id: string | null;
|
|
12
|
+
}
|
|
2
13
|
export interface DownloadItem {
|
|
3
14
|
/** Unique key (also used as menu label key). */
|
|
4
15
|
id: string;
|
|
@@ -27,7 +38,7 @@ export interface DownloadItem {
|
|
|
27
38
|
* Resolves to a Blob URL the trigger will click. Optional `revoke` is
|
|
28
39
|
* called after the click is dispatched.
|
|
29
40
|
*/
|
|
30
|
-
resolve: () => Promise<{
|
|
41
|
+
resolve: (ctx: DownloadContext) => Promise<{
|
|
31
42
|
url: string;
|
|
32
43
|
filename: string;
|
|
33
44
|
revoke?: () => void;
|