@crisp-ui-kit/crisp 0.54.2 → 0.54.3

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.
Files changed (74) hide show
  1. package/dist/chip.css +7 -1
  2. package/dist/chip.d.ts +2 -1
  3. package/dist/chip.layered.css +7 -1
  4. package/dist/cjs/components/chip/chip.js +3 -2
  5. package/dist/cjs/components/chip/chip.recipe.js +37 -1
  6. package/dist/cjs/components/datatable/datatable.js +489 -111
  7. package/dist/cjs/components/emptystate/emptystate.js +3 -2
  8. package/dist/cjs/components/emptystate/emptystate.recipe.js +26 -1
  9. package/dist/cjs/components/personchip/index.js +17 -0
  10. package/dist/cjs/components/personchip/personchip.js +50 -0
  11. package/dist/cjs/components/table/table.js +2 -2
  12. package/dist/cjs/components/tabs/tabs.js +2 -2
  13. package/dist/cjs/components/tabs/tabs.recipe.js +30 -3
  14. package/dist/cjs/components/text/index.js +7 -0
  15. package/dist/cjs/components/text/text.js +55 -0
  16. package/dist/cjs/components/text/text.recipe.js +34 -0
  17. package/dist/cjs/index.js +2 -0
  18. package/dist/cjs/product/headerbar/headerbar.recipe.js +9 -1
  19. package/dist/cjs/product/recordpage/recordpage.recipe.js +10 -1
  20. package/dist/cjs/product/recordstable/recordstable.js +89 -6
  21. package/dist/cjs/product/richtext/richtext.recipe.js +26 -1
  22. package/dist/emptystate.css +15 -1
  23. package/dist/emptystate.d.ts +2 -2
  24. package/dist/emptystate.layered.css +15 -1
  25. package/dist/esm/components/chip/chip.js +3 -2
  26. package/dist/esm/components/chip/chip.recipe.js +37 -1
  27. package/dist/esm/components/datatable/datatable.js +488 -111
  28. package/dist/esm/components/emptystate/emptystate.js +4 -3
  29. package/dist/esm/components/emptystate/emptystate.recipe.js +26 -1
  30. package/dist/esm/components/emptystate/index.js +1 -1
  31. package/dist/esm/components/personchip/index.js +1 -0
  32. package/dist/esm/components/personchip/personchip.js +47 -0
  33. package/dist/esm/components/table/table.js +2 -2
  34. package/dist/esm/components/tabs/tabs.js +2 -2
  35. package/dist/esm/components/tabs/tabs.recipe.js +30 -3
  36. package/dist/esm/components/text/index.js +2 -0
  37. package/dist/esm/components/text/text.js +19 -0
  38. package/dist/esm/components/text/text.recipe.js +31 -0
  39. package/dist/esm/index.js +2 -0
  40. package/dist/esm/product/headerbar/headerbar.recipe.js +9 -1
  41. package/dist/esm/product/recordpage/recordpage.recipe.js +10 -1
  42. package/dist/esm/product/recordstable/recordstable.js +90 -8
  43. package/dist/esm/product/richtext/richtext.recipe.js +26 -1
  44. package/dist/headerbar.css +1 -1
  45. package/dist/headerbar.layered.css +1 -1
  46. package/dist/recordpage.css +13 -2
  47. package/dist/recordpage.layered.css +13 -2
  48. package/dist/richtext.css +11 -1
  49. package/dist/richtext.layered.css +11 -1
  50. package/dist/styles.css +64 -7
  51. package/dist/styles.layered.css +64 -7
  52. package/dist/tabs.css +7 -1
  53. package/dist/tabs.d.ts +2 -2
  54. package/dist/tabs.layered.css +7 -1
  55. package/dist/text.css +9 -0
  56. package/dist/text.d.ts +7 -0
  57. package/dist/text.layered.css +11 -0
  58. package/dist/types/components/chip/chip.d.ts +32 -0
  59. package/dist/types/components/chip/chip.recipe.d.ts +31 -0
  60. package/dist/types/components/datatable/datatable.d.ts +28 -4
  61. package/dist/types/components/emptystate/emptystate.d.ts +29 -4
  62. package/dist/types/components/emptystate/emptystate.recipe.d.ts +2 -0
  63. package/dist/types/components/emptystate/index.d.ts +1 -1
  64. package/dist/types/components/personchip/index.d.ts +1 -0
  65. package/dist/types/components/personchip/personchip.d.ts +37 -0
  66. package/dist/types/components/table/table.d.ts +36 -0
  67. package/dist/types/components/tabs/tabs.d.ts +4 -2
  68. package/dist/types/components/tabs/tabs.recipe.d.ts +18 -3
  69. package/dist/types/components/text/index.d.ts +2 -0
  70. package/dist/types/components/text/text.d.ts +32 -0
  71. package/dist/types/components/text/text.recipe.d.ts +40 -0
  72. package/dist/types/index.d.ts +2 -0
  73. package/dist/types/product/recordstable/recordstable.d.ts +24 -2
  74. package/package.json +11 -1
