@crisp-ui-kit/crisp 0.54.2 → 0.54.4

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 (116) hide show
  1. package/dist/board.css +13 -1
  2. package/dist/board.layered.css +13 -1
  3. package/dist/chip.css +7 -1
  4. package/dist/chip.d.ts +2 -1
  5. package/dist/chip.layered.css +7 -1
  6. package/dist/cjs/components/chip/chip.js +3 -2
  7. package/dist/cjs/components/chip/chip.recipe.js +37 -1
  8. package/dist/cjs/components/datatable/datatable.js +489 -111
  9. package/dist/cjs/components/emptystate/emptystate.js +3 -2
  10. package/dist/cjs/components/emptystate/emptystate.recipe.js +26 -1
  11. package/dist/cjs/components/personchip/index.js +17 -0
  12. package/dist/cjs/components/personchip/personchip.js +50 -0
  13. package/dist/cjs/components/table/table.js +2 -2
  14. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +41 -4
  15. package/dist/cjs/components/tabs/tabs.js +2 -2
  16. package/dist/cjs/components/tabs/tabs.recipe.js +30 -3
  17. package/dist/cjs/components/text/index.js +7 -0
  18. package/dist/cjs/components/text/text.js +55 -0
  19. package/dist/cjs/components/text/text.recipe.js +34 -0
  20. package/dist/cjs/index.js +4 -0
  21. package/dist/cjs/product/board/board.js +60 -2
  22. package/dist/cjs/product/board/board.recipe.js +10 -0
  23. package/dist/cjs/product/comments/comments.js +426 -0
  24. package/dist/cjs/product/comments/comments.recipe.js +126 -0
  25. package/dist/cjs/product/comments/index.js +8 -0
  26. package/dist/cjs/product/headerbar/headerbar.recipe.js +9 -1
  27. package/dist/cjs/product/listpage/listpage.recipe.js +10 -1
  28. package/dist/cjs/product/objectsettings/index.js +16 -0
  29. package/dist/cjs/product/objectsettings/objectsettings.js +365 -0
  30. package/dist/cjs/product/objectsettings/objectsettings.recipe.js +65 -0
  31. package/dist/cjs/product/recordpage/recordpage.recipe.js +10 -1
  32. package/dist/cjs/product/recordstable/recordstable.js +89 -6
  33. package/dist/cjs/product/richtext/richtext.recipe.js +26 -1
  34. package/dist/cjs/product/taskstable/taskstable.recipe.js +10 -1
  35. package/dist/comments.css +80 -0
  36. package/dist/comments.d.ts +7 -0
  37. package/dist/comments.layered.css +82 -0
  38. package/dist/emptystate.css +15 -1
  39. package/dist/emptystate.d.ts +2 -2
  40. package/dist/emptystate.layered.css +15 -1
  41. package/dist/esm/components/chip/chip.js +3 -2
  42. package/dist/esm/components/chip/chip.recipe.js +37 -1
  43. package/dist/esm/components/datatable/datatable.js +488 -111
  44. package/dist/esm/components/emptystate/emptystate.js +4 -3
  45. package/dist/esm/components/emptystate/emptystate.recipe.js +26 -1
  46. package/dist/esm/components/emptystate/index.js +1 -1
  47. package/dist/esm/components/personchip/index.js +1 -0
  48. package/dist/esm/components/personchip/personchip.js +47 -0
  49. package/dist/esm/components/table/table.js +2 -2
  50. package/dist/esm/components/tabletoolbar/tabletoolbar.js +43 -6
  51. package/dist/esm/components/tabs/tabs.js +2 -2
  52. package/dist/esm/components/tabs/tabs.recipe.js +30 -3
  53. package/dist/esm/components/text/index.js +2 -0
  54. package/dist/esm/components/text/text.js +19 -0
  55. package/dist/esm/components/text/text.recipe.js +31 -0
  56. package/dist/esm/index.js +4 -0
  57. package/dist/esm/product/board/board.js +61 -3
  58. package/dist/esm/product/board/board.recipe.js +10 -0
  59. package/dist/esm/product/comments/comments.js +388 -0
  60. package/dist/esm/product/comments/comments.recipe.js +123 -0
  61. package/dist/esm/product/comments/index.js +2 -0
  62. package/dist/esm/product/headerbar/headerbar.recipe.js +9 -1
  63. package/dist/esm/product/listpage/listpage.recipe.js +10 -1
  64. package/dist/esm/product/objectsettings/index.js +2 -0
  65. package/dist/esm/product/objectsettings/objectsettings.js +322 -0
  66. package/dist/esm/product/objectsettings/objectsettings.recipe.js +62 -0
  67. package/dist/esm/product/recordpage/recordpage.recipe.js +10 -1
  68. package/dist/esm/product/recordstable/recordstable.js +90 -8
  69. package/dist/esm/product/richtext/richtext.recipe.js +26 -1
  70. package/dist/esm/product/taskstable/taskstable.recipe.js +10 -1
  71. package/dist/headerbar.css +1 -1
  72. package/dist/headerbar.layered.css +1 -1
  73. package/dist/listpage.css +8 -1
  74. package/dist/listpage.layered.css +8 -1
  75. package/dist/objectsettings.css +49 -0
  76. package/dist/objectsettings.d.ts +7 -0
  77. package/dist/objectsettings.layered.css +51 -0
  78. package/dist/recordpage.css +13 -2
  79. package/dist/recordpage.layered.css +13 -2
  80. package/dist/richtext.css +11 -1
  81. package/dist/richtext.layered.css +11 -1
  82. package/dist/styles.css +224 -10
  83. package/dist/styles.layered.css +224 -10
  84. package/dist/tabs.css +7 -1
  85. package/dist/tabs.d.ts +2 -2
  86. package/dist/tabs.layered.css +7 -1
  87. package/dist/taskstable.css +8 -1
  88. package/dist/taskstable.layered.css +8 -1
  89. package/dist/text.css +9 -0
  90. package/dist/text.d.ts +7 -0
  91. package/dist/text.layered.css +11 -0
  92. package/dist/types/components/chip/chip.d.ts +32 -0
  93. package/dist/types/components/chip/chip.recipe.d.ts +31 -0
  94. package/dist/types/components/datatable/datatable.d.ts +28 -4
  95. package/dist/types/components/emptystate/emptystate.d.ts +29 -4
  96. package/dist/types/components/emptystate/emptystate.recipe.d.ts +2 -0
  97. package/dist/types/components/emptystate/index.d.ts +1 -1
  98. package/dist/types/components/personchip/index.d.ts +1 -0
  99. package/dist/types/components/personchip/personchip.d.ts +37 -0
  100. package/dist/types/components/table/table.d.ts +36 -0
  101. package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +8 -2
  102. package/dist/types/components/tabs/tabs.d.ts +4 -2
  103. package/dist/types/components/tabs/tabs.recipe.d.ts +18 -3
  104. package/dist/types/components/text/index.d.ts +2 -0
  105. package/dist/types/components/text/text.d.ts +32 -0
  106. package/dist/types/components/text/text.recipe.d.ts +40 -0
  107. package/dist/types/index.d.ts +4 -0
  108. package/dist/types/product/board/board.d.ts +20 -1
  109. package/dist/types/product/comments/comments.d.ts +192 -0
  110. package/dist/types/product/comments/comments.recipe.d.ts +3 -0
  111. package/dist/types/product/comments/index.d.ts +2 -0
  112. package/dist/types/product/objectsettings/index.d.ts +2 -0
  113. package/dist/types/product/objectsettings/objectsettings.d.ts +261 -0
  114. package/dist/types/product/objectsettings/objectsettings.recipe.d.ts +3 -0
  115. package/dist/types/product/recordstable/recordstable.d.ts +24 -2
  116. package/package.json +21 -1
