@texturehq/edges 5.0.1 → 5.1.5

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.
@@ -205,6 +205,93 @@ interface ColorFieldProps extends Omit<TextFieldProps$1, "isRequired" | "size" |
205
205
  */
206
206
  declare function ColorField({ label, description, errorMessage, size, tooltip, isRequired, transparent, className, validationResult, value: controlledValue, defaultValue, onChange, placeholder, showColorSwatch, reserveErrorSpace, ...props }: ColorFieldProps): react_jsx_runtime.JSX.Element;
207
207
 
208
+ interface MultiSelectOption {
209
+ value: string;
210
+ label: string;
211
+ /** Display-only decoration. Never contributes to the search key. */
212
+ count?: number;
213
+ disabled?: boolean;
214
+ group?: string;
215
+ }
216
+ type MultiSelectMatcher = (text: string, query: string) => boolean;
217
+ declare const defaultMultiSelectMatcher: MultiSelectMatcher;
218
+ /**
219
+ * The only strings an option is searchable by. Presentational decoration —
220
+ * `count`, badges, anything a renderer composes — is deliberately excluded:
221
+ * making facet-count digits searchable turned a query for `5` into a match on
222
+ * a substation labelled `28 (15656)`.
223
+ */
224
+ declare function multiSelectSearchKeys(option: MultiSelectOption): string[];
225
+ declare function filterMultiSelectOptions<T extends MultiSelectOption>(options: readonly T[], query: string, matcher?: MultiSelectMatcher): T[];
226
+ /**
227
+ * Whether the typed string should be offered as a selectable literal.
228
+ *
229
+ * The trigger is "the query is not already an identity in play" — not "nothing
230
+ * in the list matched". A match-count trigger is defeatable by any incidental
231
+ * substring hit, which is how single-digit values became unreachable in the
232
+ * control this component replaces.
233
+ */
234
+ declare function shouldOfferLiteralOption(args: {
235
+ query: string;
236
+ options: readonly MultiSelectOption[];
237
+ selected: readonly string[];
238
+ }): boolean;
239
+ interface MultiSelectSelectionEntry {
240
+ value: string;
241
+ label: string;
242
+ count?: number;
243
+ /** True when the value is not present in the current `options` set. */
244
+ isUnknown: boolean;
245
+ }
246
+ /**
247
+ * Selections in insertion order, hydrating labels from `options` where possible.
248
+ * Values with no matching option still produce an entry so URL-hydrated state is
249
+ * never silently dropped.
250
+ */
251
+ declare function multiSelectSelectionEntries(selected: readonly string[], options: readonly MultiSelectOption[]): MultiSelectSelectionEntry[];
252
+
253
+ interface MultiSelectProps {
254
+ options: readonly MultiSelectOption[];
255
+ /** Controlled selection. Order is insertion order. */
256
+ value?: readonly string[];
257
+ /** Uncontrolled initial selection. */
258
+ defaultValue?: readonly string[];
259
+ onChange: (next: string[]) => void;
260
+ label: string;
261
+ placeholder?: string;
262
+ size?: Size;
263
+ loading?: boolean;
264
+ disabled?: boolean;
265
+ maxSelected?: number;
266
+ /** Offer the typed string as a selectable value. Off by default. */
267
+ allowLiteral?: boolean;
268
+ /** Server-side search. Debouncing is the caller's job. */
269
+ onSearchChange?: (query: string) => void;
270
+ /** `options` is a clipped set rather than the whole domain. */
271
+ truncated?: boolean;
272
+ /** Size of the whole domain. Rendered with `truncated` as "showing N of M". */
273
+ totalCount?: number;
274
+ emptyMessage?: string;
275
+ showSelectAll?: boolean;
276
+ description?: string;
277
+ errorMessage?: string;
278
+ isRequired?: boolean;
279
+ /** Fires when the search input loses focus. Form adapters use this to mark the field touched. */
280
+ onBlur?: (event: React__default.FocusEvent<HTMLInputElement>) => void;
281
+ /** Ref to the search input, so callers (and `setFocus`) can focus the control. */
282
+ inputRef?: React__default.Ref<HTMLInputElement>;
283
+ className?: string;
284
+ id?: string;
285
+ }
286
+ /**
287
+ * MultiSelect
288
+ *
289
+ * A combobox whose popup is a multi-select listbox (W3C ARIA APG): a search
290
+ * input narrows a checkbox list, and current selections live in their own
291
+ * pinned region above it.
292
+ */
293
+ declare function MultiSelect({ options, value, defaultValue, onChange, label, placeholder, size, loading, disabled, maxSelected, allowLiteral, onSearchChange, truncated, totalCount, emptyMessage, showSelectAll, description, errorMessage, isRequired, onBlur, inputRef: forwardedInputRef, className, id, }: MultiSelectProps): react_jsx_runtime.JSX.Element;
294
+
208
295
  /**
209
296
  * NumberField
210
297
  *
@@ -546,4 +633,4 @@ interface TimeFieldProps extends Omit<TimeFieldProps$1<TimeValue>, "isRequired"
546
633
  */
547
634
  declare function TimeField({ label, description, errorMessage, size, tooltip, isRequired, isDisabled, isInvalid, reserveErrorSpace, validationResult, className, descriptionPlacement, ...props }: TimeFieldProps): react_jsx_runtime.JSX.Element;
548
635
 