package/dist/text.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { RecipeFn } from "../core/types";
2
+
3
+ export interface TextVariants {
4
+ tone?: "default" | "muted";
5
+ }
6
+
7
+ export declare const textRecipe: RecipeFn<{ tone: { default: string; muted: string } }>;
@@ -0,0 +1,11 @@
1
+ @layer crisp-components {
2
+ .crisp-text {
3
+ display: inline;
4
+ }
5
+ .crisp-text--tone_default {
6
+ color: var(--crisp-fg-primary);
7
+ }
8
+ .crisp-text--tone_muted {
9
+ color: var(--crisp-fg-neutral-muted);
10
+ }
11
+ }
@@ -3,6 +3,18 @@ import type { VariantProps } from "../../core";
3
3
  import { chipRecipe } from "./chip.recipe";
4
4
  export type ChipProps = React.ComponentPropsWithoutRef<"span"> & VariantProps<typeof chipRecipe> & {
5
5
  asChild?: boolean;
6
+ /**
7
+ * Ellipsis-truncates the label when it no longer fits. Only meaningful
8
+ * when `children` is a plain string — anything else (an avatar, a
9
+ * multi-node label) is rendered as given, untruncated.
10
+ *
11
+ * Ellipsis only, no `Tooltip` on hover (dropped, #623 — a truncated
12
+ * value in Attio is revealed by the cell's own click-to-expand, #579,
13
+ * not by a chip tooltip; there was no Attio reference for one, which
14
+ * is exactly the "never add polish the reference lacks" case). Not
15
+ * Attio's "+N" overflow badge either — see `chip.recipe.ts` for why.
16
+ */
17
+ truncate?: boolean;
6
18
  };
7
19
  /**
8
20
  * A small pill — the same measured chip RecordsTable, RecordPanel and
@@ -19,6 +31,10 @@ export type ChipProps = React.ComponentPropsWithoutRef<"span"> & VariantProps<ty
19
31
  * spacing from the label.
20
32
  */
