@krak-stack/registry 0.1.22 → 0.1.24

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.
@@ -3,15 +3,7 @@ import { type PaginationMessages } from "./pagination.js";
3
3
  import type { QueryType } from "../../lib/query.js";
4
4
  type RowData = object;
5
5
  export type DataTableView = "table" | "gallery";
6
- export interface DataTableUiState {
7
- columnVisibility: Record<string, boolean>;
8
- columnSizing: Record<string, number>;
9
- rowSelection: Record<string, boolean>;
10
- grouping: readonly string[];
11
- collapsedGroups: Record<string, boolean>;
12
- view: DataTableView;
13
- }
14
- export type DataTablePublicState = QueryType & DataTableUiState;
6
+ export type DataTablePublicState = QueryType;
15
7
  export interface DataTableValueGetterParams<TData extends RowData> {
16
8
  data: TData;
17
9
  rowId: string;
@@ -1,7 +1,8 @@
1
1
  // ../../src/components/ui/data-table.tsx
2
2
  import { useAtom, useAtomSet } from "@effect/atom-react";
3
+ import { BrowserKeyValueStore } from "@effect/platform-browser";
3
4
  import { Schema } from "effect";
4
- import { Atom } from "effect/unstable/reactivity";
5
+ import { AsyncResult, Atom } from "effect/unstable/reactivity";
5
6
  import {
6
7
  ArrowDown,
7
8
  ArrowUp,
@@ -24,8 +25,10 @@ import {
24
25
  import {
25
26
  createContext,
26
27
  isValidElement,
28
+ useCallback as useCallback2,
27
29
  useContext,
28
30
  useLayoutEffect,
31
+ useMemo,
29
32
  useRef as useRef2,
30
33
  useState
31
34
  } from "react";
@@ -1806,6 +1809,12 @@ function VirtualizedCombobox(props) {
1806
1809
 
1807
1810
  // ../../src/components/ui/data-table.tsx
1808
1811
  import { jsx as jsx17, jsxs as jsxs9, Fragment } from "react/jsx-runtime";
1812
+ var DataTablePersistedUiStateSchema = Schema.Struct({
1813
+ columnVisibility: Schema.Record(Schema.String, Schema.Boolean),
1814
+ columnSizing: Schema.Record(Schema.String, Schema.Number),
1815
+ view: Schema.Literals(["table", "gallery"])
1816
+ }).annotate({ identifier: "DataTablePersistedUiState" });
1817
+ var dataTableStorageRuntime = Atom.runtime(BrowserKeyValueStore.layerLocalStorage);
1809
1818
  var messages3 = {
1810
1819
  en: {
1811
1820
  ...paginationMessages("en"),
@@ -1873,9 +1882,11 @@ var dataTableMessages = (overrides) => ({
1873
1882
  var DEFAULT_MIN_WIDTH = 96;
1874
1883
  var DEFAULT_WIDTH = 208;
1875
1884
  var DEFAULT_MAX_WIDTH = 640;
1876
- var DEFAULT_STATE = {
1885
+ var DEFAULT_QUERY = {
1877
1886
  page: 0,
1878
- pageSize: 10,
1887
+ pageSize: 10
1888
+ };
1889
+ var DEFAULT_UI_STATE = {
1879
1890
  columnVisibility: {},
1880
1891
  columnSizing: {},
1881
1892
  rowSelection: {},
@@ -1883,6 +1894,16 @@ var DEFAULT_STATE = {
1883
1894
  collapsedGroups: {},
1884
1895
  view: "table"
1885
1896
  };
1897
+ var persistedUiFromState = (state) => ({
1898
+ columnVisibility: state.columnVisibility,
1899
+ columnSizing: state.columnSizing,
1900
+ view: state.view
1901
+ });
1902
+ var transientUiFromState = (state) => ({
1903
+ rowSelection: state.rowSelection,
1904
+ grouping: state.grouping,
1905
+ collapsedGroups: state.collapsedGroups
1906
+ });
1886
1907
  var clampWidth = (column, width) => Math.min(column.maxWidth ?? DEFAULT_MAX_WIDTH, Math.max(column.minWidth ?? DEFAULT_MIN_WIDTH, width));
1887
1908
  var normalizeDataTableColumns = (columnDefs, columnSizing = {}) => {
1888
1909
  const ids = new Set;
@@ -1998,7 +2019,7 @@ var clearDragPresentation = (root) => {
1998
2019
  element.removeAttribute("data-drop-position");
1999
2020
  });
2000
2021
  };
2001
- var resolveConfig = (props) => {
2022
+ var resolveConfig = (props, onUiStateChange) => {
2002
2023
  const features = props.features ?? {};
2003
2024
  const selection = features.selection;
2004
2025
  const getRowId = selection && selection.getRowId || props.getRowId || undefined;
@@ -2008,21 +2029,35 @@ var resolveConfig = (props) => {
2008
2029
  return {
2009
2030
  getRowId,
2010
2031
  onStateChange: props.onStateChange,
2032
+ onUiStateChange,
2011
2033
  status: props.status ?? {},
2012
2034
  features,
2013
2035
  onRowClicked: props.onRowClicked,
2014
2036
  labels: dataTableMessages(props.messages)
2015
2037
  };
2016
2038
  };
2017
- var initialPublicState = (props) => {
2018
- const grouping = props.features?.grouping;
2019
- const groupingInitial = grouping && grouping.initial ? grouping.initial : [];
2020
- return props.state ?? {
2021
- ...DEFAULT_STATE,
2022
- grouping: groupingInitial,
2023
- ...props.initialState
2024
- };
2025
- };
2039
+ var queryFromState = (state) => ({
2040
+ page: state.page,
2041
+ pageSize: state.pageSize,
2042
+ globalFilter: state.globalFilter,
2043
+ sort: state.sort
2044
+ });
2045
+ var uiFromState = (state) => ({
2046
+ columnVisibility: state.columnVisibility,
2047
+ columnSizing: state.columnSizing,
2048
+ rowSelection: state.rowSelection,
2049
+ grouping: state.grouping,
2050
+ collapsedGroups: state.collapsedGroups,
2051
+ view: state.view
2052
+ });
2053
+ var sameUiState = (left, right) => left.columnVisibility === right.columnVisibility && left.columnSizing === right.columnSizing && left.rowSelection === right.rowSelection && left.grouping === right.grouping && left.collapsedGroups === right.collapsedGroups && left.view === right.view;
2054
+ var sameQueryState = (left, right) => left.page === right.page && left.pageSize === right.pageSize && left.globalFilter === right.globalFilter && left.sort === right.sort;
2055
+ var initialPublicState = (props, uiState) => ({
2056
+ ...DEFAULT_QUERY,
2057
+ ...props.initialState,
2058
+ ...props.state,
2059
+ ...uiState
2060
+ });
2026
2061
  var buildDataTableModel = (store) => {
2027
2062
  const columns = normalizeDataTableColumns(store.columnDefs, store.state.columnSizing);
2028
2063
  const selection = store.config.features.selection;
@@ -2049,8 +2084,15 @@ var useTableAtom = (tableAtom) => useAtom(tableAtom);
2049
2084
  var changeState = (setStore, update) => {
2050
2085
  setStore((store) => {
2051
2086
  const proposed = update(store.state);
2052
- store.config.onStateChange?.(proposed);
2053
- const state = store.controlledState ?? proposed;
2087
+ const query = queryFromState(proposed);
2088
+ if (!sameQueryState(query, store.state)) {
2089
+ store.config.onStateChange?.(query);
2090
+ }
2091
+ const uiState = uiFromState(proposed);
2092
+ if (!sameUiState(uiState, store.state)) {
2093
+ store.config.onUiStateChange(uiState);
2094
+ }
2095
+ const state = store.controlledState ? { ...proposed, ...store.controlledState } : proposed;
2054
2096
  if (sameDataTableState(state, store.state))
2055
2097
  return store;
2056
2098
  const next = { ...store, state };
@@ -2289,7 +2331,7 @@ var DataTableToolbar = ({
2289
2331
  ]
2290
2332
  }) : null,
2291
2333
  /* @__PURE__ */ jsx17("div", {
2292
- className: "-m-1 flex w-full overflow-x-auto p-1",
2334
+ className: "-m-1 flex overflow-x-auto p-1",
2293
2335
  children: /* @__PURE__ */ jsxs9(Menubar, {
2294
2336
  className: "h-auto w-max min-w-full justify-start bg-transparent shadow-none [&_[data-slot=menubar-trigger]]:gap-2 [&_[data-slot=menubar-trigger]_svg]:size-4",
2295
2337
  children: [
@@ -2905,12 +2947,20 @@ var GroupedTable = ({
2905
2947
  const renderSections = (items) => items.flatMap((section) => {
2906
2948
  const collapsed = !!store.state.collapsedGroups[section.key];
2907
2949
  const targetKey = getGroupDropKey(section.field.id, section.groupId);
2950
+ const toggleCollapsed = () => changeState(setStore, (state) => ({
2951
+ ...state,
2952
+ collapsedGroups: {
2953
+ ...state.collapsedGroups,
2954
+ [section.key]: !collapsed
2955
+ }
2956
+ }));
2908
2957
  const body = /* @__PURE__ */ jsxs9(TableBody, {
2909
2958
  className: "data-[drop-target=true]:outline-primary relative data-[drop-target=true]:z-30 data-[drop-target=true]:outline-2 data-[drop-target=true]:-outline-offset-2 data-[drop-target=true]:[&>tr]:border-transparent data-[drop-target=true]:[&>tr>td:last-child]:z-0",
2910
2959
  "data-table-group": section.field.onMoveToGroup ? targetKey : undefined,
2911
2960
  children: [
2912
2961
  /* @__PURE__ */ jsx17(TableRow, {
2913
- className: "bg-muted/40",
2962
+ className: "bg-muted/40 hover:bg-accent! cursor-pointer",
2963
+ onClick: toggleCollapsed,
2914
2964
  children: /* @__PURE__ */ jsx17(TableCell, {
2915
2965
  colSpan: model.visibleColumns.length + extra,
2916
2966
  children: /* @__PURE__ */ jsxs9("div", {
@@ -2919,14 +2969,7 @@ var GroupedTable = ({
2919
2969
  children: [
2920
2970
  /* @__PURE__ */ jsxs9("button", {
2921
2971
  "aria-expanded": !collapsed,
2922
- className: "flex flex-1 items-center gap-2 text-left",
2923
- onClick: () => changeState(setStore, (state) => ({
2924
- ...state,
2925
- collapsedGroups: {
2926
- ...state.collapsedGroups,
2927
- [section.key]: !collapsed
2928
- }
2929
- })),
2972
+ className: "flex flex-1 cursor-pointer items-center gap-2 text-left font-medium",
2930
2973
  type: "button",
2931
2974
  children: [
2932
2975
  collapsed ? /* @__PURE__ */ jsx17(ChevronRight2, {
@@ -3278,23 +3321,24 @@ var DataTableGallery = ({
3278
3321
  const renderSections = (sections) => sections.map((section) => {
3279
3322
  const collapsed = !!store.state.collapsedGroups[section.key];
3280
3323
  const targetKey = getGroupDropKey(section.field.id, section.groupId);
3324
+ const toggleCollapsed = () => changeState(setStore, (state) => ({
3325
+ ...state,
3326
+ collapsedGroups: {
3327
+ ...state.collapsedGroups,
3328
+ [section.key]: !collapsed
3329
+ }
3330
+ }));
3281
3331
  return /* @__PURE__ */ jsxs9("section", {
3282
3332
  className: "data-[drop-target=true]:ring-primary space-y-3 rounded-lg transition-shadow data-[drop-target=true]:ring-2",
3283
3333
  "data-table-group": section.field.onMoveToGroup ? targetKey : undefined,
3284
3334
  children: [
3285
3335
  /* @__PURE__ */ jsxs9("div", {
3286
- className: "flex items-center gap-2 rounded-lg border p-3",
3336
+ className: "hover:bg-accent flex cursor-pointer items-center gap-2 rounded-lg border p-3 transition-colors",
3337
+ onClick: toggleCollapsed,
3287
3338
  children: [
3288
3339
  /* @__PURE__ */ jsxs9("button", {
3289
3340
  "aria-expanded": !collapsed,
3290
- className: "flex flex-1 items-center gap-2 text-left",
3291
- onClick: () => changeState(setStore, (state) => ({
3292
- ...state,
3293
- collapsedGroups: {
3294
- ...state.collapsedGroups,
3295
- [section.key]: !collapsed
3296
- }
3297
- })),
3341
+ className: "flex flex-1 cursor-pointer items-center gap-2 text-left font-medium",
3298
3342
  type: "button",
3299
3343
  children: [
3300
3344
  collapsed ? /* @__PURE__ */ jsx17(ChevronRight2, {
@@ -3376,15 +3420,33 @@ var DataTablePagination = ({
3376
3420
  })
3377
3421
  });
3378
3422
  };
3379
- var DataTable = (props) => {
3380
- const validatedConfig = resolveConfig(props);
3423
+ var HydratedDataTable = ({
3424
+ persistedUiState,
3425
+ setPersistedUiState,
3426
+ ...props
3427
+ }) => {
3428
+ const transientUiAtomRef = useRef2(null);
3429
+ if (!transientUiAtomRef.current) {
3430
+ const grouping = props.features?.grouping;
3431
+ transientUiAtomRef.current = Atom.make({
3432
+ ...transientUiFromState(DEFAULT_UI_STATE),
3433
+ grouping: grouping && grouping.initial ? grouping.initial : []
3434
+ });
3435
+ }
3436
+ const [transientUiState, setTransientUiState] = useAtom(transientUiAtomRef.current);
3437
+ const uiState = useMemo(() => ({ ...persistedUiState, ...transientUiState }), [persistedUiState, transientUiState]);
3438
+ const setUiState = useCallback2((state) => {
3439
+ setPersistedUiState(persistedUiFromState(state));
3440
+ setTransientUiState(transientUiFromState(state));
3441
+ }, [setPersistedUiState, setTransientUiState]);
3442
+ const validatedConfig = resolveConfig(props, (state) => setUiState(state));
3381
3443
  const atomRef = useRef2(null);
3382
3444
  if (!atomRef.current) {
3383
3445
  const initial = {
3384
3446
  rowData: props.rowData,
3385
3447
  columnDefs: props.columnDefs,
3386
3448
  config: validatedConfig,
3387
- state: initialPublicState(props),
3449
+ state: initialPublicState(props, uiState),
3388
3450
  controlledState: props.state
3389
3451
  };
3390
3452
  atomRef.current = Atom.make({
@@ -3401,12 +3463,13 @@ var DataTable = (props) => {
3401
3463
  const config = {
3402
3464
  getRowId: selection && selection.getRowId || props.getRowId || undefined,
3403
3465
  onStateChange: props.onStateChange,
3466
+ onUiStateChange: (state2) => setUiState(state2),
3404
3467
  status: props.status ?? {},
3405
3468
  features,
3406
3469
  onRowClicked: props.onRowClicked,
3407
3470
  labels: dataTableMessages(props.messages)
3408
3471
  };
3409
- const state = props.state ?? store.state;
3472
+ const state = { ...store.state, ...uiState, ...props.state };
3410
3473
  const modelChanged = store.rowData !== props.rowData || store.columnDefs !== props.columnDefs || !sameDataTableState(store.state, state) || store.config.getRowId !== config.getRowId || store.config.features.pagination !== config.features.pagination;
3411
3474
  const next = {
3412
3475
  ...store,
@@ -3428,7 +3491,9 @@ var DataTable = (props) => {
3428
3491
  props.rowData,
3429
3492
  props.state,
3430
3493
  props.status,
3431
- setStore
3494
+ setStore,
3495
+ setUiState,
3496
+ uiState
3432
3497
  ]);
3433
3498
  return /* @__PURE__ */ jsxs9("div", {
3434
3499
  className: "w-full max-w-full min-w-0 rounded-md",
@@ -3446,6 +3511,34 @@ var DataTable = (props) => {
3446
3511
  ]
3447
3512
  });
3448
3513
  };
3514
+ var DataTable = (props) => {
3515
+ const persistedUiAtomRef = useRef2(null);
3516
+ if (!persistedUiAtomRef.current) {
3517
+ const pathname = globalThis.window?.location.pathname ?? "/";
3518
+ const columnIds = normalizeDataTableColumns(props.columnDefs).map(({ id }) => id).join(",");
3519
+ const viewCapability = props.features?.gallery ? "gallery" : "table";
3520
+ persistedUiAtomRef.current = Atom.kvs({
3521
+ mode: "async",
3522
+ runtime: dataTableStorageRuntime,
3523
+ key: `data-table:${pathname}:${columnIds}:${viewCapability}:ui`,
3524
+ schema: DataTablePersistedUiStateSchema,
3525
+ defaultValue: () => persistedUiFromState(DEFAULT_UI_STATE)
3526
+ });
3527
+ }
3528
+ const [persistedUiResult, setPersistedUiState] = useAtom(persistedUiAtomRef.current);
3529
+ if (!AsyncResult.isSuccess(persistedUiResult) || AsyncResult.isWaiting(persistedUiResult)) {
3530
+ return /* @__PURE__ */ jsx17("div", {
3531
+ "aria-busy": "true",
3532
+ className: "invisible w-full max-w-full min-w-0 rounded-md",
3533
+ "data-table-root": ""
3534
+ });
3535
+ }
3536
+ return /* @__PURE__ */ jsx17(HydratedDataTable, {
3537
+ ...props,
3538
+ persistedUiState: persistedUiResult.value,
3539
+ setPersistedUiState
3540
+ });
3541
+ };
3449
3542
  var DataTableContent = ({
3450
3543
  tableAtom
3451
3544
  }) => {