549
- export { Autocomplete as A, Button as B, Checkbox as C, NumberField as N, RadioCardGroup as R, Select as S, TextArea as T, CheckboxGroup as a, ColorField as b, RadioGroup as c, Switch as d, TextField as e, type TimeFieldProps as f, type ButtonProps as g, type ColorFieldProps as h, Radio as i, RadioCard as j, type RadioCardGroupProps as k, type RadioCardProps as l, type SelectItem as m, TimeField as n };
636
+ export { Autocomplete as A, Button as B, Checkbox as C, MultiSelect as M, NumberField as N, RadioCardGroup as R, Select as S, TextArea as T, CheckboxGroup as a, ColorField as b, type MultiSelectOption as c, RadioGroup as d, Switch as e, TextField as f, type TimeFieldProps as g, type ButtonProps as h, type ColorFieldProps as i, type MultiSelectMatcher as j, type MultiSelectProps as k, type MultiSelectSelectionEntry as l, Radio as m, RadioCard as n, type RadioCardGroupProps as o, type RadioCardProps as p, type SelectItem as q, TimeField as r, defaultMultiSelectMatcher as s, filterMultiSelectOptions as t, multiSelectSearchKeys as u, multiSelectSelectionEntries as v, shouldOfferLiteralOption as w };
@@ -205,6 +205,93 @@ interface ColorFieldProps extends Omit<TextFieldProps$1, "isRequired" | "size" |
205
205
  */
206
206
  declare function ColorField({ label, description, errorMessage, size, tooltip, isRequired, transparent, className, validationResult, value: controlledValue, defaultValue, onChange, placeholder, showColorSwatch, reserveErrorSpace, ...props }: ColorFieldProps): react_jsx_runtime.JSX.Element;
207
207
 
208
+ interface MultiSelectOption {
209
+ value: string;
210
+ label: string;
211
+ /** Display-only decoration. Never contributes to the search key. */
212
+ count?: number;
213
+ disabled?: boolean;
214
+ group?: string;
215
+ }
216
+ type MultiSelectMatcher = (text: string, query: string) => boolean;
217
+ declare const defaultMultiSelectMatcher: MultiSelectMatcher;
218
+ /**
219
+ * The only strings an option is searchable by. Presentational decoration —
220
+ * `count`, badges, anything a renderer composes — is deliberately excluded:
221
+ * making facet-count digits searchable turned a query for `5` into a match on
222
+ * a substation labelled `28 (15656)`.
223
+ */
224
+ declare function multiSelectSearchKeys(option: MultiSelectOption): string[];
225
+ declare function filterMultiSelectOptions<T extends MultiSelectOption>(options: readonly T[], query: string, matcher?: MultiSelectMatcher): T[];
226
+ /**
227
+ * Whether the typed string should be offered as a selectable literal.
228
+ *
229
+ * The trigger is "the query is not already an identity in play" — not "nothing
230
+ * in the list matched". A match-count trigger is defeatable by any incidental
231
+ * substring hit, which is how single-digit values became unreachable in the
232
+ * control this component replaces.
233
+ */
234
+ declare function shouldOfferLiteralOption(args: {
235
+ query: string;
236
+ options: readonly MultiSelectOption[];
237
+ selected: readonly string[];
238
+ }): boolean;
239
+ interface MultiSelectSelectionEntry {
240
+ value: string;
241
+ label: string;
242
+ count?: number;
243
+ /** True when the value is not present in the current `options` set. */
244
+ isUnknown: boolean;
245
+ }
246
+ /**
247
+ * Selections in insertion order, hydrating labels from `options` where possible.
248
+ * Values with no matching option still produce an entry so URL-hydrated state is
249
+ * never silently dropped.
250
+ */
251
+ declare function multiSelectSelectionEntries(selected: readonly string[], options: readonly MultiSelectOption[]): MultiSelectSelectionEntry[];
252
+
253
+ interface MultiSelectProps {
254
+ options: readonly MultiSelectOption[];
255
+ /** Controlled selection. Order is insertion order. */
256
+ value?: readonly string[];
257
+ /** Uncontrolled initial selection. */
258
+ defaultValue?: readonly string[];
259
+ onChange: (next: string[]) => void;
260
+ label: string;
261
+ placeholder?: string;
262
+ size?: Size;
263
+ loading?: boolean;
264
+ disabled?: boolean;
265
+ maxSelected?: number;
266
+ /** Offer the typed string as a selectable value. Off by default. */
267
+ allowLiteral?: boolean;
268
+ /** Server-side search. Debouncing is the caller's job. */
269
+ onSearchChange?: (query: string) => void;
270
+ /** `options` is a clipped set rather than the whole domain. */
271
+ truncated?: boolean;
272
+ /** Size of the whole domain. Rendered with `truncated` as "showing N of M". */
273
+ totalCount?: number;
274
+ emptyMessage?: string;
275
+ showSelectAll?: boolean;
276
+ description?: string;
277
+ errorMessage?: string;
278
+ isRequired?: boolean;
279
+ /** Fires when the search input loses focus. Form adapters use this to mark the field touched. */
280
+ onBlur?: (event: React__default.FocusEvent<HTMLInputElement>) => void;
281
+ /** Ref to the search input, so callers (and `setFocus`) can focus the control. */
282
+ inputRef?: React__default.Ref<HTMLInputElement>;
283
+ className?: string;
284
+ id?: string;
285
+ }
286
+ /**
287
+ * MultiSelect
288
+ *
289
+ * A combobox whose popup is a multi-select listbox (W3C ARIA APG): a search
290
+ * input narrows a checkbox list, and current selections live in their own
291
+ * pinned region above it.
292
+ */
293
+ declare function MultiSelect({ options, value, defaultValue, onChange, label, placeholder, size, loading, disabled, maxSelected, allowLiteral, onSearchChange, truncated, totalCount, emptyMessage, showSelectAll, description, errorMessage, isRequired, onBlur, inputRef: forwardedInputRef, className, id, }: MultiSelectProps): react_jsx_runtime.JSX.Element;
294
+
208
295
  /**
209
296
  * NumberField
210
297
  *
@@ -546,4 +633,4 @@ interface TimeFieldProps extends Omit<TimeFieldProps$1<TimeValue>, "isRequired"
546
633
  */