@@ -0,0 +1,192 @@
1
+ import * as React from "react";
2
+ import { type MentionAnchor } from "../../core";
3
+ /** One participant — crisp has no user model of its own, so every field
4
+ * beyond `id`/`name` (avatar image, colour) is fully consumer-supplied, the
5
+ * same split `Inbox`'s own `avatar` prop already draws. */
6
+ export type CommentAuthor = {
7
+ id: string;
8
+ name: string;
9
+ /** Falls back to an initials `Avatar` built from `name`'s first letter. */
10
+ avatar?: React.ReactNode;
11
+ };
12
+ export type CommentReaction = {
13
+ emoji: string;
14
+ count: number;
15
+ /** Highlights the pill and lets a click remove it — crisp has no reactor
16
+ * list of its own to check against. */
17
+ reactedByMe?: boolean;
18
+ };
19
+ export type CommentItem = {
20
+ id: string;
21
+ author: CommentAuthor;
22
+ /** Already-formatted relative time ("less than a minute ago", "2h") --
23
+ * crisp has no clock/duration-i18n model of its own, the same reasoning
24
+ * `Inbox.time` already documents. */
25
+ time: React.ReactNode;
26
+ body: React.ReactNode;
27
+ reactions?: CommentReaction[];
28
+ };
29
+ export type CommentThread = {
30
+ id: string;
31
+ root: CommentItem;
32
+ /** Reply comments, oldest first. */
33
+ replies?: CommentItem[];
34
+ resolved?: boolean;
35
+ /** Who resolved it — drives the "Resolved by you" / "Resolved by {name}"
36
+ * label. Ignored while `resolved` is false. */
37
+ resolvedBy?: CommentAuthor;
38
+ /** Whether the *current* user authored this thread (root or any reply) --
39
+ * drives "Only my threads". crisp doesn't compute this itself since it
40
+ * has no fixed notion of which replies "belong" to a thread for that
41
+ * purpose beyond what the consumer's own data already knows. */
42
+ mine?: boolean;
43
+ };
44
+ /** State handed to a `renderMentionPicker` call — the same shape
45
+ * `RichTextEditor`'s own mention trigger already uses (#372/#428), so a
46
+ * consumer with one picker built for that component can reuse it here. */
47
+ export type CommentMentionTriggerState = {
48
+ query: string;
49
+ anchor: MentionAnchor;
50
+ select: (mention: {
51
+ id: string;
52
+ label: string;
53
+ }) => void;
54
+ close: () => void;
55
+ };
56
+ /**
57
+ * Reads the composer field's DOM into plain text, serializing each mention
58
+ * chip as `@[label](id)` — a fixed, parseable token a consumer (GRC) can
59
+ * pull the mentioned record's id back out of.
60
+ *
61
+ * This is the actual fix for a real bug (GRC's own composer, a plain
62
+ * `<textarea>` holding `@[name](actor:id)` as its literal editable value:
63
+ * a caret placed inside that markup can edit it like any other character,
64
+ * so a stray keystroke corrupts the token and the broken markup posts
65
+ * verbatim — seen live, `/private/tmp/grc-land138/mentions-6-posted.png`).
66
+ * A mention here is NEVER the editable representation: it's a real DOM node
67
+ * (`contentEditable=false`, so a browser won't place a caret inside it to
68
+ * begin with) carrying its id/label in two `data-` attributes set once, at
69
+ * insertion (`insertMention`), and never touched again. This function reads
70
+ * those attributes — not the chip's own `.textContent` — specifically so
71
+ * that even if something DID manage to mutate the chip's interior (a
72
+ * hostile paste, an IME composition, a direct DOM call bypassing the
73
+ * `contentEditable=false` guard entirely — exactly the class of thing a
74
+ * real browser mostly prevents but a test, or a buggy extension, would
75
+ * not), the token this function emits still can't be corrupted: it was
76
+ * never read from the part that changed.
77
+ */
78
+ export declare function serializeComposerField(field: HTMLElement): string;
79
+ export type CommentsPanelProps = Omit<React.ComponentPropsWithoutRef<"div">, "children" | "title" | "onCopy"> & {
80
+ threads: CommentThread[];
81
+ currentUserId: string;
82
+ /** The record/page these comments belong to -- shown in the single-thread
83
+ * breadcrumb as "Comment on {subjectIcon} {subject}" (measured copy). */
84
+ subject?: React.ReactNode;
85
+ subjectIcon?: React.ReactNode;
86
+ showResolved?: boolean;
87
+ onShowResolvedChange?: (next: boolean) => void;
88
+ onlyMine?: boolean;
89
+ onOnlyMineChange?: (next: boolean) => void;
90
+ /** Which thread is narrowed into (reply view). `null`/omit = the "All
91
+ * comments" list. Uncontrolled (own state) unless `onActiveThreadChange`
92
+ * is given alongside it. */
93
+ activeThreadId?: string | null;
94
+ onActiveThreadChange?: (id: string | null) => void;
95
+ /** Post a new top-level comment (`threadId` null) or a reply (`threadId`
96
+ * set, the thread currently open). `text` is plain text with each
97
+ * mention serialized as a fixed `@[label](id)` token (see
98
+ * `serializeComposerField`'s own doc comment) — never the composer's own
99
+ * live DOM, which is why a caret placed anywhere in the field, including
100
+ * on top of a mention, can't corrupt what gets posted. */
101
+ onPost: (text: string, threadId: string | null) => void;
102
+ onReact: (threadId: string, commentId: string, emoji: string) => void;
103
+ /** Resolving only ever applies to the thread as a whole (its root),
104
+ * matching the live behaviour -- no per-reply resolve was found. */
105
+ onResolve?: (threadId: string) => void;
106
+ onDelete: (threadId: string, commentId: string) => void;
107
+ /** Defaults to copying `#comment-{commentId}` appended to the current
108
+ * URL -- override for a real permalink scheme. */
109
+ onCopyLink?: (threadId: string, commentId: string) => void;
110
+ /** Curated reaction choices (default 16) -- crisp ships no emoji library;
111
+ * see `ReactionPicker`'s own doc comment. */
112
+ emojiOptions?: string[];
113
+ mentionTrigger?: string;
114
+ renderMentionPicker?: (state: CommentMentionTriggerState) => React.ReactNode;
115
+ onClose: () => void;
116
+ closeLabel?: string;
117
+ backLabel?: string;
118
+ title?: string;
119
+ threadTitle?: string;
120
+ breadcrumbPrefix?: string;
121
+ composerPlaceholder?: string;
122
+ replyPlaceholder?: string;
123
+ postLabel?: string;
124
+ replyPostLabel?: string;
125
+ /** Shown when `threads` is empty -- omitted by default (the live
126
+ * per-record panel showed no empty-state text; pass one for the
127
+ * view/page-level context G-018 measured, "You don't have any
128
+ * comments"). */
129
+ emptyLabel?: React.ReactNode;
130
+ filterLabel?: string;
131
+ showResolvedLabel?: string;
132
+ onlyMineLabel?: string;
133
+ replyActionLabel?: string;
134
+ reactActionLabel?: string;
135
+ resolveActionLabel?: string;
136
+ resolvedByYouLabel?: string;
137
+ resolvedByLabel?: (name: string) => string;
138
+ moreActionsLabel?: string;
139
+ copyLinkLabel?: string;
140
+ deleteLabel?: string;
141
+ addReactionLabel?: string;
142
+ reactionSearchLabel?: string;
143
+ deleteConfirmTitle?: string;
144
+ deleteConfirmBody?: string;
145
+ deleteConfirmActionLabel?: string;
146
+ cancelLabel?: string;
147
+ composerReplyToolLabel?: string;
148
+ composerMentionToolLabel?: string;
149
+ className?: string;
150
+ };
151
+ /**
152
+ * Per-record comment threads (crisp#625) — measured live on app.attio.com's
153
+ * own right-hand comments panel: a header (title, filter menu), a scrolling
154
+ * thread list or a single narrowed thread, and a persistent bottom composer.
155
+ * Controlled: pass `threads` and wire the callbacks; the panel renders
156
+ * nothing on its own beyond that data. See `CommentCountBadge` for the
157
+ * separate row affordance (P-051) — deliberately NOT part of this
158
+ * component, since it lives in a table cell this component doesn't own.
159
+ */
160
+ export declare function CommentsPanel({ threads, currentUserId, subject, subjectIcon, showResolved, onShowResolvedChange, onlyMine, onOnlyMineChange, activeThreadId: activeThreadIdProp, onActiveThreadChange, onPost, onReact, onResolve, onDelete, onCopyLink, emojiOptions, mentionTrigger, renderMentionPicker, onClose, closeLabel: closeLabelProp, backLabel: backLabelProp, title: titleProp, threadTitle: threadTitleProp, breadcrumbPrefix: breadcrumbPrefixProp, composerPlaceholder: composerPlaceholderProp, replyPlaceholder: replyPlaceholderProp, postLabel: postLabelProp, replyPostLabel: replyPostLabelProp, emptyLabel, filterLabel: filterLabelProp, showResolvedLabel: showResolvedLabelProp, onlyMineLabel: onlyMineLabelProp, replyActionLabel: replyActionLabelProp, reactActionLabel: reactActionLabelProp, resolveActionLabel: resolveActionLabelProp, resolvedByYouLabel: resolvedByYouLabelProp, resolvedByLabel, moreActionsLabel: moreActionsLabelProp, copyLinkLabel: copyLinkLabelProp, deleteLabel: deleteLabelProp, addReactionLabel: addReactionLabelProp, reactionSearchLabel: reactionSearchLabelProp, deleteConfirmTitle: deleteConfirmTitleProp, deleteConfirmBody: deleteConfirmBodyProp, deleteConfirmActionLabel: deleteConfirmActionLabelProp, cancelLabel: cancelLabelProp, composerReplyToolLabel: composerReplyToolLabelProp, composerMentionToolLabel: composerMentionToolLabelProp, className, ...rest }: CommentsPanelProps): React.JSX.Element;
161
+ export declare namespace CommentsPanel {
162
+ var displayName: string;
163
+ }
164
+ export type CommentCountBadgeProps = {
165
+ /** Total comment count for the row. Renders nothing when 0 and not
166
+ * `hovered` -- the live default state was only observed with count ≥ 1
167
+ * (see the comments recipe's own note); a row with none shows no
168
+ * affordance at rest in this reading. */
169
+ count: number;
170
+ /** Pass the row's own hover state (e.g. a DataTable row's `:hover`/
171
+ * `data-hover`) -- this component has no hover detection of its own, so
172
+ * it composes into whatever hover mechanism the grid it's dropped into
173
+ * already runs (#625's own scope note: this must not edit `datatable`/
174
+ * `recordstable`). */
175
+ hovered?: boolean;
176
+ onOpen: () => void;
177
+ onOpenPreview?: () => void;
178
+ label?: string;
179
+ previewLabel?: string;
180
+ className?: string;
181
+ };
182
+ /**
183
+ * The row's own comment affordance (P-051) — a persistent 6px dot once a
184
+ * record has ≥1 comment, replaced on hover by a comment-count icon (P-035's
185
+ * "icon 1") plus, when `onOpenPreview` is given, the row's second hover icon
186
+ * ("Open preview"). A standalone piece by design (see the module doc
187
+ * comment) — the grid lane wires it into a cell.
188
+ */
189
+ export declare function CommentCountBadge({ count, hovered, onOpen, onOpenPreview, label: labelProp, previewLabel: previewLabelProp, className, }: CommentCountBadgeProps): React.JSX.Element | null;
190
+ export declare namespace CommentCountBadge {
191
+ var displayName: string;
192
+ }
@@ -0,0 +1,3 @@
1
+ declare const config: import("../..").RecipeConfig<{}>;
2
+ export declare const commentsRecipe: import("../..").RecipeFn<{}>;
3
+ export default config;
@@ -0,0 +1,2 @@
1
+ export { type CommentAuthor, CommentCountBadge, type CommentCountBadgeProps, type CommentItem, type CommentMentionTriggerState, type CommentReaction, CommentsPanel, type CommentsPanelProps, type CommentThread, } from "./comments";
2
+ export { commentsRecipe } from "./comments.recipe";
@@ -0,0 +1,2 @@
1
+ export { ATTRIBUTE_AI_AUTOFILL_OPTIONS, ATTRIBUTE_TYPE_OPTIONS, type AttributeRow, AttributesTable, type AttributesTableProps, type AttributeTypeOption, AttributeTypeSelect, type AttributeTypeSelectProps, CreateAttributeDialog, type CreateAttributeDialogProps, ObjectAppearanceSection, type ObjectAppearanceSectionProps, ObjectDetailPage, type ObjectDetailPageProps, type ObjectDetailTab, ObjectGeneralSection, type ObjectGeneralSectionProps, ObjectSettings, type ObjectSummary, ObjectsList, type ObjectsListProps, } from "./objectsettings";
2
+ export { objectsettingsRecipe } from "./objectsettings.recipe";
@@ -0,0 +1,261 @@
1
+ import * as React from "react";
2
+ export type ObjectSummary = {
3
+ id: string;
4
+ name: React.ReactNode;
5
+ /** 16px leading icon tile — a Lucide element, coloured by `iconColor`. */
6
+ icon: React.ReactNode;
7
+ iconColor?: string;
8
+ /** "Standard" / "Custom", etc. — plain text, not a coloured pill
9
+ * (measured: Attio's own Type column has no badge background). */
10
+ typeLabel: React.ReactNode;
11
+ /** Omit or 0 renders the muted "No records" copy, matching Attio. */
12
+ recordCount?: number;
13
+ attributeCount: number;
14
+ };
15
+ export type ObjectsListProps = Omit<React.ComponentPropsWithoutRef<"div">, "title"> & {
16
+ objects: ObjectSummary[];
17
+ onOpenObject?: (id: string) => void;
18
+ onEditObject?: (id: string) => void;
19
+ onCopyObjectId?: (id: string) => void;
20
+ /** Renders the trailing "New custom object" action when given. Omit to
21
+ * hide it — crisp has no billing-tier concept (HANDOFF.md), so this
22
+ * never carries Attio's own "Pro" gate badge; that plan-gate banner and
23
+ * badge are out of scope by decision (crisp#637). */
24
+ onCreateObject?: () => void;
25
+ title?: string;
26
+ subtitle?: string;
27
+ newObjectLabel?: string;
28
+ searchPlaceholder?: string;
29
+ filterLabel?: string;
30
+ objectColumnLabel?: string;
31
+ typeColumnLabel?: string;
32
+ recordsColumnLabel?: string;
33
+ attributesColumnLabel?: string;
34
+ noRecordsLabel?: string;
35
+ editLabel?: string;
36
+ copyIdLabel?: string;
37
+ rowMenuLabel?: (row: ObjectSummary) => string;
38
+ emptyLabel?: React.ReactNode;
39
+ };
40
+ /**
41
+ * Settings → Objects (crisp#637, P-122): H1 + subtitle, a search+Filter row,
42
+ * and a DataTable of every object (icon+name, type, record count,
43
+ * attribute count, a per-row "…" menu). Measured live against
44
+ * app.attio.com/<workspace>/settings/data/objects — the plan-gate banner
45
+ * above the table and the "5/3" object-count pill in the "Object" header
46
+ * (both billing-tier chrome) are skipped by decision, not oversight.
47
+ */
48
+ export declare function ObjectsList({ objects, onOpenObject, onEditObject, onCopyObjectId, onCreateObject, title: titleProp, subtitle: subtitleProp, newObjectLabel: newObjectLabelProp, searchPlaceholder: searchPlaceholderProp, filterLabel: filterLabelProp, objectColumnLabel: objectColumnLabelProp, typeColumnLabel: typeColumnLabelProp, recordsColumnLabel: recordsColumnLabelProp, attributesColumnLabel: attributesColumnLabelProp, noRecordsLabel: noRecordsLabelProp, editLabel: editLabelProp, copyIdLabel: copyIdLabelProp, rowMenuLabel, emptyLabel, className, ...rest }: ObjectsListProps): React.JSX.Element;
49
+ export declare namespace ObjectsList {
50
+ var displayName: string;
51
+ }
52
+ export type ObjectDetailTab = "configuration" | "attributes";
53
+ export type ObjectDetailPageProps = {
54
+ icon: React.ReactNode;
55
+ iconColor?: string;
56
+ name: React.ReactNode;
57
+ /** "Standard" / "Custom". */
58
+ typeLabel?: React.ReactNode;
59
+ description?: React.ReactNode;
60
+ tab?: ObjectDetailTab;
61
+ defaultTab?: ObjectDetailTab;
62
+ onTabChange?: (tab: ObjectDetailTab) => void;
63
+ attributeCount?: number;
64
+ configurationLabel?: string;
65
+ attributesLabel?: string;
66
+ children: (tab: ObjectDetailTab) => React.ReactNode;
67
+ };
68
+ /**
69
+ * Settings → Objects → an object (crisp#637, P-123, verified live against
70
+ * .../objects/companies/general): 48px icon tile + name + type badge, a
71
+ * description line, then a Configuration/Attributes tab bar (Attio's own
72
+ * tab bar also carries Permissions/Templates/Notifications/Imports — out of
73
+ * scope here, see #613/#638; only the two rows this task covers are built).
74
+ * Tab content is a render prop, the same shape crisp's own `Tabs` already
75
+ * takes, so a consumer composes `ObjectGeneralSection`/
76
+ * `ObjectAppearanceSection` and `AttributesTable` underneath.
77
+ */
78
+ export declare function ObjectDetailPage({ icon, iconColor, name, typeLabel, description, tab, defaultTab, onTabChange, attributeCount, configurationLabel: configurationLabelProp, attributesLabel: attributesLabelProp, children, }: ObjectDetailPageProps): React.JSX.Element;
79
+ export declare namespace ObjectDetailPage {
80
+ var displayName: string;
81
+ }
82
+ export type ObjectGeneralSectionProps = {
83
+ pluralNoun: string;
84
+ onPluralNounChange?: (v: string) => void;
85
+ singularNoun: string;
86
+ onSingularNounChange?: (v: string) => void;
87
+ slug: string;
88
+ /** Attio disables this for a system object ("You can't change the slug of
89
+ * a system object", measured verbatim) — pass `false` for Companies/
90
+ * Deals/People/Users/Workspaces, `true` for a custom object. */
91
+ slugEditable?: boolean;
92
+ onSlugChange?: (v: string) => void;
93
+ titleLabel?: string;
94
+ descriptionLabel?: string;
95
+ pluralLabel?: string;
96
+ singularLabel?: string;
97
+ slugLabel?: string;
98
+ slugHelpLabel?: string;
99
+ };
100
+ /** The Configuration tab's "General" section (crisp#637, P-123): plural/
101
+ * singular noun inputs side by side, then a slug input Attio locks for
102
+ * system objects. Composes `SettingsSection` + `FormField`, no new chrome. */
103
+ export declare function ObjectGeneralSection({ pluralNoun, onPluralNounChange, singularNoun, onSingularNounChange, slug, slugEditable, onSlugChange, titleLabel: titleLabelProp, descriptionLabel: descriptionLabelProp, pluralLabel: pluralLabelProp, singularLabel: singularLabelProp, slugLabel: slugLabelProp, slugHelpLabel: slugHelpLabelProp, }: ObjectGeneralSectionProps): React.JSX.Element;
104
+ export declare namespace ObjectGeneralSection {
105
+ var displayName: string;
106
+ }
107
+ export type ObjectAppearanceSectionProps = {
108
+ onConfigureRecordPage?: () => void;
109
+ titleLabel?: string;
110
+ rowLabel?: string;
111
+ rowDescriptionLabel?: string;
112
+ actionLabel?: string;
113
+ };
114
+ /** The Configuration tab's "Appearance" section (crisp#637, P-123): a single
115
+ * "Record page layout" row with a "Configure record page" button — the
116
+ * target flow itself (crisp's own record-page-layout editor) is a separate,
117
+ * unbuilt surface; this only renders the row and its click. */
118
+ export declare function ObjectAppearanceSection({ onConfigureRecordPage, titleLabel: titleLabelProp, rowLabel: rowLabelProp, rowDescriptionLabel: rowDescriptionLabelProp, actionLabel: actionLabelProp, }: ObjectAppearanceSectionProps): React.JSX.Element;
119
+ export declare namespace ObjectAppearanceSection {
120
+ var displayName: string;
121
+ }
122
+ export type AttributeRow = {
123
+ id: string;
124
+ name: React.ReactNode;
125
+ icon: React.ReactNode;
126
+ /** e.g. "Text", "Relationship" — the measured Data type column. */
127
+ dataType: React.ReactNode;
128
+ /** e.g. "Unique" — rendered as a plain constraint label per row. */
129
+ constraint?: React.ReactNode;
130
+ system?: boolean;
131
+ enriched?: boolean;
132
+ };
133
+ export type AttributesTableProps = {
134
+ attributes: AttributeRow[];
135
+ onOpenAttribute?: (id: string) => void;
136
+ onEditAttribute?: (id: string) => void;
137
+ onArchiveAttribute?: (id: string) => void;
138
+ onReorder?: (rows: AttributeRow[]) => void;
139
+ onCreateAttribute?: () => void;
140
+ title?: string;
141
+ subtitle?: string;
142
+ createLabel?: string;
143
+ searchPlaceholder?: string;
144
+ filterLabel?: string;
145
+ nameColumnLabel?: string;
146
+ dataTypeColumnLabel?: string;
147
+ constraintsColumnLabel?: string;
148
+ propertiesColumnLabel?: string;
149
+ systemLabel?: string;
150
+ enrichedLabel?: string;
151
+ editLabel?: string;
152
+ archiveLabel?: string;
153
+ /** Overrides the row "…" menu entirely — return the `MenuItem`s a
154
+ * consumer's own actions need (crisp#660). Attio's own row menu is
155
+ * Edit/Archive (the default, unchanged when this is omitted); a
156
+ * consumer whose data isn't Attio's own attribute model (no "archive"
157
+ * concept, a different action set entirely) supplies its own instead of
158
+ * working around two fixed items that don't fit. Receives the row so an
159
+ * item's handler can close over its id. */
160
+ rowActions?: (row: AttributeRow) => React.ReactNode;
161
+ emptyLabel?: React.ReactNode;
162
+ };
163
+ /**
164
+ * The Attributes tab's table (crisp#637, P-124, verified live): H2 +
165
+ * "Create attribute", a search+Filter row, then a DataTable of every
166
+ * attribute — drag handle (via `DataTable`'s own `onRowsReorder`) + type
167
+ * icon + name, Data type, a constraint label, and System (grey)/Enriched
168
+ * (purple) property badges. Row height is DataTable's own 36px; Attio's
169
+ * measures 40px here — a real, small divergence left to DataTable's owner
170
+ * rather than patched locally (see the PR).
171
+ */
172
+ export declare function AttributesTable({ attributes, onOpenAttribute, onEditAttribute, onArchiveAttribute, onReorder, onCreateAttribute, title: titleProp, subtitle: subtitleProp, createLabel: createLabelProp, searchPlaceholder: searchPlaceholderProp, filterLabel: filterLabelProp, nameColumnLabel: nameColumnLabelProp, dataTypeColumnLabel: dataTypeColumnLabelProp, constraintsColumnLabel: constraintsColumnLabelProp, propertiesColumnLabel: propertiesColumnLabelProp, systemLabel: systemLabelProp, enrichedLabel: enrichedLabelProp, editLabel: editLabelProp, archiveLabel: archiveLabelProp, rowActions, emptyLabel, }: AttributesTableProps): React.JSX.Element;
173
+ export declare namespace AttributesTable {
174
+ var displayName: string;
175
+ }
176
+ export type AttributeTypeOption = {
177
+ value: string;
178
+ label: string;
179
+ icon: React.ComponentType<{
180
+ size?: number;
181
+ }>;
182
+ /** e.g. "Pro" — Attio's own per-item plan-gate badge (measured on
183
+ * "Relationship"). Opt in per option; crisp models no billing tiers of
184
+ * its own, so nothing sets this by default. */
185
+ badge?: React.ReactNode;
186
+ };
187
+ /** Attio's own "Type" group, verbatim (crisp#637, P-126) — icons are
188
+ * crisp's Lucide choices, not Attio's proprietary set (golden rule 4). */
189
+ export declare const ATTRIBUTE_TYPE_OPTIONS: AttributeTypeOption[];
190
+ /** Attio's own "AI Autofill" group, verbatim (crisp#637, P-126) — opt in via
191
+ * `AttributeTypeSelect`'s `aiAutofillOptions`; omitted by default, since a
192
+ * consumer with no autofill backend of its own (GRC) has nothing to wire
193
+ * these to. */
194
+ export declare const ATTRIBUTE_AI_AUTOFILL_OPTIONS: AttributeTypeOption[];
195
+ export type AttributeTypeSelectProps = {
196
+ value: string;
197
+ onValueChange: (value: string) => void;
198
+ options?: AttributeTypeOption[];
199
+ /** Renders an "AI Autofill" group above "Type" (see
200
+ * `ATTRIBUTE_AI_AUTOFILL_OPTIONS`) — omitted by default. */
201
+ aiAutofillOptions?: AttributeTypeOption[];
202
+ aiAutofillGroupLabel?: string;
203
+ typeGroupLabel?: string;
204
+ searchPlaceholder?: string;
205
+ id?: string;
206
+ };
207
+ /** The "Attribute Type" dropdown (crisp#637, P-126, verified live): a
208
+ * searchable, grouped `Select` — reused as-is, not a new picker primitive.
209
+ * Grouping and the per-item trailing "Pro" badge are composed through
210
+ * `Select`'s existing `group` field and rich `label` ReactNode. */
211
+ export declare function AttributeTypeSelect({ value, onValueChange, options, aiAutofillOptions, aiAutofillGroupLabel: aiAutofillGroupLabelProp, typeGroupLabel: typeGroupLabelProp, searchPlaceholder: searchPlaceholderProp, id, }: AttributeTypeSelectProps): React.JSX.Element;
212
+ export declare namespace AttributeTypeSelect {
213
+ var displayName: string;
214
+ }
215
+ export type CreateAttributeDialogProps = {
216
+ type: string;
217
+ onTypeChange: (value: string) => void;
218
+ typeOptions?: AttributeTypeOption[];
219
+ aiAutofillTypeOptions?: AttributeTypeOption[];
220
+ name: string;
221
+ onNameChange: (value: string) => void;
222
+ description: string;
223
+ onDescriptionChange: (value: string) => void;
224
+ aiAutofillEnabled?: boolean;
225
+ onAiAutofillChange?: (enabled: boolean) => void;
226
+ onSubmit: () => void;
227
+ onClose: () => void;
228
+ busy?: boolean;
229
+ error?: React.ReactNode;
230
+ title?: string;
231
+ attributeTypeLabel?: string;
232
+ nameLabel?: string;
233
+ descriptionLabel?: string;
234
+ descriptionPlaceholder?: string;
235
+ aiAutofillLabel?: string;
236
+ setUpAiAutofillLabel?: string;
237
+ createLabel?: string;
238
+ };
239
+ /**
240
+ * "Create attribute" (crisp#637, P-125, verified live): Attribute Type
241
+ * select (defaults to Text) + Name (autofocused) + Description (optional)
242
+ * + an AI-autofill switch row, footer Cancel/Create. Built on `FormDialog`
243
+ * in its plain (non-`createMode`) shape — Attio's own footer here has a
244
+ * real Cancel button, unlike the record-create dialog `createMode` models
245
+ * (crisp#548), so `createMode` would be the wrong fit even though the
246
+ * button carries the same ⌘↵ hint; that hint is rendered locally instead.
247
+ */
248
+ export declare function CreateAttributeDialog({ type, onTypeChange, typeOptions, aiAutofillTypeOptions, name, onNameChange, description, onDescriptionChange, aiAutofillEnabled, onAiAutofillChange, onSubmit, onClose, busy, error, title: titleProp, attributeTypeLabel: attributeTypeLabelProp, nameLabel: nameLabelProp, descriptionLabel: descriptionLabelProp, descriptionPlaceholder: descriptionPlaceholderProp, aiAutofillLabel: aiAutofillLabelProp, setUpAiAutofillLabel: setUpAiAutofillLabelProp, createLabel: createLabelProp, }: CreateAttributeDialogProps): React.JSX.Element;
249
+ export declare namespace CreateAttributeDialog {
250
+ var displayName: string;
251
+ }
252
+ /**
253
+ * This folder holds several components (`ObjectsList`, `ObjectDetailPage`,
254
+ * `AttributesTable`, `CreateAttributeDialog`, …), not one named after the
255
+ * slug — unlike every other product dir, whose docs `<ManualInstallation>`
256
+ * resolves an import binding from the folder slug ("avatargroup" →
257
+ * `AvatarGroup`) by reading this file's exports. This alias exists only so
258
+ * that resolver finds a match for "objectsettings"; consumers should import
259
+ * the real names above, never this one.
260
+ */
261
+ export declare const ObjectSettings: typeof ObjectsList;
@@ -0,0 +1,3 @@
1
+ declare const config: import("../..").RecipeConfig<{}>;
2
+ export declare const objectsettingsRecipe: import("../..").RecipeFn<{}>;
3
+ export default config;
@@ -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.4",
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",
@@ -353,6 +363,11 @@
353
363
  "import": "./dist/esm/product/command/index.js",
354
364
  "require": "./dist/cjs/product/command/index.js"
355
365
  },
366
+ "./comments": {
367
+ "types": "./dist/types/product/comments/index.d.ts",
368
+ "import": "./dist/esm/product/comments/index.js",
369
+ "require": "./dist/cjs/product/comments/index.js"
370
+ },
356
371
  "./entitycard": {
357
372
  "types": "./dist/types/product/entitycard/index.d.ts",
358
373
  "import": "./dist/esm/product/entitycard/index.js",
@@ -393,6 +408,11 @@
393
408
  "import": "./dist/esm/product/navitem/index.js",
394
409
  "require": "./dist/cjs/product/navitem/index.js"
395
410
  },
411
+ "./objectsettings": {
412
+ "types": "./dist/types/product/objectsettings/index.d.ts",
413
+ "import": "./dist/esm/product/objectsettings/index.js",
414
+ "require": "./dist/cjs/product/objectsettings/index.js"
415
+ },
396
416
  "./onboarding": {
397
417
  "types": "./dist/types/product/onboarding/index.d.ts",
398
418
  "import": "./dist/esm/product/onboarding/index.js",