21
33
  export declare const Chip: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & VariantProps<import("../..").RecipeFn<{
34
+ readonly truncate: {
35
+ readonly true: string;
36
+ readonly false: string;
37
+ };
22
38
  readonly tone: {
23
39
  readonly neutral: string;
24
40
  readonly brand: string;
@@ -31,6 +47,10 @@ export declare const Chip: React.ForwardRefExoticComponent<Omit<React.DetailedHT
31
47
  };
32
48
  }> & {
33
49
  config: import("../..").RecipeConfig<{
50
+ readonly truncate: {
51
+ readonly true: string;
52
+ readonly false: string;
53
+ };
34
54
  readonly tone: {
35
55
  readonly neutral: string;
36
56
  readonly brand: string;
@@ -44,4 +64,16 @@ export declare const Chip: React.ForwardRefExoticComponent<Omit<React.DetailedHT
44
64
  }>;
45
65
  }> & {
46
66
  asChild?: boolean;
67
+ /**
68
+ * Ellipsis-truncates the label when it no longer fits. Only meaningful
69
+ * when `children` is a plain string — anything else (an avatar, a
70
+ * multi-node label) is rendered as given, untruncated.
71
+ *
72
+ * Ellipsis only, no `Tooltip` on hover (dropped, #623 — a truncated
73
+ * value in Attio is revealed by the cell's own click-to-expand, #579,
74
+ * not by a chip tooltip; there was no Attio reference for one, which
75
+ * is exactly the "never add polish the reference lacks" case). Not
76
+ * Attio's "+N" overflow badge either — see `chip.recipe.ts` for why.
77
+ */
78
+ truncate?: boolean;
47
79
  } & React.RefAttributes<HTMLSpanElement>>;
@@ -3,7 +3,9 @@ declare const spec: {
3
3
  readonly base: {
4
4
  readonly display: "inline-flex";
5
5
  readonly alignItems: "center";
6
+ readonly gap: "3px";
6
7
  readonly height: `var(--${string})`;
8
+ readonly minWidth: 0;
7
9
  readonly paddingInline: `var(--${string})`;
8
10
  readonly borderRadius: `var(--${string})`;
9
11
  readonly fontSize: `var(--${string})`;
@@ -12,6 +14,22 @@ declare const spec: {
12
14
  readonly whiteSpace: "nowrap";
13
15
  };
14
16
  readonly variants: {
17
+ readonly truncate: {
18
+ readonly true: {
19
+ readonly decls: {};
20
+ readonly parts: [{
21
+ readonly selector: "& .crisp-chip-label";
22
+ readonly decls: {
23
+ readonly minWidth: 0;
24
+ readonly overflow: "hidden";
25
+ readonly textOverflow: "ellipsis";
26
+ readonly whiteSpace: "nowrap";
27
+ readonly display: "block";
28
+ };
29
+ }];
30
+ };
31
+ readonly false: {};
32
+ };
15
33
  readonly tone: {
16
34
  readonly neutral: {
17
35
  readonly background: string;
@@ -57,9 +75,14 @@ declare const spec: {
57
75
  };
58
76
  readonly defaultVariants: {
59
77
  readonly tone: "neutral";
78
+ readonly truncate: false;
60
79
  };
61
80
  };
62
81
  declare const config: import("../..").RecipeConfig<{
82
+ readonly truncate: {
83
+ readonly true: string;
84
+ readonly false: string;
85
+ };
63
86
  readonly tone: {
64
87
  readonly neutral: string;
65
88
  readonly brand: string;
@@ -72,6 +95,10 @@ declare const config: import("../..").RecipeConfig<{
72
95
  };
73
96
  }>;
74
97
  export declare const chipRecipe: import("../..").RecipeFn<{
98
+ readonly truncate: {
99
+ readonly true: string;
100
+ readonly false: string;
101
+ };
75
102
  readonly tone: {
76
103
  readonly neutral: string;
77
104
  readonly brand: string;
@@ -84,6 +111,10 @@ export declare const chipRecipe: import("../..").RecipeFn<{
84
111
  };
85
112
  }> & {
86
113
  config: import("../..").RecipeConfig<{
114
+ readonly truncate: {
115
+ readonly true: string;
116
+ readonly false: string;
117
+ };
87
118
  readonly tone: {
88
119
  readonly neutral: string;
89
120
  readonly brand: string;
@@ -3,6 +3,10 @@ type IconType = React.ComponentType<{
3
3
  size?: number;
4
4
  strokeWidth?: number;
5
5
  }>;
6
+ export declare function isLabelTruncated(el: {
7
+ scrollWidth: number;
8
+ clientWidth: number;
9
+ }): boolean;
6
10
  export type EntityValue = {
7
11
  name: string;
8
12
  avatar?: string;
@@ -21,9 +25,10 @@ export type DataEditableOption = {
21
25
  export type DataCellType = "text" | "entity" | "tags" | "status" | "date" | "datetime" | "number" | "currency";
22
26
  export type DataTableColumn<T> = {
23
27
  key: string;
24
- /** Truncates with an ellipsis when it's wider than the
25
- * column. The full text stays in the DOM, so assistive tech and copy/paste
26
- * get all of it; there is deliberately no `title` tooltip — see the recipe. */
28
+ /** Truncates with an ellipsis when it's wider than the column (#534: a
29
+ * `Tooltip` with the full text appears on hover/focus once it actually
30
+ * overflows — see `ThLabel` below). The full text stays in the DOM
31
+ * regardless, so assistive tech and copy/paste get all of it either way. */
27
32
  header: React.ReactNode;
28
33
  /** Built-in rich renderer: entity (avatar+name), tags (colour pills), status
29
34
  * (dot), date, number, currency. Overridden by `render`. */
@@ -261,11 +266,30 @@ export type DataTableProps<T extends {
261
266
  countLabel?: (shown: number, total: number) => React.ReactNode;
262
267
  /** Extra toolbar content (e.g. buttons) on the right of the toolbar. */
263
268
  toolbar?: React.ReactNode;
269
+ /**
270
+ * Bounds the grid's body to a fixed viewport height and makes it scroll
271
+ * internally (the way Attio's own grid does), which is also what turns on
272
+ * ROW virtualization (#577) -- only rows inside that viewport (plus a
273
+ * small overscan) render; rows outside it collapse into two spacer `<tr>`s
274
+ * so the scrollbar still reflects the true row count. A number is pixels;
275
+ * a string is any CSS length ("100%", "60vh") -- the first paint
276
+ * (including SSR) windows to an assumed viewport before the real size is
277
+ * measured on mount, so a plain number gets a pixel-accurate first window
278
+ * and a string gets an approximate one that corrects itself right after
279
+ * hydration.
280
+ *
281
+ * Omitted (the default): the grid grows to fit every row, exactly as
282
+ * before -- there is no internal scroll position for row windowing to mean
283
+ * anything, so this is the opt-in half of virtualization. COLUMN
284
+ * virtualization (below) is the other half and does NOT need this prop --
285
+ * the grid already has a determinate horizontal scroll container.
286
+ */
287
+ height?: number | string;
264
288
  className?: string;
265
289
  };
266
290
  export declare function DataTable<T extends {
267
291
  id: string;
268
- }>({ columns: columnsProp, data, selectable, selectedIds, onSelectionChange, selectAllLabel: selectAllLabelProp, selectRowLabel, selectionAnnouncement, columnMenu, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable, searchPlaceholder: searchPlaceholderProp, searchLabel: searchLabelProp, onEdit, stickyFirst, stickyLast, scrollProps, locale: localeProp, avatarTone, surface, interactive, onRowClick, onAddRow, addRowLabel: addRowLabelProp, empty: emptyProp, showCount, countLabel, toolbar, className, reorderRowLabel: reorderRowLabelProp, sortAscendingLabel: sortAscendingLabelProp, sortDescendingLabel: sortDescendingLabelProp, moveColumnLeftLabel: moveColumnLeftLabelProp, moveColumnRightLabel: moveColumnRightLabelProp, editColumnLabel: editColumnLabelProp, hideColumnLabel: hideColumnLabelProp, renameColumnLabel: renameColumnLabelProp, viewSettingsLabel: viewSettingsLabelProp, columnsGroupLabel: columnsGroupLabelProp, ...rest }: DataTableProps<T>): React.JSX.Element;
292
+ }>({ columns: columnsProp, data, selectable, selectedIds, onSelectionChange, selectAllLabel: selectAllLabelProp, selectRowLabel, selectionAnnouncement, columnMenu, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable, searchPlaceholder: searchPlaceholderProp, searchLabel: searchLabelProp, onEdit, stickyFirst, stickyLast, scrollProps, locale: localeProp, avatarTone, surface, interactive, onRowClick, onAddRow, addRowLabel: addRowLabelProp, empty: emptyProp, showCount, countLabel, toolbar, height, className, reorderRowLabel: reorderRowLabelProp, sortAscendingLabel: sortAscendingLabelProp, sortDescendingLabel: sortDescendingLabelProp, moveColumnLeftLabel: moveColumnLeftLabelProp, moveColumnRightLabel: moveColumnRightLabelProp, editColumnLabel: editColumnLabelProp, hideColumnLabel: hideColumnLabelProp, renameColumnLabel: renameColumnLabelProp, viewSettingsLabel: viewSettingsLabelProp, columnsGroupLabel: columnsGroupLabelProp, ...rest }: DataTableProps<T>): React.JSX.Element;
269
293
  export declare namespace DataTable {
270
294
  var displayName: string;
271
295
  }
@@ -1,19 +1,44 @@
1
1
  import type * as React from "react";
2
+ /**
3
+ * #603: Attio's zero-*records* state (Users/Workspaces with nothing
4
+ * imported yet) pairs a "Learn more" label with a clickable card — an
5
+ * icon tile plus a title, e.g. "Learn more" / "Understanding records".
6
+ * Rendered as an `<a>` when `href` is given (matches Attio's own
7
+ * "Import CSV"/card being real links), a `<button>` otherwise.
8
+ */
9
+ export type EmptyStateLearnMore = {
10
+ icon: React.ReactNode;
11
+ /** Defaults to "Learn more". */
12
+ label?: React.ReactNode;
13
+ title: React.ReactNode;
14
+ href?: string;
15
+ onClick?: () => void;
16
+ };
2
17
  export type EmptyStateProps = Omit<React.ComponentPropsWithoutRef<"div">, "title"> & {
3
18
  icon?: React.ReactNode;
4
19
  title: React.ReactNode;
5
20
  description?: React.ReactNode;
6
- /** A primary action (e.g. a Button) shown below. */
21
+ /**
22
+ * A primary action (e.g. a Button) shown below. Pass more than one
23
+ * (a Fragment of Buttons) for a multi-CTA state (#603, measured:
24
+ * Attio's zero-records "Import CSV" + "Connect data source" pair,
25
+ * 8px gap) -- the container lays them out in a row automatically.
26
+ */
7
27
  action?: React.ReactNode;
28
+ /** A "Learn more" card below the action(s) (#603). */
29
+ learnMore?: EmptyStateLearnMore;
8
30
  /**
9
31
  * `illustrated` shows a large icon on a dotted-grid backdrop; `page` is
10
- * the full-view empty state (ringed circle icon + 20px heading).
32
+ * the full-view empty state (ringed circle icon + 20px heading);
33
+ * `records` is the larger (138px) dotted-grid tile Attio's zero-records
34
+ * table state uses (#603) -- same backdrop idiom as `illustrated`, a
35
+ * different measured size because it's a different surface.
11
36
  */
12
- variant?: "default" | "illustrated" | "page";
37
+ variant?: "default" | "illustrated" | "page" | "records";
13
38
  className?: string;
14
39
  };
15
40
  /** A centred empty-state panel — icon, title, description, optional action. */
16
- export declare function EmptyState({ icon, title, description, action, variant, className, ...rest }: EmptyStateProps): React.JSX.Element;
41
+ export declare function EmptyState({ icon, title, description, action, learnMore, variant, className, ...rest }: EmptyStateProps): React.JSX.Element;
17
42
  export declare namespace EmptyState {
18
43
  var displayName: string;
19
44
  }
@@ -3,6 +3,7 @@ declare const config: import("../..").RecipeConfig<{
3
3
  default: string;
4
4
  illustrated: string;
5
5
  page: string;
6
+ records: string;
6
7
  };
7
8
  }>;
8
9
  export declare const emptystateRecipe: import("../..").RecipeFn<{
@@ -10,6 +11,7 @@ export declare const emptystateRecipe: import("../..").RecipeFn<{
10
11
  default: string;
11
12
  illustrated: string;
12
13
  page: string;
14
+ records: string;
13
15
  };
14
16
  }>;
15
17
  export default config;
@@ -1,2 +1,2 @@
1
- export { EmptyState, type EmptyStateProps } from "./emptystate";
1
+ export { EmptyState, type EmptyStateLearnMore, type EmptyStateProps, } from "./emptystate";
2
2
  export { emptystateRecipe } from "./emptystate.recipe";
@@ -0,0 +1 @@
1
+ export * from "./personchip";
@@ -0,0 +1,37 @@
1
+ import type * as React from "react";
2
+ export type PersonChipProps = Omit<React.ComponentPropsWithoutRef<"span">, "children"> & {
3
+ /** The person's display name — also the avatar's initials fallback. */
4
+ name: string;
5
+ /** A photo URL. Omitted (no populated photo field was reachable to
6
+ * measure this round), the avatar falls back to a per-name hashed-colour
7
+ * initials tile. */
8
+ avatar?: string;
9
+ /** De-emphasises the name (e.g. a departed person, a system actor) —
10
+ * `fgNeutralMuted`, the same token `Text`'s own `tone="muted"` uses.
11
+ * Applied to the name only; the avatar keeps its full-strength tone so
12
+ * the chip still reads as a distinct person, not a disabled control. */
13
+ muted?: boolean;
14
+ className?: string;
15
+ };
16
+ /**
17
+ * A person, as a chip: a small avatar (a photo, or hashed-colour initials)
18
+ * plus their name, truncating with an ellipsis when it doesn't fit — Attio's
19
+ * own actor chip (measured live on `techpartners`, Tasks page, "Assigned to"
20
+ * column): a 16px circular avatar in a neutral `Chip`, `gap: 3px` between
21
+ * avatar and name (now `Chip`'s own base — every multi-child `Chip` gets
22
+ * it). Every other value — the pill's height, padding, radius, ring and text
23
+ * — is already `Chip`'s, unchanged; `PersonChip` adds no recipe of its own.
24
+ *
25
+ * Ellipsis only, no `Tooltip` on hover (#623 — no Attio reference for one;
26
+ * a truncated cell there is revealed by its own click-to-expand, #579, a
27
+ * different, DataTable-specific interaction).
28
+ *
29
+ * Composes `Chip`'s `truncate` CSS directly rather than its string-only
30
+ * auto-wrap (children here is an avatar plus a name, not a single string),
31
+ * so the name gets its own `.crisp-chip-label` span while the avatar stays
32
+ * fixed-size.
33
+ */
34
+ export declare function PersonChip({ name, avatar, muted, className, ...props }: PersonChipProps): React.JSX.Element;
35
+ export declare namespace PersonChip {
36
+ var displayName: string;
37
+ }
@@ -8,6 +8,24 @@ export type TableProps = React.ComponentPropsWithoutRef<"table"> & VariantProps<
8
8
  scrollProps?: React.ComponentPropsWithoutRef<"div"> & {
9
9
  ref?: React.Ref<HTMLDivElement>;
10
10
  };
11
+ /**
12
+ * Style applied to the `<table>` element itself, as opposed to `style`
13
+ * (below), which sizes the OUTER bordered wrapper -- crisp/#581.
14
+ * `DataTable` uses this for its `min-width: <sum of column widths>`,
15
+ * which forces `<table>` to its true content width and lets
16
+ * `.crisp-table-scroll`'s existing `overflow-x: auto` scroll it
17
+ * internally. Putting that same min-width on the outer wrapper
18
+ * (`style`) instead, as this component used to require, forces the
19
+ * WRAPPER itself that wide -- a plain block box's width is normally set
20
+ * by its own container regardless of a child's min-width, so the only
21
+ * element that should ever be forced wider than its container is the
22
+ * scrollable one, never an ancestor of it. Getting this backwards is
23
+ * exactly what made a `DataTable` widen its own page instead of
24
+ * scrolling in place (internal/grc#117), forcing GRC to hand-build its
25
+ * own `overflow: hidden` clipping wrapper around it -- which the
26
+ * crisp-only rule forbids and which this makes unnecessary.
27
+ */
28
+ tableStyle?: React.CSSProperties;
11
29
  };
12
30
  /**
13
31
  * A composable data table. Wraps `<table>` in a horizontally scrollable
@@ -32,6 +50,24 @@ export declare const Table: React.ForwardRefExoticComponent<Omit<React.DetailedH
32
50
  scrollProps?: React.ComponentPropsWithoutRef<"div"> & {
33
51
  ref?: React.Ref<HTMLDivElement>;
34
52
  };
53
+ /**
54
+ * Style applied to the `<table>` element itself, as opposed to `style`
55
+ * (below), which sizes the OUTER bordered wrapper -- crisp/#581.
56
+ * `DataTable` uses this for its `min-width: <sum of column widths>`,
57
+ * which forces `<table>` to its true content width and lets
58
+ * `.crisp-table-scroll`'s existing `overflow-x: auto` scroll it
59
+ * internally. Putting that same min-width on the outer wrapper
60
+ * (`style`) instead, as this component used to require, forces the
61
+ * WRAPPER itself that wide -- a plain block box's width is normally set
62
+ * by its own container regardless of a child's min-width, so the only
63
+ * element that should ever be forced wider than its container is the
64
+ * scrollable one, never an ancestor of it. Getting this backwards is
65
+ * exactly what made a `DataTable` widen its own page instead of
66
+ * scrolling in place (internal/grc#117), forcing GRC to hand-build its
67
+ * own `overflow: hidden` clipping wrapper around it -- which the
68
+ * crisp-only rule forbids and which this makes unnecessary.
69
+ */
70
+ tableStyle?: React.CSSProperties;
35
71
  } & React.RefAttributes<HTMLTableElement>>;
36
72
  export declare const TableHeader: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & React.RefAttributes<HTMLTableSectionElement>>;
37
73
  export declare const TableBody: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & React.RefAttributes<HTMLTableSectionElement>>;
@@ -1,4 +1,6 @@
1
1
  import * as React from "react";
2
+ import type { VariantProps } from "../../core";
3
+ import { tabsRecipe } from "./tabs.recipe";
2
4
  export type TabItem = {
3
5
  value: string;
4
6
  label: React.ReactNode;
@@ -8,7 +10,7 @@ export type TabItem = {
8
10
  badge?: React.ReactNode;
9
11
  disabled?: boolean;
10
12
  };
11
- export type TabsProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "defaultValue" | "children"> & {
13
+ export type TabsProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "defaultValue" | "children"> & VariantProps<typeof tabsRecipe> & {
12
14
  tabs: TabItem[];
13
15
  /** Controlled active value. Omit to let Tabs manage it (see defaultValue). */
14
16
  value?: string;
@@ -27,7 +29,7 @@ export type TabsProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "d
27
29
  * Home/End jump); activation follows focus. Controlled via
28
30
  * `value`/`onValueChange`, or uncontrolled from `defaultValue`.
29
31
  */
30
- export declare function Tabs({ tabs, value, defaultValue, onValueChange, leading, children, className, "aria-label": ariaLabel, ...rest }: TabsProps): React.JSX.Element;
32
+ export declare function Tabs({ tabs, value, defaultValue, onValueChange, leading, children, className, fill, "aria-label": ariaLabel, ...rest }: TabsProps): React.JSX.Element;
31
33
  export declare namespace Tabs {
32
34
  var displayName: string;
33
35
  }
@@ -1,5 +1,20 @@
1
- declare const config: import("../..").RecipeConfig<{}>;
2
- export declare const tabsRecipe: import("../..").RecipeFn<{}> & {
3
- config: import("../..").RecipeConfig<{}>;
1
+ declare const config: import("../..").RecipeConfig<{
2
+ fill: {
3
+ true: string;
4
+ false: string;
5
+ };
6
+ }>;
7
+ export declare const tabsRecipe: import("../..").RecipeFn<{
8
+ fill: {
9
+ true: string;
10
+ false: string;
11
+ };
12
+ }> & {
13
+ config: import("../..").RecipeConfig<{
14
+ fill: {
15
+ true: string;
16
+ false: string;
17
+ };
18
+ }>;
4
19
  };
5
20
  export default config;
@@ -0,0 +1,2 @@
1
+ export { Text, type TextProps } from "./text";
2
+ export { textRecipe } from "./text.recipe";
@@ -0,0 +1,32 @@
1
+ import * as React from "react";
2
+ import type { VariantProps } from "../../core";
3
+ import { textRecipe } from "./text.recipe";
4
+ export type TextProps = React.ComponentPropsWithoutRef<"span"> & VariantProps<typeof textRecipe> & {
5
+ asChild?: boolean;
6
+ };
7
+ /**
8
+ * Plain coloured text — `tone="default"` (the app's primary text colour) or
9
+ * `"muted"` — for the runs of text that aren't a Badge, a Chip, a link, or
10
+ * any of crisp's other typed things: a cell's own yes/no, an empty-state
11
+ * caption, a secondary line under a heading. One component so every such
12
+ * spot reaches for crisp's own tokens instead of each hand-writing its own
13
+ * colour utility for the same two values.
14
+ *
15
+ * Renders a `<span>` (inherits its size/weight/line-height from context —
16
+ * see `text.recipe.ts`'s doc for why `Text` sets none of those itself).
17
+ */
18
+ export declare const Text: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & VariantProps<import("../..").RecipeFn<{
19
+ readonly tone: {
20
+ readonly default: string;
21
+ readonly muted: string;
22
+ };
23
+ }> & {
24
+ config: import("../..").RecipeConfig<{
25
+ readonly tone: {
26
+ readonly default: string;
27
+ readonly muted: string;
28
+ };
29
+ }>;
30
+ }> & {
31
+ asChild?: boolean;
32
+ } & React.RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,40 @@
1
+ declare const spec: {
2
+ readonly name: "text";
3
+ readonly base: {
4
+ readonly display: "inline";
5
+ };
6
+ readonly variants: {
7
+ tone: {
8
+ default: {
9
+ color: `var(--${string})`;
10
+ };
11
+ muted: {
12
+ color: `var(--${string})`;
13
+ };
14
+ };
15
+ };
16
+ readonly defaultVariants: {
17
+ readonly tone: "default";
18
+ };
19
+ };
20
+ declare const config: import("../..").RecipeConfig<{
21
+ readonly tone: {
22
+ readonly default: string;
23
+ readonly muted: string;
24
+ };
25
+ }>;
26
+ export declare const textRecipe: import("../..").RecipeFn<{
27
+ readonly tone: {
28
+ readonly default: string;
29
+ readonly muted: string;
30
+ };
31
+ }> & {
32
+ config: import("../..").RecipeConfig<{
33
+ readonly tone: {
34
+ readonly default: string;
35
+ readonly muted: string;
36
+ };
37
+ }>;
38
+ };
39
+ export { spec };
40
+ export default config;
@@ -33,6 +33,7 @@ export * from "./components/mentionchip";
33
33
  export * from "./components/menu";
34
34
  export * from "./components/middletruncate";
35
35
  export * from "./components/multiselect";
36
+ export * from "./components/personchip";
36
37
  export * from "./components/popover";
37
38
  export * from "./components/progress";
38
39
  export * from "./components/quantitypicker";
@@ -50,6 +51,7 @@ export * from "./components/switch";
50
51
  export * from "./components/table";
51
52
  export * from "./components/tabletoolbar";
52
53
  export * from "./components/tabs";
54
+ export * from "./components/text";
53
55
  export * from "./components/textarea";
54
56
  export * from "./components/textlink";
55
57
  export * from "./components/timepicker";
@@ -1,9 +1,14 @@
1
1
  import * as React from "react";
2
+ import { type EmptyStateLearnMore } from "../../components/emptystate";
2
3
  import type { EditableOption } from "./editable-field";
3
4
  type IconType = React.ComponentType<{
4
5
  size?: number;
5
6
  strokeWidth?: number;
6
7
  }>;
8
+ export declare function isLabelTruncated(el: {
9
+ scrollWidth: number;
10
+ clientWidth: number;
11
+ }): boolean;
7
12
  export type ColumnType = "entity" | "text" | "tags" | "number" | "url" | "date" | "currency" | "status" | "reference";
8
13
  export type StatusOption = {
9
14
  value: string;
@@ -123,6 +128,20 @@ export type RecordsTableProps = Omit<React.ComponentPropsWithoutRef<"div">, "chi
123
128
  * stable colour per name, matching what `DataTable`'s `avatarTone` offers).
124
129
  * Entity avatars only — `TAG_TONES`/tag/status tone logic is untouched. */
125
130
  avatarTone?: "brand" | "hashed";
131
+ /**
132
+ * #603: Attio's zero-*records* state (nothing imported yet, no active
133
+ * filter) adds an "Import CSV" / "Connect data source" pair and a
134
+ * "Learn more" card next to the usual "New record" action -- measured
135
+ * on Users/Workspaces, which show nothing else. Omit any of these and
136
+ * that piece is left out; omit the whole prop and the empty state is
137
+ * unchanged (just "New record"), since this hasn't been confirmed for
138
+ * every object type.
139
+ */
140
+ emptyStateExtra?: {
141
+ onImportCsv?: () => void;
142
+ onConnectDataSource?: () => void;
143
+ learnMore?: EmptyStateLearnMore;
144
+ };
126
145
  className?: string;
127
146
  };
128
147
  export declare function tagTone(t: string): string;
@@ -204,6 +223,9 @@ export type RecordsTableLabels = {
204
223
  setRecordPlaceholder: string;
205
224
  noRecords: string;
206
225
  untitled: string;
226
+ /** #603: the zero-records state's optional extra CTAs. */
227
+ importCsv: string;
228
+ connectDataSource: string;
207
229
  /** Aggregation names, keyed by the aggregation. */
208
230
  agg: Record<Agg, string>;
209
231
  /** Filter operator names, keyed by the operator. */
@@ -229,7 +251,7 @@ export type RecordsTableLabelsInput = Partial<Omit<RecordsTableLabels, "agg" | "
229
251
  agg?: Partial<Record<Agg, string>>;
230
252
  op?: Partial<Record<FilterOp, string>>;
231
253
  };
232
- type FilterOp = "contains" | "is" | "isnot" | "empty" | "notempty";
254
+ type FilterOp = "contains" | "doesnotcontain" | "startswith" | "endswith" | "is" | "isnot" | "empty" | "notempty";
233
255
  /**
234
256
  * A date-only cell is a CALENDAR DATE, not an instant. ECMA-262 parses the
235
257
  * date-only ISO forms — `1998`, `1998-09`, `1998-09-04` — as UTC midnight, and
@@ -251,6 +273,6 @@ export { formatCellDate, parseCellDate };
251
273
  * and a floating bulk-action bar (delete / deselect) when rows are selected.
252
274
  * Selection can be controlled via `selectedIds`/`onSelectionChange`.
253
275
  */
254
- export declare function RecordsTable({ labels, columns: columnsProp, rows: rowsProp, selectedIds, onSelectionChange, showNew, allowAddColumn, onOpenRecord, onOpenRecordPage, avatarTone, className, ...rest }: RecordsTableProps): React.JSX.Element;
276
+ export declare function RecordsTable({ labels, columns: columnsProp, rows: rowsProp, selectedIds, onSelectionChange, showNew, allowAddColumn, onOpenRecord, onOpenRecordPage, avatarTone, emptyStateExtra, className, ...rest }: RecordsTableProps): React.JSX.Element;
255
277
  export declare const defaultColumns: Column[];
256
278
  export declare const defaultRows: Row[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crisp-ui-kit/crisp",
3
- "version": "0.54.2",
3
+ "version": "0.54.3",
4
4
  "description": "A lean React design system, measured pixel-for-pixel from Attio.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -208,6 +208,11 @@
208
208
  "import": "./dist/esm/components/multiselect/index.js",
209
209
  "require": "./dist/cjs/components/multiselect/index.js"
210
210
  },
211
+ "./personchip": {
212
+ "types": "./dist/types/components/personchip/index.d.ts",
213
+ "import": "./dist/esm/components/personchip/index.js",
214
+ "require": "./dist/cjs/components/personchip/index.js"
215
+ },
211
216
  "./popover": {
212
217
  "types": "./dist/types/components/popover/index.d.ts",
213
218
  "import": "./dist/esm/components/popover/index.js",
@@ -293,6 +298,11 @@
293
298
  "import": "./dist/esm/components/tabs/index.js",
294
299
  "require": "./dist/cjs/components/tabs/index.js"
295
300
  },
301
+ "./text": {
302
+ "types": "./dist/types/components/text/index.d.ts",
303
+ "import": "./dist/esm/components/text/index.js",
304
+ "require": "./dist/cjs/components/text/index.js"
305
+ },
296
306
  "./textarea": {
297
307
  "types": "./dist/types/components/textarea/index.d.ts",
298
308
  "import": "./dist/esm/components/textarea/index.js",