@multiplatform.one/table-primitives 7.45.1 → 7.47.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/cjs/index.cjs +186 -29
- package/dist/cjs/index.native.js +202 -37
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/esm/index.mjs +185 -33
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +201 -41
- package/dist/esm/index.native.js.map +1 -1
- package/dist/jsx/index.js +185 -33
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +185 -33
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +202 -37
- package/dist/jsx/index.native.js.map +1 -1
- package/package.json +4 -4
- package/src/index.tsx +252 -40
- package/types/index.d.ts +55 -8
- package/types/index.d.ts.map +1 -1
package/src/index.tsx
CHANGED
|
@@ -6,21 +6,27 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
+
edgeColorAt,
|
|
9
10
|
hairline,
|
|
10
11
|
MIN_PRESS_TARGET,
|
|
12
|
+
PageGutter,
|
|
11
13
|
Surface,
|
|
12
14
|
transitionProps,
|
|
15
|
+
usePhoneTableBleed,
|
|
13
16
|
useResolvedKnobs,
|
|
14
17
|
sizeTokenStop,
|
|
18
|
+
SizableText,
|
|
19
|
+
type PhoneTableBleed,
|
|
15
20
|
} from "@multiplatform.one/theme";
|
|
16
21
|
import { TableCellContext } from "./tableCellContext";
|
|
17
22
|
import { wrapBareTextChildren } from "./textRidesText";
|
|
18
23
|
import { Children, Fragment, createContext, isValidElement, useContext } from "react";
|
|
19
|
-
import type { FontSizeTokens, SizeTokens } from "tamagui";
|
|
24
|
+
import type { FontSizeTokens, SizeTokens, SpaceTokens } from "tamagui";
|
|
20
25
|
import {
|
|
21
|
-
SizableText,
|
|
26
|
+
SizableText as TamaguiSizableText,
|
|
22
27
|
Theme,
|
|
23
28
|
ThemeableStack,
|
|
29
|
+
YStack,
|
|
24
30
|
createStyledContext,
|
|
25
31
|
isWeb,
|
|
26
32
|
styled,
|
|
@@ -263,6 +269,122 @@ export function tablePressFill(restFill: unknown): `$color${number}` {
|
|
|
263
269
|
return `$color${Math.max(step + 1, 4)}`;
|
|
264
270
|
}
|
|
265
271
|
|
|
272
|
+
// LC-146 PHONE-TABLE-BLEED: below `$sm` a table on the page line runs edge to
|
|
273
|
+
// edge, and the gutter it dropped becomes the inset of each row's first and
|
|
274
|
+
// last cell, so text stays on the page line while rows reach the screen edge.
|
|
275
|
+
const TableEdgeInsetContext = createContext<string | null>(null);
|
|
276
|
+
|
|
277
|
+
type CellEdge = "first" | "last" | "only";
|
|
278
|
+
const CellEdgeContext = createContext<CellEdge | undefined>(undefined);
|
|
279
|
+
|
|
280
|
+
/** The gutter the cells of the enclosing table take at its edges, or null. */
|
|
281
|
+
export function useTableEdgeInset(): string | null {
|
|
282
|
+
return useContext(TableEdgeInsetContext);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Hands every row a full-bleed table's edge inset. Hosts that bleed their own
|
|
287
|
+
* outer frame (a scroll viewport around the Table) wrap custom rows in it;
|
|
288
|
+
* the Table primitive provides it itself.
|
|
289
|
+
*/
|
|
290
|
+
export function TableEdgeInset({
|
|
291
|
+
inset,
|
|
292
|
+
children,
|
|
293
|
+
}: {
|
|
294
|
+
inset: string | null;
|
|
295
|
+
children: React.ReactNode;
|
|
296
|
+
}) {
|
|
297
|
+
return (
|
|
298
|
+
<TableEdgeInsetContext.Provider value={inset}>
|
|
299
|
+
<PageGutter inset={null}>{children}</PageGutter>
|
|
300
|
+
</TableEdgeInsetContext.Provider>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function isRtlDocument(): boolean {
|
|
305
|
+
return isWeb && typeof document !== "undefined" && document.documentElement?.dir === "rtl";
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* The horizontal padding of an edge cell: the gutter on the outer side, the
|
|
310
|
+
* cell's own padding on the inner side. Native takes logical edges (Yoga lets
|
|
311
|
+
* start/end win over left/right); web writes the physical sides so they
|
|
312
|
+
* replace the cell's own `paddingHorizontal` instead of racing it in CSS.
|
|
313
|
+
*/
|
|
314
|
+
function cellEdgePadding(
|
|
315
|
+
edge: CellEdge,
|
|
316
|
+
inset: string,
|
|
317
|
+
own: { paddingHorizontal?: unknown; paddingLeft?: unknown; paddingRight?: unknown },
|
|
318
|
+
): Record<string, unknown> {
|
|
319
|
+
const start = edge === "first" || edge === "only";
|
|
320
|
+
const end = edge === "last" || edge === "only";
|
|
321
|
+
if (!isWeb) {
|
|
322
|
+
return {
|
|
323
|
+
...(start ? { paddingStart: inset } : {}),
|
|
324
|
+
...(end ? { paddingEnd: inset } : {}),
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const rtl = isRtlDocument();
|
|
328
|
+
const left = rtl ? end : start;
|
|
329
|
+
const right = rtl ? start : end;
|
|
330
|
+
return {
|
|
331
|
+
paddingLeft: left ? inset : (own.paddingLeft ?? own.paddingHorizontal),
|
|
332
|
+
paddingRight: right ? inset : (own.paddingRight ?? own.paddingHorizontal),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** Marks a row's first and last element children for their edge inset. */
|
|
337
|
+
function markEdgeCells(children: React.ReactNode): React.ReactNode {
|
|
338
|
+
const cells = flattenChildren(children).filter(isValidElement);
|
|
339
|
+
return cells.map((cell, index) => {
|
|
340
|
+
const edge: CellEdge | undefined =
|
|
341
|
+
cells.length === 1
|
|
342
|
+
? "only"
|
|
343
|
+
: index === 0
|
|
344
|
+
? "first"
|
|
345
|
+
: index === cells.length - 1
|
|
346
|
+
? "last"
|
|
347
|
+
: undefined;
|
|
348
|
+
return (
|
|
349
|
+
<CellEdgeContext.Provider key={cell.key ?? index} value={edge}>
|
|
350
|
+
{cell}
|
|
351
|
+
</CellEdgeContext.Provider>
|
|
352
|
+
);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Marks the first and last cells of a row that is not a Table.Row (a
|
|
358
|
+
* virtualized host's div rows) for the enclosing table's edge inset.
|
|
359
|
+
*/
|
|
360
|
+
export function TableEdgeCells({ children }: { children: React.ReactNode }) {
|
|
361
|
+
const inset = useContext(TableEdgeInsetContext);
|
|
362
|
+
return <>{inset ? markEdgeCells(children) : children}</>;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* LC-146 recipe for one row of a full-bleed card or document list: no card
|
|
367
|
+
* chrome at the screen edge, a hairline between rows, and the gutter as the
|
|
368
|
+
* row's horizontal inset.
|
|
369
|
+
*/
|
|
370
|
+
export function phoneBleedRowProps(inset: string) {
|
|
371
|
+
return {
|
|
372
|
+
borderRadius: 0,
|
|
373
|
+
borderWidth: 0,
|
|
374
|
+
...hairline.bottom,
|
|
375
|
+
borderColor: "$borderColor",
|
|
376
|
+
elevation: 0,
|
|
377
|
+
shadowColor: "transparent",
|
|
378
|
+
paddingLeft: inset,
|
|
379
|
+
paddingRight: inset,
|
|
380
|
+
} as const;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** LC-146 recipe for a full-bleed list frame: out to the screen edges, rows abut. */
|
|
384
|
+
export function phoneBleedListProps(bleed: Pick<PhoneTableBleed, "frame"> | null) {
|
|
385
|
+
return { ...(bleed ? bleed.frame : {}), gap: 0 } as const;
|
|
386
|
+
}
|
|
387
|
+
|
|
266
388
|
const BodyRowIndexContext = createContext<number | undefined>(undefined);
|
|
267
389
|
|
|
268
390
|
function indexBodyRows(children: React.ReactNode, counter: { next: number }): React.ReactNode {
|
|
@@ -275,6 +397,8 @@ function indexBodyRows(children: React.ReactNode, counter: { next: number }): Re
|
|
|
275
397
|
</Fragment>
|
|
276
398
|
);
|
|
277
399
|
}
|
|
400
|
+
// A hidden row (DataTable's filler and clip fade) is chrome, not a record.
|
|
401
|
+
if ((child.props as { "aria-hidden"?: unknown })["aria-hidden"] === true) return child;
|
|
278
402
|
return (
|
|
279
403
|
<BodyRowIndexContext.Provider value={counter.next++}>{child}</BodyRowIndexContext.Provider>
|
|
280
404
|
);
|
|
@@ -521,9 +645,13 @@ function extractCardModel(children: React.ReactNode): {
|
|
|
521
645
|
/** Card list rendering for the Table primitive (layout="cards" / narrow auto). */
|
|
522
646
|
function TableCardsList({
|
|
523
647
|
children,
|
|
648
|
+
edgeInset,
|
|
649
|
+
selfBleed,
|
|
524
650
|
...props
|
|
525
651
|
}: {
|
|
526
652
|
children?: React.ReactNode;
|
|
653
|
+
edgeInset?: string | null;
|
|
654
|
+
selfBleed?: PhoneTableBleed | null;
|
|
527
655
|
[key: string]: any;
|
|
528
656
|
}) {
|
|
529
657
|
const { knobProps } = useResolvedKnobs();
|
|
@@ -551,15 +679,21 @@ function TableCardsList({
|
|
|
551
679
|
unknown
|
|
552
680
|
>)}
|
|
553
681
|
{...viewProps}
|
|
682
|
+
{...(edgeInset ? phoneBleedListProps(selfBleed ?? null) : {})}
|
|
683
|
+
{...(edgeInset ? ({ "data-phone-bleed": "true" } as Record<string, unknown>) : {})}
|
|
554
684
|
>
|
|
555
|
-
{caption != null &&
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
685
|
+
{caption != null && (
|
|
686
|
+
// LC-146: the caption stays on the page line while the cards bleed.
|
|
687
|
+
<YStack {...(edgeInset ? { paddingHorizontal: edgeInset as SpaceTokens } : {})}>
|
|
688
|
+
{typeof caption === "string" || typeof caption === "number" ? (
|
|
689
|
+
<SizableText fontSize={knobProps.sizeToken as FontSizeTokens} color="$color10">
|
|
690
|
+
{caption}
|
|
691
|
+
</SizableText>
|
|
692
|
+
) : (
|
|
693
|
+
caption
|
|
694
|
+
)}
|
|
695
|
+
</YStack>
|
|
696
|
+
)}
|
|
563
697
|
{rows.map((row, rowIndex) => {
|
|
564
698
|
const stripe = tableZebraStripe(knobProps.tableZebra, rowIndex);
|
|
565
699
|
const card = (
|
|
@@ -568,13 +702,17 @@ function TableCardsList({
|
|
|
568
702
|
testID="table-card"
|
|
569
703
|
{...knobProps.surface}
|
|
570
704
|
{...knobProps.cardSurface}
|
|
571
|
-
elevation={knobProps.elevation}
|
|
572
705
|
{...motion}
|
|
573
|
-
borderColor="$color6"
|
|
574
706
|
{...(stripe === "odd"
|
|
575
707
|
? { backgroundColor: tableZebraFill(knobProps.cardSurface.backgroundColor) }
|
|
576
708
|
: {})}
|
|
577
709
|
{...(row.intent ? { backgroundColor: "$color3" as const } : {})}
|
|
710
|
+
{...(edgeInset
|
|
711
|
+
? phoneBleedRowProps(edgeInset)
|
|
712
|
+
: {
|
|
713
|
+
elevation: knobProps.elevation,
|
|
714
|
+
borderColor: edgeColorAt("$color6", knobProps.borderWidthStop),
|
|
715
|
+
})}
|
|
578
716
|
{...({ "data-table-zebra": stripe } as Record<string, unknown>)}
|
|
579
717
|
>
|
|
580
718
|
{row.cells.map((cell, index) => {
|
|
@@ -627,6 +765,13 @@ export interface ThemedTableProps extends Omit<React.ComponentProps<typeof Table
|
|
|
627
765
|
size?: SizeTokens;
|
|
628
766
|
/** Size key every cell's Surface forwards to its content. Default `size`, else `$3`. */
|
|
629
767
|
cellSize?: SizeTokens;
|
|
768
|
+
/**
|
|
769
|
+
* LC-146: the gutter each row's first and last cell take as their inset
|
|
770
|
+
* when the table runs edge to edge below `$sm`. Omitted, a Table on the page
|
|
771
|
+
* line bleeds itself; a host that bleeds its own outer frame (a scroll
|
|
772
|
+
* viewport) passes the inset; null keeps the table inside the gutter.
|
|
773
|
+
*/
|
|
774
|
+
edgeInset?: string | null;
|
|
630
775
|
}
|
|
631
776
|
|
|
632
777
|
/** The size key every cell's Surface forwards to its content (default `$3`). */
|
|
@@ -645,44 +790,81 @@ function ThemedTableComp({ size, cellSize, ...props }: ThemedTableProps) {
|
|
|
645
790
|
|
|
646
791
|
function ThemedTableFrame({
|
|
647
792
|
layout = "table",
|
|
793
|
+
edgeInset,
|
|
648
794
|
...props
|
|
649
795
|
}: Omit<ThemedTableProps, "size" | "cellSize">) {
|
|
650
796
|
const { knobProps } = useResolvedKnobs();
|
|
651
797
|
const { sm } = useMedia();
|
|
798
|
+
const bleed = usePhoneTableBleed();
|
|
799
|
+
// LC-146: auto-bleed only when no host has decided for the table.
|
|
800
|
+
const selfBleed = edgeInset === undefined ? bleed : null;
|
|
801
|
+
const inset = edgeInset === undefined ? (bleed?.inset ?? null) : edgeInset;
|
|
652
802
|
// LC-86: resolveKnobs already floors outlined+none to the hairline (0.5).
|
|
653
803
|
const resolvedBorderWidth = knobProps.surface.borderWidth;
|
|
654
804
|
|
|
655
805
|
const showCards = layout === "cards" || (layout === "auto" && sm === false);
|
|
656
806
|
if (showCards) {
|
|
657
|
-
return
|
|
807
|
+
return (
|
|
808
|
+
<PageGutter inset={null}>
|
|
809
|
+
<TableCardsList {...props} edgeInset={inset} selfBleed={selfBleed} />
|
|
810
|
+
</PageGutter>
|
|
811
|
+
);
|
|
658
812
|
}
|
|
659
813
|
|
|
660
814
|
const motion = transitionProps(knobProps.motion.control);
|
|
815
|
+
const table = (
|
|
816
|
+
<TableComp
|
|
817
|
+
// Table frames are R-OUTER + SF-CARD-tier surface (theme-propagation-spec
|
|
818
|
+
// `@multiplatform.one/table-primitives`): outer corners follow the capped
|
|
819
|
+
// outer radius map; like the card list, the fill never takes the
|
|
820
|
+
// control flip.
|
|
821
|
+
{...knobProps.surface}
|
|
822
|
+
{...knobProps.borderRadiusNested}
|
|
823
|
+
borderWidth={resolvedBorderWidth}
|
|
824
|
+
elevation={knobProps.elevation}
|
|
825
|
+
{...motion}
|
|
826
|
+
// Size knob sets default row height through the table context; consumer
|
|
827
|
+
// cellHeight (table- or cell-level) still overrides via {...props}.
|
|
828
|
+
cellHeight={knobProps.sizeToken as SizeTokens}
|
|
829
|
+
{...({ "data-animation": knobProps.motion.control.transition ? "on" : "none" } as Record<
|
|
830
|
+
string,
|
|
831
|
+
unknown
|
|
832
|
+
>)}
|
|
833
|
+
{...props}
|
|
834
|
+
// A full-bleed table has no side frame: the screen edge is its edge.
|
|
835
|
+
{...(inset
|
|
836
|
+
? {
|
|
837
|
+
borderLeftWidth: 0,
|
|
838
|
+
borderRightWidth: 0,
|
|
839
|
+
borderRadius: 0,
|
|
840
|
+
...({ "data-phone-bleed": "true" } as Record<string, unknown>),
|
|
841
|
+
}
|
|
842
|
+
: {})}
|
|
843
|
+
// borderSpacing 0 neutralizes the real <table> UA default (2px gaps
|
|
844
|
+
// between cells) so the migrated element keeps the div-table look.
|
|
845
|
+
style={[{ tableLayout: "fixed" as const, borderSpacing: 0 }, props.style]}
|
|
846
|
+
>
|
|
847
|
+
<TableEdgeInset inset={inset}>{props.children}</TableEdgeInset>
|
|
848
|
+
</TableComp>
|
|
849
|
+
);
|
|
661
850
|
return (
|
|
662
851
|
// A table nested in a body cell must not stripe its rows by the outer index.
|
|
663
852
|
<BodyRowIndexContext.Provider value={undefined}>
|
|
664
|
-
|
|
665
|
-
//
|
|
666
|
-
//
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
unknown
|
|
680
|
-
>)}
|
|
681
|
-
{...props}
|
|
682
|
-
// borderSpacing 0 neutralizes the real <table> UA default (2px gaps
|
|
683
|
-
// between cells) so the migrated element keeps the div-table look.
|
|
684
|
-
style={[{ tableLayout: "fixed" as const, borderSpacing: 0 }, props.style]}
|
|
685
|
-
/>
|
|
853
|
+
{selfBleed ? (
|
|
854
|
+
// The table keeps width 100%, which ignores a negative end margin, so
|
|
855
|
+
// a plain stack takes the bleed and the table fills it.
|
|
856
|
+
<YStack
|
|
857
|
+
{...selfBleed.frame}
|
|
858
|
+
alignSelf="stretch"
|
|
859
|
+
{...((props.displayMode ?? (isWeb ? "table" : "flex")) === "flex"
|
|
860
|
+
? { flexGrow: 1, flexShrink: 1, flexBasis: "auto" as const, minHeight: 0 }
|
|
861
|
+
: {})}
|
|
862
|
+
>
|
|
863
|
+
{table}
|
|
864
|
+
</YStack>
|
|
865
|
+
) : (
|
|
866
|
+
table
|
|
867
|
+
)}
|
|
686
868
|
</BodyRowIndexContext.Provider>
|
|
687
869
|
);
|
|
688
870
|
}
|
|
@@ -700,6 +882,11 @@ function ThemedTableHead(props: React.ComponentProps<typeof TableHead>) {
|
|
|
700
882
|
function ThemedRow({ accent, error, warning, success, ...props }: ThemedRowProps) {
|
|
701
883
|
const { knobProps } = useResolvedKnobs();
|
|
702
884
|
const context = TableContext.useStyledContext();
|
|
885
|
+
const edgeInset = useContext(TableEdgeInsetContext);
|
|
886
|
+
// A presentation row only hosts nested rows (the virtualized body), which
|
|
887
|
+
// mark their own edge cells through TableEdgeCells.
|
|
888
|
+
const children =
|
|
889
|
+
edgeInset && props.role !== "presentation" ? markEdgeCells(props.children) : props.children;
|
|
703
890
|
const motion = transitionProps(knobProps.motion.control);
|
|
704
891
|
const intent = resolveIntent({ accent, error, warning, success } as ThemedRowProps);
|
|
705
892
|
const bodyIndex = useContext(BodyRowIndexContext);
|
|
@@ -742,7 +929,9 @@ function ThemedRow({ accent, error, warning, success, ...props }: ThemedRowProps
|
|
|
742
929
|
{...(stripe === "odd" && !intent && props.backgroundColor == null
|
|
743
930
|
? { backgroundColor: tableZebraFill(knobProps.surface.backgroundColor) }
|
|
744
931
|
: {})}
|
|
745
|
-
|
|
932
|
+
>
|
|
933
|
+
{children}
|
|
934
|
+
</Row>
|
|
746
935
|
);
|
|
747
936
|
|
|
748
937
|
if (intent) {
|
|
@@ -787,7 +976,7 @@ function TableCellSurfaceBody({
|
|
|
787
976
|
// fontWeight like any body text (MPO-446); the weight is the last prop so
|
|
788
977
|
// no size or family variant paints the font ramp's weight over it.
|
|
789
978
|
return wrapBareTextChildren(children, (label, key) => (
|
|
790
|
-
<
|
|
979
|
+
<TamaguiSizableText
|
|
791
980
|
key={key}
|
|
792
981
|
{...(isHeader ? {} : body)}
|
|
793
982
|
fontSize={knobProps.sizeToken as FontSizeTokens}
|
|
@@ -805,22 +994,42 @@ function TableCellSurfaceBody({
|
|
|
805
994
|
fontWeight={isHeader ? "600" : (bodyWeight as "400")}
|
|
806
995
|
>
|
|
807
996
|
{label}
|
|
808
|
-
</
|
|
997
|
+
</TamaguiSizableText>
|
|
809
998
|
));
|
|
810
999
|
}
|
|
811
1000
|
|
|
1001
|
+
function useCellEdgePadding(
|
|
1002
|
+
own: Record<string, unknown>,
|
|
1003
|
+
base: { paddingHorizontal: string },
|
|
1004
|
+
): Record<string, unknown> | null {
|
|
1005
|
+
const inset = useContext(TableEdgeInsetContext);
|
|
1006
|
+
const edge = useContext(CellEdgeContext);
|
|
1007
|
+
if (!inset || !edge) return null;
|
|
1008
|
+
return {
|
|
1009
|
+
...cellEdgePadding(edge, inset, {
|
|
1010
|
+
paddingHorizontal: own.paddingHorizontal ?? base.paddingHorizontal,
|
|
1011
|
+
paddingLeft: own.paddingLeft,
|
|
1012
|
+
paddingRight: own.paddingRight,
|
|
1013
|
+
}),
|
|
1014
|
+
"data-cell-edge": edge,
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
|
|
812
1018
|
function ThemedCell({ children, style, ...props }: React.ComponentProps<typeof Cell>) {
|
|
813
1019
|
const { knobProps } = useResolvedKnobs();
|
|
814
1020
|
const motion = transitionProps(knobProps.motion.control);
|
|
1021
|
+
const base = getTableCellPadding(sizeTokenStop(knobProps.sizeToken));
|
|
1022
|
+
const edgePadding = useCellEdgePadding(props as Record<string, unknown>, base);
|
|
815
1023
|
return (
|
|
816
1024
|
<Cell
|
|
817
|
-
{...
|
|
1025
|
+
{...base}
|
|
818
1026
|
{...motion}
|
|
819
1027
|
{...({ "data-animation": knobProps.motion.control.transition ? "on" : "none" } as Record<
|
|
820
1028
|
string,
|
|
821
1029
|
unknown
|
|
822
1030
|
>)}
|
|
823
1031
|
{...props}
|
|
1032
|
+
{...edgePadding}
|
|
824
1033
|
// Compose (not replace) the inline style so a consumer style (e.g.
|
|
825
1034
|
// sticky pinned cells) keeps the verticalAlign baseline.
|
|
826
1035
|
style={[{ verticalAlign: "middle" }, style as any]}
|
|
@@ -833,15 +1042,18 @@ function ThemedCell({ children, style, ...props }: React.ComponentProps<typeof C
|
|
|
833
1042
|
function ThemedHeaderCell({ children, style, ...props }: React.ComponentProps<typeof HeaderCell>) {
|
|
834
1043
|
const { knobProps } = useResolvedKnobs();
|
|
835
1044
|
const motion = transitionProps(knobProps.motion.control);
|
|
1045
|
+
const base = getTableCellPadding(sizeTokenStop(knobProps.sizeToken));
|
|
1046
|
+
const edgePadding = useCellEdgePadding(props as Record<string, unknown>, base);
|
|
836
1047
|
return (
|
|
837
1048
|
<HeaderCell
|
|
838
|
-
{...
|
|
1049
|
+
{...base}
|
|
839
1050
|
{...motion}
|
|
840
1051
|
{...({ "data-animation": knobProps.motion.control.transition ? "on" : "none" } as Record<
|
|
841
1052
|
string,
|
|
842
1053
|
unknown
|
|
843
1054
|
>)}
|
|
844
1055
|
{...props}
|
|
1056
|
+
{...edgePadding}
|
|
845
1057
|
// Compose (not replace) the inline style so consumer styles (sticky
|
|
846
1058
|
// pinned headers) keep the real-<th> UA neutralizers (bold/centered).
|
|
847
1059
|
style={[{ verticalAlign: "middle", fontWeight: "normal", textAlign: "start" }, style as any]}
|
package/types/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Layer 1 only: depends on theme + Tamagui (no forms, no data-table).
|
|
5
5
|
* Consumed by @multiplatform.one/table, @multiplatform.one/forms, etc.
|
|
6
6
|
*/
|
|
7
|
+
import { type PhoneTableBleed } from "@multiplatform.one/theme";
|
|
7
8
|
import type { SizeTokens } from "tamagui";
|
|
8
9
|
export { TableCellContext, useIsInTableCell, useTableCellContext } from "./tableCellContext";
|
|
9
10
|
export type { TableCellContextValue } from "./tableCellContext";
|
|
@@ -27,8 +28,8 @@ type AlignCells = {
|
|
|
27
28
|
declare const Row: import("tamagui").TamaguiComponent<import("@tamagui/web").TamaDefer, import("tamagui").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/web").StackStyleBase, {
|
|
28
29
|
elevation?: number | SizeTokens | undefined;
|
|
29
30
|
transparent?: boolean | undefined;
|
|
30
|
-
fullscreen?: boolean | undefined;
|
|
31
31
|
circular?: boolean | undefined;
|
|
32
|
+
fullscreen?: boolean | undefined;
|
|
32
33
|
elevate?: boolean | undefined;
|
|
33
34
|
bordered?: boolean | undefined;
|
|
34
35
|
chromeless?: boolean | "all" | undefined;
|
|
@@ -38,8 +39,8 @@ declare const Row: import("tamagui").TamaguiComponent<import("@tamagui/web").Tam
|
|
|
38
39
|
declare const Cell: import("tamagui").TamaguiComponent<import("@tamagui/web").TamaDefer, import("tamagui").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/web").StackStyleBase, {
|
|
39
40
|
elevation?: number | SizeTokens | undefined;
|
|
40
41
|
transparent?: boolean | undefined;
|
|
41
|
-
fullscreen?: boolean | undefined;
|
|
42
42
|
circular?: boolean | undefined;
|
|
43
|
+
fullscreen?: boolean | undefined;
|
|
43
44
|
elevate?: boolean | undefined;
|
|
44
45
|
bordered?: boolean | undefined;
|
|
45
46
|
chromeless?: boolean | "all" | undefined;
|
|
@@ -52,8 +53,8 @@ declare const Cell: import("tamagui").TamaguiComponent<import("@tamagui/web").Ta
|
|
|
52
53
|
declare const HeaderCell: import("tamagui").TamaguiComponent<import("@tamagui/web").TamaDefer, import("tamagui").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/web").StackStyleBase, {
|
|
53
54
|
elevation?: number | SizeTokens | undefined;
|
|
54
55
|
transparent?: boolean | undefined;
|
|
55
|
-
fullscreen?: boolean | undefined;
|
|
56
56
|
circular?: boolean | undefined;
|
|
57
|
+
fullscreen?: boolean | undefined;
|
|
57
58
|
elevate?: boolean | undefined;
|
|
58
59
|
bordered?: boolean | undefined;
|
|
59
60
|
chromeless?: boolean | "all" | undefined;
|
|
@@ -67,11 +68,50 @@ export type TableZebraStripe = "off" | "even" | "odd";
|
|
|
67
68
|
export declare function tableZebraStripe(tableZebra: unknown, index: number): TableZebraStripe;
|
|
68
69
|
export declare function tableZebraFill(hostFill: unknown): `$color${number}`;
|
|
69
70
|
export declare function tablePressFill(restFill: unknown): `$color${number}`;
|
|
71
|
+
/** The gutter the cells of the enclosing table take at its edges, or null. */
|
|
72
|
+
export declare function useTableEdgeInset(): string | null;
|
|
73
|
+
/**
|
|
74
|
+
* Hands every row a full-bleed table's edge inset. Hosts that bleed their own
|
|
75
|
+
* outer frame (a scroll viewport around the Table) wrap custom rows in it;
|
|
76
|
+
* the Table primitive provides it itself.
|
|
77
|
+
*/
|
|
78
|
+
export declare function TableEdgeInset({ inset, children, }: {
|
|
79
|
+
inset: string | null;
|
|
80
|
+
children: React.ReactNode;
|
|
81
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
82
|
+
/**
|
|
83
|
+
* Marks the first and last cells of a row that is not a Table.Row (a
|
|
84
|
+
* virtualized host's div rows) for the enclosing table's edge inset.
|
|
85
|
+
*/
|
|
86
|
+
export declare function TableEdgeCells({ children }: {
|
|
87
|
+
children: React.ReactNode;
|
|
88
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
89
|
+
/**
|
|
90
|
+
* LC-146 recipe for one row of a full-bleed card or document list: no card
|
|
91
|
+
* chrome at the screen edge, a hairline between rows, and the gutter as the
|
|
92
|
+
* row's horizontal inset.
|
|
93
|
+
*/
|
|
94
|
+
export declare function phoneBleedRowProps(inset: string): {
|
|
95
|
+
readonly borderColor: "$borderColor";
|
|
96
|
+
readonly elevation: 0;
|
|
97
|
+
readonly shadowColor: "transparent";
|
|
98
|
+
readonly paddingLeft: string;
|
|
99
|
+
readonly paddingRight: string;
|
|
100
|
+
readonly borderBottomWidth: number;
|
|
101
|
+
readonly className: "mp-hairline-b";
|
|
102
|
+
readonly borderRadius: 0;
|
|
103
|
+
readonly borderWidth: 0;
|
|
104
|
+
};
|
|
105
|
+
/** LC-146 recipe for a full-bleed list frame: out to the screen edges, rows abut. */
|
|
106
|
+
export declare function phoneBleedListProps(bleed: Pick<PhoneTableBleed, "frame"> | null): {
|
|
107
|
+
readonly gap: 0;
|
|
108
|
+
readonly marginHorizontal?: string | undefined;
|
|
109
|
+
};
|
|
70
110
|
declare const TableBody: import("tamagui").TamaguiComponent<import("@tamagui/web").TamaDefer, import("tamagui").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/web").StackStyleBase, {
|
|
71
111
|
elevation?: number | SizeTokens | undefined;
|
|
72
112
|
transparent?: boolean | undefined;
|
|
73
|
-
fullscreen?: boolean | undefined;
|
|
74
113
|
circular?: boolean | undefined;
|
|
114
|
+
fullscreen?: boolean | undefined;
|
|
75
115
|
elevate?: boolean | undefined;
|
|
76
116
|
bordered?: boolean | undefined;
|
|
77
117
|
chromeless?: boolean | "all" | undefined;
|
|
@@ -80,8 +120,8 @@ declare const TableBody: import("tamagui").TamaguiComponent<import("@tamagui/web
|
|
|
80
120
|
declare const TableHead: import("tamagui").TamaguiComponent<import("@tamagui/web").TamaDefer, import("tamagui").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/web").StackStyleBase, {
|
|
81
121
|
elevation?: number | SizeTokens | undefined;
|
|
82
122
|
transparent?: boolean | undefined;
|
|
83
|
-
fullscreen?: boolean | undefined;
|
|
84
123
|
circular?: boolean | undefined;
|
|
124
|
+
fullscreen?: boolean | undefined;
|
|
85
125
|
elevate?: boolean | undefined;
|
|
86
126
|
bordered?: boolean | undefined;
|
|
87
127
|
chromeless?: boolean | "all" | undefined;
|
|
@@ -90,8 +130,8 @@ declare const TableHead: import("tamagui").TamaguiComponent<import("@tamagui/web
|
|
|
90
130
|
declare const TableFoot: import("tamagui").TamaguiComponent<import("@tamagui/web").TamaDefer, import("tamagui").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/web").StackStyleBase, {
|
|
91
131
|
elevation?: number | SizeTokens | undefined;
|
|
92
132
|
transparent?: boolean | undefined;
|
|
93
|
-
fullscreen?: boolean | undefined;
|
|
94
133
|
circular?: boolean | undefined;
|
|
134
|
+
fullscreen?: boolean | undefined;
|
|
95
135
|
elevate?: boolean | undefined;
|
|
96
136
|
bordered?: boolean | undefined;
|
|
97
137
|
chromeless?: boolean | "all" | undefined;
|
|
@@ -109,8 +149,8 @@ declare const TableCaption: import("tamagui").TamaguiComponent<import("@tamagui/
|
|
|
109
149
|
declare const TableComp: import("tamagui").TamaguiComponent<import("@tamagui/web").TamaDefer, import("tamagui").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/web").StackStyleBase, {
|
|
110
150
|
elevation?: number | SizeTokens | undefined;
|
|
111
151
|
transparent?: boolean | undefined;
|
|
112
|
-
fullscreen?: boolean | undefined;
|
|
113
152
|
circular?: boolean | undefined;
|
|
153
|
+
fullscreen?: boolean | undefined;
|
|
114
154
|
elevate?: boolean | undefined;
|
|
115
155
|
bordered?: boolean | undefined;
|
|
116
156
|
chromeless?: boolean | "all" | undefined;
|
|
@@ -153,6 +193,13 @@ export interface ThemedTableProps extends Omit<React.ComponentProps<typeof Table
|
|
|
153
193
|
size?: SizeTokens;
|
|
154
194
|
/** Size key every cell's Surface forwards to its content. Default `size`, else `$3`. */
|
|
155
195
|
cellSize?: SizeTokens;
|
|
196
|
+
/**
|
|
197
|
+
* LC-146: the gutter each row's first and last cell take as their inset
|
|
198
|
+
* when the table runs edge to edge below `$sm`. Omitted, a Table on the page
|
|
199
|
+
* line bleeds itself; a host that bleeds its own outer frame (a scroll
|
|
200
|
+
* viewport) passes the inset; null keeps the table inside the gutter.
|
|
201
|
+
*/
|
|
202
|
+
edgeInset?: string | null;
|
|
156
203
|
}
|
|
157
204
|
declare function ThemedTableComp({ size, cellSize, ...props }: ThemedTableProps): import("react/jsx-runtime").JSX.Element;
|
|
158
205
|
declare function ThemedTableBody({ children, ...props }: React.ComponentProps<typeof TableBody>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -169,8 +216,8 @@ export declare const Table: typeof ThemedTableComp & {
|
|
|
169
216
|
Foot: import("tamagui").TamaguiComponent<import("@tamagui/web").TamaDefer, import("tamagui").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/web").StackStyleBase, {
|
|
170
217
|
elevation?: number | SizeTokens | undefined;
|
|
171
218
|
transparent?: boolean | undefined;
|
|
172
|
-
fullscreen?: boolean | undefined;
|
|
173
219
|
circular?: boolean | undefined;
|
|
220
|
+
fullscreen?: boolean | undefined;
|
|
174
221
|
elevate?: boolean | undefined;
|
|
175
222
|
bordered?: boolean | undefined;
|
|
176
223
|
chromeless?: boolean | "all" | undefined;
|
package/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|