547
634
  declare function TimeField({ label, description, errorMessage, size, tooltip, isRequired, isDisabled, isInvalid, reserveErrorSpace, validationResult, className, descriptionPlacement, ...props }: TimeFieldProps): react_jsx_runtime.JSX.Element;
548
635
 
549
- export { Autocomplete as A, Button as B, Checkbox as C, NumberField as N, RadioCardGroup as R, Select as S, TextArea as T, CheckboxGroup as a, ColorField as b, RadioGroup as c, Switch as d, TextField as e, type TimeFieldProps as f, type ButtonProps as g, type ColorFieldProps as h, Radio as i, RadioCard as j, type RadioCardGroupProps as k, type RadioCardProps as l, type SelectItem as m, TimeField as n };
636
+ export { Autocomplete as A, Button as B, Checkbox as C, MultiSelect as M, NumberField as N, RadioCardGroup as R, Select as S, TextArea as T, CheckboxGroup as a, ColorField as b, type MultiSelectOption as c, RadioGroup as d, Switch as e, TextField as f, type TimeFieldProps as g, type ButtonProps as h, type ColorFieldProps as i, type MultiSelectMatcher as j, type MultiSelectProps as k, type MultiSelectSelectionEntry as l, Radio as m, RadioCard as n, type RadioCardGroupProps as o, type RadioCardProps as p, type SelectItem as q, TimeField as r, defaultMultiSelectMatcher as s, filterMultiSelectOptions as t, multiSelectSearchKeys as u, multiSelectSelectionEntries as v, shouldOfferLiteralOption as w };
@@ -1,9 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React$1 from 'react';
3
- import React__default, { ReactNode, ComponentType } from 'react';
3
+ import React__default, { ReactNode, RefObject, ComponentType } from 'react';
4
4
  import { d as IconName } from './RichTextEditor-B_GaE_Yf.js';
5
5
  import * as _visx_vendor_d3_scale from '@visx/vendor/d3-scale';
6
6
  import { ScaleTime, ScaleLinear } from 'd3-scale';
7
+ import { Virtualizer } from '@tanstack/react-virtual';
7
8
  import * as react_map_gl from 'react-map-gl';
8
9
  import { ViewState, MapRef } from 'react-map-gl';
9
10
  import { MeterProps as MeterProps$1 } from 'react-aria-components';
