@12-apps/ui 1.23.0 → 2.0.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/package.json +3 -1
- package/src/components/data-display/Alert/Alert.types.ts +2 -1
- package/src/components/data-display/Avatar/Avatar.types.ts +10 -2
- package/src/components/data-display/Badge/Badge.types.ts +3 -2
- package/src/components/data-display/Carousel/Carousel.parts.tsx +12 -10
- package/src/components/data-display/Carousel/Carousel.styles.ts +4 -3
- package/src/components/data-display/Carousel/Carousel.tsx +2 -1
- package/src/components/data-display/Carousel/Carousel.types.ts +7 -6
- package/src/components/data-display/Chart/Chart.tsx +2 -1
- package/src/components/data-display/Chart/Chart.types.ts +3 -2
- package/src/components/data-display/Chart/ChartSpec.types.ts +6 -7
- package/src/components/data-display/Chart/SpecChart.tsx +2 -1
- package/src/components/data-display/Chart/chart-internals.ts +3 -2
- package/src/components/data-display/Chart/chart-spec.ts +11 -1
- package/src/components/data-display/Chip/Chip.tsx +23 -3
- package/src/components/data-display/Chip/Chip.types.ts +37 -3
- package/src/components/data-display/Chip/chip.md +7 -3
- package/src/components/data-display/Chip/index.ts +1 -1
- package/src/components/data-display/DataViews/DataViewsGrid.tsx +10 -0
- package/src/components/data-display/DataViews/DataViewsTableBase.tsx +3 -0
- package/src/components/data-display/DataViews/data-views-grid-bodies.tsx +113 -62
- package/src/components/data-display/DataViews/data-views-grid-parts.tsx +4 -0
- package/src/components/data-display/DataViews/data-views-overflow.ts +23 -51
- package/src/components/data-display/DataViews/index.ts +4 -0
- package/src/components/data-display/DataViews/list-card-rails.tsx +29 -0
- package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +8 -5
- package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.types.ts +2 -1
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.types.ts +2 -1
- package/src/components/data-display/LoadingState/LoadingState.types.ts +2 -1
- package/src/components/data-display/Progress/Progress.types.ts +3 -2
- package/src/components/data-display/Sheet/Sheet.body.tsx +2 -1
- package/src/components/data-display/Sheet/Sheet.styles.ts +3 -2
- package/src/components/data-display/Sheet/Sheet.types.ts +7 -2
- package/src/components/data-display/Stepper/Stepper.types.ts +2 -1
- package/src/components/data-display/Table/Table.styles.ts +1 -1
- package/src/components/data-display/Table/Table.types.ts +3 -1
- package/src/components/data-display/Tooltip/Tooltip.types.ts +2 -1
- package/src/components/feedback/Dialog/Dialog.types.ts +2 -1
- package/src/components/feedback/Modal/Modal.types.ts +2 -1
- package/src/components/form/Button/Button.types.ts +3 -2
- package/src/components/form/Command/Command.styles.ts +8 -7
- package/src/components/form/Command/Command.types.ts +3 -2
- package/src/components/form/CreatableSelect/CreatableSelect.types.ts +2 -1
- package/src/components/form/Input/Input.types.ts +2 -1
- package/src/components/form/InputOTP/InputOTP.types.ts +3 -2
- package/src/components/form/Label/Label.styles.ts +8 -5
- package/src/components/form/Label/Label.tsx +1 -1
- package/src/components/form/Label/Label.types.ts +3 -2
- package/src/components/form/Menubar/Menubar.styles.ts +10 -8
- package/src/components/form/Menubar/Menubar.tsx +2 -1
- package/src/components/form/Menubar/Menubar.types.ts +7 -6
- package/src/components/form/RadioGroup/RadioGroup.types.ts +3 -2
- package/src/components/form/Select/Select.tsx +13 -1
- package/src/components/form/Select/Select.types.ts +5 -2
- package/src/components/form/Slider/Slider.types.ts +3 -2
- package/src/components/form/Switch/Switch.types.ts +3 -2
- package/src/components/form/Textarea/Textarea.types.ts +3 -2
- package/src/components/form/Toggle/Toggle.types.ts +3 -2
- package/src/components/form/ToggleGroup/ToggleGroup.types.ts +3 -2
- package/src/components/layout/Separator/Separator.types.ts +2 -1
- package/src/components/layout/Spacer/Spacer.types.ts +2 -1
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +1 -1
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.types.ts +7 -2
- package/src/components/navigation/ContextMenu/ContextMenu.types.ts +3 -2
- package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +1 -0
- package/src/components/navigation/DropdownMenu/DropdownMenu.types.ts +12 -2
- package/src/components/navigation/NavigationMenu/NavigationMenu.types.ts +7 -2
- package/src/components/navigation/Pagination/Pagination.tsx +3 -1
- package/src/components/navigation/Pagination/Pagination.types.ts +5 -3
- package/src/components/navigation/Tabs/Tabs.types.ts +3 -2
- package/src/components/typography/Blockquote/Blockquote.types.ts +2 -1
- package/src/components/typography/Code/Code.types.ts +2 -1
- package/src/components/typography/Heading/Heading.types.ts +2 -1
- package/src/components/typography/Paragraph/Paragraph.types.ts +3 -2
- package/src/components/typography/Text/Text.types.ts +3 -2
- package/src/components/utility/AnimatedIcon/AnimatedIcon.types.ts +2 -1
- package/src/components/utility/Overflow/index.ts +6 -0
- package/src/components/utility/Overflow/overflow.ts +125 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.types.ts +3 -2
- package/src/components/utility/index.ts +1 -0
- package/src/tokens/scales.ts +153 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
3
5
|
import { DataGrid, type GridColumn, type GridSort } from "../DataGrid";
|
|
4
6
|
import { Box } from "../../../mui/Box";
|
|
5
7
|
|
|
@@ -10,9 +12,11 @@ import {
|
|
|
10
12
|
DENSITY_CARD_COLUMNS,
|
|
11
13
|
DENSITY_ROW_PADDING,
|
|
12
14
|
useDataViewsLayout,
|
|
15
|
+
type DataViewsDensity,
|
|
13
16
|
} from "./data-views-layout-context";
|
|
14
17
|
import { DataViewsBoard, type BoardConfig } from "./DataViewsBoard";
|
|
15
18
|
import { SelectAllStrip } from "./data-views-select-all-strip";
|
|
19
|
+
import { ListCardGroup, type ListGroupConfig } from "./list-card-rails";
|
|
16
20
|
import type { DataViewCardSelection } from "./data-views-types";
|
|
17
21
|
import type { DataViewsController } from "./use-data-views-state";
|
|
18
22
|
|
|
@@ -160,6 +164,10 @@ interface ListBodyProps<T extends Record<string, unknown>> {
|
|
|
160
164
|
onToggleId: (id: string | number) => void;
|
|
161
165
|
/** Gap between rows, from the density preference. */
|
|
162
166
|
rowGap: number;
|
|
167
|
+
/** The list's shared column config. See {@link ListGroupConfig}. */
|
|
168
|
+
group?: ListGroupConfig<T>;
|
|
169
|
+
/** The density every row answers, handed to the group when there is one. */
|
|
170
|
+
density: DataViewsDensity;
|
|
163
171
|
dataTestId?: string;
|
|
164
172
|
emptyState?: React.ReactNode;
|
|
165
173
|
}
|
|
@@ -186,28 +194,59 @@ function ListBody<T extends Record<string, unknown>>({
|
|
|
186
194
|
selectedIds,
|
|
187
195
|
onToggleId,
|
|
188
196
|
rowGap,
|
|
197
|
+
group,
|
|
198
|
+
density,
|
|
189
199
|
dataTestId,
|
|
190
200
|
emptyState,
|
|
191
201
|
}: ListBodyProps<T>): React.JSX.Element {
|
|
192
202
|
if (rows.length === 0) {
|
|
193
203
|
return <Box sx={{ mt: 1.5 }}>{emptyState}</Box>;
|
|
194
204
|
}
|
|
205
|
+
const testId = dataTestId ? `${dataTestId}-list` : "data-views-list";
|
|
206
|
+
const selectionFor = (id: string | number): DataViewCardSelection => ({
|
|
207
|
+
selected: selectedIds.has(id),
|
|
208
|
+
onToggleSelect: () => onToggleId(id),
|
|
209
|
+
scale: 1,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
if (group) {
|
|
213
|
+
return (
|
|
214
|
+
<Box sx={{ mt: 1.5 }}>
|
|
215
|
+
<ListCardGroup
|
|
216
|
+
cells={group.cells}
|
|
217
|
+
metaColumns={group.metaColumns}
|
|
218
|
+
rails={group.rails}
|
|
219
|
+
reserveGutters={group.reserveGutters}
|
|
220
|
+
density={density}
|
|
221
|
+
gap={rowGap}
|
|
222
|
+
dataTestId={testId}
|
|
223
|
+
>
|
|
224
|
+
{rows.map((row) => {
|
|
225
|
+
const id = getRowId(row);
|
|
226
|
+
// A FRAGMENT, NOT A BOX. The row is subgrid over the group's tracks
|
|
227
|
+
// (`gridColumn: span railCount`), which only resolves while the card
|
|
228
|
+
// is a DIRECT child of the group's grid. One wrapper element and the
|
|
229
|
+
// span is measured against a grid that isn't there, so every rail
|
|
230
|
+
// collapses — the exact failure the group exists to prevent.
|
|
231
|
+
return (
|
|
232
|
+
<React.Fragment key={id}>
|
|
233
|
+
{renderListRow(row, selectionFor(id))}
|
|
234
|
+
</React.Fragment>
|
|
235
|
+
);
|
|
236
|
+
})}
|
|
237
|
+
</ListCardGroup>
|
|
238
|
+
</Box>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
195
242
|
return (
|
|
196
243
|
<Box
|
|
197
244
|
sx={{ mt: 1.5, display: "flex", flexDirection: "column", gap: rowGap }}
|
|
198
|
-
data-testid={
|
|
245
|
+
data-testid={testId}
|
|
199
246
|
>
|
|
200
247
|
{rows.map((row) => {
|
|
201
248
|
const id = getRowId(row);
|
|
202
|
-
return (
|
|
203
|
-
<Box key={id}>
|
|
204
|
-
{renderListRow(row, {
|
|
205
|
-
selected: selectedIds.has(id),
|
|
206
|
-
onToggleSelect: () => onToggleId(id),
|
|
207
|
-
scale: 1,
|
|
208
|
-
})}
|
|
209
|
-
</Box>
|
|
210
|
-
);
|
|
249
|
+
return <Box key={id}>{renderListRow(row, selectionFor(id))}</Box>;
|
|
211
250
|
})}
|
|
212
251
|
</Box>
|
|
213
252
|
);
|
|
@@ -221,6 +260,8 @@ interface GridMainProps<T extends Record<string, unknown>> {
|
|
|
221
260
|
renderCard?: (row: T, selection: DataViewCardSelection) => React.ReactNode;
|
|
222
261
|
/** Opt-in "Lista" layout — one full-width row per record. */
|
|
223
262
|
renderListRow?: (row: T, selection: DataViewCardSelection) => React.ReactNode;
|
|
263
|
+
/** The Lista's shared columns. Omitted, each row resolves its own tracks. */
|
|
264
|
+
listGroup?: ListGroupConfig<T>;
|
|
224
265
|
/** Opt-in "Quadro" (board) layout — needs `renderCard`, since it reuses the card. */
|
|
225
266
|
board?: BoardConfig<T>;
|
|
226
267
|
dataTestId?: string;
|
|
@@ -260,68 +301,78 @@ function Headerless<T extends Record<string, unknown>>({
|
|
|
260
301
|
);
|
|
261
302
|
}
|
|
262
303
|
|
|
263
|
-
/**
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
emptyState
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const { layout, zoom, density } = useDataViewsLayout();
|
|
304
|
+
/**
|
|
305
|
+
* The body for one of the three HEADERLESS layouts, or `null` for the table.
|
|
306
|
+
*
|
|
307
|
+
* Split out from {@link GridMain} so the select-all strip is wrapped around the
|
|
308
|
+
* result exactly once instead of being repeated identically in every branch —
|
|
309
|
+
* which is also what keeps either function inside the line budget.
|
|
310
|
+
*/
|
|
311
|
+
function headerlessBody<T extends Record<string, unknown>>(
|
|
312
|
+
{ c, getRowId, renderCard, renderListRow, listGroup, board, dataTestId, emptyState }: GridMainProps<T>,
|
|
313
|
+
{ layout, zoom, density }: ReturnType<typeof useDataViewsLayout>,
|
|
314
|
+
): React.ReactNode | null {
|
|
275
315
|
if (layout === "list" && renderListRow) {
|
|
276
316
|
return (
|
|
277
|
-
<
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
317
|
+
<ListBody
|
|
318
|
+
rows={c.matched}
|
|
319
|
+
renderListRow={renderListRow}
|
|
320
|
+
getRowId={getRowId}
|
|
321
|
+
selectedIds={c.selectedIds}
|
|
322
|
+
onToggleId={c.toggleId}
|
|
323
|
+
rowGap={DENSITY_ROW_PADDING[density]}
|
|
324
|
+
group={listGroup}
|
|
325
|
+
density={density}
|
|
326
|
+
dataTestId={dataTestId}
|
|
327
|
+
emptyState={emptyState}
|
|
328
|
+
/>
|
|
289
329
|
);
|
|
290
330
|
}
|
|
291
331
|
if (layout === "board" && board && renderCard) {
|
|
292
332
|
return (
|
|
293
|
-
<
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
/>
|
|
307
|
-
</Headerless>
|
|
333
|
+
<DataViewsBoard
|
|
334
|
+
rows={c.matched}
|
|
335
|
+
board={board}
|
|
336
|
+
getRowId={getRowId}
|
|
337
|
+
renderCard={renderCard}
|
|
338
|
+
selectedIds={c.selectedIds}
|
|
339
|
+
onToggleId={c.toggleId}
|
|
340
|
+
// DENSITY, not zoom: the board's own knob in the Exibição tab is how
|
|
341
|
+
// wide its columns are, and it is the only sizing control the board
|
|
342
|
+
// has since the zoom slider was removed.
|
|
343
|
+
cardScale={DENSITY_BOARD_SCALE[density]}
|
|
344
|
+
dataTestId={dataTestId}
|
|
345
|
+
/>
|
|
308
346
|
);
|
|
309
347
|
}
|
|
310
348
|
if (layout === "cards" && renderCard) {
|
|
349
|
+
return (
|
|
350
|
+
<CardBody
|
|
351
|
+
rows={c.matched}
|
|
352
|
+
renderCard={renderCard}
|
|
353
|
+
getRowId={getRowId}
|
|
354
|
+
selectedIds={c.selectedIds}
|
|
355
|
+
onToggleId={c.toggleId}
|
|
356
|
+
minCardWidth={cardMinWidthForZoom(zoom)}
|
|
357
|
+
maxColumns={DENSITY_CARD_COLUMNS[density]}
|
|
358
|
+
cardScale={cardScaleForZoom(zoom)}
|
|
359
|
+
dataTestId={dataTestId}
|
|
360
|
+
emptyState={emptyState}
|
|
361
|
+
/>
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** Picks the body from the layout context: board, list, cards, or the dense grid. */
|
|
368
|
+
export function GridMain<T extends Record<string, unknown>>(props: GridMainProps<T>): React.JSX.Element {
|
|
369
|
+
const { c, getRowId, dataTestId, emptyState, testIdPrefix } = props;
|
|
370
|
+
const layoutState = useDataViewsLayout();
|
|
371
|
+
const body = headerlessBody(props, layoutState);
|
|
372
|
+
if (body) {
|
|
311
373
|
return (
|
|
312
374
|
<Headerless c={c} getRowId={getRowId} testIdPrefix={testIdPrefix}>
|
|
313
|
-
|
|
314
|
-
rows={c.matched}
|
|
315
|
-
renderCard={renderCard}
|
|
316
|
-
getRowId={getRowId}
|
|
317
|
-
selectedIds={c.selectedIds}
|
|
318
|
-
onToggleId={c.toggleId}
|
|
319
|
-
minCardWidth={cardMinWidthForZoom(zoom)}
|
|
320
|
-
maxColumns={DENSITY_CARD_COLUMNS[density]}
|
|
321
|
-
cardScale={cardScaleForZoom(zoom)}
|
|
322
|
-
dataTestId={dataTestId}
|
|
323
|
-
emptyState={emptyState}
|
|
324
|
-
/>
|
|
375
|
+
{body}
|
|
325
376
|
</Headerless>
|
|
326
377
|
);
|
|
327
378
|
}
|
|
@@ -335,7 +386,7 @@ export function GridMain<T extends Record<string, unknown>>({
|
|
|
335
386
|
sortBy={c.state.sortBy}
|
|
336
387
|
onChangeSortBy={(next: GridSort[]) => c.patch({ sortBy: next })}
|
|
337
388
|
sortMode={c.serverMode ? "server" : "client"}
|
|
338
|
-
rowPadding={DENSITY_ROW_PADDING[density]}
|
|
389
|
+
rowPadding={DENSITY_ROW_PADDING[layoutState.density]}
|
|
339
390
|
dataTestId={dataTestId}
|
|
340
391
|
emptyState={emptyState}
|
|
341
392
|
/>
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "./data-views-layout-context";
|
|
15
15
|
import { FilterDialog, GridFilterPanel } from "./data-views-filter-panel";
|
|
16
16
|
import { GridMain } from "./data-views-grid-bodies";
|
|
17
|
+
import type { ListGroupConfig } from "./list-card-rails";
|
|
17
18
|
import { InlineFilterControls } from "./data-views-inline-bar";
|
|
18
19
|
import { toOverflowFields, useFilterOverflow, type OverflowSplit } from "./data-views-overflow";
|
|
19
20
|
import { ShellToolbar } from "./data-views-shell-toolbar";
|
|
@@ -238,6 +239,8 @@ interface GridShellProps<T extends Record<string, unknown>> {
|
|
|
238
239
|
board?: BoardConfig<T>;
|
|
239
240
|
/** Opt-in "Lista" layout: one full-width, entity-rendered row per record. */
|
|
240
241
|
renderListRow?: (row: T, selection: DataViewCardSelection) => React.ReactNode;
|
|
242
|
+
/** The Lista's shared columns, so its rows line up by construction. */
|
|
243
|
+
listGroup?: ListGroupConfig<T>;
|
|
241
244
|
/** The page-level partition rendered as tabs under the toolbar. */
|
|
242
245
|
scopes?: ScopeConfig[];
|
|
243
246
|
/**
|
|
@@ -340,6 +343,7 @@ function ShellStack<T extends Record<string, unknown>>({
|
|
|
340
343
|
getRowId={props.getRowId}
|
|
341
344
|
renderCard={props.renderCard}
|
|
342
345
|
renderListRow={props.renderListRow}
|
|
346
|
+
listGroup={props.listGroup}
|
|
343
347
|
board={props.board}
|
|
344
348
|
dataTestId={dataTestId}
|
|
345
349
|
testIdPrefix={testIdPrefix}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useRef } from "react";
|
|
4
4
|
|
|
5
|
+
import { splitToFit, useMeasuredWidth } from "../../utility/Overflow";
|
|
5
6
|
import {
|
|
6
7
|
estimateWidth,
|
|
7
8
|
furnitureCost,
|
|
@@ -106,26 +107,6 @@ export function toOverflowFields<T extends Record<string, unknown>>(
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
|
|
109
|
-
/** Observe the bar's width. Returns 0 until the first measurement lands. */
|
|
110
|
-
function useBarWidth(): { barRef: React.RefObject<HTMLDivElement | null>; width: number } {
|
|
111
|
-
const barRef = useRef<HTMLDivElement | null>(null);
|
|
112
|
-
const [width, setWidth] = useState(0);
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
const element = barRef.current;
|
|
115
|
-
// jsdom has no ResizeObserver, and neither does an SSR pass — with no
|
|
116
|
-
// measurement the hook keeps every control inline, which is the honest
|
|
117
|
-
// fallback: nothing is hidden behind a menu nobody can see.
|
|
118
|
-
if (!element || typeof ResizeObserver === "undefined") return undefined;
|
|
119
|
-
const observer = new ResizeObserver((entries) => {
|
|
120
|
-
const entry = entries[0];
|
|
121
|
-
if (entry) setWidth(entry.contentRect.width);
|
|
122
|
-
});
|
|
123
|
-
observer.observe(element);
|
|
124
|
-
return () => observer.disconnect();
|
|
125
|
-
}, []);
|
|
126
|
-
return { barRef, width };
|
|
127
|
-
}
|
|
128
|
-
|
|
129
110
|
/** Is this control carrying a value the operator set? */
|
|
130
111
|
function isActiveField<T extends Record<string, unknown>>(
|
|
131
112
|
field: OverflowField<T>,
|
|
@@ -167,24 +148,11 @@ function splitFilters<T extends Record<string, unknown>>(
|
|
|
167
148
|
/** Is the bar already down to icons? "Mais" shrinks with everything else. */
|
|
168
149
|
compact: boolean,
|
|
169
150
|
): Split<T> {
|
|
170
|
-
const none: OverflowField<T>[] = [];
|
|
171
|
-
const widthOf = (field: OverflowField<T>): number => fieldWidth(field, pills, ranges);
|
|
172
|
-
const cost = (fields: OverflowField<T>[]): number =>
|
|
173
|
-
fields.reduce((sum, field) => sum + widthOf(field) + GAP, 0);
|
|
174
151
|
const active = all.filter((field) => isActiveField(field, pills, ranges));
|
|
175
152
|
const idle = all.filter((field) => !isActiveField(field, pills, ranges));
|
|
176
153
|
|
|
177
154
|
// "Limpar" rides the end of the cluster whenever anything is applied.
|
|
178
155
|
const clearCost = active.length > 0 ? RESERVED.clearAll + GAP : 0;
|
|
179
|
-
let available = width - furniture - clearCost;
|
|
180
|
-
if (cost(all) <= available) {
|
|
181
|
-
return { inline: all, overflow: none, used: cost(all) + clearCost };
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// There IS an overflow, so its button now costs room too — at the width it
|
|
185
|
-
// will actually have, which on a phone is the icon-and-badge one.
|
|
186
|
-
const overflowButton = compact ? RESERVED.overflowButtonCompact : RESERVED.overflowButton;
|
|
187
|
-
available -= overflowButton;
|
|
188
156
|
// APPLIED FIRST, BUT NOT EXEMPT.
|
|
189
157
|
//
|
|
190
158
|
// Applied controls take the visible slots ahead of idle ones — that part was
|
|
@@ -197,22 +165,21 @@ function splitFilters<T extends Record<string, unknown>>(
|
|
|
197
165
|
// vanished silently: the trigger goes to the applied tone and says how many
|
|
198
166
|
// are in there (see `MoreTrigger`), which is the same signal the pill itself
|
|
199
167
|
// was carrying. A control you scroll off-screen carries no signal at all.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
};
|
|
168
|
+
//
|
|
169
|
+
// The keep-what-fits loop itself is `splitToFit` (`utility/Overflow`) — the
|
|
170
|
+
// one part of this that is not filter-shaped, and the part a second cluster
|
|
171
|
+
// in the design system would otherwise have had to reimplement.
|
|
172
|
+
const split = splitToFit(all, {
|
|
173
|
+
widthOf: (field) => fieldWidth(field, pills, ranges),
|
|
174
|
+
keyOf: (field) => field.id,
|
|
175
|
+
gap: GAP,
|
|
176
|
+
available: width - furniture - clearCost,
|
|
177
|
+
// The overflow button at the width it will actually have, which on a phone
|
|
178
|
+
// is the icon-and-badge one.
|
|
179
|
+
overflowCost: compact ? RESERVED.overflowButtonCompact : RESERVED.overflowButton,
|
|
180
|
+
priority: [...active, ...idle],
|
|
181
|
+
});
|
|
182
|
+
return { ...split, used: split.used + clearCost };
|
|
216
183
|
}
|
|
217
184
|
|
|
218
185
|
/**
|
|
@@ -363,7 +330,12 @@ export function useFilterOverflow<T extends Record<string, unknown>>(
|
|
|
363
330
|
/** Whether "Exportar" is on the bar — see `rightClusterCost`. */
|
|
364
331
|
hasExport = true,
|
|
365
332
|
): OverflowSplit<T> {
|
|
366
|
-
|
|
333
|
+
// The measurement is `useMeasuredWidth` (`utility/Overflow`): the same
|
|
334
|
+
// ResizeObserver every collapsing cluster in the design system reads, so
|
|
335
|
+
// there is one loop to get right rather than one per bar. `0` until the
|
|
336
|
+
// first measurement lands (and forever under SSR or jsdom), which
|
|
337
|
+
// `computeSplit` reads as "degrade nothing".
|
|
338
|
+
const { ref: barRef, width } = useMeasuredWidth<HTMLDivElement>();
|
|
367
339
|
const signature = JSON.stringify({
|
|
368
340
|
ids: all.map((field) => field.id),
|
|
369
341
|
pills,
|
|
@@ -22,6 +22,10 @@ export {
|
|
|
22
22
|
type ListCardCellConfig,
|
|
23
23
|
DEFAULT_CELL_WIDTH,
|
|
24
24
|
} from "./list-card-cells";
|
|
25
|
+
// The list's columns declared at the TABLE, not per card — which is what makes
|
|
26
|
+
// a Lista line up by construction. Without it a consumer can still hand a cell
|
|
27
|
+
// config to each row, and they agree until one row carries a wider value.
|
|
28
|
+
export type { ListGroupConfig } from "./list-card-rails";
|
|
25
29
|
// Published by a drag container so a row can draw the marker; a consumer wiring
|
|
26
30
|
// its own DnD needs the type to build the value.
|
|
27
31
|
export { DropIndicator } from "./data-views-drag";
|
|
@@ -223,6 +223,35 @@ export function cellRailCount(cells: number): number {
|
|
|
223
223
|
return CELL_FIXED_RAILS + cells + 1;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
/**
|
|
227
|
+
* A {@link ListCardGroup}'s configuration, as a value a caller can pass around.
|
|
228
|
+
*
|
|
229
|
+
* The same fields the group takes as props, named once so a table can accept
|
|
230
|
+
* "the list's columns" as a single prop and hand them straight over. It is what
|
|
231
|
+
* makes a list line up BY CONSTRUCTION rather than by convention: without it
|
|
232
|
+
* every row resolves its own tracks from its own copy of the config, which
|
|
233
|
+
* agrees with its neighbours right until one row carries an unusually wide value.
|
|
234
|
+
*/
|
|
235
|
+
export interface ListGroupConfig<T extends Record<string, unknown>> {
|
|
236
|
+
/**
|
|
237
|
+
* The cells every row renders. Supplying these replaces the named-slot layout
|
|
238
|
+
* (title/subtitle/meta/value/status) for the rows inside.
|
|
239
|
+
*/
|
|
240
|
+
cells?: readonly ListCardCellConfig<T>[];
|
|
241
|
+
/**
|
|
242
|
+
* How many labelled pairs the rows carry, in the named-slot layout. The group
|
|
243
|
+
* renders its children opaquely and cannot count them.
|
|
244
|
+
*/
|
|
245
|
+
metaColumns?: number;
|
|
246
|
+
/** Override individual rails; anything omitted keeps its default. */
|
|
247
|
+
rails?: Partial<ListRails>;
|
|
248
|
+
/**
|
|
249
|
+
* Hold the drag and select gutters open even when nothing uses them. On by
|
|
250
|
+
* default, so a selectable list and a read-only one still line up.
|
|
251
|
+
*/
|
|
252
|
+
reserveGutters?: boolean;
|
|
253
|
+
}
|
|
254
|
+
|
|
226
255
|
/**
|
|
227
256
|
* A list of {@link BaseListCard}s that share one set of columns.
|
|
228
257
|
*
|
|
@@ -3,17 +3,20 @@ import { forwardRef } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { useDateTimeParts } from './DateTimeDisplay.hooks';
|
|
5
5
|
import type { DateTimeDisplayProps } from './DateTimeDisplay.types';
|
|
6
|
+
import type { SizeValue } from '../../../tokens/scales';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Get font sizes based on size prop
|
|
9
10
|
*/
|
|
10
|
-
function getFontSizes(size:
|
|
11
|
+
function getFontSizes(size: SizeValue) {
|
|
11
12
|
switch (size) {
|
|
12
|
-
case '
|
|
13
|
+
case 'xs':
|
|
14
|
+
case 'sm':
|
|
13
15
|
return { date: '0.75rem', time: '0.65rem' };
|
|
14
|
-
case '
|
|
16
|
+
case 'lg':
|
|
17
|
+
case 'xl':
|
|
15
18
|
return { date: '1rem', time: '0.875rem' };
|
|
16
|
-
case '
|
|
19
|
+
case 'md':
|
|
17
20
|
default:
|
|
18
21
|
return { date: '0.875rem', time: '0.75rem' };
|
|
19
22
|
}
|
|
@@ -81,7 +84,7 @@ export const DateTimeDisplay = forwardRef<HTMLSpanElement, DateTimeDisplayProps>
|
|
|
81
84
|
dateFormat = 'short',
|
|
82
85
|
timeFormat = '12h',
|
|
83
86
|
showTimezone = false,
|
|
84
|
-
size = '
|
|
87
|
+
size = 'md',
|
|
85
88
|
showTooltip = true,
|
|
86
89
|
tooltipContent,
|
|
87
90
|
sx,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { SxProps, Theme } from '@mui/material';
|
|
2
3
|
|
|
3
4
|
export interface DateTimeDisplayProps {
|
|
@@ -25,7 +26,7 @@ export interface DateTimeDisplayProps {
|
|
|
25
26
|
* Size variant
|
|
26
27
|
* @default 'medium'
|
|
27
28
|
*/
|
|
28
|
-
size?: '
|
|
29
|
+
size?: Extract<SizeValue, 'sm' | 'md' | 'lg'>;
|
|
29
30
|
/**
|
|
30
31
|
* Whether to show a tooltip with full date/time
|
|
31
32
|
* @default true
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { TooltipProps as MuiTooltipProps } from '@mui/material';
|
|
2
3
|
|
|
3
4
|
export interface InteractiveTooltipProps extends Omit<MuiTooltipProps, 'variant' | 'title'> {
|
|
@@ -19,7 +20,7 @@ export interface InteractiveTooltipProps extends Omit<MuiTooltipProps, 'variant'
|
|
|
19
20
|
/**
|
|
20
21
|
* Size of the tooltip
|
|
21
22
|
*/
|
|
22
|
-
size?: 'sm' | 'md' | 'lg'
|
|
23
|
+
size?: Extract<SizeValue, 'sm' | 'md' | 'lg'>;
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Maximum width of the tooltip
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { SizeValue } from '../../../tokens/scales';
|
|
1
2
|
export type LoadingStateVariant = 'spinner' | 'skeleton';
|
|
2
|
-
export type LoadingStateSize = 'sm' | 'md' | 'lg'
|
|
3
|
+
export type LoadingStateSize = Extract<SizeValue, 'sm' | 'md' | 'lg'>;
|
|
3
4
|
|
|
4
5
|
export interface LoadingStateProps {
|
|
5
6
|
/**
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { ColorValue, SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { LinearProgressProps } from '@mui/material';
|
|
2
3
|
|
|
3
4
|
export type ProgressVariant = 'linear' | 'circular' | 'segmented' | 'gradient' | 'glass';
|
|
4
|
-
export type ProgressSize = 'sm' | 'md' | 'lg'
|
|
5
|
+
export type ProgressSize = Extract<SizeValue, 'sm' | 'md' | 'lg'>;
|
|
5
6
|
|
|
6
7
|
export interface ProgressProps extends Omit<LinearProgressProps, 'variant' | 'color'> {
|
|
7
8
|
/**
|
|
@@ -17,7 +18,7 @@ export interface ProgressProps extends Omit<LinearProgressProps, 'variant' | 'co
|
|
|
17
18
|
/**
|
|
18
19
|
* The color of the progress
|
|
19
20
|
*/
|
|
20
|
-
color?:
|
|
21
|
+
color?: Exclude<ColorValue, 'info'>;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Whether the progress should have a glow effect
|
|
@@ -3,6 +3,7 @@ import React from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { SheetContent, SheetFooter, SheetHeader } from './Sheet.parts';
|
|
5
5
|
import type { SheetProps } from './Sheet.types';
|
|
6
|
+
import { muiColor } from '../../../tokens/scales';
|
|
6
7
|
|
|
7
8
|
export interface SheetBodyProps extends Pick<
|
|
8
9
|
SheetProps,
|
|
@@ -50,7 +51,7 @@ const SheetLoading: React.FC<Pick<SheetBodyProps, 'color'>> = ({ color }) => (
|
|
|
50
51
|
minHeight: 200,
|
|
51
52
|
}}
|
|
52
53
|
>
|
|
53
|
-
<CircularProgress color={color} />
|
|
54
|
+
<CircularProgress color={color === undefined ? undefined : muiColor(color, 'inherit')} />
|
|
54
55
|
</Box>
|
|
55
56
|
);
|
|
56
57
|
|
|
@@ -4,6 +4,7 @@ import type React from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { glowAnimation, pulseAnimation, shimmerAnimation } from './Sheet.animations';
|
|
6
6
|
import type { SheetProps } from './Sheet.types';
|
|
7
|
+
import { accentFor } from '../../../tokens/scales';
|
|
7
8
|
|
|
8
9
|
type Position = NonNullable<SheetProps['position']>;
|
|
9
10
|
type Variant = NonNullable<SheetProps['variant']>;
|
|
@@ -140,7 +141,7 @@ const SURFACES: Record<Variant, (input: SurfaceInput) => Record<string, unknown>
|
|
|
140
141
|
135deg,
|
|
141
142
|
${theme.palette.background.paper} 0%,
|
|
142
143
|
${alpha(accent, 0.08)} 50%,
|
|
143
|
-
${alpha(theme
|
|
144
|
+
${alpha(accentFor(theme, color)?.dark || accent, 0.12)} 100%
|
|
144
145
|
)`
|
|
145
146
|
: theme.palette.background.paper,
|
|
146
147
|
position: 'relative' as const,
|
|
@@ -211,7 +212,7 @@ const baseSurface = (input: VariantStyleInput, accent: string) => {
|
|
|
211
212
|
|
|
212
213
|
const variantStyles = (input: VariantStyleInput) => {
|
|
213
214
|
const { theme, variant, color, position, glow, pulse, rounded } = input;
|
|
214
|
-
const accent = theme
|
|
215
|
+
const accent = accentFor(theme, color)?.main || theme.palette.primary.main;
|
|
215
216
|
|
|
216
217
|
return {
|
|
217
218
|
...baseSurface(input, accent),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorValue, SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { CSSProperties,ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
export interface SheetProps {
|
|
@@ -8,8 +9,12 @@ export interface SheetProps {
|
|
|
8
9
|
description?: string;
|
|
9
10
|
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
10
11
|
variant?: 'default' | 'glass' | 'gradient' | 'elevated' | 'minimal' | 'draggable';
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The house scale, plus `full`. `full` is not a size on the scale — it is
|
|
14
|
+
* "the whole viewport", so it extends rather than replaces.
|
|
15
|
+
*/
|
|
16
|
+
size?: SizeValue | 'full';
|
|
17
|
+
color?: Exclude<ColorValue, 'neutral'>;
|
|
13
18
|
glow?: boolean;
|
|
14
19
|
pulse?: boolean;
|
|
15
20
|
glass?: boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
export interface Step {
|
|
@@ -40,7 +41,7 @@ export interface StepperProps {
|
|
|
40
41
|
* takes far less vertical space — useful above the fold on mobile checkouts.
|
|
41
42
|
* @default 'md'
|
|
42
43
|
*/
|
|
43
|
-
size?: 'sm' | 'md'
|
|
44
|
+
size?: Extract<SizeValue, 'sm' | 'md'>;
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* Navigation variant controlling step access
|
|
@@ -46,7 +46,7 @@ const getStripeColorFromTheme = (theme: { palette: { primary: { main: string };
|
|
|
46
46
|
info: theme.palette.info.main,
|
|
47
47
|
success: theme.palette.success.main,
|
|
48
48
|
warning: theme.palette.warning.main,
|
|
49
|
-
|
|
49
|
+
danger: theme.palette.error.main,
|
|
50
50
|
neutral: theme.palette.action.hover };
|
|
51
51
|
return colorMap[stripeColor];
|
|
52
52
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorValue } from '../../../tokens/scales';
|
|
1
2
|
import type { TableProps as MuiTableProps } from '@mui/material';
|
|
2
3
|
import type React from 'react';
|
|
3
4
|
|
|
@@ -57,7 +58,8 @@ export interface SelectionConfig {
|
|
|
57
58
|
rowKeyExtractor?: (rowData: Record<string, unknown>, index: number) => string | number;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
/** The full house vocabulary — a stripe can take any accent, or none. */
|
|
62
|
+
export type TableStripeColor = ColorValue;
|
|
61
63
|
|
|
62
64
|
export interface TableProps extends Omit<MuiTableProps, 'variant'> {
|
|
63
65
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { TooltipProps as MuiTooltipProps } from '@mui/material';
|
|
2
3
|
|
|
3
4
|
export interface TooltipProps extends Omit<MuiTooltipProps, 'variant'> {
|
|
@@ -19,7 +20,7 @@ export interface TooltipProps extends Omit<MuiTooltipProps, 'variant'> {
|
|
|
19
20
|
/**
|
|
20
21
|
* Size of the tooltip
|
|
21
22
|
*/
|
|
22
|
-
size?: 'sm' | 'md' | 'lg'
|
|
23
|
+
size?: Extract<SizeValue, 'sm' | 'md' | 'lg'>;
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Maximum width of the tooltip
|