@crispy-seed/data-table 0.6.0 → 0.8.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/index.d.ts CHANGED
@@ -57,15 +57,18 @@ interface ToolbarFilter {
57
57
  }
58
58
 
59
59
  /**
60
- * The six aggregations DATATABLE-ATTIO-SPEC.md's ColumnCalc footer offers (crisp's own
61
- * `ColumnCalc` ships nine -- adding percent-empty/-filled and a "none" clearing op --
62
- * but this table's contract is exactly the six named in the spec doc: count /
63
- * countFilled / sum / average / min / max). `count`/`countFilled` apply to every
64
- * column; `sum`/`average`/`min`/`max` only make sense on a numeric column, so the
65
- * styled layer only offers those four when the column's cell type is number/currency
66
- * (see DataTable.tsx's `ColumnCalcMenu`).
60
+ * Live-review fix (Attio/GRC parity): the ColumnCalc footer's own aggregation set --
61
+ * three apply to every column, six more to numeric ones, one more to non-numeric ones.
62
+ * Distinct from crisp's own `ColumnCalc` (`countEmpty`/`countFilled`/`percentEmpty`/
63
+ * `percentFilled` + sum/average/min/max + "none") -- crisp's own set was read for the
64
+ * MENU/trigger interaction (`column-calc.tsx`'s own doc comment), not copied op-for-op;
65
+ * this table's contract is the ten named directly in DATATABLE-ATTIO-SPEC.md/the GRC
66
+ * feature contract: count / empty / not-empty everywhere, sum / average / median / min
67
+ * / max / range on a numeric column, count-unique on a non-numeric one. The styled
68
+ * layer picks which extra set to offer off the column's own cell type (`column-calc.tsx`'s
69
+ * `ColumnCalcCell`).
67
70
  */
68
- type DataTableCalcOp = "count" | "countFilled" | "sum" | "average" | "min" | "max";
71
+ type DataTableCalcOp = "count" | "empty" | "notEmpty" | "sum" | "average" | "median" | "min" | "max" | "range" | "countUnique";
69
72
 
70
73
  /** Everything a saved view actually captures -- deliberately the same five controlled
71
74
  * props `useDataTableColumns` + the toolbar sort/filter hooks already expose, so
@@ -278,8 +281,9 @@ interface DataTableProps<TRow extends {
278
281
  sort?: DataTableSortState;
279
282
  /** 비제어 방식으로 사용할 때의 초기 정렬 상태입니다. */
280
283
  defaultSort?: DataTableSortState;
281
- /** 정렬 가능한 열을 클릭해 정렬 상태가 바뀔 때 호출됩니다. */
282
- onSortChange?: (sort: DataTableSortState) => void;
284
+ /** 정렬 가능한 열을 클릭해 정렬 상태가 바뀔 때, 그리고 열 메뉴의 "Clear sort"로
285
+ * 정렬이 지워질 때 호출됩니다 -- 지워진 상태는 `undefined`로 전달됩니다. */
286
+ onSortChange?: (sort: DataTableSortState | undefined) => void;
283
287
  /**
284
288
  * 정렬 아이콘입니다. `idle`은 정렬 가능하지만 아직 정렬되지 않은 열의 헤더에
285
289
  * (호버 시에만 드러나는) 기본 표시로 쓰이고, `asc`/`desc`는 실제로 정렬된 열에
@@ -538,18 +542,20 @@ type ResizablePanelProps = Omit<react.ComponentPropsWithoutRef<"div">, "children
538
542
  */
539
543
  max?: number | string;
540
544
  /**
541
- * Layout model: "docked" (default) reserves flow width and sits in-line
542
- * with a hairline border; "floating" takes the panel out of flow
543
- * (`position: fixed`, an 8px gutter, r10, the measured floating shadow).
545
+ * Visual variant -- BOTH are in-flow (a resizing/opening panel always
546
+ * reserves real width from `spacer`, shrinking a `flex: 1` sibling
547
+ * beside it; neither ever becomes a `position: fixed` viewport overlay).
548
+ * "docked" (default) sits flush with a hairline border; "floating" is
549
+ * Attio's own inset-card look (8px gutter, r12, the measured elevation).
544
550
  */
545
551
  floating?: boolean;
546
552
  /** Resize-handle geometry -- "panel" (default) or "column" (table edges). */
547
553
  handleVariant?: ResizablePanelHandleVariant;