@@ -113,6 +114,67 @@ interface ActionMenuProps {
113
114
  */
114
115
  declare function ActionMenu({ children, items, className, align, textAlign, size, onAction, header, footer, useMobileTray, popoverClassName, }: ActionMenuProps): react_jsx_runtime.JSX.Element;
115
116
 
117
+ type LoadingState = "idle" | "loading" | "loading-more" | "error";
118
+ interface UseInfiniteScrollOptions<T = unknown> {
119
+ /** Array of items being displayed */
120
+ items: T[];
121
+ /** Callback to load more items (optional - if not provided, no infinite scroll) */
122
+ onLoadMore?: () => void | Promise<void>;
123
+ /** Whether there are more items to load */
124
+ hasMore?: boolean;
125
+ /** Auto-detects initial vs loading-more from items.length */
126
+ isLoading?: boolean;
127
+ /** Explicit loading state override (takes precedence) */
128
+ loadingState?: LoadingState;
129
+ /** Enable virtualization (default: true for 100+ items) */
130
+ enableVirtualization?: boolean;
131
+ /** Estimated size of each item in pixels */
132
+ estimatedItemSize?: number;
133
+ /** Number of items to render outside viewport */
134
+ overscan?: number;
135
+ /** Custom scroll element (defaults to parent) */
136
+ scrollElement?: HTMLElement | null;
137
+ /** Distance from bottom in pixels to trigger load */
138
+ loadMoreThreshold?: number;
139
+ }
140
+ interface UseInfiniteScrollReturn {
141
+ virtualizer: Virtualizer<HTMLElement, Element> | null;
142
+ virtualItems: ReturnType<Virtualizer<HTMLElement, Element>["getVirtualItems"]>;
143
+ computedLoadingState: LoadingState;
144
+ isInitialLoad: boolean;
145
+ isLoadingMore: boolean;
146
+ scrollRef: RefObject<HTMLDivElement | null>;
147
+ loadMoreRef: RefObject<HTMLDivElement | null>;
148
+ scrollToIndex: (index: number, options?: {
149
+ align?: "start" | "center" | "end";
150
+ }) => void;
151
+ scrollToTop: () => void;
152
+ }
153
+ /**
154
+ * useInfiniteScroll
155
+ *
156
+ * Hook for implementing infinite scroll with optional virtualization.
157
+ * Intelligently detects initial vs loading-more states from context.
158
+ *
159
+ * Features:
160
+ * - Smart loading state detection (initial vs loading-more)
161
+ * - Optional explicit state control
162
+ * - TanStack Virtual integration for performance
163
+ * - Intersection Observer for load triggering
164
+ * - Configurable virtualization threshold
165
+ *
166
+ * @example
167
+ * ```tsx
168
+ * const { scrollRef, computedLoadingState, isLoadingMore } = useInfiniteScroll({
169
+ * items,
170
+ * onLoadMore: fetchNextPage,
171
+ * hasMore: hasNextPage,
172
+ * isLoading: isFetching,
173
+ * });
174
+ * ```
175
+ */
176
+ declare function useInfiniteScroll<T = unknown>({ items, onLoadMore, hasMore, isLoading, loadingState, enableVirtualization, estimatedItemSize, overscan, scrollElement, loadMoreThreshold, }: UseInfiniteScrollOptions<T>): UseInfiniteScrollReturn;
177
+
116
178
  type SideNavItem = {
117
179
  id: string;
118
180
  label: string;
@@ -731,6 +793,195 @@ interface CodeEditorProps {
731
793
  */
732
794
  declare function CodeEditor({ value, readOnly, onChange, language, theme, height, width, className, lineHeight, minLines, maxLines, showLineNumbers, showGutter, fontSize, wrapEnabled, }: CodeEditorProps): react_jsx_runtime.JSX.Element;
733
795
 
796
+ type SortDirection = "asc" | "desc";
797
+ type CellAlignment = "left" | "center" | "right";
798
+ type TableDensity = "compact" | "default" | "relaxed";
799
+ type CellEmphasis = "strong" | "high" | "normal" | "low";
800
+ type LinkBehavior = "none" | "hover" | "visible";
801
+ type TableLayout = "auto" | "fixed" | "responsive";
802
+ type TableWidth = "full" | "auto" | "contained";
803
+ type MobileRenderer = "auto" | "cards" | "custom" | "none";
804
+ type MobileBreakpoint = "sm" | "md" | "lg" | "xl";
805
+ interface SortConfig {
806
+ columnId: string;
807
+ direction: SortDirection;
808
+ }
809
+ interface CellContext {
810
+ isLoading: boolean;
811
+ /**
812
+ * Whether this cell's row is selected.
813
+ *
814
+ * Populated whenever the table is driven by `onSelectionChange` — before that
815
+ * it was declared here and assigned by nothing, so `SelectCell` was a checkbox
816
+ * that reported to nobody. Every cell in a selected row sees it, not just the
817
+ * checkbox: a cell that wants to render differently inside a selection (a muted
818
+ * action, a highlighted value) reads it from here.
819
+ *
820
+ * `undefined` (not `false`) when selection is off, so a cell can tell "not
821
+ * selected" from "this table has no selection model".
822
+ */
823
+ isSelected?: boolean;
824
+ isHovered?: boolean;
825
+ rowIndex: number;
826
+ columnIndex: number;
827
+ density: TableDensity;
828
+ }
829
+ interface CellComponentProps<T = any> {
830
+ value: any;
831
+ row: T;
832
+ context: CellContext;
833
+ [key: string]: any;
834
+ }
835
+ type CellComponent<T = any> = ComponentType<CellComponentProps<T>>;
836
+ interface MobileConfig {
837
+ priority?: 1 | 2 | 3;
838
+ format?: "primary" | "secondary" | "badge" | "inline";
839
+ label?: boolean;
840
+ icon?: string;
841
+ }
842
+ interface Column<T> {
843
+ id: string;
844
+ label: string;
845
+ accessor?: keyof T | ((row: T) => any);
846
+ align?: CellAlignment;
847
+ width?: string | number;
848
+ minWidth?: string | number;
849
+ maxWidth?: string | number;
850
+ flex?: number;
851
+ cell?: CellComponent<T>;
852
+ cellProps?: Record<string, any> | ((value: any, row: T) => Record<string, any>);
853
+ render?: (value: any, row: T, context: CellContext) => ReactNode;
854
+ sortable?: boolean;
855
+ /**
856
+ * Whether this column can be reordered via drag-and-drop.
857
+ * Defaults to true. Set to false to lock a column in place (e.g., sticky first column).
858
+ */
859
+ reorderable?: boolean;
860
+ noCellPadding?: boolean;
861
+ mobile?: MobileConfig | false;
862
+ popover?: string | ((value: unknown, row: T) => ReactNode) | {
863
+ content: string | ((value: unknown, row: T) => ReactNode);
864
+ placement?: "top" | "bottom" | "left" | "right";
865
+ showArrow?: boolean;
866
+ trigger?: "hover" | "click";
867
+ };
868
+ /** Label to use for this column in CSV export headers. Falls back to `label` if not provided. */
869
+ exportLabel?: string;
870
+ /**
871
+ * Custom function to transform the cell value for export.
872
+ * If not provided, uses the raw accessor value converted to string.
873
+ * @param value - The raw cell value from the accessor
874
+ * @param row - The full row data
875
+ * @returns The value to export (will be converted to string)
876
+ */
877
+ exportValue?: (value: unknown, row: T) => string | number | boolean | null;
878
+ /**
879
+ * Whether to include this column in CSV exports.
880
+ * Defaults to true. Set to false to exclude columns like action buttons.
881
+ */
882
+ exportable?: boolean;
883
+ }
884
+ interface DataTableProps<T> {
885
+ columns: Column<T>[];
886
+ data: T[];
887
+ className?: string;
888
+ density?: TableDensity;
889
+ width?: TableWidth;
890
+ height?: string | number;
891
+ maxHeight?: string | number;
892
+ layout?: TableLayout;
893
+ mobileRenderer?: MobileRenderer;
894
+ customMobileRowRender?: (row: T, index: number) => ReactNode;
895
+ mobileBreakpoint?: MobileBreakpoint;
896
+ isLoading?: boolean;
897
+ loadingState?: LoadingState;
898
+ loadingRowCount?: number;
899
+ onLoadMore?: () => void | Promise<void>;
900
+ hasMore?: boolean;
901
+ enableVirtualization?: boolean;
902
+ estimatedRowHeight?: number;
903
+ loadingIndicator?: ReactNode;
904
+ stickyHeader?: boolean;
905
+ /** Make the first column sticky on horizontal scroll */
906
+ stickyFirstColumn?: boolean;
907
+ onRowClick?: (row: T) => void;
908
+ /**
909
+ * How to identify a row. Used for React keys and, when selection is on, as the
910
+ * key the selection set is expressed in. Defaults to `row.id` when the row has
911
+ * a string or finite-number one, and to the row's position otherwise —
912
+ * positional identity is a last resort, because a re-sort moves it.
913
+ */
914
+ getRowId?: (row: T) => string;
915
+ hideHeader?: boolean;
916
+ /**
917
+ * Selected row ids. **Controlled**: the table never mutates this and holds no
918
+ * selection state of its own.
919
+ *
920
+ * A table that owned its selection could not be driven by a bulk-action bar
921
+ * outside it, reset after the action completed, or restored when the user
922
+ * navigated back — and every consumer here is a host that already holds state.
923
+ *
924
+ * Ids the table cannot see are kept, not pruned: a user who selects three rows,
925
+ * paginates, and selects two more is acting on five, and dropping the first
926
+ * three would silently narrow a bulk action. The host owns showing the count.
927
+ */
928
+ selectedRowIds?: ReadonlySet<string>;
929
+ /**
930
+ * Called with the **full** next selection — never a delta, so a host can never
931
+ * accumulate a stale union.
932
+ *
933
+ * Absent means selection is off: no checkbox column, no selected-row
934
+ * background, and `CellContext.isSelected` stays `undefined`. Rendering is
935
+ * gated on this handler rather than on `selectionMode`, because a checkbox that
936
+ * reports to nobody is the state this model exists to remove.
937
+ */
938
+ onSelectionChange?: (next: ReadonlySet<string>) => void;
939
+ /**
940
+ * `"multi"` (the default) adds the page-scoped header checkbox; `"single"`
941
+ * replaces the selection on each pick and renders no header checkbox.
942
+ */
943
+ selectionMode?: "single" | "multi";
944
+ /** Controlled sort configuration - when provided, DataTable becomes controlled */
945
+ sortConfig?: SortConfig | null;
946
+ onSort?: (sortConfig: SortConfig | null) => void;
947
+ /**
948
+ * A caveat about the *currently sorted* column, for the case where the sort is
949
+ * real but has nothing to act on — every row on this page is empty in that
950
+ * column, so the order the table is showing carries no information.
951
+ *
952
+ * When set (and a sort is active), the sorted column's caret renders muted and
953
+ * the string is attached to the header as a `title` and an `sr-only` line.
954
+ * `aria-sort` is deliberately left alone: the column *is* sorted, and lying
955
+ * about that to assistive tech would be a worse bug than the one this fixes.
956
+ *
957
+ * Nothing about the data changes — no reorder, no dropped sort. This is a
958
+ * statement about the sort, not a replacement for it.
959
+ *
960
+ * A plain `string` rather than a `ReactNode`, and scoped to the sorted column
961
+ * rather than keyed by column id, because the only caller is the one that owns
962
+ * `sortConfig`: a general per-column header API was considered and rejected
963
+ * (see `TableHeaderCell.headerContent`).
964
+ */
965
+ sortNote?: string;
966
+ "aria-label"?: string;
967
+ /**
968
+ * Enable drag-and-drop column reordering (like Notion tables).
969
+ * When enabled, users can drag column headers to reorder columns.
970
+ */
971
+ enableColumnReorder?: boolean;
972
+ /**
973
+ * Controlled column order - array of column IDs in display order.
974
+ * When provided, DataTable uses this order instead of the columns array order.
975
+ * Use with onColumnOrderChange for controlled behavior.
976
+ */
977
+ columnOrder?: string[];
978
+ /**
979
+ * Callback fired when column order changes via drag-and-drop.
980
+ * Receives the new array of column IDs in their new order.
981
+ */
982
+ onColumnOrderChange?: (columnOrder: string[]) => void;
983
+ }
984
+
734
985
  /**
735
986
  * Core types for the formatting system
736
987
  */
@@ -1085,6 +1336,120 @@ declare function getYFormatSettings(formatter?: YFormatType): YFormatSettings;
1085
1336
  declare const createXScale: (data: BaseDataPoint[], width: number) => _visx_vendor_d3_scale.ScaleTime<number, number, never>;
1086
1337
  declare const createYScale: (data: BaseDataPoint[], height: number, formatType: YFormatType, explicitDomain?: [number, number]) => _visx_vendor_d3_scale.ScaleLinear<number, number, never>;
1087
1338
 
1339
+ /**
1340
+ * The category palette, kept apart from the cell that draws it.
1341
+ *
1342
+ * `CategoryCell` is a `"use client"` module, so a server component — or a Next.js app
1343
+ * route, which resolves `@texturehq/edges` through the `react-server` condition and
1344
+ * therefore against `dist/server.js` — cannot reach anything declared inside it. These
1345
+ * two are plain data derived from `getDefaultColors()`: no JSX, no hooks, no client
1346
+ * directive. Splitting them out is what lets `@texturehq/edges/server` re-export them,
1347
+ * which is what the boards table-cell planner needs to assign colour slots on the
1348
+ * server. The same split `deviceStateLabels` already has, for the same reason.
1349
+ */
1350
+ /**
1351
+ * The swatch for a value with no slot of its own.
1352
+ *
1353
+ * Twelve categorical slots exist; a rendering with more distinct values than that
1354
+ * gives the overflow this one shared grey. Deliberately not a thirteenth colour and
1355
+ * deliberately not slot 1 again: a recycled colour asserts that two unrelated values
1356
+ * belong together, which is the exact failure a category swatch is supposed to
1357
+ * prevent. Grey says "not one of the twelve", which is true.
1358
+ */
1359
+ declare const CATEGORY_NEUTRAL_COLOR = "var(--color-text-subtle)";
1360
+ /**
1361
+ * The categorical slots, as CSS custom-property references, in the palette's own
1362
+ * order: `CATEGORY_COLOR_TOKENS[i]` names the variable `getThemeCategoricalColors()`
1363
+ * reads at index `i`.
1364
+ *
1365
+ * This is the single source of truth for "slot i ↔ colour", and it exists so the
1366
+ * caller that assigns slots (a table's column-level colour map) and the charts that
1367
+ * read the palette cannot disagree. The length is taken from `getDefaultColors()`
1368
+ * rather than written as `12`, so adding a thirteenth slot to the ramp extends this
1369
+ * list instead of silently capping it — and the array is index-aligned with the
1370
+ * variables by construction there.
1371
+ *
1372
+ * References, not resolved colours: the browser resolves them per theme, so one
1373
+ * stored value is right in light and dark and a persisted board never freezes
1374
+ * today's palette. No DOM is needed to build this, which is what lets a server
1375
+ * render assign slots.
1376
+ */
1377
+ declare const CATEGORY_COLOR_TOKENS: ReadonlyArray<string>;
1378
+
1379
+ /**
1380
+ * Where a percentage stops being unremarkable.
1381
+ *
1382
+ * Both bounds are **inclusive**: a value exactly at `critical` colours. Exclusive
1383
+ * would leave the round number — the one a human configured — as the only
1384
+ * uncoloured value on the scale, which is the opposite of useful.
1385
+ *
1386
+ * Both are optional and independent: a column may want only a critical line.
1387
+ * `critical` wins when a value satisfies both.
1388
+ *
1389
+ * Deliberately *numbers*, not a level. What counts as low is a question about the
1390
+ * device and its configuration — a battery told to hold a 30% reserve is in trouble
1391
+ * at 28% and fine at 28% if its reserve is 5% — so the caller decides and this cell
1392
+ * only compares. See the `thresholds` prop.
1393
+ */
1394
+ interface PercentThresholds {
1395
+ /** Warn at or below this value. */
1396
+ low?: number;
1397
+ /** Alarm at or below this value. Takes precedence over `low`. */
1398
+ critical?: number;
1399
+ }
1400
+ /** The level a value falls into, or `undefined` when it is unremarkable. */
1401
+ type PercentThresholdLevel = "low" | "critical";
1402
+ /**
1403
+ * Classify a percentage against its thresholds.
1404
+ *
1405
+ * Exported because three callers need the same answer and must not each derive it:
1406
+ * this cell (to colour the fill), its serializable twin (to keep the label and the
1407
+ * marker consistent with it), and the tests.
1408
+ */
1409
+ declare function percentThresholdLevel(percentage: number, thresholds: PercentThresholds | undefined): PercentThresholdLevel | undefined;
1410
+ interface PercentBarCellProps extends CellComponentProps {
1411
+ value: number;
1412
+ showLabel?: boolean;
1413
+ color?: string | "auto";
1414
+ backgroundColor?: string | "none";
1415
+ height?: number;
1416
+ segments?: number;
1417
+ segmentGap?: number;
1418
+ colorScale?: {
1419
+ type: "sequential" | "diverging";
1420
+ scheme?: string;
1421
+ center?: number;
1422
+ };
1423
+ /**
1424
+ * Recolours the **fill** when the value is at or below a bound.
1425
+ *
1426
+ * The design inventory's `MeterCell` asks for a "threshold recolor below 20%"; the
1427
+ * number is the caller's because 20% is not universally low. Absent — the default —
1428
+ * renders exactly what this cell rendered before thresholds existed.
1429
+ *
1430
+ * Three things it deliberately does not do:
1431
+ *
1432
+ * - **The track never recolours.** The track is the scale, and a scale that changes
1433
+ * colour with the reading is no longer a scale.
1434
+ * - **It does not replace the label.** Colour is the scan and the number is the
1435
+ * answer; colour is never the only signal, which is also the accessibility floor.
1436
+ * - **It does not clamp or convert.** The comparison runs on the same 0–100 value
1437
+ * the bar draws.
1438
+ *
1439
+ * Wins over `color` and `colorScale`: a threshold is a statement about this
1440
+ * reading, and a gradient is a restatement of the value the bar already shows.
1441
+ */
1442
+ thresholds?: PercentThresholds;
1443
+ }
1444
+ /**
1445
+ * PercentBarCell
1446
+ *
1447
+ * Horizontal bar showing percentage (0-100%).
1448
+ * Perfect for battery charge, progress indicators, and utilization metrics.
1449
+ * Supports segmented "LED meter" style with optional gradient coloring.
1450
+ */
1451
+ declare const PercentBarCell: React__default.NamedExoticComponent<PercentBarCellProps>;
1452
+
1088
1453
  declare const variantSizeMap: {
1089
1454
  readonly heading: {
1090
1455
  readonly sm: "text-heading-sm";
@@ -4366,4 +4731,4 @@ declare const getContrastingTextColor: (backgroundColor: string) => string;
4366
4731
  */
4367
4732
  declare const mapValuesToCategoricalColors: (values: (string | number)[]) => Record<string | number, string>;
4368
4733
 
4369
- export { defaultMargin as $, ABSENT_GRID_FIELDS as A, type BadgeProps as B, type ChartMargin as C, type DeviceState as D, ENTITY_CONFIG as E, type SideNavItem as F, GRID_ELEMENT_TYPE_BY_ENTITY as G, HEADLINE_METRIC_BOUNDS as H, type InteractiveMapProps as I, type SideNavProps as J, type StaticMapProps as K, Loader as L, type MapPoint as M, type TooltipData as N, type TooltipSeries as O, TopNav as P, type TopNavProps as Q, type YFormatType as R, type SegmentOption as S, TextLink as T, activeDeviceStates as U, archetypeFor as V, clearColorCache as W, createCategoryColorMap as X, type YFormatSettings as Y, createXScale as Z, createYScale as _, type ActionItem as a, type EntityCategoryConfig as a$, deviceStateLabels as a0, deviceStateMetricFormats as a1, entityHasDetailPage as a2, entityHasStatList as a3, entityShowsNow as a4, getContrastingTextColor as a5, getDefaultChartColor as a6, getDefaultColors as a7, getDeviceStateLabel as a8, getEntityConfig as a9, type TemperatureUnitString as aA, type TemperatureUnit as aB, type TextFormat as aC, type VoltageFormat as aD, type ComponentFormatter as aE, type LayerSpec as aF, type CustomPinsSpec as aG, type GeoJsonLayerSpec as aH, type RasterLayerSpec as aI, type VectorLayerSpec as aJ, type ClusteredVectorLayerSpec as aK, type ColorSpec as aL, ActionMenu as aM, AppShell as aN, Avatar as aO, Badge as aP, type BaseFormat as aQ, ChartContext as aR, CodeEditor as aS, type ComponentFormatOptions as aT, type CurrentUnit as aU, type CustomFormat as aV, DEFAULT_MAP_TYPE as aW, type DateFormatStyle as aX, type DistanceUnit as aY, ENTITY_CATEGORY_CONFIG as aZ, type EntityCategory as a_, getEntityIcon as aa, getEntityLabel as ab, getEntityStatList as ac, getGridStateLabel as ad, getResolvedColor as ae, getThemeCategoricalColors as af, getYFormatSettings as ag, gridStateLabels as ah, isActiveState as ai, isLightColor as aj, type FieldValue as ak, type BooleanFormat as al, type FormattedValue as am, type FieldFormat as an, type CurrentFormat as ao, type DateFormat as ap, type DistanceFormat as aq, type EnergyUnit as ar, type EnergyFormat as as, type CurrencyFormat as at, type NumberFormat as au, type PhoneFormat as av, type PowerFormat as aw, type FormatterFunction as ax, type ResistanceFormat as ay, type TemperatureFormat as az, type ActionMenuProps as b, GRID_STATE_COLORS as b0, type GridStateColor as b1, InteractiveMap as b2, type InteractiveMapHandle as b3, type LayerCheckState as b4, type LayerFeature as b5, type LayerSelection as b6, type LayerStyle as b7, type LayerTreeNode as b8, type LayerVisibilityPatch as b9, useChartContext as bA, useComponentFormatter as bB, MAP_TYPES as ba, type MapType as bb, Meter as bc, type PercentageFormat as bd, type PowerUnit as be, type RenderType as bf, type ResistanceUnit as bg, SegmentedControl as bh, StackNav as bi, type StackNavGroup as bj, type StackNavItem as bk, type StackNavLinkComponentProps as bl, type StackNavProps as bm, type StackNavRenderRow as bn, type StackNavRowRenderProps as bo, type StackNavTheme as bp, StaticMap as bq, type TextTransform as br, type TextTruncatePosition as bs, UNVERIFIED_VOLTAGE_UNIT_ROWS as bt, type VoltageUnit as bu, type ZoomStops as bv, baselineFromPoint as bw, formatComponentValue as bx, getEntityCategory as by, mapValuesToCategoricalColors as bz, type AppShellProps as c, type AvatarProps as d, type BaseDataPoint as e, type CodeEditorProps as f, type CodeLanguage as g, type CodeTheme as h, type EntityArchetype as i, type EntityConfig as j, type EntityStateRule as k, type EntityType as l, GRID_STAT_LIST as m, type GridElementSourceType as n, type GridStatField as o, type GridStatFieldFormat as p, type GridState as q, Heading as r, type HeadlineMetric as s, Logo as t, type MeterProps as u, type MetricFormat as v, type MetricSource as w, type SegmentedControlProps as x, type SerializableFieldFormat as y, SideNav as z };
4734
+ export { clearColorCache as $, ABSENT_GRID_FIELDS as A, type BadgeProps as B, CATEGORY_COLOR_TOKENS as C, type DeviceState as D, ENTITY_CONFIG as E, type SegmentedControlProps as F, GRID_ELEMENT_TYPE_BY_ENTITY as G, HEADLINE_METRIC_BOUNDS as H, type InteractiveMapProps as I, type SerializableFieldFormat as J, SideNav as K, Loader as L, type MapPoint as M, type SideNavItem as N, type SideNavProps as O, type PercentThresholdLevel as P, type StaticMapProps as Q, type TooltipData as R, type SegmentOption as S, TextLink as T, type TooltipSeries as U, TopNav as V, type TopNavProps as W, type YFormatType as X, type YFormatSettings as Y, activeDeviceStates as Z, archetypeFor as _, type ActionItem as a, type BaseFormat as a$, createCategoryColorMap as a0, createXScale as a1, createYScale as a2, defaultMargin as a3, deviceStateLabels as a4, deviceStateMetricFormats as a5, entityHasDetailPage as a6, entityHasStatList as a7, entityShowsNow as a8, getContrastingTextColor as a9, type CurrencyFormat as aA, type NumberFormat as aB, type PhoneFormat as aC, type PowerFormat as aD, type FormatterFunction as aE, type ResistanceFormat as aF, type TemperatureFormat as aG, type TemperatureUnitString as aH, type TemperatureUnit as aI, type TextFormat as aJ, type VoltageFormat as aK, type CellComponentProps as aL, type CellAlignment as aM, type LinkBehavior as aN, type ComponentFormatter as aO, type DataTableProps as aP, type LayerSpec as aQ, type CustomPinsSpec as aR, type GeoJsonLayerSpec as aS, type RasterLayerSpec as aT, type VectorLayerSpec as aU, type ClusteredVectorLayerSpec as aV, type ColorSpec as aW, ActionMenu as aX, AppShell as aY, Avatar as aZ, Badge as a_, getDefaultChartColor as aa, getDefaultColors as ab, getDeviceStateLabel as ac, getEntityConfig as ad, getEntityIcon as ae, getEntityLabel as af, getEntityStatList as ag, getGridStateLabel as ah, getResolvedColor as ai, getThemeCategoricalColors as aj, getYFormatSettings as ak, gridStateLabels as al, isActiveState as am, isLightColor as an, type LoadingState as ao, type Column as ap, type CellEmphasis as aq, type FieldValue as ar, type BooleanFormat as as, type FormattedValue as at, type FieldFormat as au, type CurrentFormat as av, type DateFormat as aw, type DistanceFormat as ax, type EnergyUnit as ay, type EnergyFormat as az, type ActionMenuProps as b, useComponentFormatter as b$, type CellComponent as b0, type CellContext as b1, ChartContext as b2, CodeEditor as b3, type ComponentFormatOptions as b4, type CurrentUnit as b5, type CustomFormat as b6, DEFAULT_MAP_TYPE as b7, type DateFormatStyle as b8, type DistanceUnit as b9, type SortConfig as bA, type SortDirection as bB, StackNav as bC, type StackNavGroup as bD, type StackNavItem as bE, type StackNavLinkComponentProps as bF, type StackNavProps as bG, type StackNavRenderRow as bH, type StackNavRowRenderProps as bI, type StackNavTheme as bJ, StaticMap as bK, type TableDensity as bL, type TableLayout as bM, type TableWidth as bN, type TextTransform as bO, type TextTruncatePosition as bP, UNVERIFIED_VOLTAGE_UNIT_ROWS as bQ, type UseInfiniteScrollOptions as bR, type UseInfiniteScrollReturn as bS, type VoltageUnit as bT, type ZoomStops as bU, baselineFromPoint as bV, formatComponentValue as bW, getEntityCategory as bX, mapValuesToCategoricalColors as bY, percentThresholdLevel as bZ, useChartContext as b_, ENTITY_CATEGORY_CONFIG as ba, type EntityCategory as bb, type EntityCategoryConfig as bc, GRID_STATE_COLORS as bd, type GridStateColor as be, InteractiveMap as bf, type InteractiveMapHandle as bg, type LayerCheckState as bh, type LayerFeature as bi, type LayerSelection as bj, type LayerStyle as bk, type LayerTreeNode as bl, type LayerVisibilityPatch as bm, MAP_TYPES as bn, type MapType as bo, Meter as bp, type MobileBreakpoint as bq, type MobileConfig as br, type MobileRenderer as bs, PercentBarCell as bt, type PercentBarCellProps as bu, type PercentageFormat as bv, type PowerUnit as bw, type RenderType as bx, type ResistanceUnit as by, SegmentedControl as bz, type AppShellProps as c, useInfiniteScroll as c0, type AvatarProps as d, type BaseDataPoint as e, CATEGORY_NEUTRAL_COLOR as f, type ChartMargin as g, type CodeEditorProps as h, type CodeLanguage as i, type CodeTheme as j, type EntityArchetype as k, type EntityConfig as l, type EntityStateRule as m, type EntityType as n, GRID_STAT_LIST as o, type GridElementSourceType as p, type GridStatField as q, type GridStatFieldFormat as r, type GridState as s, Heading as t, type HeadlineMetric as u, Logo as v, type MeterProps as w, type MetricFormat as x, type MetricSource as y, type PercentThresholds as z };