@12-apps/ui 6.57.0 → 6.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/components/data-display/Avatar/Avatar.js +2 -2
- package/dist/_internal/components/data-display/Badge/Badge.js +2 -2
- package/dist/_internal/components/data-display/Carousel/Carousel.js +2 -2
- package/dist/_internal/components/data-display/Chart/Chart.js +4 -4
- package/dist/_internal/components/data-display/Chart/SpecChart.js +6 -6
- package/dist/_internal/components/data-display/Chart/chart-context.js +2 -2
- package/dist/_internal/components/data-display/Chart/chart-renderers.js +3 -3
- package/dist/_internal/components/data-display/DataGrid/DataGrid.js +2 -2
- package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +18 -18
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +20 -19
- package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +5 -3
- package/dist/_internal/components/data-display/DataViews/base-list-card-layout.js +45 -0
- package/dist/_internal/components/data-display/DataViews/base-list-card-layout.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +2 -2
- package/dist/_internal/components/data-display/DataViews/base-list-card.js +5 -4
- package/dist/_internal/components/data-display/DataViews/data-views-category-pill.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +4 -4
- package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +4 -4
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +17 -17
- package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +6 -6
- package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +4 -4
- package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-selection-extra.js +3 -1
- package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +3 -3
- package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-url-echo.js +13 -0
- package/dist/_internal/components/data-display/DataViews/data-views-url-echo.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/list-card-rails.js +1 -1
- package/dist/_internal/components/data-display/FleetMap/FleetMap.fixtures.js +1 -1
- package/dist/_internal/components/data-display/index.js +14 -14
- package/dist/_internal/components/index.js +22 -22
- package/dist/_internal/components/layout/ContentToolbar/ContentToolbar.js +1 -1
- package/dist/_internal/components/layout/index.js +1 -1
- package/dist/_internal/components/navigation/SectionNav/SectionNav.bar.js +6 -6
- package/dist/_internal/components/navigation/SectionNav/SectionNav.js +9 -9
- package/dist/_internal/components/navigation/SectionNav/SectionNav.parts.js +3 -3
- package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js +4 -4
- package/dist/_internal/components/navigation/SectionNav/SectionNav.rail.js +5 -5
- package/dist/_internal/components/navigation/SectionNav/SectionNav.railCreate.js +4 -4
- package/dist/_internal/components/navigation/SectionNav/SectionNav.sheet.js +4 -4
- package/dist/_internal/components/navigation/index.js +9 -9
- package/dist/_internal/en-US.data-display.js +1 -1
- package/dist/_internal/pt-BR.data-display.js +1 -1
- package/dist/_internal/user-avatar/user-avatar.js +3 -3
- package/dist/charts.js +6 -6
- package/dist/{chunk-MKAA3YIJ.js → chunk-3K7WN2PO.js} +3 -3
- package/dist/{chunk-573XC4HK.js → chunk-4QKS5Y35.js} +2 -2
- package/dist/{chunk-KX75HM5U.js → chunk-5YDS6HO3.js} +7 -2
- package/dist/{chunk-KX75HM5U.js.map → chunk-5YDS6HO3.js.map} +1 -1
- package/dist/{chunk-N4MR4EMC.js → chunk-6D2PFC5C.js} +2 -2
- package/dist/{chunk-LJKWWXZD.js → chunk-6OSUK2C7.js} +28 -22
- package/dist/chunk-6OSUK2C7.js.map +1 -0
- package/dist/{chunk-ICSXPZXT.js → chunk-6QBT5TPS.js} +2 -2
- package/dist/{chunk-C67FDYG7.js → chunk-7CWZI6MQ.js} +5 -5
- package/dist/{chunk-JL77BSOL.js → chunk-AQI3UK6P.js} +2 -2
- package/dist/{chunk-A6EUQDRK.js → chunk-ARJIKW56.js} +4 -2
- package/dist/chunk-ARJIKW56.js.map +1 -0
- package/dist/{chunk-GI24X7XA.js → chunk-DZIRCD2W.js} +2 -2
- package/dist/{chunk-53ACGKBW.js → chunk-EDBP62WG.js} +3 -3
- package/dist/{chunk-YXIVQFNW.js → chunk-EWIKSTJV.js} +4 -4
- package/dist/{chunk-LWZ2K225.js → chunk-FXZUVZON.js} +6 -6
- package/dist/chunk-G6EJLEVV.js +75 -0
- package/dist/chunk-G6EJLEVV.js.map +1 -0
- package/dist/{chunk-IK2ZVV3M.js → chunk-GK7JNSMK.js} +2 -2
- package/dist/{chunk-HFBQCJNP.js → chunk-HCYRCU4W.js} +2 -2
- package/dist/{chunk-BJMNAPKH.js → chunk-HH7PM5HT.js} +10 -22
- package/dist/chunk-HH7PM5HT.js.map +1 -0
- package/dist/{chunk-7AAJYWC3.js → chunk-HPO7PB4F.js} +2 -2
- package/dist/{chunk-WF3P7GE5.js → chunk-I3CQBEKS.js} +2 -2
- package/dist/{chunk-RREWYOKS.js → chunk-IL4FCC54.js} +2 -2
- package/dist/{chunk-7M3DRP7Q.js → chunk-ILNO4ZJ6.js} +3 -3
- package/dist/{chunk-2CJZLL5Y.js → chunk-NHVL2QPG.js} +2 -1
- package/dist/{chunk-2CJZLL5Y.js.map → chunk-NHVL2QPG.js.map} +1 -1
- package/dist/{chunk-45PGSVOH.js → chunk-NTJUAPJM.js} +10 -8
- package/dist/chunk-NTJUAPJM.js.map +1 -0
- package/dist/{chunk-EUPUEMFX.js → chunk-PC4H5LVB.js} +7 -7
- package/dist/{chunk-KEKOPD43.js → chunk-PQ7RWH7L.js} +4 -2
- package/dist/chunk-PQ7RWH7L.js.map +1 -0
- package/dist/{chunk-HRMB72E4.js → chunk-QHP5PZNC.js} +2 -1
- package/dist/{chunk-HRMB72E4.js.map → chunk-QHP5PZNC.js.map} +1 -1
- package/dist/{chunk-GNBCSTXF.js → chunk-QKAYXAQE.js} +6 -6
- package/dist/{chunk-GNBCSTXF.js.map → chunk-QKAYXAQE.js.map} +1 -1
- package/dist/{chunk-TZFBJ47T.js → chunk-SFLNHCA2.js} +39 -15
- package/dist/chunk-SFLNHCA2.js.map +1 -0
- package/dist/{chunk-OBMPE6PW.js → chunk-SSDYEOU4.js} +5 -5
- package/dist/{chunk-I6ESCBY3.js → chunk-TF27Z27K.js} +2 -2
- package/dist/{chunk-JF5LQOGB.js → chunk-U47KRLEW.js} +57 -45
- package/dist/chunk-U47KRLEW.js.map +1 -0
- package/dist/{chunk-RBHBJDOZ.js → chunk-UEU5NSIG.js} +4 -4
- package/dist/chunk-V4V2N6YJ.js +55 -0
- package/dist/chunk-V4V2N6YJ.js.map +1 -0
- package/dist/{chunk-G76BNXWE.js → chunk-XW5SEW3H.js} +6 -6
- package/dist/{chunk-46ZATLQV.js → chunk-YIKFYWKD.js} +3 -3
- package/dist/{chunk-4JBS6NOT.js → chunk-ZWBGQYVO.js} +35 -6
- package/dist/chunk-ZWBGQYVO.js.map +1 -0
- package/dist/{chunk-VWW2EXH7.js → chunk-ZYJZHXFU.js} +4 -4
- package/dist/data-display/Avatar.js +2 -2
- package/dist/data-display/Badge.js +2 -2
- package/dist/data-display/CardKit.js +10 -10
- package/dist/data-display/Carousel.js +2 -2
- package/dist/data-display/Chart.js +6 -6
- package/dist/data-display/DataGrid.js +2 -2
- package/dist/data-display/DataViews.js +25 -23
- package/dist/en-US.js +1 -1
- package/dist/layout/ContentToolbar.js +1 -1
- package/dist/locales.js +2 -2
- package/dist/navigation/SectionNav.js +9 -9
- package/dist/pt-BR.js +1 -1
- package/dist/types/components/data-display/DataViews/DataViewsTableBase.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/base-list-card-geometry.d.ts +29 -1
- package/dist/types/components/data-display/DataViews/base-list-card-geometry.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/base-list-card-layout.d.ts +46 -0
- package/dist/types/components/data-display/DataViews/base-list-card-layout.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/base-list-card-slots.d.ts +5 -2
- package/dist/types/components/data-display/DataViews/base-list-card-slots.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/base-list-card.d.ts +10 -1
- package/dist/types/components/data-display/DataViews/base-list-card.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +7 -0
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-grid-parts.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-selection-extra.d.ts +2 -0
- package/dist/types/components/data-display/DataViews/data-views-selection-extra.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-shell-toolbar.d.ts +3 -1
- package/dist/types/components/data-display/DataViews/data-views-shell-toolbar.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-toolbar.d.ts +2 -0
- package/dist/types/components/data-display/DataViews/data-views-toolbar.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-url-echo.d.ts +47 -0
- package/dist/types/components/data-display/DataViews/data-views-url-echo.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/list-card-rails.d.ts +17 -2
- package/dist/types/components/data-display/DataViews/list-card-rails.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.d.ts +3 -2
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts +14 -0
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts.map +1 -1
- package/dist/types/en-US.data-display.d.ts.map +1 -1
- package/dist/types/pt-BR.data-display.d.ts.map +1 -1
- package/dist/user-avatar.js +3 -3
- package/package.json +1 -1
- package/src/components/data-display/DataViews/DataViewsTableBase.tsx +7 -36
- package/src/components/data-display/DataViews/base-list-card-geometry.tsx +114 -40
- package/src/components/data-display/DataViews/base-list-card-layout.tsx +104 -0
- package/src/components/data-display/DataViews/base-list-card-slots.tsx +47 -3
- package/src/components/data-display/DataViews/base-list-card.tsx +65 -68
- package/src/components/data-display/DataViews/data-views-copy.ts +7 -0
- package/src/components/data-display/DataViews/data-views-grid-parts.tsx +2 -1
- package/src/components/data-display/DataViews/data-views-selection-extra.ts +10 -1
- package/src/components/data-display/DataViews/data-views-shell-toolbar.tsx +4 -0
- package/src/components/data-display/DataViews/data-views-toolbar.tsx +4 -0
- package/src/components/data-display/DataViews/data-views-url-echo.ts +134 -0
- package/src/components/data-display/DataViews/list-card-rails.tsx +22 -6
- package/src/components/layout/ContentToolbar/ContentToolbar.md +5 -2
- package/src/components/layout/ContentToolbar/ContentToolbar.tsx +51 -10
- package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +14 -0
- package/src/en-US.data-display.ts +1 -0
- package/src/pt-BR.data-display.ts +1 -0
- package/dist/chunk-45PGSVOH.js.map +0 -1
- package/dist/chunk-4JBS6NOT.js.map +0 -1
- package/dist/chunk-A6EUQDRK.js.map +0 -1
- package/dist/chunk-BJMNAPKH.js.map +0 -1
- package/dist/chunk-JF5LQOGB.js.map +0 -1
- package/dist/chunk-KEKOPD43.js.map +0 -1
- package/dist/chunk-LJKWWXZD.js.map +0 -1
- package/dist/chunk-TZFBJ47T.js.map +0 -1
- /package/dist/{chunk-MKAA3YIJ.js.map → chunk-3K7WN2PO.js.map} +0 -0
- /package/dist/{chunk-573XC4HK.js.map → chunk-4QKS5Y35.js.map} +0 -0
- /package/dist/{chunk-N4MR4EMC.js.map → chunk-6D2PFC5C.js.map} +0 -0
- /package/dist/{chunk-ICSXPZXT.js.map → chunk-6QBT5TPS.js.map} +0 -0
- /package/dist/{chunk-C67FDYG7.js.map → chunk-7CWZI6MQ.js.map} +0 -0
- /package/dist/{chunk-JL77BSOL.js.map → chunk-AQI3UK6P.js.map} +0 -0
- /package/dist/{chunk-GI24X7XA.js.map → chunk-DZIRCD2W.js.map} +0 -0
- /package/dist/{chunk-53ACGKBW.js.map → chunk-EDBP62WG.js.map} +0 -0
- /package/dist/{chunk-YXIVQFNW.js.map → chunk-EWIKSTJV.js.map} +0 -0
- /package/dist/{chunk-LWZ2K225.js.map → chunk-FXZUVZON.js.map} +0 -0
- /package/dist/{chunk-IK2ZVV3M.js.map → chunk-GK7JNSMK.js.map} +0 -0
- /package/dist/{chunk-HFBQCJNP.js.map → chunk-HCYRCU4W.js.map} +0 -0
- /package/dist/{chunk-7AAJYWC3.js.map → chunk-HPO7PB4F.js.map} +0 -0
- /package/dist/{chunk-WF3P7GE5.js.map → chunk-I3CQBEKS.js.map} +0 -0
- /package/dist/{chunk-RREWYOKS.js.map → chunk-IL4FCC54.js.map} +0 -0
- /package/dist/{chunk-7M3DRP7Q.js.map → chunk-ILNO4ZJ6.js.map} +0 -0
- /package/dist/{chunk-EUPUEMFX.js.map → chunk-PC4H5LVB.js.map} +0 -0
- /package/dist/{chunk-OBMPE6PW.js.map → chunk-SSDYEOU4.js.map} +0 -0
- /package/dist/{chunk-I6ESCBY3.js.map → chunk-TF27Z27K.js.map} +0 -0
- /package/dist/{chunk-RBHBJDOZ.js.map → chunk-UEU5NSIG.js.map} +0 -0
- /package/dist/{chunk-G76BNXWE.js.map → chunk-XW5SEW3H.js.map} +0 -0
- /package/dist/{chunk-46ZATLQV.js.map → chunk-YIKFYWKD.js.map} +0 -0
- /package/dist/{chunk-VWW2EXH7.js.map → chunk-ZYJZHXFU.js.map} +0 -0
|
@@ -74,8 +74,90 @@ interface RowSxOptions {
|
|
|
74
74
|
divider: boolean;
|
|
75
75
|
interactive: boolean;
|
|
76
76
|
draggable: boolean;
|
|
77
|
+
/** What the two-line layout below `STACK_BREAK` has to place by name. */
|
|
78
|
+
stack: StackPlacement;
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
/**
|
|
82
|
+
* The slots the stacked row places that the named-slot rules cannot know about.
|
|
83
|
+
*
|
|
84
|
+
* For a CONFIGURED row, `firstCell` is the cell that takes the title's place and
|
|
85
|
+
* `valueCell` the one that takes the value's (null for a named-slot row, or for
|
|
86
|
+
* a one-cell row with no value to show). `expandable` decides whether the
|
|
87
|
+
* disclosure button gets a place or, when it is only a reserved empty gutter,
|
|
88
|
+
* none at all.
|
|
89
|
+
*/
|
|
90
|
+
export interface StackPlacement {
|
|
91
|
+
firstCell: string | null;
|
|
92
|
+
valueCell: string | null;
|
|
93
|
+
expandable: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** A `[data-slot="cell-<id>"]` child selector, quoted so any id is safe. */
|
|
97
|
+
const cellSlot = (id: string): string => `& > [data-slot=${JSON.stringify(`cell-${id}`)}]`;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* A configured row, stacked, keeps the SAME two facts a named-slot row keeps:
|
|
101
|
+
* what the record is (the first cell, in the title's place on line 1) and the
|
|
102
|
+
* figure it is about (the value cell, on line 2 from under the title to the
|
|
103
|
+
* right edge, where an `end` cell sits flush right). Every other cell goes, as
|
|
104
|
+
* `meta` goes — a row is a fixed-height scanning unit, and what does not fit
|
|
105
|
+
* belongs in its expandable body.
|
|
106
|
+
*
|
|
107
|
+
* Left to auto-placement these cells had flowed into whatever track was free:
|
|
108
|
+
* a name squeezed beside the glyph, an amount clipped to "R$ …".
|
|
109
|
+
*
|
|
110
|
+
* The hide-all rule comes first and the two named cells after it: the
|
|
111
|
+
* selectors have equal specificity, so the later rule wins for those cells.
|
|
112
|
+
*/
|
|
113
|
+
function stackedCells(stack: StackPlacement): Record<string, unknown> {
|
|
114
|
+
if (stack.firstCell == null) return {};
|
|
115
|
+
return {
|
|
116
|
+
'& > [data-slot^="cell-"]': { display: "none" },
|
|
117
|
+
[cellSlot(stack.firstCell)]: { display: "flex", gridArea: "1 / 3" },
|
|
118
|
+
...(stack.valueCell == null ? {} : { [cellSlot(stack.valueCell)]: { display: "flex", gridArea: "2 / 3 / 3 / 5" } }),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* TWO-LINE, below the point where the shared rails stop helping.
|
|
124
|
+
*
|
|
125
|
+
* The standard mobile transaction row: what the record IS on the first line,
|
|
126
|
+
* what it COSTS under it at the right edge. Better than
|
|
127
|
+
* truncating four columns into ellipses, and the reason each slot carries a
|
|
128
|
+
* `data-slot` — the placement is explicit rather than whatever order the
|
|
129
|
+
* children happen to be in.
|
|
130
|
+
*
|
|
131
|
+
* [ select ][ leading ][ title …………… ][ menu ]
|
|
132
|
+
* [ (disclose) ] [ (cells) …………… ][ value ]
|
|
133
|
+
*
|
|
134
|
+
* The MENU stays in the top-right corner at every width. It is the row's
|
|
135
|
+
* one fixed landmark — an overflow that moves to the second line on a phone
|
|
136
|
+
* is an overflow nobody finds twice.
|
|
137
|
+
*/
|
|
138
|
+
const stackedRowSx = (inGroup: boolean, railCount: number, stack: StackPlacement): Record<string, unknown> => ({
|
|
139
|
+
gridTemplateColumns: "auto auto minmax(0, 1fr) max-content",
|
|
140
|
+
// The GROUP's track count, which a configured list sets from its cells
|
|
141
|
+
// (`cellRailCount`) — not the named-slot RAIL_COUNT, which over-spans a
|
|
142
|
+
// configured group and adds an implicit track at its end.
|
|
143
|
+
...(inGroup ? { gridColumn: `span ${railCount}` } : {}),
|
|
144
|
+
rowGap: 0.75,
|
|
145
|
+
columnGap: 1,
|
|
146
|
+
'& > [data-slot="drag"]': { display: "none" },
|
|
147
|
+
// The disclosure button, when there is one, under the checkbox: the head of
|
|
148
|
+
// the row, where it sits at every other width — never beside the menu, where
|
|
149
|
+
// it read as an "open" arrow. A reserved empty gutter takes no place at all.
|
|
150
|
+
'& > [data-slot="disclose"]': stack.expandable ? { gridArea: "2 / 1", justifySelf: "center" } : { display: "none" },
|
|
151
|
+
'& > [data-slot="select"]': { gridArea: "1 / 1" },
|
|
152
|
+
'& > [data-slot="leading"]': { gridArea: "1 / 2" },
|
|
153
|
+
'& > [data-slot="caption"]': { gridArea: "1 / 3" },
|
|
154
|
+
'& > [data-slot="actions"]': { gridArea: "1 / 4", justifyContent: "flex-end" },
|
|
155
|
+
'& > [data-slot="meta"]': { display: "none" },
|
|
156
|
+
// Second line, starting under the title rather than under the checkbox.
|
|
157
|
+
'& > [data-slot="value"]': { gridArea: "2 / 4", textAlign: "right" },
|
|
158
|
+
...stackedCells(stack),
|
|
159
|
+
});
|
|
160
|
+
|
|
79
161
|
/**
|
|
80
162
|
* DIVIDER COMPOSES WITH THE VARIANT — it changes the row's SHAPE, not its
|
|
81
163
|
* surface.
|
|
@@ -91,7 +173,7 @@ interface RowSxOptions {
|
|
|
91
173
|
* {@link rowStyles}.
|
|
92
174
|
*/
|
|
93
175
|
export const rowSx = (theme: Theme, opts: RowSxOptions): Record<string, unknown> => {
|
|
94
|
-
const { inGroup, railCount, cellTemplate, gutters, metaColumns, pad, padY, scale, divider, interactive, draggable } = opts;
|
|
176
|
+
const { inGroup, railCount, cellTemplate, gutters, metaColumns, pad, padY, scale, divider, interactive, draggable, stack } = opts;
|
|
95
177
|
return {
|
|
96
178
|
position: "relative",
|
|
97
179
|
borderRadius: CARD_RADIUS,
|
|
@@ -103,13 +185,14 @@ export const rowSx = (theme: Theme, opts: RowSxOptions): Record<string, unknown>
|
|
|
103
185
|
// computed `grid-template-columns: 1222px` on a card asking for subgrid.)
|
|
104
186
|
//
|
|
105
187
|
// So inside a group the GROUP is the query container and the row is the
|
|
106
|
-
// subgrid
|
|
188
|
+
// subgrid. Standalone, the row is its own grid but NOT its own container:
|
|
189
|
+
// a container query matches an ANCESTOR, never the element itself, so a
|
|
190
|
+
// row that was its own container placed its children for two lines while
|
|
191
|
+
// its own template stayed wide. A standalone card renders inside a wrapper
|
|
192
|
+
// that is the container (`BaseListCard`).
|
|
107
193
|
...(inGroup
|
|
108
194
|
? { gridColumn: `span ${railCount}`, gridTemplateColumns: "subgrid" }
|
|
109
|
-
: {
|
|
110
|
-
containerType: "inline-size",
|
|
111
|
-
gridTemplateColumns: cellTemplate ?? railsTemplateFor(gutters, metaColumns),
|
|
112
|
-
}),
|
|
195
|
+
: { gridTemplateColumns: cellTemplate ?? railsTemplateFor(gutters, metaColumns) }),
|
|
113
196
|
alignItems: "center",
|
|
114
197
|
// Wide enough that the meta cluster, the value and the status read as three
|
|
115
198
|
// columns rather than one run of text — the complaint that started all this
|
|
@@ -128,34 +211,8 @@ export const rowSx = (theme: Theme, opts: RowSxOptions): Record<string, unknown>
|
|
|
128
211
|
outlineColor: "primary.main",
|
|
129
212
|
outlineOffset: rem(theme, 2),
|
|
130
213
|
},
|
|
131
|
-
// TWO-LINE
|
|
132
|
-
|
|
133
|
-
// The standard mobile transaction row: what the record IS and what it COST
|
|
134
|
-
// on the first line, the supporting detail on the second. Better than
|
|
135
|
-
// truncating four columns into ellipses, and the reason each slot carries a
|
|
136
|
-
// `data-slot` — the placement is explicit rather than whatever order the
|
|
137
|
-
// children happen to be in.
|
|
138
|
-
//
|
|
139
|
-
// [ select ][ leading ][ title …………… ][ menu ]
|
|
140
|
-
// [ (cells) …………… ][ value ]
|
|
141
|
-
//
|
|
142
|
-
// The MENU stays in the top-right corner at every width. It is the row's
|
|
143
|
-
// one fixed landmark — an overflow that moves to the second line on a phone
|
|
144
|
-
// is an overflow nobody finds twice.
|
|
145
|
-
[`@container (max-width: ${rem(theme, STACK_BREAK)})`]: {
|
|
146
|
-
gridTemplateColumns: "auto auto minmax(0, 1fr) max-content",
|
|
147
|
-
...(inGroup ? { gridColumn: `span ${RAIL_COUNT}` } : {}),
|
|
148
|
-
rowGap: 0.75,
|
|
149
|
-
columnGap: 1,
|
|
150
|
-
'& > [data-slot="drag"]': { display: "none" },
|
|
151
|
-
'& > [data-slot="select"]': { gridArea: "1 / 1" },
|
|
152
|
-
'& > [data-slot="leading"]': { gridArea: "1 / 2" },
|
|
153
|
-
'& > [data-slot="caption"]': { gridArea: "1 / 3" },
|
|
154
|
-
'& > [data-slot="actions"]': { gridArea: "1 / 4", justifyContent: "flex-end" },
|
|
155
|
-
'& > [data-slot="meta"]': { display: "none" },
|
|
156
|
-
// Second line, starting under the title rather than under the checkbox.
|
|
157
|
-
'& > [data-slot="value"]': { gridArea: "2 / 4", textAlign: "right" },
|
|
158
|
-
},
|
|
214
|
+
// TWO-LINE below STACK_BREAK: see {@link stackedRowSx}.
|
|
215
|
+
[`@container (max-width: ${rem(theme, STACK_BREAK)})`]: stackedRowSx(inGroup, railCount, stack),
|
|
159
216
|
...(divider
|
|
160
217
|
? { borderRadius: 0, borderWidth: 0, borderBottomWidth: 1, borderStyle: "solid" }
|
|
161
218
|
: {}),
|
|
@@ -262,23 +319,39 @@ function rowSurface(
|
|
|
262
319
|
return { ...surface, borderBottomColor: theme.palette.divider };
|
|
263
320
|
}
|
|
264
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Which head gutters this row renders: the ones it uses, or all three when its
|
|
324
|
+
* group reserves them. The template is built from this; the three gutter slots
|
|
325
|
+
* (`base-list-card-gutters.tsx`) apply the SAME conditions on their own — keep
|
|
326
|
+
* the two in step, because a template that disagrees with the slots is exactly
|
|
327
|
+
* how cells slid two tracks.
|
|
328
|
+
*/
|
|
329
|
+
export function rowGutters(
|
|
330
|
+
props: BaseListCardProps,
|
|
331
|
+
shell: ReturnType<typeof useRowShell>,
|
|
332
|
+
): { disclose: boolean; drag: boolean; select: boolean } {
|
|
333
|
+
const { selectable, drag, reserve } = shell;
|
|
334
|
+
return {
|
|
335
|
+
disclose: reserve || props.children != null,
|
|
336
|
+
drag: reserve || drag.draggable,
|
|
337
|
+
select: reserve || selectable,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
265
341
|
export function rowStyles(
|
|
266
342
|
props: BaseListCardProps,
|
|
267
343
|
shell: ReturnType<typeof useRowShell>,
|
|
268
344
|
cellTemplate: string | null,
|
|
345
|
+
stack: StackPlacement,
|
|
269
346
|
): Record<string, unknown> {
|
|
270
|
-
const { theme, group,
|
|
347
|
+
const { theme, group, drag, pad, padY, scale, acts } = shell;
|
|
271
348
|
return {
|
|
272
349
|
...rowSurface(props, shell),
|
|
273
350
|
...rowSx(theme, {
|
|
274
351
|
inGroup: group !== null,
|
|
275
352
|
railCount: group?.railCount ?? RAIL_COUNT,
|
|
276
353
|
cellTemplate,
|
|
277
|
-
gutters:
|
|
278
|
-
disclose: reserve || props.children != null,
|
|
279
|
-
drag: reserve || drag.draggable,
|
|
280
|
-
select: reserve || selectable,
|
|
281
|
-
},
|
|
354
|
+
gutters: rowGutters(props, shell),
|
|
282
355
|
metaColumns: metaShape(props).columns,
|
|
283
356
|
pad,
|
|
284
357
|
padY,
|
|
@@ -286,6 +359,7 @@ export function rowStyles(
|
|
|
286
359
|
divider: props.divider ?? false,
|
|
287
360
|
interactive: acts || props.href != null,
|
|
288
361
|
draggable: drag.draggable && drag.handleProps === undefined,
|
|
362
|
+
stack,
|
|
289
363
|
}),
|
|
290
364
|
};
|
|
291
365
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
import { Box } from "../../../mui/Box";
|
|
6
|
+
import type { BaseListCardProps } from "./base-list-card";
|
|
7
|
+
import { rowGutters, type StackPlacement, type useRowShell } from "./base-list-card-geometry";
|
|
8
|
+
import { cellRailsTemplate } from "./list-card-rails";
|
|
9
|
+
import { cellTracks, useCellConfig, type ListCardCellConfig } from "./list-card-cells";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* WHAT SHAPE A ROW TAKES, resolved once: its cells and their template, whether
|
|
13
|
+
* it ends in the "this opens" chevron, and what its two-line form keeps.
|
|
14
|
+
*
|
|
15
|
+
* Split from the card at the file-size gate. Everything here decides; nothing
|
|
16
|
+
* here renders but the standalone container.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Which cell config applies, and whether this row resolves its own tracks.
|
|
21
|
+
*
|
|
22
|
+
* The list's config wins over the card's: one declaration of the list's shape is
|
|
23
|
+
* the point, so a row inside a group cannot introduce a column of its own. And
|
|
24
|
+
* the template is standalone-only — inside a group the GROUP owns it and the row
|
|
25
|
+
* is subgrid over it, because a row resolving its own tracks is exactly what
|
|
26
|
+
* stops a list from lining up.
|
|
27
|
+
*/
|
|
28
|
+
function useResolvedCells(
|
|
29
|
+
props: BaseListCardProps,
|
|
30
|
+
inGroup: boolean,
|
|
31
|
+
gutters: { disclose: boolean; drag: boolean; select: boolean },
|
|
32
|
+
): {
|
|
33
|
+
cells: readonly ListCardCellConfig<never>[] | null;
|
|
34
|
+
configured: boolean;
|
|
35
|
+
cellTemplate: string | null;
|
|
36
|
+
} {
|
|
37
|
+
const groupCells = useCellConfig();
|
|
38
|
+
const cells = groupCells ?? props.cells ?? null;
|
|
39
|
+
const configured = cells != null && cells.length > 0 && props.row != null;
|
|
40
|
+
const cellTemplate = configured && !inGroup ? cellRailsTemplate(cellTracks(cells), gutters) : null;
|
|
41
|
+
return { cells, configured, cellTemplate };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Whether the row ends in the "this opens" chevron: it is live and leads
|
|
46
|
+
* somewhere it can actually go — a click handler, or a link the row renders.
|
|
47
|
+
* Only a named-slot row with a title renders an anchor for `href` (the caption
|
|
48
|
+
* wraps the title), so an `href` alone does not count elsewhere: a chevron on
|
|
49
|
+
* a row that cannot open is the promise the disclosure chevron's docblock
|
|
50
|
+
* warns about. Not when the row expands either:
|
|
51
|
+
* the disclosure chevron already speaks, and a second arrow meaning something
|
|
52
|
+
* else beside it would contradict it.
|
|
53
|
+
*/
|
|
54
|
+
function rowOpens(
|
|
55
|
+
props: BaseListCardProps,
|
|
56
|
+
shell: ReturnType<typeof useRowShell>,
|
|
57
|
+
configured: boolean,
|
|
58
|
+
expandable: boolean,
|
|
59
|
+
): boolean {
|
|
60
|
+
if (expandable) return false;
|
|
61
|
+
// The named-slot caption renders its anchor only around a title.
|
|
62
|
+
return shell.acts || (shell.actionable && props.href != null && props.title != null && !configured);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The cell that takes the VALUE's place when the row stacks: the one the config
|
|
67
|
+
* marks `strong` ("the figure the row is really about"), else the last — as
|
|
68
|
+
* long as it is not the first cell, which already holds the title's place.
|
|
69
|
+
*/
|
|
70
|
+
function valueCellId(cells: readonly ListCardCellConfig<never>[]): string | null {
|
|
71
|
+
const first = cells[0];
|
|
72
|
+
const candidate = cells.find((cell) => cell.strong === true && cell !== first) ?? cells[cells.length - 1];
|
|
73
|
+
return candidate != null && candidate !== first ? candidate.id : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Everything the row's shape depends on, resolved once. */
|
|
77
|
+
export function useRowLayout(
|
|
78
|
+
props: BaseListCardProps,
|
|
79
|
+
shell: ReturnType<typeof useRowShell>,
|
|
80
|
+
expandable: boolean,
|
|
81
|
+
): ReturnType<typeof useResolvedCells> & { opens: boolean; stack: StackPlacement } {
|
|
82
|
+
const resolved = useResolvedCells(props, shell.group != null, rowGutters(props, shell));
|
|
83
|
+
const cells = resolved.configured ? resolved.cells : null;
|
|
84
|
+
return {
|
|
85
|
+
...resolved,
|
|
86
|
+
opens: rowOpens(props, shell, resolved.configured, expandable),
|
|
87
|
+
stack: {
|
|
88
|
+
firstCell: cells?.[0]?.id ?? null,
|
|
89
|
+
valueCell: cells == null ? null : valueCellId(cells),
|
|
90
|
+
expandable,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* A standalone row's QUERY CONTAINER. A container query matches an ancestor,
|
|
97
|
+
* never the element itself, so the row cannot be the container its own
|
|
98
|
+
* two-line template asks about. In a group the group is the container, and the
|
|
99
|
+
* row must stay its direct child for subgrid, so no wrapper there.
|
|
100
|
+
*/
|
|
101
|
+
export function StandaloneContainer({ inGroup, children }: { inGroup: boolean; children: ReactNode }): React.JSX.Element {
|
|
102
|
+
if (inGroup) return <>{children}</>;
|
|
103
|
+
return <Box sx={{ containerType: "inline-size", width: "100%", minWidth: 0 }}>{children}</Box>;
|
|
104
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
|
|
3
4
|
import { Fragment, type ReactNode } from "react";
|
|
4
5
|
|
|
5
6
|
import { DescriptionItem, type DescriptionItemProps } from "../DescriptionItem";
|
|
@@ -242,19 +243,34 @@ export function ListCardActions({
|
|
|
242
243
|
actions,
|
|
243
244
|
alwaysVisible,
|
|
244
245
|
menu,
|
|
246
|
+
opens = false,
|
|
245
247
|
testId,
|
|
246
248
|
}: {
|
|
247
249
|
actions?: ReactNode;
|
|
248
250
|
alwaysVisible?: boolean;
|
|
249
251
|
menu?: ReactNode;
|
|
252
|
+
/** End the row with the "this opens" chevron. */
|
|
253
|
+
opens?: boolean;
|
|
250
254
|
testId: (slot: string) => string | undefined;
|
|
251
255
|
}): React.JSX.Element | null {
|
|
252
|
-
if (actions == null && menu == null) return null;
|
|
256
|
+
if (actions == null && menu == null && !opens) return null;
|
|
253
257
|
return (
|
|
254
|
-
// z-index 1: above the stretched link, so these stay clickable.
|
|
258
|
+
// z-index 1: above the stretched link, so these stay clickable. The box
|
|
259
|
+
// itself lets clicks through (`pointer-events: none`, re-enabled on its
|
|
260
|
+
// children): only the controls inside it are meant to catch one, and the
|
|
261
|
+
// chevron, which re-disables it, must hand its click to the row or link
|
|
262
|
+
// underneath rather than swallow it.
|
|
255
263
|
<Box
|
|
256
264
|
data-slot="actions"
|
|
257
|
-
sx={{
|
|
265
|
+
sx={{
|
|
266
|
+
display: "flex",
|
|
267
|
+
alignItems: "center",
|
|
268
|
+
gap: 0.5,
|
|
269
|
+
position: "relative",
|
|
270
|
+
zIndex: 1,
|
|
271
|
+
pointerEvents: "none",
|
|
272
|
+
"& > *": { pointerEvents: "auto" },
|
|
273
|
+
}}
|
|
258
274
|
>
|
|
259
275
|
{actions && (
|
|
260
276
|
<Box
|
|
@@ -282,6 +298,31 @@ export function ListCardActions({
|
|
|
282
298
|
{menu}
|
|
283
299
|
</Box>
|
|
284
300
|
)}
|
|
301
|
+
{opens && <OpenChevron testId={testId("open")} />}
|
|
302
|
+
</Box>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* THE "THIS OPENS" CHEVRON, at the end of a row that leads somewhere.
|
|
308
|
+
*
|
|
309
|
+
* A row that navigates or opens a record looked exactly like a row that does
|
|
310
|
+
* nothing until a pointer hovered it, and a phone has no hover. Always visible —
|
|
311
|
+
* unlike `actions`, it is a statement about the row, not a control to reveal.
|
|
312
|
+
*
|
|
313
|
+
* Decorative to assistive tech (`aria-hidden`): the row itself is the button or
|
|
314
|
+
* the link, and already says so. It takes no click of its own for the same
|
|
315
|
+
* reason; the click falls through to the row.
|
|
316
|
+
*/
|
|
317
|
+
function OpenChevron({ testId }: { testId?: string }): React.JSX.Element {
|
|
318
|
+
return (
|
|
319
|
+
<Box
|
|
320
|
+
component="span"
|
|
321
|
+
aria-hidden
|
|
322
|
+
data-testid={testId}
|
|
323
|
+
sx={{ display: "flex", alignItems: "center", color: "text.secondary", pointerEvents: "none !important" }}
|
|
324
|
+
>
|
|
325
|
+
<KeyboardArrowRightIcon fontSize="small" />
|
|
285
326
|
</Box>
|
|
286
327
|
);
|
|
287
328
|
}
|
|
@@ -293,6 +334,7 @@ export function ListCardTail({
|
|
|
293
334
|
actions,
|
|
294
335
|
actionsAlwaysVisible,
|
|
295
336
|
menu,
|
|
337
|
+
opens,
|
|
296
338
|
testId,
|
|
297
339
|
}: {
|
|
298
340
|
value?: ReactNode;
|
|
@@ -301,6 +343,7 @@ export function ListCardTail({
|
|
|
301
343
|
actions?: ReactNode;
|
|
302
344
|
actionsAlwaysVisible?: boolean;
|
|
303
345
|
menu?: ReactNode;
|
|
346
|
+
opens?: boolean;
|
|
304
347
|
testId: (slot: string) => string | undefined;
|
|
305
348
|
}): React.JSX.Element {
|
|
306
349
|
return (
|
|
@@ -319,6 +362,7 @@ export function ListCardTail({
|
|
|
319
362
|
actions={actions}
|
|
320
363
|
alwaysVisible={actionsAlwaysVisible}
|
|
321
364
|
menu={menu}
|
|
365
|
+
opens={opens}
|
|
322
366
|
testId={testId}
|
|
323
367
|
/>
|
|
324
368
|
</>
|
|
@@ -11,10 +11,10 @@ import { type CardSurfaceProps } from "./card-surface";
|
|
|
11
11
|
import { DropIndicator } from "./data-views-drag";
|
|
12
12
|
import { useDisclosure } from "./base-list-card-disclosure";
|
|
13
13
|
import { actionProps, metaShape, rowStyles, useRowShell } from "./base-list-card-geometry";
|
|
14
|
+
import { StandaloneContainer, useRowLayout } from "./base-list-card-layout";
|
|
14
15
|
import { DiscloseSlot, DragSlot, SelectSlot } from "./base-list-card-gutters";
|
|
15
16
|
import { type DataViewsDensity } from "./data-views-layout-context";
|
|
16
|
-
import {
|
|
17
|
-
import { ListCardCells, cellTracks, useCellConfig, type ListCardCellConfig } from "./list-card-cells";
|
|
17
|
+
import { ListCardCells, type ListCardCellConfig } from "./list-card-cells";
|
|
18
18
|
import {
|
|
19
19
|
ListCardActions,
|
|
20
20
|
ListCardCaption,
|
|
@@ -41,7 +41,16 @@ import {
|
|
|
41
41
|
* same row renders full-bleed on a phone, in a 300px board column, and beside a
|
|
42
42
|
* filter panel that opens and closes. Below `STACK_BREAK` it leaves the shared
|
|
43
43
|
* rails entirely and goes two-line, which is the standard mobile transaction
|
|
44
|
-
* row and beats truncating everything: title
|
|
44
|
+
* row and beats truncating everything: the title (with its subtitle) on line
|
|
45
|
+
* 1, the value under it at the right edge.
|
|
46
|
+
* A CONFIGURED row keeps the same two facts — its first cell in the title's
|
|
47
|
+
* place, its `strong` (else last) cell in the value's — and drops the rest
|
|
48
|
+
* into the expandable body's job. Standalone, the card renders inside a
|
|
49
|
+
* wrapper that is the query container, since a row cannot query itself.
|
|
50
|
+
*
|
|
51
|
+
* A row that OPENS something (a click handler, or a link it renders) ends in a
|
|
52
|
+
* chevron saying so, at every width — unless it expands, where the disclosure
|
|
53
|
+
* chevron is the only arrow it carries.
|
|
45
54
|
*/
|
|
46
55
|
|
|
47
56
|
export interface BaseListCardProps extends CardSurfaceProps {
|
|
@@ -145,33 +154,6 @@ export interface BaseListCardProps extends CardSurfaceProps {
|
|
|
145
154
|
}
|
|
146
155
|
|
|
147
156
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Which cell config applies, and whether this row resolves its own tracks.
|
|
152
|
-
*
|
|
153
|
-
* The list's config wins over the card's: one declaration of the list's shape is
|
|
154
|
-
* the point, so a row inside a group cannot introduce a column of its own. And
|
|
155
|
-
* the template is standalone-only — inside a group the GROUP owns it and the row
|
|
156
|
-
* is subgrid over it, because a row resolving its own tracks is exactly what
|
|
157
|
-
* stops a list from lining up.
|
|
158
|
-
*/
|
|
159
|
-
function useResolvedCells(
|
|
160
|
-
props: BaseListCardProps,
|
|
161
|
-
inGroup: boolean,
|
|
162
|
-
): {
|
|
163
|
-
cells: readonly ListCardCellConfig<never>[] | null;
|
|
164
|
-
configured: boolean;
|
|
165
|
-
cellTemplate: string | null;
|
|
166
|
-
} {
|
|
167
|
-
const groupCells = useCellConfig();
|
|
168
|
-
const cells = groupCells ?? props.cells ?? null;
|
|
169
|
-
const configured = cells != null && cells.length > 0 && props.row != null;
|
|
170
|
-
const cellTemplate = configured && !inGroup ? cellRailsTemplate(cellTracks(cells)) : null;
|
|
171
|
-
return { cells, configured, cellTemplate };
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
157
|
/**
|
|
176
158
|
* The row's middle: either the list's configured cells, or the named slots.
|
|
177
159
|
*
|
|
@@ -185,6 +167,7 @@ function RowContent({
|
|
|
185
167
|
slot,
|
|
186
168
|
actionable,
|
|
187
169
|
meta,
|
|
170
|
+
opens,
|
|
188
171
|
}: {
|
|
189
172
|
card: BaseListCardProps;
|
|
190
173
|
cells: readonly ListCardCellConfig<never>[] | null;
|
|
@@ -192,6 +175,8 @@ function RowContent({
|
|
|
192
175
|
slot: (name: string) => string | undefined;
|
|
193
176
|
actionable: boolean;
|
|
194
177
|
meta: { columns: number; present: boolean };
|
|
178
|
+
/** Whether the row ends in the "this opens" chevron. */
|
|
179
|
+
opens: boolean;
|
|
195
180
|
}): React.JSX.Element {
|
|
196
181
|
if (configured && cells != null) {
|
|
197
182
|
return (
|
|
@@ -206,6 +191,7 @@ function RowContent({
|
|
|
206
191
|
actions={actionable ? card.actions : undefined}
|
|
207
192
|
alwaysVisible={card.actionsAlwaysVisible}
|
|
208
193
|
menu={card.menu}
|
|
194
|
+
opens={opens}
|
|
209
195
|
testId={slot}
|
|
210
196
|
/>
|
|
211
197
|
</>
|
|
@@ -227,6 +213,7 @@ function RowContent({
|
|
|
227
213
|
actions={actionable ? card.actions : undefined}
|
|
228
214
|
actionsAlwaysVisible={card.actionsAlwaysVisible}
|
|
229
215
|
menu={card.menu}
|
|
216
|
+
opens={opens}
|
|
230
217
|
testId={slot}
|
|
231
218
|
/>
|
|
232
219
|
</>
|
|
@@ -294,46 +281,56 @@ export function BaseListCard(props: BaseListCardProps): React.JSX.Element {
|
|
|
294
281
|
const { actionable, selectable, slot, drag, reserve, pad, padY, acts } = shell;
|
|
295
282
|
const meta = metaShape(props);
|
|
296
283
|
const disclosure = useDisclosure(props);
|
|
297
|
-
const { cells, configured, cellTemplate } =
|
|
284
|
+
const { cells, configured, cellTemplate, opens, stack } = useRowLayout(props, shell, disclosure.expandable);
|
|
298
285
|
|
|
299
286
|
return (
|
|
300
|
-
<
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
{
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
287
|
+
<StandaloneContainer inGroup={shell.group != null}>
|
|
288
|
+
<Card
|
|
289
|
+
variant="outlined"
|
|
290
|
+
className={props.className}
|
|
291
|
+
dataTestId={props.testId}
|
|
292
|
+
aria-label={props["aria-label"]}
|
|
293
|
+
aria-disabled={actionable ? undefined : true}
|
|
294
|
+
onContextMenu={props.onContextMenu}
|
|
295
|
+
{...(acts ? actionProps(onClick) : {})}
|
|
296
|
+
{...drag.itemProps}
|
|
297
|
+
// A PLAIN OBJECT: `Card` merges by spreading, so a function sx vanishes.
|
|
298
|
+
sx={rowStyles(props, shell, cellTemplate, stack)}
|
|
299
|
+
>
|
|
300
|
+
{drag.dropEdge != null && <DropIndicator edge={drag.dropEdge} />}
|
|
301
|
+
<DiscloseSlot
|
|
302
|
+
expandable={disclosure.expandable}
|
|
303
|
+
expanded={disclosure.expanded}
|
|
304
|
+
reserve={reserve}
|
|
305
|
+
onToggle={disclosure.toggle}
|
|
306
|
+
controls={disclosure.regionId}
|
|
307
|
+
testId={slot("disclose")}
|
|
308
|
+
/>
|
|
309
|
+
<DragSlot drag={drag} reserve={reserve} testId={slot("drag")} />
|
|
310
|
+
<SelectSlot
|
|
311
|
+
selectable={selectable}
|
|
312
|
+
selected={selected}
|
|
313
|
+
reserve={reserve}
|
|
314
|
+
onToggleSelect={props.onToggleSelect}
|
|
315
|
+
testId={slot("checkbox")}
|
|
316
|
+
/>
|
|
317
|
+
<Box data-slot="leading" sx={{ display: "flex", alignItems: "center" }}>
|
|
318
|
+
{props.leading}
|
|
319
|
+
</Box>
|
|
320
|
+
<RowContent
|
|
321
|
+
card={props}
|
|
322
|
+
cells={cells}
|
|
323
|
+
configured={configured}
|
|
324
|
+
slot={slot}
|
|
325
|
+
actionable={actionable}
|
|
326
|
+
meta={meta}
|
|
327
|
+
opens={opens}
|
|
328
|
+
/>
|
|
329
|
+
<ExpandableBody disclosure={disclosure} padY={padY} pad={pad}>
|
|
330
|
+
{props.children}
|
|
331
|
+
</ExpandableBody>
|
|
332
|
+
</Card>
|
|
333
|
+
</StandaloneContainer>
|
|
337
334
|
);
|
|
338
335
|
}
|
|
339
336
|
|
|
@@ -225,6 +225,13 @@ export interface DataViewsSelectionCopy {
|
|
|
225
225
|
clearSelection: string;
|
|
226
226
|
selectAll: string;
|
|
227
227
|
onThisPage(count: number): string;
|
|
228
|
+
/**
|
|
229
|
+
* The toolbar's count while rows are ticked: "1 selecionado". A plural, so a
|
|
230
|
+
* function. Keep it SHORT: at 320 it shares line 1 with the clear button and
|
|
231
|
+
* has about 118px — "20 itens selecionados" (135px) wrapped and stranded the
|
|
232
|
+
* divider before it; "20 selecionados" fits.
|
|
233
|
+
*/
|
|
234
|
+
selectedCount(count: number): string;
|
|
228
235
|
/** One row's checkbox, which carries no visible label of its own. */
|
|
229
236
|
selectRow: string;
|
|
230
237
|
/**
|
|
@@ -16,7 +16,7 @@ import type { ListGroupConfig } from "./list-card-rails";
|
|
|
16
16
|
import { InlineFilterControls } from "./data-views-inline-bar";
|
|
17
17
|
import { toOverflowFields, useFilterOverflow, type OverflowSplit } from "./data-views-overflow";
|
|
18
18
|
import { GridHeaderRow } from "./data-views-header-row";
|
|
19
|
-
import { resolveSelectionExtra, type SelectionExtraRender } from "./data-views-selection-extra";
|
|
19
|
+
import { allOnPageSelected, resolveSelectionExtra, type SelectionExtraRender } from "./data-views-selection-extra";
|
|
20
20
|
import { ShellToolbar } from "./data-views-shell-toolbar";
|
|
21
21
|
import type { DisplayPanelView } from "./data-views-display-panel";
|
|
22
22
|
import type { DataViewExport } from "./data-views-export";
|
|
@@ -284,6 +284,7 @@ function ShellStack<T extends Record<string, unknown>>({
|
|
|
284
284
|
rowActions={props.rowActions}
|
|
285
285
|
bulkActions={props.bulkActions}
|
|
286
286
|
selectionExtra={resolveSelectionExtra(props)}
|
|
287
|
+
allOnPageSelected={allOnPageSelected(c, props.getRowId)}
|
|
287
288
|
toolbarRightSlot={props.toolbarRightSlot}
|
|
288
289
|
compactControls={showInline && split.compactControls}
|
|
289
290
|
counterHidden={showInline && split.counterHidden}
|
|
@@ -47,6 +47,15 @@ export type SelectionExtraRender<T extends Record<string, unknown>> = (
|
|
|
47
47
|
* Returns `undefined` with nothing selected, so the toolbar renders no empty
|
|
48
48
|
* slot: a widening with nothing to widen is not a control.
|
|
49
49
|
*/
|
|
50
|
+
/** Every row the page is rendering is selected — and the page is not empty. */
|
|
51
|
+
export function allOnPageSelected<T extends Record<string, unknown>>(
|
|
52
|
+
c: DataViewsController<T>,
|
|
53
|
+
getRowId: (row: T) => string | number,
|
|
54
|
+
): boolean {
|
|
55
|
+
const page = c.matched;
|
|
56
|
+
return page.length > 0 && page.every((row) => c.selectedIds.has(getRowId(row)));
|
|
57
|
+
}
|
|
58
|
+
|
|
50
59
|
export function resolveSelectionExtra<T extends Record<string, unknown>>({
|
|
51
60
|
c,
|
|
52
61
|
getRowId,
|
|
@@ -61,7 +70,7 @@ export function resolveSelectionExtra<T extends Record<string, unknown>>({
|
|
|
61
70
|
return selectionExtra({
|
|
62
71
|
selectedRows: c.selectedRows,
|
|
63
72
|
clearSelection: c.clearSelection,
|
|
64
|
-
allOnPageSelected:
|
|
73
|
+
allOnPageSelected: allOnPageSelected(c, getRowId),
|
|
65
74
|
pageRowCount: page.length,
|
|
66
75
|
});
|
|
67
76
|
}
|