548
554
  /**
549
555
  * Renders the drag handle. `false` gives a fixed-width, non-interactive
550
- * panel (e.g. `RecordPanel`'s own `resizable={false}` default) -- not part
556
+ * panel (e.g. `RecordPreview`'s own `resizable={false}` default) -- not part
551
557
  * of crisp's own API, added here so a consumer built ON this primitive
552
- * (like `RecordPanel`) can opt out of dragging entirely without crisp's
558
+ * (like `RecordPreview`) can opt out of dragging entirely without crisp's
553
559
  * duplicate resize-handle implementation. @default true
554
560
  */
555
561
  resizable?: boolean;
@@ -559,18 +565,41 @@ type ResizablePanelProps = Omit<react.ComponentPropsWithoutRef<"div">, "children
559
565
  * `width` is uncontrolled.
560
566
  */
561
567
  storageKey?: string;
568
+ /**
569
+ * Drives the floating panel's own enter/exit keyframe animation (only
570
+ * meaningful together with `floating`) -- "open" plays the slide-and-fade
571
+ * in on mount, "closed" plays it in reverse. A consumer that keeps this
572
+ * component mounted through its own close transition (e.g.
573
+ * `@seed-design/react-presence`'s `usePresence`, the same idiom Dialog/
574
+ * Drawer use) flips this once `open` goes false, then unmounts once that
575
+ * hook reports the exit animation finished. Omit for a panel that
576
+ * shouldn't animate at all.
577
+ */
578
+ animationState?: "open" | "closed";
579
+ /**
580
+ * Ref to the panel element itself (not the outer root/spacer wrapper this
581
+ * component's own `ref` targets) -- lets a consumer's presence hook
582
+ * observe `animationName` changes on the SAME node that carries
583
+ * `data-state`/the keyframe animation above.
584
+ */
585
+ panelElementRef?: react.Ref<HTMLDivElement>;
562
586
  className?: string;
563
587
  children?: react.ReactNode;
564
588
  };
565
589
  /**
566
590
  * An adjustable-panel primitive: a spacer that reserves layout width plus a
567
- * panel that overlays it, so the panel can move between docked (in-flow) and
568
- * floating (`position: fixed`, an overlay) without a reflow glitch. Drag the
569
- * edge handle to resize; constraints are CSS `min-width`/`max-width`, never
570
- * re-clamped in JS. Ported from your-moon/crisp's `ResizablePanel`
571
- * (`components/resizablepanel/`); state/drag behavior lives in
572
- * `useResizablePanel` (`@seed-design/react-resizable-panel`), this component
573
- * owns the DOM + recipe classes on top of it.
591
+ * panel that overlays it, so it can resize (or animate open/closed) without
592
+ * a reflow glitch on the rest of the layout -- the spacer always reserves
593
+ * the panel's real width, in BOTH the docked and floating visual variants
594
+ * (floating changes only the panel's own look -- gutter, radius, shadow --
595
+ * never its `position`, so a consumer laying this out as a row-flex sibling
596
+ * of e.g. a table sees that table genuinely shrink to make room, matching
597
+ * Attio's own measured peek). Drag the edge handle to resize; constraints
598
+ * are CSS `min-width`/`max-width`, never re-clamped in JS. Ported from
599
+ * your-moon/crisp's `ResizablePanel` (`components/resizablepanel/`);
600
+ * state/drag behavior lives in `useResizablePanel`
601
+ * (`@seed-design/react-resizable-panel`), this component owns the DOM +
602
+ * recipe classes on top of it.
574
603
  */
