@mendylanda/ui 0.4.3-dev.69.b44a9721f450 → 0.4.3-dev.72.7ee3a6f295d2

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.
@@ -12,6 +12,8 @@ export interface FilterMenuGroup {
12
12
  export interface FilterRootProps {
13
13
  classNames?: FilterClassNames;
14
14
  filters: FilterController;
15
+ /** Apply main search after a typing pause. Set 0 for immediate writes or an existing draft adapter. */
16
+ searchDebounceMs?: number;
15
17
  summary?: SummaryPolicy;
16
18
  /** Keep the filter menu open for applying more filters by default. */
17
19
  closeMenuOnApply?: boolean;
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useMendyLocale } from "../locale-context.js";
4
4
  import { FilterCollection } from "./filter-collection.js";
5
+ import { useBufferedFilters } from "./use-buffered-filters.js";
5
6
  import { createContext, useContext, useEffect, useLayoutEffect, useMemo, useId, useRef, useState, useSyncExternalStore, } from "react";
6
7
  import { ListFilter, Search, X, Circle, ListChecks, Type, Hash, CalendarDays, SlidersHorizontal, Layers, } from "lucide-react";
7
8
  import { Button } from "../customization.js";
@@ -39,7 +40,8 @@ function useRoot() {
39
40
  export function FilterRoot({ classNames, ...props }) {
40
41
  return (_jsx(MendyUIProvider, { classNames: classNames, children: _jsx(FilterRootContent, { ...props }) }));
41
42
  }
42
- function FilterRootContent({ filters, summary = defaultSummary, suggestions = "always", closeMenuOnApply = false, groups = defaultGroups, disabled: disabledProp = false, className, children, }) {
43
+ function FilterRootContent({ filters: appliedFilters, searchDebounceMs = 300, summary = defaultSummary, suggestions = "always", closeMenuOnApply = false, groups = defaultGroups, disabled: disabledProp = false, className, children, }) {
44
+ const { filters, flushSearch } = useBufferedFilters(appliedFilters, searchDebounceMs);
43
45
  const { classNames } = useMendyUI();
44
46
  const locale = useMendyLocale();
45
47
  // Server HTML must not accept edits that React cannot handle yet. Client-only
@@ -61,6 +63,7 @@ function FilterRootContent({ filters, summary = defaultSummary, suggestions = "a
61
63
  const context = useMemo(() => ({
62
64
  direction,
63
65
  filters,
66
+ flushSearch,
64
67
  summary,
65
68
  suggestions,
66
69
  closeMenuOnApply,
@@ -70,14 +73,24 @@ function FilterRootContent({ filters, summary = defaultSummary, suggestions = "a
70
73
  editingField,
71
74
  ambiguous,
72
75
  setAmbiguous,
73
- }), [filters, summary, suggestions, closeMenuOnApply, groups, disabled, ambiguous, direction]);
76
+ }), [
77
+ filters,
78
+ flushSearch,
79
+ summary,
80
+ suggestions,
81
+ closeMenuOnApply,
82
+ groups,
83
+ disabled,
84
+ ambiguous,
85
+ direction,
86
+ ]);
74
87
  return (_jsx(FilterOptionCache.Provider, { value: cache, children: _jsx(Context.Provider, { value: context, children: _jsx("div", { "data-mendy-ui": "", dir: locale.configured ? locale.direction : undefined, lang: locale.code, "aria-busy": !hydrated || undefined, className: cn("mui-222f930b8752 mui-faa8a23c68f6 mui-71556df3b421 mui-074569488cca", classNames?.root, className), children: children }) }) }));
75
88
  }
76
89
  export function FilterBar({ showClear = true, ...props }) {
77
90
  return (_jsxs(FilterRoot, { ...props, children: [_jsx(FilterSearch, { label: props.searchLabel, placeholder: props.searchPlaceholder }), _jsx(FilterList, { showClear: showClear }), _jsx(FilterFeedback, {})] }));
78
91
  }
79
92
  export function FilterSearch({ label, placeholder }) {
80
- const { filters, trigger, disabled, setAmbiguous, direction } = useRoot();
93
+ const { filters, flushSearch, trigger, disabled, setAmbiguous, direction } = useRoot();
81
94
  const { t } = useMendyLocale();
82
95
  const { classNames } = useMendyUI();
83
96
  const anchor = useRef(null);
@@ -107,6 +120,9 @@ export function FilterSearch({ label, placeholder }) {
107
120
  const result = filters.paste(event.currentTarget.value, { before: "", after: "" });
108
121
  setAmbiguous(result.ambiguous);
109
122
  }
123
+ else {
124
+ flushSearch();
125
+ }
110
126
  }
111
127
  }, onKeyUp: (event) => {
112
128
  shift.current = event.shiftKey;
@@ -0,0 +1,12 @@
1
+ import type { FilterController } from "./use-filters.js";
2
+ /** Shared operations for an applied controller and the search draft shown by FilterRoot. */
3
+ export declare function filterControllerActions(controller: Pick<FilterController, "entries" | "search" | "batch" | "edit" | "setMenuOpen" | "setOpenField">): {
4
+ commit: (id: string, value: unknown, source?: Parameters<FilterController["commit"]>[2]) => string | undefined;
5
+ remove(id: string): void;
6
+ clear(): void;
7
+ setSearch: (text: string) => void;
8
+ paste(text: string, remainder?: {
9
+ before: string;
10
+ after: string;
11
+ }): import("./filter-state.js").PasteResult;
12
+ };
@@ -0,0 +1,44 @@
1
+ import { classifyPaste } from "./filter-state.js";
2
+ /** Shared operations for an applied controller and the search draft shown by FilterRoot. */
3
+ export function filterControllerActions(controller) {
4
+ const { entries, search, batch, edit, setMenuOpen, setOpenField } = controller;
5
+ return {
6
+ commit: (id, value, source) => batch({ [id]: value }, undefined, source),
7
+ remove(id) {
8
+ const entry = entries.find((item) => item.id === id);
9
+ if (entry?.field.removable !== false) {
10
+ batch({ [id]: entry?.field.clearValue }, undefined, "remove");
11
+ edit(null);
12
+ }
13
+ },
14
+ clear() {
15
+ batch(Object.fromEntries(entries.flatMap((entry) => entry.field.removable !== false && !entry.field.hidden && !entry.field.disabled
16
+ ? [[entry.id, entry.field.clearValue]]
17
+ : [])), "", "clear");
18
+ edit(null);
19
+ setMenuOpen(false);
20
+ setOpenField(null);
21
+ },
22
+ setSearch: (text) => {
23
+ batch({}, text, "search");
24
+ },
25
+ paste(text, remainder) {
26
+ const result = classifyPaste(text, entries);
27
+ const unmatched = [...result.unmatched, ...result.ambiguous.map((item) => item.token)].join(" ");
28
+ const nextSearch = remainder
29
+ ? [remainder.before, unmatched, remainder.after].filter(Boolean).join(" ")
30
+ : [search, unmatched].filter(Boolean).join(" ");
31
+ let cursor = [remainder ? remainder.before : search, result.unmatched.join(" ")]
32
+ .filter(Boolean)
33
+ .join(" ").length;
34
+ for (const item of result.ambiguous) {
35
+ if (cursor)
36
+ cursor++;
37
+ item.searchRange = { start: cursor, end: cursor + item.token.length };
38
+ cursor += item.token.length;
39
+ }
40
+ batch(result.changes, nextSearch, "paste");
41
+ return result;
42
+ },
43
+ };
44
+ }
@@ -0,0 +1,6 @@
1
+ import type { FilterController } from "./use-filters.js";
2
+ /** Root-local draft; the caller's controller always exposes the applied search. */
3
+ export declare function useBufferedFilters(filters: FilterController, delay: number): {
4
+ filters: FilterController<unknown>;
5
+ flushSearch: () => void;
6
+ };
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import { filterControllerActions } from "./filter-controller-actions.js";
3
+ import { useSearchDraft } from "./use-search-draft.js";
4
+ const trim = (search) => search.trim();
5
+ function contextValue(field, value) {
6
+ return value == null ? null : field.codec.serialize(value);
7
+ }
8
+ function filterContext(entries, changes = {}) {
9
+ return JSON.stringify(entries.map(({ id, field, value }) => [
10
+ id,
11
+ contextValue(field, id in changes && !field.disabled ? field.normalize(changes[id]) : value),
12
+ ]));
13
+ }
14
+ function filterAcknowledgement(entries, changes) {
15
+ const expected = entries.flatMap(({ id, field }) => id in changes && !field.disabled
16
+ ? [[id, contextValue(field, field.normalize(changes[id]))]]
17
+ : []);
18
+ if (!expected.length)
19
+ return undefined;
20
+ return (context) => {
21
+ const applied = new Map(JSON.parse(context));
22
+ return (applied.size === entries.length &&
23
+ entries.every(({ id }) => applied.has(id)) &&
24
+ expected.every(([id, value]) => applied.get(id) === value));
25
+ };
26
+ }
27
+ /** Root-local draft; the caller's controller always exposes the applied search. */
28
+ export function useBufferedFilters(filters, delay) {
29
+ const draft = useSearchDraft({
30
+ value: filters.search,
31
+ context: filterContext(filters.entries),
32
+ onApply: filters.setSearch,
33
+ normalize: trim,
34
+ delay,
35
+ });
36
+ const batch = (changes, search, source = "edit") => {
37
+ if (source === "search") {
38
+ draft.setValue(search ?? draft.value);
39
+ return;
40
+ }
41
+ // Validation belongs to the applied controller. Invalid editors keep their draft.
42
+ const result = filters.batch(changes, trim(search ?? draft.value), source);
43
+ if (result)
44
+ return result;
45
+ // Bindings can update related fields in the same patch. Match the requested
46
+ // fields while allowing those domain updates in the acknowledgement.
47
+ draft.apply(search ?? draft.value, () => { }, filterContext(filters.entries, changes), filterAcknowledgement(filters.entries, changes));
48
+ };
49
+ if (delay <= 0)
50
+ return { filters, flushSearch: () => { } };
51
+ return {
52
+ filters: {
53
+ ...filters,
54
+ ...filterControllerActions({ ...filters, search: draft.value, batch }),
55
+ search: draft.value,
56
+ setSearch: draft.setValue,
57
+ batch,
58
+ },
59
+ flushSearch: draft.flush,
60
+ };
61
+ }
@@ -1,5 +1,12 @@
1
- /** Debounce URL-backed queries without replacing newer typing with an older URL acknowledgement. */
2
- export declare function useFilterSearch(value: string | null | undefined, onChange: (value: string | null) => void, delay?: number): {
1
+ export interface FilterSearchOptions {
2
+ /** Applied filters or another scope whose external changes discard unfinished typing. */
3
+ context?: string;
4
+ /** Normalize applied queries while preserving the exact text in the input. */
5
+ normalize?: (search: string) => string;
6
+ }
7
+ /** Buffer standalone search inputs; FilterRoot and FilterBar do this automatically. */
8
+ export declare function useFilterSearch(value: string | null | undefined, onChange: (value: string | null) => void, delay?: number, options?: FilterSearchOptions): {
3
9
  value: string;
4
- setValue: (next: string) => void;
10
+ setValue: (text: string) => void;
11
+ flush: () => void;
5
12
  };
@@ -1,44 +1,12 @@
1
1
  "use client";
2
- import { useEffect, useLayoutEffect, useRef, useState } from "react";
3
- /** Debounce URL-backed queries without replacing newer typing with an older URL acknowledgement. */
4
- export function useFilterSearch(value, onChange, delay = 300) {
5
- const committed = value ?? "";
6
- const [state, setState] = useState({ committed, draft: committed });
7
- const timer = useRef(null);
8
- const pending = useRef([]);
9
- const change = useRef(onChange);
10
- useLayoutEffect(() => {
11
- change.current = onChange;
2
+ import { useSearchDraft } from "./use-search-draft.js";
3
+ /** Buffer standalone search inputs; FilterRoot and FilterBar do this automatically. */
4
+ export function useFilterSearch(value, onChange, delay = 300, options = {}) {
5
+ const draft = useSearchDraft({
6
+ ...options,
7
+ value: value ?? "",
8
+ onApply: (search) => onChange(search || null),
9
+ delay,
12
10
  });
13
- if (state.committed !== committed) {
14
- setState({
15
- committed,
16
- draft: pending.current.includes(committed) ? state.draft : committed,
17
- });
18
- }
19
- useLayoutEffect(() => {
20
- const acknowledgement = pending.current.includes(committed);
21
- pending.current = pending.current.filter((request) => request !== committed);
22
- if (!acknowledgement && timer.current)
23
- clearTimeout(timer.current);
24
- }, [committed]);
25
- useEffect(() => () => {
26
- if (timer.current)
27
- clearTimeout(timer.current);
28
- }, []);
29
- function setValue(next) {
30
- if (timer.current)
31
- clearTimeout(timer.current);
32
- setState((current) => ({ ...current, draft: next }));
33
- function commit() {
34
- if (next !== committed)
35
- pending.current.push(next);
36
- change.current(next || null);
37
- }
38
- if (!next)
39
- commit();
40
- else
41
- timer.current = setTimeout(commit, delay);
42
- }
43
- return { value: state.draft, setValue };
11
+ return { value: draft.value, setValue: draft.setValue, flush: draft.flush };
44
12
  }
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import { useMendyLocale } from "../locale-context.js";
3
3
  import { useLayoutEffect, useRef, useState } from "react";
4
- import { classifyPaste, initialValues } from "./filter-state.js";
4
+ import { initialValues } from "./filter-state.js";
5
+ import { filterControllerActions } from "./filter-controller-actions.js";
5
6
  export function useFilterController(options) {
6
7
  const { t, messages } = useMendyLocale();
7
8
  const [menuOpen, setMenuOpen] = useState(false);
@@ -57,43 +58,14 @@ export function useFilterController(options) {
57
58
  setError(null);
58
59
  },
59
60
  batch,
60
- commit: (id, value, source) => batch({ [id]: value }, undefined, source),
61
- remove(id) {
62
- const entry = options.entries.find((item) => item.id === id);
63
- if (entry?.field.removable !== false) {
64
- batch({ [id]: entry?.field.clearValue }, undefined, "remove");
65
- edit(null);
66
- }
67
- },
68
- clear() {
69
- batch(Object.fromEntries(options.entries.flatMap((entry) => entry.field.removable !== false && !entry.field.hidden && !entry.field.disabled
70
- ? [[entry.id, entry.field.clearValue]]
71
- : [])), "", "clear");
72
- edit(null);
73
- setMenuOpen(false);
74
- setOpenField(null);
75
- },
76
- setSearch: (search) => {
77
- batch({}, search, "search");
78
- },
79
- paste(text, remainder) {
80
- const result = classifyPaste(text, options.entries);
81
- const unmatched = [...result.unmatched, ...result.ambiguous.map((item) => item.token)].join(" ");
82
- const search = remainder
83
- ? [remainder.before, unmatched, remainder.after].filter(Boolean).join(" ")
84
- : [options.search, unmatched].filter(Boolean).join(" ");
85
- let cursor = [remainder ? remainder.before : options.search, result.unmatched.join(" ")]
86
- .filter(Boolean)
87
- .join(" ").length;
88
- for (const item of result.ambiguous) {
89
- if (cursor)
90
- cursor++;
91
- item.searchRange = { start: cursor, end: cursor + item.token.length };
92
- cursor += item.token.length;
93
- }
94
- batch(result.changes, search, "paste");
95
- return result;
96
- },
61
+ ...filterControllerActions({
62
+ entries: options.entries,
63
+ search: options.search,
64
+ batch,
65
+ edit,
66
+ setMenuOpen,
67
+ setOpenField,
68
+ }),
97
69
  error,
98
70
  shareable: true,
99
71
  };
@@ -0,0 +1,13 @@
1
+ /** Keep keystrokes local while an applied query or URL update is in flight. */
2
+ export declare function useSearchDraft({ value, onApply, context, delay, normalize, }: {
3
+ value: string;
4
+ onApply: (search: string) => void;
5
+ context?: string;
6
+ delay?: number;
7
+ normalize?: (search: string) => string;
8
+ }): {
9
+ value: string;
10
+ setValue: (text: string) => void;
11
+ apply: (text: string, action?: (search: string) => void, nextContext?: string, acknowledgeContext?: (context: string) => boolean) => void;
12
+ flush: () => void;
13
+ };
@@ -0,0 +1,71 @@
1
+ "use client";
2
+ import { startTransition, useEffect, useLayoutEffect, useRef, useState } from "react";
3
+ const identity = (value) => value;
4
+ /** Keep keystrokes local while an applied query or URL update is in flight. */
5
+ export function useSearchDraft({ value, onApply, context = "", delay = 300, normalize = identity, }) {
6
+ const key = (search, scope) => JSON.stringify([normalize(search), scope]);
7
+ const appliedKey = key(value, context);
8
+ const [state, setState] = useState(() => ({
9
+ appliedKey,
10
+ draft: value,
11
+ pending: [],
12
+ reset: 0,
13
+ }));
14
+ const timer = useRef(null);
15
+ if (state.appliedKey !== appliedKey) {
16
+ const acknowledged = state.pending.findIndex((request) => request.key === appliedKey ||
17
+ (request.search === normalize(value) && request.acknowledgeContext?.(context)));
18
+ setState({
19
+ appliedKey,
20
+ draft: acknowledged < 0 ? value : state.draft,
21
+ pending: acknowledged < 0 ? [] : state.pending.slice(acknowledged + 1),
22
+ reset: state.reset + (acknowledged < 0 ? 1 : 0),
23
+ });
24
+ }
25
+ function cancel() {
26
+ if (timer.current !== null)
27
+ clearTimeout(timer.current);
28
+ timer.current = null;
29
+ }
30
+ function apply(text, action = onApply, nextContext = context, acknowledgeContext) {
31
+ const search = normalize(text);
32
+ action(search);
33
+ cancel();
34
+ const nextKey = key(search, nextContext);
35
+ setState((current) => ({
36
+ ...current,
37
+ draft: text,
38
+ pending: nextKey === current.appliedKey && current.pending.length === 0
39
+ ? current.pending
40
+ : [
41
+ ...current.pending.filter((request) => request.key !== nextKey),
42
+ { key: nextKey, search, acknowledgeContext },
43
+ ],
44
+ }));
45
+ }
46
+ const applyLatest = useRef(apply);
47
+ useLayoutEffect(() => {
48
+ applyLatest.current = apply;
49
+ });
50
+ useLayoutEffect(() => cancel(), [state.reset]);
51
+ useEffect(() => cancel, []);
52
+ function setValue(text) {
53
+ cancel();
54
+ setState((current) => ({ ...current, draft: text }));
55
+ const search = normalize(text);
56
+ if ((search === normalize(value) && state.pending.length === 0) ||
57
+ state.pending.at(-1)?.search === search)
58
+ return;
59
+ if (!text || delay <= 0)
60
+ apply(text);
61
+ else {
62
+ timer.current = setTimeout(() => {
63
+ timer.current = null;
64
+ startTransition(() => {
65
+ applyLatest.current(text);
66
+ });
67
+ }, delay);
68
+ }
69
+ }
70
+ return { value: state.draft, setValue, apply, flush: () => apply(state.draft) };
71
+ }
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useContext, useId, useLayoutEffect, useMemo } from "react";
4
4
  import * as Dialog from "@radix-ui/react-dialog";
5
- import { Pin, PinOff, X } from "lucide-react";
5
+ import { Pin, X } from "lucide-react";
6
6
  import { Button } from "../customization.js";
7
7
  import { useMendyLocale } from "../locale-context.js";
8
8
  import { cn } from "../utils.js";
@@ -31,14 +31,13 @@ export function SheetClose({ onClick, ...props }) {
31
31
  export function SheetPin({ onClick, ...props }) {
32
32
  const instance = useSheetInstance();
33
33
  const { t } = useMendyLocale();
34
- if (!instance.pinned && !instance.layout?.canPin)
34
+ if (instance.pinned || !instance.layout?.canPin)
35
35
  return null;
36
- return (_jsx(Button, { type: "button", variant: "ghost", size: "icon", ...props, "aria-label": props["aria-label"] ?? t(instance.pinned ? "sheetUnpin" : "sheetPin"), "aria-pressed": instance.pinned, "aria-keyshortcuts": instance.pinned ? undefined : "P", title: props.title ?? (instance.pinned ? t("sheetUnpin") : `${t("sheetPin")} (P)`), onClick: (event) => {
36
+ return (_jsx(Button, { type: "button", variant: "ghost", size: "icon", ...props, "aria-label": props["aria-label"] ?? t("sheetPin"), "aria-keyshortcuts": "P", title: props.title ?? `${t("sheetPin")} (P)`, onClick: (event) => {
37
37
  onClick?.(event);
38
38
  if (!event.defaultPrevented)
39
- instance.setPinned(!instance.pinned);
40
- }, children: props.children ??
41
- (instance.pinned ? _jsx(PinOff, { "aria-hidden": "true" }) : _jsx(Pin, { "aria-hidden": "true" })) }));
39
+ instance.setPinned(true);
40
+ }, children: props.children ?? _jsx(Pin, { "aria-hidden": "true" }) }));
42
41
  }
43
42
  export function SheetHeader({ title, description, actions, controls = true, children, className, ...props }) {
44
43
  const { t } = useMendyLocale();
@@ -54,7 +54,8 @@ export function TableView({ table, label, height = "auto", layout: layoutMode =
54
54
  const { totalWidth, pinningActive } = layout;
55
55
  const { inlineSelection, selectLoaded } = useInlineRowSelection(table, layout.columns, rowSelectionControls);
56
56
  const focused = table.getFocusedCell();
57
- const { columns, columnGaps, cellStyle } = useColumnWindow(layout, container, viewportWidth, focused?.column.id, !autoRowHeight);
57
+ const selectionFocusColumn = table.atoms.cellSelection.get().at(-1)?.focusColumnId;
58
+ const { columns, columnGaps, cellStyle } = useColumnWindow(layout, container, viewportWidth, selectionFocusColumn ?? focused?.column.id, !autoRowHeight);
58
59
  const columnIndexes = useMemo(() => new Map(layout.columns.map((column, index) => [column.id, index])), [layout.columns]);
59
60
  const { announcement, copied, onKeyDown } = useTableInteraction({
60
61
  table,
@@ -139,11 +139,37 @@ export function useTableInteraction({ table, pinningActive, container, queryKey,
139
139
  const direction = directions[event.key];
140
140
  if (direction) {
141
141
  event.preventDefault();
142
- if (!table.getFocusedCell() && rows[0] && columns[0])
143
- table.setFocusedCell(rows[0].id, columns[0].id);
144
- else if (event.shiftKey)
142
+ const hadFocusedCell = Boolean(table.getFocusedCell());
143
+ if (!hadFocusedCell && rows[0]) {
144
+ const firstSelectable = columns.find((column) => column.columnDef.enableCellSelection !== false);
145
+ if (firstSelectable)
146
+ table.setFocusedCell(rows[0].id, firstSelectable.id);
147
+ }
148
+ if (event.shiftKey && (event.metaKey || event.ctrlKey)) {
149
+ const selectableColumns = columns.filter((column) => column.columnDef.enableCellSelection !== false);
150
+ const targetRow = direction === "up" ? rows[0] : rows.at(-1);
151
+ const targetColumn = direction === "left" ? selectableColumns[0] : selectableColumns.at(-1);
152
+ if (rows.length && selectableColumns.length) {
153
+ table.setCellSelection((ranges) => {
154
+ const active = ranges.at(-1);
155
+ if (!active)
156
+ return ranges;
157
+ return [
158
+ ...ranges.slice(0, -1),
159
+ {
160
+ ...active,
161
+ focusRowId: direction === "up" || direction === "down" ? targetRow.id : active.focusRowId,
162
+ focusColumnId: direction === "left" || direction === "right"
163
+ ? targetColumn.id
164
+ : active.focusColumnId,
165
+ },
166
+ ];
167
+ });
168
+ }
169
+ }
170
+ else if (hadFocusedCell && event.shiftKey)
145
171
  table.extendCellSelection(direction);
146
- else
172
+ else if (hadFocusedCell)
147
173
  table.moveCellSelection(direction);
148
174
  const range = table.atoms.cellSelection.get().at(-1);
149
175
  if (range)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mendylanda/ui",
3
- "version": "0.4.3-dev.69.b44a9721f450",
3
+ "version": "0.4.3-dev.72.7ee3a6f295d2",
4
4
  "description": "Mendy Landa's reusable React components. Tables, filters, and sheets with shared interactions and customizable UI.",
5
5
  "homepage": "https://ui.mendylanda.com",
6
6
  "license": "MIT",
@@ -126,5 +126,5 @@
126
126
  "build": "tsc -p tsconfig.build.json && node scripts/build-css.mjs",
127
127
  "typecheck": "tsc -p tsconfig.build.json --noEmit"
128
128
  },
129
- "gitHead": "b44a9721f450b4f8ce6e0bb3dc7e9e76452d2649"
129
+ "gitHead": "7ee3a6f295d2aa60fcdb858e39aca730b473a50e"
130
130
  }