575
604
  declare const ResizablePanel: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "children" | "onResize"> & {
576
605
  /** Which edge of its container the panel is anchored to. @default "left" */
@@ -592,18 +621,20 @@ declare const ResizablePanel: react.ForwardRefExoticComponent<Omit<Omit<react.De
592
621
  */
593
622
  max?: number | string;
594
623
  /**
595
- * Layout model: "docked" (default) reserves flow width and sits in-line
596
- * with a hairline border; "floating" takes the panel out of flow
597
- * (`position: fixed`, an 8px gutter, r10, the measured floating shadow).
624
+ * Visual variant -- BOTH are in-flow (a resizing/opening panel always
625
+ * reserves real width from `spacer`, shrinking a `flex: 1` sibling
626
+ * beside it; neither ever becomes a `position: fixed` viewport overlay).
627
+ * "docked" (default) sits flush with a hairline border; "floating" is
628
+ * Attio's own inset-card look (8px gutter, r12, the measured elevation).
598
629
  */
599
630
  floating?: boolean;
600
631
  /** Resize-handle geometry -- "panel" (default) or "column" (table edges). */
601
632
  handleVariant?: ResizablePanelHandleVariant;
602
633
  /**
603
634
  * Renders the drag handle. `false` gives a fixed-width, non-interactive
604
- * panel (e.g. `RecordPanel`'s own `resizable={false}` default) -- not part
635
+ * panel (e.g. `RecordPreview`'s own `resizable={false}` default) -- not part
605
636
  * of crisp's own API, added here so a consumer built ON this primitive
606
- * (like `RecordPanel`) can opt out of dragging entirely without crisp's
637
+ * (like `RecordPreview`) can opt out of dragging entirely without crisp's
607
638
  * duplicate resize-handle implementation. @default true
608
639
  */
609
640
  resizable?: boolean;
@@ -613,6 +644,24 @@ declare const ResizablePanel: react.ForwardRefExoticComponent<Omit<Omit<react.De
613
644
  * `width` is uncontrolled.
614
645
  */
615
646
  storageKey?: string;
647
+ /**
648
+ * Drives the floating panel's own enter/exit keyframe animation (only
649
+ * meaningful together with `floating`) -- "open" plays the slide-and-fade
650
+ * in on mount, "closed" plays it in reverse. A consumer that keeps this
651
+ * component mounted through its own close transition (e.g.
652
+ * `@seed-design/react-presence`'s `usePresence`, the same idiom Dialog/
653
+ * Drawer use) flips this once `open` goes false, then unmounts once that
654
+ * hook reports the exit animation finished. Omit for a panel that
655
+ * shouldn't animate at all.
656
+ */
657
+ animationState?: "open" | "closed";
658
+ /**
659
+ * Ref to the panel element itself (not the outer root/spacer wrapper this
660
+ * component's own `ref` targets) -- lets a consumer's presence hook
661
+ * observe `animationName` changes on the SAME node that carries
662
+ * `data-state`/the keyframe animation above.
663
+ */
664
+ panelElementRef?: react.Ref<HTMLDivElement>;
616
665
  className?: string;
617
666
  children?: react.ReactNode;
618
667
  } & react.RefAttributes<HTMLDivElement>>;
@@ -621,7 +670,7 @@ declare const ResizablePanel: react.ForwardRefExoticComponent<Omit<Omit<react.De
621
670
  * Attio's own peek panel lays its own out (your-moon/crisp#448, measured
622
671
  * live): a 2-column grid, no card chrome, a muted label row with a
623
672
  * trailing icon, a filled-colour value below it. */
624
- type RecordPanelHighlight = {
673
+ type RecordPreviewHighlight = {
625
674
  key: string;
626
675
  label: string;
627
676
  value: react.ReactNode;
@@ -634,7 +683,7 @@ type RecordPanelHighlight = {
634
683
  * into the consumer's own content when clicked. Omitting `content` renders
635
684
  * the row but not as a button, matching the live DOM measured on an empty
636
685
  * section: no chevron, no click handler, nothing to expand into yet. */
637
- type RecordPanelSection = {
686
+ type RecordPreviewSection = {
638
687
  key: string;
639
688
  label: string;
640
689
  count: number;
@@ -646,11 +695,11 @@ type RecordPanelSection = {
646
695
  * (which reads `Row` from `product/recordpage/column`), this port has no
647
696
  * such type to depend on -- crispy-seed has no RecordPage -- so this stays
648
697
  * a minimal, consumer-extendable shape. */
649
- type RecordPanelRecord = {
698
+ type RecordPreviewRecord = {
650
699
  name?: string;
651
700
  [key: string]: unknown;
652
701
  };
653
- type RecordPanelProps = Omit<react.ComponentPropsWithoutRef<"div">, "children" | "title" | "onResize"> & {
702
+ type RecordPreviewProps = Omit<react.ComponentPropsWithoutRef<"div">, "children" | "title" | "onResize"> & {
654
703
  /** Whether the panel is mounted/visible. */
655
704
  open: boolean;
656
705
  onClose: () => void;
@@ -693,11 +742,11 @@ type RecordPanelProps = Omit<react.ComponentPropsWithoutRef<"div">, "children" |
693
742
  avatar?: string;
694
743
  /** The record to show; renders nothing when `open` is false or `record`
695
744
  * is null. */
696
- record: RecordPanelRecord | null;
745
+ record: RecordPreviewRecord | null;
697
746
  /** Heading above the highlight cards (default "Highlights"). Omit the
698
747
  * whole section by omitting `highlights`. */
699
748
  highlightsLabel?: react.ReactNode;
700
- highlights?: RecordPanelHighlight[];
749
+ highlights?: RecordPreviewHighlight[];
701
750
  /** Heading above the activity feed (default "Activity"). */
702
751
  activityLabel?: react.ReactNode;
703
752
  viewAllActivityLabel?: react.ReactNode;
@@ -705,7 +754,7 @@ type RecordPanelProps = Omit<react.ComponentPropsWithoutRef<"div">, "children" |
705
754
  activity?: react.ReactNode;
706
755
  /** Collapsed sections below Activity (your-moon/crisp#413). Omit for no
707
756
  * sections at all. */
708
- sections?: RecordPanelSection[];
757
+ sections?: RecordPreviewSection[];
709
758
  /** Rendered below the panel's content, e.g. an Edit button. */
710
759
  footer?: react.ReactNode;
711
760
  className?: string;
@@ -716,14 +765,24 @@ type RecordPanelProps = Omit<react.ComponentPropsWithoutRef<"div">, "children" |
716
765
  * `RecordPanel` (`product/recordpanel/`), built ON `ResizablePanel`
717
766
  * (`side="right" floating`) rather than crisp's own duplicate absolute-
718
767
  * positioning/slide-in/resize-handle implementation -- the outer shell (the
719
- * `@starting-style` slide-in, the floating elevation, the drag handle
768
+ * enter/exit keyframe animation, the floating elevation, the drag handle
720
769
  * itself) all come from that primitive; this component only renders the
721
770
  * CONTENT inside it.
771
+ *
772
+ * Enter/exit: closing this panel is a state change (`open` -> false) that
773
+ * typically clears `record` in the SAME update (see the DataTable story's
774
+ * own `onClose={() => setPreviewRow(null)}`), so by the time an exit
775
+ * animation should play, the values this component would render are
776
+ * already gone. `usePresence` (`@seed-design/react-presence`, the same
777
+ * idiom Dialog/Drawer already use for their own floating layers) keeps the
778
+ * tree mounted for exactly the exit animation's duration; the snapshot
779
+ * below keeps the LAST visible props around for that same window, since
780
+ * without it the panel would animate out empty.
722
781
  */
723
- declare function RecordPanel({ open, record, onClose, className, closeLabel, onOpenRecord, openRecordLabel, onPrevious, previousRecordLabel, onNext, nextRecordLabel, title, avatar, highlightsLabel, highlights, counterLabel, resizable, width, defaultWidth, onWidthChange, minWidth, maxWidth, activityLabel, viewAllActivityLabel, onViewAllActivity, activity, sections, footer, ...rest }: RecordPanelProps): react_jsx_runtime.JSX.Element | null;
724
- declare namespace RecordPanel {
782
+ declare function RecordPreview(props: RecordPreviewProps): react_jsx_runtime.JSX.Element | null;
783
+ declare namespace RecordPreview {
725
784
  var displayName: string;
726
785
  }
727
786
 
728
- export { DataTable, DataTableViewsControl, RecordPanel, ResizablePanel };
729
- export type { DataTableColumn, DataTableColumnKind, DataTableProps, DataTableView, DataTableViewState, DataTableViewsControlProps, RecordPanelHighlight, RecordPanelProps, RecordPanelRecord, RecordPanelSection, ResizablePanelHandleVariant, ResizablePanelProps, ResizablePanelSide, ToolbarFilter, ToolbarFilterOp, ToolbarSort, ToolbarSortDirection };
787
+ export { DataTable, DataTableViewsControl, RecordPreview, ResizablePanel };
788
+ export type { DataTableColumn, DataTableColumnKind, DataTableProps, DataTableView, DataTableViewState, DataTableViewsControlProps, RecordPreviewHighlight, RecordPreviewProps, RecordPreviewRecord, RecordPreviewSection, ResizablePanelHandleVariant, ResizablePanelProps, ResizablePanelSide, ToolbarFilter, ToolbarFilterOp, ToolbarSort, ToolbarSortDirection };