@crisp-ui-kit/crisp 0.49.0 → 0.51.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/components/composewindow/composewindow.js +144 -0
- package/dist/cjs/components/composewindow/composewindow.recipe.js +45 -0
- package/dist/cjs/components/composewindow/index.js +8 -0
- package/dist/cjs/components/datatable/datatable.js +224 -43
- package/dist/cjs/components/datatable/datatable.recipe.js +38 -4
- package/dist/cjs/components/datatable/index.js +6 -0
- package/dist/cjs/components/datepickerfield/datepickerfield.js +25 -15
- package/dist/cjs/components/datepickerfield/datepickerfield.recipe.js +25 -8
- package/dist/cjs/components/dialog/dialog.recipe.js +9 -1
- package/dist/cjs/components/menu/menu.js +4 -2
- package/dist/cjs/components/multiselect/multiselect.recipe.js +14 -8
- package/dist/cjs/components/select/select.js +2 -1
- package/dist/cjs/components/table/table.recipe.js +12 -3
- package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +2 -1
- package/dist/cjs/components/tabletoolbar/tabletoolbar.js +39 -8
- package/dist/cjs/core/cell-date.js +11 -0
- package/dist/cjs/core/index.js +2 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/product/recordpage/recordpage.js +88 -10
- package/dist/cjs/product/recordpage/recordpage.recipe.js +30 -0
- package/dist/cjs/product/recordpanel/recordpanel.js +54 -4
- package/dist/cjs/product/recordpanel/recordpanel.recipe.js +29 -0
- package/dist/cjs/product/recordstable/editable-field.js +110 -0
- package/dist/cjs/product/recordstable/index.js +4 -1
- package/dist/cjs/product/recordstable/recordstable.js +67 -11
- package/dist/cjs/product/recordstable/recordstable.recipe.js +9 -1
- package/dist/cjs/product/settingsshell/settingsshell.recipe.js +13 -4
- package/dist/cjs/product/sidebar/sidebar.js +15 -3
- package/dist/cjs/product/sidebar/sidebar.recipe.js +21 -2
- package/dist/composewindow.css +24 -0
- package/dist/composewindow.d.ts +7 -0
- package/dist/composewindow.layered.css +26 -0
- package/dist/datatable.css +34 -15
- package/dist/datatable.layered.css +34 -15
- package/dist/datepickerfield.css +9 -4
- package/dist/datepickerfield.layered.css +9 -4
- package/dist/dialog.css +2 -1
- package/dist/dialog.layered.css +2 -1
- package/dist/esm/components/composewindow/composewindow.js +107 -0
- package/dist/esm/components/composewindow/composewindow.recipe.js +42 -0
- package/dist/esm/components/composewindow/index.js +2 -0
- package/dist/esm/components/datatable/datatable.js +226 -45
- package/dist/esm/components/datatable/datatable.recipe.js +38 -4
- package/dist/esm/components/datatable/index.js +6 -0
- package/dist/esm/components/datepickerfield/datepickerfield.js +26 -16
- package/dist/esm/components/datepickerfield/datepickerfield.recipe.js +25 -8
- package/dist/esm/components/dialog/dialog.recipe.js +9 -1
- package/dist/esm/components/menu/menu.js +4 -2
- package/dist/esm/components/multiselect/multiselect.recipe.js +14 -8
- package/dist/esm/components/select/select.js +2 -1
- package/dist/esm/components/table/table.recipe.js +12 -3
- package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +2 -1
- package/dist/esm/components/tabletoolbar/tabletoolbar.js +38 -8
- package/dist/esm/core/cell-date.js +10 -0
- package/dist/esm/core/index.js +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/product/recordpage/recordpage.js +89 -11
- package/dist/esm/product/recordpage/recordpage.recipe.js +30 -0
- package/dist/esm/product/recordpanel/recordpanel.js +55 -5
- package/dist/esm/product/recordpanel/recordpanel.recipe.js +29 -0
- package/dist/esm/product/recordstable/editable-field.js +73 -0
- package/dist/esm/product/recordstable/index.js +1 -0
- package/dist/esm/product/recordstable/recordstable.js +69 -13
- package/dist/esm/product/recordstable/recordstable.recipe.js +9 -1
- package/dist/esm/product/settingsshell/settingsshell.recipe.js +13 -4
- package/dist/esm/product/sidebar/sidebar.js +15 -3
- package/dist/esm/product/sidebar/sidebar.recipe.js +21 -2
- package/dist/multiselect.css +8 -8
- package/dist/multiselect.layered.css +8 -8
- package/dist/recordpage.css +25 -13
- package/dist/recordpage.layered.css +25 -13
- package/dist/recordpanel.css +22 -5
- package/dist/recordpanel.layered.css +22 -5
- package/dist/recordstable.css +10 -2
- package/dist/recordstable.layered.css +10 -2
- package/dist/settingsshell.css +2 -2
- package/dist/settingsshell.layered.css +2 -2
- package/dist/sidebar.css +7 -2
- package/dist/sidebar.layered.css +7 -2
- package/dist/styles.css +150 -55
- package/dist/styles.layered.css +150 -55
- package/dist/table.css +4 -2
- package/dist/table.layered.css +4 -2
- package/dist/tabletoolbar.css +2 -1
- package/dist/tabletoolbar.layered.css +2 -1
- package/dist/types/components/composewindow/composewindow.d.ts +80 -0
- package/dist/types/components/composewindow/composewindow.recipe.d.ts +3 -0
- package/dist/types/components/composewindow/index.d.ts +2 -0
- package/dist/types/components/datatable/datatable.d.ts +58 -4
- package/dist/types/components/datatable/index.d.ts +1 -1
- package/dist/types/components/datepickerfield/datepickerfield.d.ts +18 -4
- package/dist/types/components/menu/menu.d.ts +10 -1
- package/dist/types/components/select/select.d.ts +6 -1
- package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +62 -5
- package/dist/types/core/cell-date.d.ts +17 -0
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/product/recordpage/recordpage.d.ts +59 -1
- package/dist/types/product/recordpanel/recordpanel.d.ts +11 -1
- package/dist/types/product/recordstable/editable-field.d.ts +45 -0
- package/dist/types/product/recordstable/index.d.ts +1 -0
- package/dist/types/product/recordstable/recordstable.d.ts +29 -0
- package/dist/types/product/sidebar/sidebar.d.ts +60 -4
- package/package.json +6 -1
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { defineRecipe, resolveRecipe, rtlFlipCss } from "../../core/index.js";
|
|
2
2
|
import { contract as c } from "../../tokens/index.js";
|
|
3
|
-
// The Settings layout — measured from a Settings screen: a
|
|
3
|
+
// The Settings layout — measured from a Settings screen: a 275px left nav with a
|
|
4
4
|
// back header, a search field, and grouped nav items (active row raised), beside
|
|
5
|
-
// a scrolling content pane.
|
|
5
|
+
// a scrolling content pane. Fills whatever height its container gives it, the
|
|
6
|
+
// way Attio's settings nav runs the container's full height (#435) — the root
|
|
7
|
+
// used to carry only `min-height: 0` (lets it *shrink* inside a flex ancestor)
|
|
8
|
+
// with no `height` of its own, so it sized to its content instead of filling,
|
|
9
|
+
// and the nav's own border-inline-end stopped where the nav content ended
|
|
10
|
+
// rather than running the full height. A consumer (GRC) had to paper over it
|
|
11
|
+
// with an external `h-full` class.
|
|
12
|
+
// 275px, not the 256px this recipe used to claim (#410) — the same width
|
|
13
|
+
// AppShell's own Attio-measured `defaultWidth` already uses for the main
|
|
14
|
+
// sidebar pane; re-measured live at app.attio.com/<workspace>/settings/account.
|
|
6
15
|
const config = defineRecipe({
|
|
7
16
|
name: "settingsshell",
|
|
8
|
-
base: `display: flex; min-height: 0; box-sizing: border-box; font-family: ${c.font.sans}; color: ${c.fgPrimary};
|
|
17
|
+
base: `display: flex; height: 100%; min-height: 0; box-sizing: border-box; font-family: ${c.font.sans}; color: ${c.fgPrimary};
|
|
9
18
|
-webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
10
19
|
|
|
11
|
-
& .crisp-settingsshell-nav { display: flex; flex-direction: column; width:
|
|
20
|
+
& .crisp-settingsshell-nav { display: flex; flex-direction: column; width: 275px; flex-shrink: 0; min-height: 0; padding: ${c.space["3"]}; border-inline-end: 1px solid ${c.borderSubtle}; }
|
|
12
21
|
& .crisp-settingsshell-back { display: inline-flex; align-items: center; gap: ${c.space["1.5"]}; height: 28px; padding: 0 ${c.space["1"]}; margin: 0 0 ${c.space["2"]}; border: none; background: none; font-family: inherit; font-size: ${c.text.lg}; font-weight: ${c.weight.semibold}; color: ${c.fgPrimary}; cursor: pointer; border-radius: ${c.radius.md}; }
|
|
13
22
|
& .crisp-settingsshell-back svg { color: ${c.fgMuted}; }
|
|
14
23
|
& .crisp-settingsshell-back:hover svg { color: ${c.fgPrimary}; }
|
|
@@ -4,10 +4,20 @@ import * as React from "react";
|
|
|
4
4
|
import { Avatar } from "../../components/avatar/index.js";
|
|
5
5
|
import { Badge } from "../../components/badge/index.js";
|
|
6
6
|
import { Button } from "../../components/button/index.js";
|
|
7
|
+
import { Menu } from "../../components/menu/index.js";
|
|
7
8
|
import { Primitive } from "../../core/index.js";
|
|
8
9
|
import { Command } from "../command/index.js";
|
|
9
10
|
import { NavItem } from "../navitem/index.js";
|
|
10
11
|
import { sidebarRecipe } from "./sidebar.recipe.js";
|
|
12
|
+
/** A plain `{ gettingStartedLabel, inviteLabel, trialText, trialActionLabel }`
|
|
13
|
+
* object (not a React element) — the shape `footer` renders as Attio's fixed
|
|
14
|
+
* onboarding/invite/trial copy, as opposed to a caller-supplied override. */
|
|
15
|
+
function isSidebarFooterCopy(value) {
|
|
16
|
+
return (typeof value === "object" &&
|
|
17
|
+
value !== null &&
|
|
18
|
+
!React.isValidElement(value) &&
|
|
19
|
+
"gettingStartedLabel" in value);
|
|
20
|
+
}
|
|
11
21
|
const IconHome = ({ className }) => (_jsx(House, { className: className, size: 16, strokeWidth: 1.75, "aria-hidden": "true" }));
|
|
12
22
|
const IconTasks = ({ className }) => (_jsx(SquareCheck, { className: className, size: 16, strokeWidth: 1.75, "aria-hidden": "true" }));
|
|
13
23
|
const IconNotes = ({ className }) => (_jsx(FileText, { className: className, size: 16, strokeWidth: 1.75, "aria-hidden": "true" }));
|
|
@@ -81,7 +91,7 @@ export const ATTIO_SIDEBAR_FOOTER = {
|
|
|
81
91
|
function SectionHeader({ label, open, onToggle, }) {
|
|
82
92
|
return (_jsxs("button", { type: "button", className: "crisp-sidebar-section-header", "data-collapsed": open ? undefined : "", "aria-expanded": open, onClick: onToggle, children: [_jsx(IconChevronMini, {}), _jsx("span", { children: label })] }));
|
|
83
93
|
}
|
|
84
|
-
export const Sidebar = React.forwardRef(({ className, asChild, onToggleCollapse, collapseLabel = "Collapse sidebar", inboxLabel = "Inbox", searchLabel = "Search", workspace = ATTIO_SIDEBAR_WORKSPACE, items = ATTIO_SIDEBAR_ITEMS, recordsSection = ATTIO_SIDEBAR_RECORDS_SECTION, listsSection = ATTIO_SIDEBAR_LISTS_SECTION, chatsSection = ATTIO_SIDEBAR_CHATS_SECTION, groups, footer = ATTIO_SIDEBAR_FOOTER, commandItems, commandOpen: commandOpenProp, defaultCommandOpen, onCommandOpenChange, commandShortcut = true, "aria-label": ariaLabel = "Main", ...props }, ref) => {
|
|
94
|
+
export const Sidebar = React.forwardRef(({ className, asChild, onToggleCollapse, collapseLabel = "Collapse sidebar", inboxLabel = "Inbox", searchLabel = "Search", workspace = ATTIO_SIDEBAR_WORKSPACE, workspaceMenu, items = ATTIO_SIDEBAR_ITEMS, recordsSection = ATTIO_SIDEBAR_RECORDS_SECTION, listsSection = ATTIO_SIDEBAR_LISTS_SECTION, chatsSection = ATTIO_SIDEBAR_CHATS_SECTION, groups, footer = ATTIO_SIDEBAR_FOOTER, commandItems, commandOpen: commandOpenProp, defaultCommandOpen, onCommandOpenChange, commandShortcut = true, "aria-label": ariaLabel = "Main", ...props }, ref) => {
|
|
85
95
|
// Seeded once, on mount, from whatever groups start collapsed — not
|
|
86
96
|
// reactive to `groups` changing later, matching every other piece of
|
|
87
97
|
// this component's state (recordsSection/listsSection/chatsSection have
|
|
@@ -127,13 +137,15 @@ export const Sidebar = React.forwardRef(({ className, asChild, onToggleCollapse,
|
|
|
127
137
|
return next;
|
|
128
138
|
});
|
|
129
139
|
}, []);
|
|
130
|
-
|
|
140
|
+
const workspaceTrigger = (_jsxs("button", { type: "button", className: "crisp-sidebar-ws", children: [_jsx(Avatar, { size: "lg", shape: "rounded", tone: workspace.avatarTone, children: workspace.avatarLabel }), _jsx("span", { className: "crisp-sidebar-ws-name", children: workspace.name }), _jsx(IconChevronDown, {})] }));
|
|
141
|
+
return (_jsxs(Primitive.nav, { ref: ref, asChild: asChild, "aria-label": ariaLabel, className: sidebarRecipe({ className }), ...props, children: [_jsxs("div", { className: "crisp-sidebar-ws-row", children: [workspaceMenu ? (_jsx(Menu, { trigger: workspaceTrigger, className: "crisp-sidebar-ws-menuroot", contentClassName: "crisp-sidebar-ws-menu-content", children: workspaceMenu })) : (workspaceTrigger), _jsx(Button, { intent: "ghost", size: "sm", shape: "icon", className: "crisp-sidebar-ws-collapse", "aria-label": collapseLabel, onClick: onToggleCollapse, children: _jsx(IconCollapsePanel, {}) })] }), _jsxs("div", { className: "crisp-sidebar-searchrow", children: [_jsxs("button", { type: "button", className: "crisp-sidebar-search", onClick: () => setCommandOpen(true), children: [_jsx(IconSearch, {}), _jsx("span", { className: "crisp-sidebar-search-label", children: searchLabel }), _jsx("span", { className: "crisp-sidebar-search-kbd", children: "\u2318K" })] }), _jsx(Button, { intent: "neutral", size: "sm", shape: "icon", "aria-label": inboxLabel, children: _jsx(IconInbox, {}) })] }), _jsx("div", { className: "crisp-sidebar-divider" }), _jsx("div", { className: "crisp-sidebar-section", children: items.map(({ label, icon: ItemIcon, active, trailing, href, onSelect }) => (_jsx(NavItem, { href: href ?? "#", active: active, icon: _jsx(ItemIcon, {}), trailing: trailing, onClick: onSelect, children: label }, href ?? label))) }), groups ? (
|
|
131
142
|
// #325: navigation as data, reusing the exact section markup/
|
|
132
143
|
// recipe above — SectionHeader + .crisp-sidebar-section — instead
|
|
133
144
|
// of the three fixed Attio sections.
|
|
134
145
|
groups.map((group) => {
|
|
135
146
|
const groupKey = group.key ?? group.label;
|
|
136
147
|
return (_jsxs(React.Fragment, { children: [_jsx(SectionHeader, { label: group.label, open: !collapsedSections.has(groupKey), onToggle: () => toggleSection(groupKey) }), _jsx("div", { className: "crisp-sidebar-section", "data-collapsed": collapsedSections.has(groupKey) ? "" : undefined, children: group.items.map((item) => (_jsx(NavItem, { href: item.href ?? "#", active: item.active, icon: item.icon ? _jsx(item.icon, {}) : undefined, trailing: item.count, onClick: item.onSelect, children: item.label }, item.href ?? item.label))) })] }, groupKey));
|
|
137
|
-
})) : (_jsxs(_Fragment, { children: [_jsx(SectionHeader, { label: recordsSection.label, open: !collapsedSections.has("records"), onToggle: () => toggleSection("records") }), _jsx("div", { className: "crisp-sidebar-section", "data-collapsed": collapsedSections.has("records") ? "" : undefined, children: recordsSection.items.map(({ label, tone, glyph: Glyph }) => (_jsx(NavItem, { href: "#", icon: _jsx(Avatar, { size: "sm", shape: "rounded", tone: tone, children: _jsx(Glyph, {}) }), children: label }, label))) }), _jsx(SectionHeader, { label: listsSection.label, open: !collapsedSections.has("lists"), onToggle: () => toggleSection("lists") }), _jsx("div", { className: "crisp-sidebar-section", "data-collapsed": collapsedSections.has("lists") ? "" : undefined, children: _jsx("button", { type: "button", className: "crisp-sidebar-newlist", children: listsSection.newListLabel }) }), _jsx(SectionHeader, { label: chatsSection.label, open: !collapsedSections.has("chats"), onToggle: () => toggleSection("chats") }), _jsx("div", { className: "crisp-sidebar-section", "data-collapsed": collapsedSections.has("chats") ? "" : undefined, children: chatsSection.items.map(({ label, icon: ItemIcon
|
|
148
|
+
})) : (_jsxs(_Fragment, { children: [_jsx(SectionHeader, { label: recordsSection.label, open: !collapsedSections.has("records"), onToggle: () => toggleSection("records") }), _jsx("div", { className: "crisp-sidebar-section", "data-collapsed": collapsedSections.has("records") ? "" : undefined, children: recordsSection.items.map(({ label, tone, glyph: Glyph }) => (_jsx(NavItem, { href: "#", icon: _jsx(Avatar, { size: "sm", shape: "rounded", tone: tone, children: _jsx(Glyph, {}) }), children: label }, label))) }), _jsx(SectionHeader, { label: listsSection.label, open: !collapsedSections.has("lists"), onToggle: () => toggleSection("lists") }), _jsx("div", { className: "crisp-sidebar-section", "data-collapsed": collapsedSections.has("lists") ? "" : undefined, children: _jsx("button", { type: "button", className: "crisp-sidebar-newlist", children: listsSection.newListLabel }) }), _jsx(SectionHeader, { label: chatsSection.label, open: !collapsedSections.has("chats"), onToggle: () => toggleSection("chats") }), _jsx("div", { className: "crisp-sidebar-section", "data-collapsed": collapsedSections.has("chats") ? "" : undefined, children: chatsSection.items.map(({ label, icon: ItemIcon, active, trailing, href, onSelect, }) => (_jsx(NavItem, { href: href ?? "#", active: active, icon: _jsx(ItemIcon, {}), trailing: trailing, onClick: onSelect, children: label }, href ?? label))) })] })), footer !== false &&
|
|
149
|
+
(isSidebarFooterCopy(footer) ? (_jsxs("div", { className: "crisp-sidebar-footer", children: [_jsx(Button, { intent: "neutral", size: "sm", className: "crisp-sidebar-pill", children: footer.gettingStartedLabel }), _jsx(NavItem, { href: "#", icon: _jsx(IconInvite, {}), children: footer.inviteLabel }), _jsx("div", { className: "crisp-sidebar-divider" }), _jsxs("div", { className: "crisp-sidebar-trial", children: [_jsx("span", { children: footer.trialText }), _jsx(Button, { intent: "neutral", size: "sm", children: footer.trialActionLabel })] })] })) : (_jsx("div", { className: "crisp-sidebar-footer", children: footer }))), _jsx(Command, { open: commandOpen, onOpenChange: setCommandOpen, items: commandItems })] }));
|
|
138
150
|
});
|
|
139
151
|
Sidebar.displayName = "Sidebar";
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { defineRecipe, resolveRecipe, rtlFlipCss } from "../../core/index.js";
|
|
2
2
|
import { contract as c, elevation as e } from "../../tokens/index.js";
|
|
3
|
+
// The workspace switcher's menu (#415) is 280px wide on app.attio.com --
|
|
4
|
+
// measured live via getComputedStyle on its [role="menu"], not derived from
|
|
5
|
+
// the trigger's own width (which reads 295-296px including its collapse
|
|
6
|
+
// button) or from Menu's generic 200px content-sized min-width. Everything
|
|
7
|
+
// else about the popover -- 4px padding, 12px radius, 32px/8px-radius items,
|
|
8
|
+
// 14px/500 labels, the layered shadow -- already matches Menu's own measured
|
|
9
|
+
// chrome, confirmed against this specific menu rather than assumed from it.
|
|
3
10
|
const config = defineRecipe({
|
|
4
11
|
name: "sidebar",
|
|
5
12
|
base: `box-sizing: border-box; display: flex; flex-direction: column; width: 275px; height: 100%; background: ${c.bgSidebar}
|
|
@@ -12,10 +19,12 @@ const config = defineRecipe({
|
|
|
12
19
|
& .crisp-sidebar-section-header { display: flex; align-items: center; gap: ${c.space["1"]}; width: 100%; margin: 0; border: none; background: none; padding: ${c.space["1.5"]} ${c.space["2"]} ${c.space["0.5"]}; font-family: ${c.font.sans}; font-size: ${c.text.sm}; font-weight: ${c.weight.medium}; color: ${c.fgMuted}; cursor: pointer; }
|
|
13
20
|
& .crisp-sidebar-section-header svg { flex-shrink: 0; transition: transform .15s ease; }
|
|
14
21
|
& .crisp-sidebar-section-header[data-collapsed] svg { transform: rotate(-90deg); }
|
|
15
|
-
& .crisp-sidebar-ws { display: flex; align-items: center; gap: ${c.space["2"]}; height: ${c.size.header}; padding: 0 ${c.space["2"]};
|
|
22
|
+
& .crisp-sidebar-ws-row { display: flex; align-items: center; gap: ${c.space["2"]}; height: ${c.size.header}; padding: 0 ${c.space["2"]}; }
|
|
23
|
+
& .crisp-sidebar-ws-menuroot { display: flex; flex: 1; min-width: 0; }
|
|
24
|
+
& .crisp-sidebar-ws { box-sizing: border-box; display: flex; align-items: center; gap: ${c.space["2"]}; flex: 1; min-width: 0; height: 100%; margin: 0; padding: 0; border: none; background: none; border-radius: ${c.radius.lg}; font-family: inherit; font-size: inherit; color: inherit; text-align: start; cursor: pointer; transition: background-color 0.16s; }
|
|
16
25
|
& .crisp-sidebar-ws:hover { background: color-mix(in srgb, ${c.fgPrimary} 5%, transparent); }
|
|
17
26
|
& .crisp-sidebar-ws-name { font-size: ${c.text.lg}; font-weight: ${c.weight.semibold}; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
18
|
-
& .crisp-sidebar-ws-collapse {
|
|
27
|
+
& .crisp-sidebar-ws-collapse { flex-shrink: 0; }
|
|
19
28
|
& .crisp-sidebar-searchrow { display: flex; align-items: center; gap: ${c.space["1.5"]}; margin-top: ${c.space["2.5"]}; padding-inline-end: ${c.space["2"]}; }
|
|
20
29
|
& .crisp-sidebar-footer { margin-top: auto; display: flex; flex-direction: column; gap: ${c.space["0.5"]}; }
|
|
21
30
|
& .crisp-sidebar-trial { display: flex; align-items: center; justify-content: space-between; gap: ${c.space["2"]}; padding: ${c.space["1.5"]} ${c.space["2"]}; font-size: ${c.text.sm}; color: ${c.fgMuted}; }
|
|
@@ -29,6 +38,16 @@ const config = defineRecipe({
|
|
|
29
38
|
& .crisp-sidebar-newlist:hover { background: ${c.bgRaised}; color: ${c.fgPrimary}; }
|
|
30
39
|
|
|
31
40
|
${rtlFlipCss}
|
|
41
|
+
`,
|
|
42
|
+
// Menu's own floating content is portaled to document.body (#357), so a
|
|
43
|
+
// `&`-nested rule here -- which compiles to a real descendant combinator
|
|
44
|
+
// scoped to .crisp-sidebar -- matches nothing once the popover leaves the
|
|
45
|
+
// sidebar's DOM subtree. Same fix Menu's own recipe already uses: the
|
|
46
|
+
// content's override lives in globalCss instead, keyed off the
|
|
47
|
+
// \`contentClassName\` Menu now hands the workspace switcher's portaled
|
|
48
|
+
// surface (#415).
|
|
49
|
+
globalCss: `
|
|
50
|
+
.crisp-sidebar-ws-menu-content { width: 280px; }
|
|
32
51
|
`,
|
|
33
52
|
variants: {},
|
|
34
53
|
defaultVariants: {},
|
package/dist/multiselect.css
CHANGED
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
.crisp-multiselect-option[aria-selected="true"] .crisp-multiselect-check { background: var(--crisp-bg-brand-solid); box-shadow: none; color: #fff; }
|
|
33
33
|
.crisp-multiselect-empty { padding: var(--crisp-space-3) var(--crisp-space-2); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
34
34
|
|
|
35
|
-
.crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
36
|
-
.crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); }
|
|
37
|
-
.crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); }
|
|
38
|
-
.crisp-recordstable-tag[data-tone="warning"] { background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); }
|
|
39
|
-
.crisp-recordstable-tag[data-tone="danger"] { background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); }
|
|
40
|
-
.crisp-recordstable-tag[data-tone="purple"] { background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); }
|
|
41
|
-
.crisp-recordstable-tag[data-tone="cyan"] { background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); }
|
|
42
|
-
.crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); }
|
|
35
|
+
.crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); }
|
|
36
|
+
.crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent); }
|
|
37
|
+
.crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent); }
|
|
38
|
+
.crisp-recordstable-tag[data-tone="warning"] { background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-warning) 30%, transparent); }
|
|
39
|
+
.crisp-recordstable-tag[data-tone="danger"] { background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-danger) 30%, transparent); }
|
|
40
|
+
.crisp-recordstable-tag[data-tone="purple"] { background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-purple) 30%, transparent); }
|
|
41
|
+
.crisp-recordstable-tag[data-tone="cyan"] { background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-cyan) 30%, transparent); }
|
|
42
|
+
.crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
|
|
43
43
|
|
|
44
44
|
.crisp-multiselect {
|
|
45
45
|
position: relative; display: inline-flex; width: 100%; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
.crisp-multiselect-option[aria-selected="true"] .crisp-multiselect-check { background: var(--crisp-bg-brand-solid); box-shadow: none; color: #fff; }
|
|
34
34
|
.crisp-multiselect-empty { padding: var(--crisp-space-3) var(--crisp-space-2); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
35
35
|
|
|
36
|
-
.crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
37
|
-
.crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); }
|
|
38
|
-
.crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); }
|
|
39
|
-
.crisp-recordstable-tag[data-tone="warning"] { background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); }
|
|
40
|
-
.crisp-recordstable-tag[data-tone="danger"] { background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); }
|
|
41
|
-
.crisp-recordstable-tag[data-tone="purple"] { background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); }
|
|
42
|
-
.crisp-recordstable-tag[data-tone="cyan"] { background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); }
|
|
43
|
-
.crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); }
|
|
36
|
+
.crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); }
|
|
37
|
+
.crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent); }
|
|
38
|
+
.crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent); }
|
|
39
|
+
.crisp-recordstable-tag[data-tone="warning"] { background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-warning) 30%, transparent); }
|
|
40
|
+
.crisp-recordstable-tag[data-tone="danger"] { background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-danger) 30%, transparent); }
|
|
41
|
+
.crisp-recordstable-tag[data-tone="purple"] { background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-purple) 30%, transparent); }
|
|
42
|
+
.crisp-recordstable-tag[data-tone="cyan"] { background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-cyan) 30%, transparent); }
|
|
43
|
+
.crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
|
|
44
44
|
|
|
45
45
|
.crisp-multiselect {
|
|
46
46
|
position: relative; display: inline-flex; width: 100%; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
package/dist/recordpage.css
CHANGED
|
@@ -60,27 +60,46 @@
|
|
|
60
60
|
& .crisp-recordpage-field-label svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
61
61
|
& .crisp-recordpage-field-label-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
62
62
|
& .crisp-recordpage-field-value { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); padding-top: 2px; line-height: 20px; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
63
|
+
& .crisp-recordpage-field-value[data-editable] { cursor: pointer; }
|
|
64
|
+
/* the click-to-edit trigger is a real <button> (keyboard-operable),
|
|
65
|
+
reset back to plain inline text and made a flex-wrap container of its
|
|
66
|
+
own -- FieldValue can render several chips (tags), which still need
|
|
67
|
+
to wrap the way they did before this had a button around them at
|
|
68
|
+
all. It wraps only FieldValue, never the error slot beside it (see
|
|
69
|
+
the component's own comment) -- NOT `display: contents`, which drops a button's accessible semantics in some engines. */
|
|
70
|
+
& .crisp-recordpage-edit-trigger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); margin: 0; padding: 0; border: none; background: none; text-align: start; font: inherit; color: inherit; cursor: pointer; }
|
|
63
71
|
& .crisp-recordpage-empty { color: var(--crisp-fg-muted); }
|
|
72
|
+
|
|
73
|
+
/* #431: measured live on app.attio.com's record page Details column -- clicking a field's value opens a plain, borderless field exactly
|
|
74
|
+
filling the value's own box (no border, no background, no box-shadow), same font as the value it replaces (hence `font: inherit`, not a restated size/weight). A field row's own hover tint
|
|
75
|
+
above already carries the "this is interactive" affordance; the
|
|
76
|
+
pending/error treatment isn't Attio-measured -- it reuses the same tokens DataTable's identical states already use (opacity 0.5,
|
|
77
|
+
`bgDanger`), per #385/#430. */
|
|
78
|
+
& .crisp-recordpage-edit { display: block; width: 100%; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; box-shadow: none; outline: none; font: inherit; color: inherit; }
|
|
79
|
+
/* not Attio-measured (its own field shows no focus ring either, caret
|
|
80
|
+
only) -- kept for real keyboard users, the same brand ring every
|
|
81
|
+
other crisp field already shows on focus (DataTable's identical .crisp-datatable-edit:focus, e.g.). */
|
|
82
|
+
& .crisp-recordpage-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
83
|
+
& .crisp-recordpage-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
84
|
+
& .crisp-recordpage-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
85
|
+
& .crisp-recordpage-edit-error { flex-basis: 100%; margin-top: var(--crisp-space-0-5); font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
86
|
+
& .crisp-recordpage-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
|
|
87
|
+
& .crisp-recordpage-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; }
|
|
64
88
|
& .crisp-recordpage-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
65
89
|
& .crisp-recordpage-link:hover { text-decoration: underline; }
|
|
66
90
|
& .crisp-recordpage-emptystate { padding: var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
67
|
-
|
|
68
91
|
& .crisp-recordpage-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; overflow-y: auto; padding: var(--crisp-space-3) var(--crisp-space-5); }
|
|
69
|
-
|
|
70
92
|
& .crisp-recordpage-panel { padding-top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-4); }
|
|
71
93
|
& .crisp-recordpage-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); background: var(--crisp-bg-surface); overflow: hidden; }
|
|
72
94
|
& .crisp-recordpage-card-title { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); letter-spacing: -0.14px; color: var(--crisp-fg-primary); padding: var(--crisp-space-3) var(--crisp-space-3) var(--crisp-space-2); }
|
|
73
95
|
& .crisp-recordpage-hl-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); overflow: hidden; }
|
|
74
|
-
/* gap-as-gridlines: a 1px gap over the border colour draws dividers at any
|
|
75
|
-
column count, so the grid stays responsive (auto-fit) without per-cell
|
|
76
|
-
nth-child border hacks that break when the column count changes. */
|
|
96
|
+
/* gap-as-gridlines: a 1px gap over the border colour draws dividers at any column count, so the grid stays responsive (auto-fit) without per-cell nth-child border hacks that break when the column count changes. */
|
|
77
97
|
& .crisp-recordpage-hl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px; background: var(--crisp-border-subtle); }
|
|
78
98
|
& .crisp-recordpage-hl-cell { position: relative; min-height: 84px; padding: var(--crisp-space-2-5) var(--crisp-space-3); background: var(--crisp-bg-surface); }
|
|
79
99
|
& .crisp-recordpage-hl-icon { position: absolute; top: var(--crisp-space-2-5); inset-inline-end: var(--crisp-space-3); color: var(--crisp-fg-muted); }
|
|
80
100
|
& .crisp-recordpage-hl-label { font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); margin-bottom: var(--crisp-space-2-5); padding-inline-end: var(--crisp-space-4); }
|
|
81
101
|
& .crisp-recordpage-hl-value { display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
82
102
|
& .crisp-recordpage-hl-value--empty { color: var(--crisp-fg-muted); font-weight: var(--crisp-weight-regular); }
|
|
83
|
-
|
|
84
103
|
& .crisp-recordpage-feed { display: flex; flex-direction: column; }
|
|
85
104
|
& .crisp-recordpage-feed-item { display: flex; align-items: flex-start; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2) 0; }
|
|
86
105
|
& .crisp-recordpage-feed-dot { position: relative; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex-shrink: 0; border-radius: var(--crisp-radius-full); background: var(--crisp-bg-raised); color: var(--crisp-fg-muted); }
|
|
@@ -89,7 +108,6 @@
|
|
|
89
108
|
& .crisp-recordpage-feed-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); margin-top: 2px; }
|
|
90
109
|
& .crisp-recordpage-feed-more { align-self: flex-start; margin-top: var(--crisp-space-1); border: none; background: none; padding: var(--crisp-space-1) 0; color: var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
|
|
91
110
|
& .crisp-recordpage-feed-more:hover { text-decoration: underline; }
|
|
92
|
-
|
|
93
111
|
& .crisp-recordpage-section-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-1); }
|
|
94
112
|
& .crisp-recordpage-section-head .crisp-recordpage-section-title { padding: 0; }
|
|
95
113
|
& .crisp-recordpage-section-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-sm); background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); font-size: var(--crisp-text-xs); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
@@ -97,7 +115,6 @@
|
|
|
97
115
|
& .crisp-recordpage-addbtn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: 26px; padding: 0 var(--crisp-space-1-5); margin: 0; border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-neutral), 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
|
|
98
116
|
& .crisp-recordpage-addbtn:hover { background: var(--crisp-bg-raised); }
|
|
99
117
|
& .crisp-recordpage-addbtn svg { flex-shrink: 0; }
|
|
100
|
-
|
|
101
118
|
& .crisp-recordpage-composer { display: flex; flex-direction: column; gap: var(--crisp-space-2); padding: var(--crisp-space-2); border: 1px solid var(--crisp-border-default); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); margin-bottom: var(--crisp-space-2); }
|
|
102
119
|
& .crisp-recordpage-composer textarea { width: 100%; min-height: 56px; resize: vertical; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
103
120
|
& .crisp-recordpage-composer textarea:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); border-radius: var(--crisp-radius-md); }
|
|
@@ -107,23 +124,18 @@
|
|
|
107
124
|
& .crisp-recordpage-btn:hover { background: var(--crisp-bg-raised); }
|
|
108
125
|
& .crisp-recordpage-btn--primary { box-shadow: none; background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); }
|
|
109
126
|
& .crisp-recordpage-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
110
|
-
|
|
111
127
|
& .crisp-recordpage-note { display: flex; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2-5) 0; border-top: 1px solid var(--crisp-border-subtle); }
|
|
112
128
|
& .crisp-recordpage-note-body { flex: 1; min-width: 0; }
|
|
113
129
|
& .crisp-recordpage-note-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-bottom: var(--crisp-space-0-5); }
|
|
114
130
|
& .crisp-recordpage-note-author { font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
115
131
|
& .crisp-recordpage-note-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
|
|
116
132
|
& .crisp-recordpage-note-text { font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); white-space: pre-wrap; word-break: break-word; }
|
|
117
|
-
|
|
118
133
|
& .crisp-recordpage-task { display: flex; align-items: flex-start; gap: var(--crisp-space-2); padding: var(--crisp-space-1-5) 0; border-top: 1px solid var(--crisp-border-subtle); }
|
|
119
134
|
& .crisp-recordpage-task-text { flex: 1; min-width: 0; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); padding-top: 1px; }
|
|
120
135
|
& .crisp-recordpage-task[data-done] .crisp-recordpage-task-text { text-decoration: line-through; color: var(--crisp-fg-muted); }
|
|
121
|
-
|
|
122
136
|
& .crisp-recordpage-emptycard { display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-6) var(--crisp-space-3); border: 1px dashed var(--crisp-border-default); border-radius: var(--crisp-radius-xl); color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); text-align: center; }
|
|
123
137
|
& .crisp-recordpage-emptycard svg { color: var(--crisp-fg-muted); opacity: 0.7; }
|
|
124
|
-
|
|
125
138
|
& .crisp-recordpage-action[data-active] svg { color: #f5b83d; fill: #f5b83d; }
|
|
126
|
-
|
|
127
139
|
& .crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
128
140
|
& .crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); }
|
|
129
141
|
& .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); }
|
|
@@ -61,27 +61,46 @@
|
|
|
61
61
|
& .crisp-recordpage-field-label svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
62
62
|
& .crisp-recordpage-field-label-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
63
63
|
& .crisp-recordpage-field-value { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); padding-top: 2px; line-height: 20px; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
64
|
+
& .crisp-recordpage-field-value[data-editable] { cursor: pointer; }
|
|
65
|
+
/* the click-to-edit trigger is a real <button> (keyboard-operable),
|
|
66
|
+
reset back to plain inline text and made a flex-wrap container of its
|
|
67
|
+
own -- FieldValue can render several chips (tags), which still need
|
|
68
|
+
to wrap the way they did before this had a button around them at
|
|
69
|
+
all. It wraps only FieldValue, never the error slot beside it (see
|
|
70
|
+
the component's own comment) -- NOT `display: contents`, which drops a button's accessible semantics in some engines. */
|
|
71
|
+
& .crisp-recordpage-edit-trigger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); margin: 0; padding: 0; border: none; background: none; text-align: start; font: inherit; color: inherit; cursor: pointer; }
|
|
64
72
|
& .crisp-recordpage-empty { color: var(--crisp-fg-muted); }
|
|
73
|
+
|
|
74
|
+
/* #431: measured live on app.attio.com's record page Details column -- clicking a field's value opens a plain, borderless field exactly
|
|
75
|
+
filling the value's own box (no border, no background, no box-shadow), same font as the value it replaces (hence `font: inherit`, not a restated size/weight). A field row's own hover tint
|
|
76
|
+
above already carries the "this is interactive" affordance; the
|
|
77
|
+
pending/error treatment isn't Attio-measured -- it reuses the same tokens DataTable's identical states already use (opacity 0.5,
|
|
78
|
+
`bgDanger`), per #385/#430. */
|
|
79
|
+
& .crisp-recordpage-edit { display: block; width: 100%; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; box-shadow: none; outline: none; font: inherit; color: inherit; }
|
|
80
|
+
/* not Attio-measured (its own field shows no focus ring either, caret
|
|
81
|
+
only) -- kept for real keyboard users, the same brand ring every
|
|
82
|
+
other crisp field already shows on focus (DataTable's identical .crisp-datatable-edit:focus, e.g.). */
|
|
83
|
+
& .crisp-recordpage-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
84
|
+
& .crisp-recordpage-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
85
|
+
& .crisp-recordpage-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
86
|
+
& .crisp-recordpage-edit-error { flex-basis: 100%; margin-top: var(--crisp-space-0-5); font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
87
|
+
& .crisp-recordpage-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
|
|
88
|
+
& .crisp-recordpage-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; }
|
|
65
89
|
& .crisp-recordpage-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
66
90
|
& .crisp-recordpage-link:hover { text-decoration: underline; }
|
|
67
91
|
& .crisp-recordpage-emptystate { padding: var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
68
|
-
|
|
69
92
|
& .crisp-recordpage-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; overflow-y: auto; padding: var(--crisp-space-3) var(--crisp-space-5); }
|
|
70
|
-
|
|
71
93
|
& .crisp-recordpage-panel { padding-top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-4); }
|
|
72
94
|
& .crisp-recordpage-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); background: var(--crisp-bg-surface); overflow: hidden; }
|
|
73
95
|
& .crisp-recordpage-card-title { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); letter-spacing: -0.14px; color: var(--crisp-fg-primary); padding: var(--crisp-space-3) var(--crisp-space-3) var(--crisp-space-2); }
|
|
74
96
|
& .crisp-recordpage-hl-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); overflow: hidden; }
|
|
75
|
-
/* gap-as-gridlines: a 1px gap over the border colour draws dividers at any
|
|
76
|
-
column count, so the grid stays responsive (auto-fit) without per-cell
|
|
77
|
-
nth-child border hacks that break when the column count changes. */
|
|
97
|
+
/* gap-as-gridlines: a 1px gap over the border colour draws dividers at any column count, so the grid stays responsive (auto-fit) without per-cell nth-child border hacks that break when the column count changes. */
|
|
78
98
|
& .crisp-recordpage-hl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px; background: var(--crisp-border-subtle); }
|
|
79
99
|
& .crisp-recordpage-hl-cell { position: relative; min-height: 84px; padding: var(--crisp-space-2-5) var(--crisp-space-3); background: var(--crisp-bg-surface); }
|
|
80
100
|
& .crisp-recordpage-hl-icon { position: absolute; top: var(--crisp-space-2-5); inset-inline-end: var(--crisp-space-3); color: var(--crisp-fg-muted); }
|
|
81
101
|
& .crisp-recordpage-hl-label { font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); margin-bottom: var(--crisp-space-2-5); padding-inline-end: var(--crisp-space-4); }
|
|
82
102
|
& .crisp-recordpage-hl-value { display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
83
103
|
& .crisp-recordpage-hl-value--empty { color: var(--crisp-fg-muted); font-weight: var(--crisp-weight-regular); }
|
|
84
|
-
|
|
85
104
|
& .crisp-recordpage-feed { display: flex; flex-direction: column; }
|
|
86
105
|
& .crisp-recordpage-feed-item { display: flex; align-items: flex-start; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2) 0; }
|
|
87
106
|
& .crisp-recordpage-feed-dot { position: relative; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex-shrink: 0; border-radius: var(--crisp-radius-full); background: var(--crisp-bg-raised); color: var(--crisp-fg-muted); }
|
|
@@ -90,7 +109,6 @@
|
|
|
90
109
|
& .crisp-recordpage-feed-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); margin-top: 2px; }
|
|
91
110
|
& .crisp-recordpage-feed-more { align-self: flex-start; margin-top: var(--crisp-space-1); border: none; background: none; padding: var(--crisp-space-1) 0; color: var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
|
|
92
111
|
& .crisp-recordpage-feed-more:hover { text-decoration: underline; }
|
|
93
|
-
|
|
94
112
|
& .crisp-recordpage-section-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-1); }
|
|
95
113
|
& .crisp-recordpage-section-head .crisp-recordpage-section-title { padding: 0; }
|
|
96
114
|
& .crisp-recordpage-section-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-sm); background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); font-size: var(--crisp-text-xs); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
@@ -98,7 +116,6 @@
|
|
|
98
116
|
& .crisp-recordpage-addbtn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: 26px; padding: 0 var(--crisp-space-1-5); margin: 0; border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-neutral), 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
|
|
99
117
|
& .crisp-recordpage-addbtn:hover { background: var(--crisp-bg-raised); }
|
|
100
118
|
& .crisp-recordpage-addbtn svg { flex-shrink: 0; }
|
|
101
|
-
|
|
102
119
|
& .crisp-recordpage-composer { display: flex; flex-direction: column; gap: var(--crisp-space-2); padding: var(--crisp-space-2); border: 1px solid var(--crisp-border-default); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); margin-bottom: var(--crisp-space-2); }
|
|
103
120
|
& .crisp-recordpage-composer textarea { width: 100%; min-height: 56px; resize: vertical; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
104
121
|
& .crisp-recordpage-composer textarea:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); border-radius: var(--crisp-radius-md); }
|
|
@@ -108,23 +125,18 @@
|
|
|
108
125
|
& .crisp-recordpage-btn:hover { background: var(--crisp-bg-raised); }
|
|
109
126
|
& .crisp-recordpage-btn--primary { box-shadow: none; background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); }
|
|
110
127
|
& .crisp-recordpage-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
111
|
-
|
|
112
128
|
& .crisp-recordpage-note { display: flex; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2-5) 0; border-top: 1px solid var(--crisp-border-subtle); }
|
|
113
129
|
& .crisp-recordpage-note-body { flex: 1; min-width: 0; }
|
|
114
130
|
& .crisp-recordpage-note-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-bottom: var(--crisp-space-0-5); }
|
|
115
131
|
& .crisp-recordpage-note-author { font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
116
132
|
& .crisp-recordpage-note-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
|
|
117
133
|
& .crisp-recordpage-note-text { font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); white-space: pre-wrap; word-break: break-word; }
|
|
118
|
-
|
|
119
134
|
& .crisp-recordpage-task { display: flex; align-items: flex-start; gap: var(--crisp-space-2); padding: var(--crisp-space-1-5) 0; border-top: 1px solid var(--crisp-border-subtle); }
|
|
120
135
|
& .crisp-recordpage-task-text { flex: 1; min-width: 0; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); padding-top: 1px; }
|
|
121
136
|
& .crisp-recordpage-task[data-done] .crisp-recordpage-task-text { text-decoration: line-through; color: var(--crisp-fg-muted); }
|
|
122
|
-
|
|
123
137
|
& .crisp-recordpage-emptycard { display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-6) var(--crisp-space-3); border: 1px dashed var(--crisp-border-default); border-radius: var(--crisp-radius-xl); color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); text-align: center; }
|
|
124
138
|
& .crisp-recordpage-emptycard svg { color: var(--crisp-fg-muted); opacity: 0.7; }
|
|
125
|
-
|
|
126
139
|
& .crisp-recordpage-action[data-active] svg { color: #f5b83d; fill: #f5b83d; }
|
|
127
|
-
|
|
128
140
|
& .crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
129
141
|
& .crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); }
|
|
130
142
|
& .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); }
|
package/dist/recordpanel.css
CHANGED
|
@@ -14,7 +14,26 @@
|
|
|
14
14
|
& .crisp-recordpanel-field-label { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 132px; flex-shrink: 0; padding-top: 3px; color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); }
|
|
15
15
|
& .crisp-recordpanel-field-label svg { flex-shrink: 0; }
|
|
16
16
|
& .crisp-recordpanel-field-value { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); padding-top: 3px; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
17
|
+
& .crisp-recordpanel-field-value[data-editable] { cursor: pointer; }
|
|
18
|
+
/* the click-to-edit trigger is a real <button> (keyboard-operable), reset back to plain inline text and made a flex-wrap container of its own -- FieldValue can render several chips (tags), which still need to wrap the way they did before this had a button around them at all. It wraps only FieldValue, never the error slot beside it (see the component's own comment) -- NOT `display: contents`, which
|
|
19
|
+
drops a button's accessible semantics in some engines. */
|
|
20
|
+
& .crisp-recordpanel-edit-trigger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); margin: 0; padding: 0; border: none; background: none; text-align: start; font: inherit; color: inherit; cursor: pointer; }
|
|
17
21
|
& .crisp-recordpanel-empty { color: var(--crisp-fg-muted); }
|
|
22
|
+
/* #431: measured live on app.attio.com's record side panel -- clicking a
|
|
23
|
+
field's value opens a plain, borderless field exactly filling the value's own box (no border, no background, no box-shadow), same font
|
|
24
|
+
as the value it replaces (hence `font: inherit`, not a restated
|
|
25
|
+
size/weight). A field row's own hover tint above already carries the "this is interactive" affordance; the pending/error treatment isn't
|
|
26
|
+
Attio-measured -- it reuses the same tokens DataTable's identical states already use (opacity 0.5, `bgDanger`), per #385/#430. */
|
|
27
|
+
& .crisp-recordpanel-edit { display: block; width: 100%; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; box-shadow: none; outline: none; font: inherit; color: inherit; }
|
|
28
|
+
/* not Attio-measured (its own field shows no focus ring either, caret only) -- kept for real keyboard users, the same brand ring every other crisp field already shows on focus (DataTable's identical
|
|
29
|
+
.crisp-datatable-edit:focus, e.g.). */
|
|
30
|
+
& .crisp-recordpanel-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
31
|
+
& .crisp-recordpanel-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
32
|
+
& .crisp-recordpanel-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
33
|
+
& .crisp-recordpanel-edit-error { flex-basis: 100%; margin-top: var(--crisp-space-0-5); font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
34
|
+
& .crisp-recordpanel-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
|
|
35
|
+
& .crisp-recordpanel-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; }
|
|
36
|
+
|
|
18
37
|
& .crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); }
|
|
19
38
|
& .crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent); }
|
|
20
39
|
& .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent); }
|
|
@@ -25,11 +44,9 @@
|
|
|
25
44
|
& .crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
|
|
26
45
|
& .crisp-recordpanel-link { color: var(--crisp-bg-brand-solid); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
27
46
|
& .crisp-recordpanel-link:hover { text-decoration: underline; }
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
(borderSubtle, flipped to border-top since this sits at the opposite
|
|
31
|
-
edge), and the header/body gap (space.2) for its own vertical padding
|
|
32
|
-
and for spacing between whatever it's given. */
|
|
47
|
+
|
|
48
|
+
/* #329: an optional slot for record actions (e.g. Edit). Reuses the
|
|
49
|
+
header's own measured values rather than inventing new ones -- the same horizontal inset (space.3), the same hairline border token (borderSubtle, flipped to border-top since this sits at the opposite edge), and the header/body gap (space.2) for its own vertical padding and for spacing between whatever it's given. */
|
|
33
50
|
& .crisp-recordpanel-footer { flex-shrink: 0; display: flex; align-items: center; gap: var(--crisp-space-2); padding: var(--crisp-space-2) var(--crisp-space-3); border-top: 1px solid var(--crisp-border-subtle); }
|
|
34
51
|
}
|
|
35
52
|
|
|
@@ -15,7 +15,26 @@
|
|
|
15
15
|
& .crisp-recordpanel-field-label { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 132px; flex-shrink: 0; padding-top: 3px; color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); }
|
|
16
16
|
& .crisp-recordpanel-field-label svg { flex-shrink: 0; }
|
|
17
17
|
& .crisp-recordpanel-field-value { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); padding-top: 3px; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
18
|
+
& .crisp-recordpanel-field-value[data-editable] { cursor: pointer; }
|
|
19
|
+
/* the click-to-edit trigger is a real <button> (keyboard-operable), reset back to plain inline text and made a flex-wrap container of its own -- FieldValue can render several chips (tags), which still need to wrap the way they did before this had a button around them at all. It wraps only FieldValue, never the error slot beside it (see the component's own comment) -- NOT `display: contents`, which
|
|
20
|
+
drops a button's accessible semantics in some engines. */
|
|
21
|
+
& .crisp-recordpanel-edit-trigger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); margin: 0; padding: 0; border: none; background: none; text-align: start; font: inherit; color: inherit; cursor: pointer; }
|
|
18
22
|
& .crisp-recordpanel-empty { color: var(--crisp-fg-muted); }
|
|
23
|
+
/* #431: measured live on app.attio.com's record side panel -- clicking a
|
|
24
|
+
field's value opens a plain, borderless field exactly filling the value's own box (no border, no background, no box-shadow), same font
|
|
25
|
+
as the value it replaces (hence `font: inherit`, not a restated
|
|
26
|
+
size/weight). A field row's own hover tint above already carries the "this is interactive" affordance; the pending/error treatment isn't
|
|
27
|
+
Attio-measured -- it reuses the same tokens DataTable's identical states already use (opacity 0.5, `bgDanger`), per #385/#430. */
|
|
28
|
+
& .crisp-recordpanel-edit { display: block; width: 100%; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; box-shadow: none; outline: none; font: inherit; color: inherit; }
|
|
29
|
+
/* not Attio-measured (its own field shows no focus ring either, caret only) -- kept for real keyboard users, the same brand ring every other crisp field already shows on focus (DataTable's identical
|
|
30
|
+
.crisp-datatable-edit:focus, e.g.). */
|
|
31
|
+
& .crisp-recordpanel-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
32
|
+
& .crisp-recordpanel-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
33
|
+
& .crisp-recordpanel-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
34
|
+
& .crisp-recordpanel-edit-error { flex-basis: 100%; margin-top: var(--crisp-space-0-5); font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
35
|
+
& .crisp-recordpanel-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
|
|
36
|
+
& .crisp-recordpanel-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; }
|
|
37
|
+
|
|
19
38
|
& .crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); }
|
|
20
39
|
& .crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent); }
|
|
21
40
|
& .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent); }
|
|
@@ -26,11 +45,9 @@
|
|
|
26
45
|
& .crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
|
|
27
46
|
& .crisp-recordpanel-link { color: var(--crisp-bg-brand-solid); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
28
47
|
& .crisp-recordpanel-link:hover { text-decoration: underline; }
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
(borderSubtle, flipped to border-top since this sits at the opposite
|
|
32
|
-
edge), and the header/body gap (space.2) for its own vertical padding
|
|
33
|
-
and for spacing between whatever it's given. */
|
|
48
|
+
|
|
49
|
+
/* #329: an optional slot for record actions (e.g. Edit). Reuses the
|
|
50
|
+
header's own measured values rather than inventing new ones -- the same horizontal inset (space.3), the same hairline border token (borderSubtle, flipped to border-top since this sits at the opposite edge), and the header/body gap (space.2) for its own vertical padding and for spacing between whatever it's given. */
|
|
34
51
|
& .crisp-recordpanel-footer { flex-shrink: 0; display: flex; align-items: center; gap: var(--crisp-space-2); padding: var(--crisp-space-2) var(--crisp-space-3); border-top: 1px solid var(--crisp-border-subtle); }
|
|
35
52
|
}
|
|
36
53
|
|
package/dist/recordstable.css
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
& * { box-sizing: border-box; }
|
|
4
4
|
/* toolbar */
|
|
5
5
|
& .crisp-recordstable-toolbar { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: 0 var(--crisp-space-3) var(--crisp-space-2); }
|
|
6
|
+
& .crisp-recordstable-toolbar[data-inline] { padding-bottom: 0; }
|
|
6
7
|
& .crisp-recordstable-search { display: flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); padding: 0 var(--crisp-space-2-5); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); color: var(--crisp-fg-muted); }
|
|
7
8
|
& .crisp-recordstable-search svg { flex-shrink: 0; }
|
|
8
9
|
& .crisp-recordstable-search input { border: none; outline: none; background: transparent; font-family: inherit; font-size: var(--crisp-text-md); color: var(--crisp-fg-primary); width: 180px; }
|
|
9
10
|
& .crisp-recordstable-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
10
|
-
& .crisp-recordstable-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .12s; }
|
|
11
|
+
& .crisp-recordstable-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
|
|
11
12
|
& .crisp-recordstable-tool:hover { background: var(--crisp-bg-raised); }
|
|
12
13
|
& .crisp-recordstable-tool svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
13
14
|
& .crisp-recordstable-tool--active { background: var(--crisp-bg-raised); }
|
|
@@ -111,6 +112,13 @@
|
|
|
111
112
|
& .crisp-recordstable-td--picker .crisp-multiselect-chips .crisp-recordstable-tag { flex-shrink: 0; max-width: none; }
|
|
112
113
|
& .crisp-recordstable-td--picker .crisp-multiselect-chevron { display: none; }
|
|
113
114
|
& .crisp-recordstable-td--picker .crisp-multiselect-placeholder { color: var(--crisp-fg-muted); }
|
|
115
|
+
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
116
|
+
"Create X" row when the consumer supplies one (#449) -- measured live
|
|
117
|
+
against Attio's own picker (16px circular avatar, 16px plain icon for the create row, both sitting in the option's existing 8px gap, no new
|
|
118
|
+
gap value invented). */
|
|
119
|
+
& .crisp-recordstable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
120
|
+
& .crisp-recordstable-refoption-avatar { flex-shrink: 0; }
|
|
121
|
+
& .crisp-recordstable-refoption--create { color: var(--crisp-fg-muted); }
|
|
114
122
|
& .crisp-recordstable-status { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
|
|
115
123
|
& .crisp-recordstable-status-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: var(--crisp-radius-full); }
|
|
116
124
|
& .crisp-recordstable-cell { display: flex; align-items: center; gap: var(--crisp-space-2); height: 100%; min-width: 0; }
|
|
@@ -176,7 +184,7 @@
|
|
|
176
184
|
& .crisp-recordstable-empty { display: flex; align-items: center; justify-content: center; min-height: 320px; padding: var(--crisp-space-8) var(--crisp-space-4); }
|
|
177
185
|
|
|
178
186
|
/* summary footer — per-column aggregation, sticky to the bottom */
|
|
179
|
-
& .crisp-recordstable-sum { position: sticky; bottom: 0; z-index: 2; height: var(--crisp-size-tableRow); padding: 0; border-top: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); background: var(--crisp-bg-surface); }
|
|
187
|
+
& .crisp-recordstable-sum { position: sticky; bottom: 0; z-index: 2; height: var(--crisp-size-tableRow); padding: 0; border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); background: var(--crisp-bg-surface); }
|
|
180
188
|
& tfoot .crisp-recordstable-col-check, & tfoot .crisp-recordstable-col-entity { position: sticky; bottom: 0; z-index: 3; }
|
|
181
189
|
& .crisp-recordstable-sum:last-child { border-inline-end: none; }
|
|
182
190
|
& .crisp-recordstable-sum-btn { display: flex; align-items: center; justify-content: flex-end; gap: var(--crisp-space-1-5); width: 100%; height: 100%; margin: 0; padding: 0 var(--crisp-space-3); border: none; background: none; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); cursor: pointer; white-space: nowrap; overflow: hidden; }
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
& * { box-sizing: border-box; }
|
|
5
5
|
/* toolbar */
|
|
6
6
|
& .crisp-recordstable-toolbar { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: 0 var(--crisp-space-3) var(--crisp-space-2); }
|
|
7
|
+
& .crisp-recordstable-toolbar[data-inline] { padding-bottom: 0; }
|
|
7
8
|
& .crisp-recordstable-search { display: flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); padding: 0 var(--crisp-space-2-5); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); color: var(--crisp-fg-muted); }
|
|
8
9
|
& .crisp-recordstable-search svg { flex-shrink: 0; }
|
|
9
10
|
& .crisp-recordstable-search input { border: none; outline: none; background: transparent; font-family: inherit; font-size: var(--crisp-text-md); color: var(--crisp-fg-primary); width: 180px; }
|
|
10
11
|
& .crisp-recordstable-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
11
|
-
& .crisp-recordstable-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .12s; }
|
|
12
|
+
& .crisp-recordstable-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
|
|
12
13
|
& .crisp-recordstable-tool:hover { background: var(--crisp-bg-raised); }
|
|
13
14
|
& .crisp-recordstable-tool svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
14
15
|
& .crisp-recordstable-tool--active { background: var(--crisp-bg-raised); }
|
|
@@ -112,6 +113,13 @@
|
|
|
112
113
|
& .crisp-recordstable-td--picker .crisp-multiselect-chips .crisp-recordstable-tag { flex-shrink: 0; max-width: none; }
|
|
113
114
|
& .crisp-recordstable-td--picker .crisp-multiselect-chevron { display: none; }
|
|
114
115
|
& .crisp-recordstable-td--picker .crisp-multiselect-placeholder { color: var(--crisp-fg-muted); }
|
|
116
|
+
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
117
|
+
"Create X" row when the consumer supplies one (#449) -- measured live
|
|
118
|
+
against Attio's own picker (16px circular avatar, 16px plain icon for the create row, both sitting in the option's existing 8px gap, no new
|
|
119
|
+
gap value invented). */
|
|
120
|
+
& .crisp-recordstable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
121
|
+
& .crisp-recordstable-refoption-avatar { flex-shrink: 0; }
|
|
122
|
+
& .crisp-recordstable-refoption--create { color: var(--crisp-fg-muted); }
|
|
115
123
|
& .crisp-recordstable-status { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
|
|
116
124
|
& .crisp-recordstable-status-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: var(--crisp-radius-full); }
|
|
117
125
|
& .crisp-recordstable-cell { display: flex; align-items: center; gap: var(--crisp-space-2); height: 100%; min-width: 0; }
|
|
@@ -177,7 +185,7 @@
|
|
|
177
185
|
& .crisp-recordstable-empty { display: flex; align-items: center; justify-content: center; min-height: 320px; padding: var(--crisp-space-8) var(--crisp-space-4); }
|
|
178
186
|
|
|
179
187
|
/* summary footer — per-column aggregation, sticky to the bottom */
|
|
180
|
-
& .crisp-recordstable-sum { position: sticky; bottom: 0; z-index: 2; height: var(--crisp-size-tableRow); padding: 0; border-top: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); background: var(--crisp-bg-surface); }
|
|
188
|
+
& .crisp-recordstable-sum { position: sticky; bottom: 0; z-index: 2; height: var(--crisp-size-tableRow); padding: 0; border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); background: var(--crisp-bg-surface); }
|
|
181
189
|
& tfoot .crisp-recordstable-col-check, & tfoot .crisp-recordstable-col-entity { position: sticky; bottom: 0; z-index: 3; }
|
|
182
190
|
& .crisp-recordstable-sum:last-child { border-inline-end: none; }
|
|
183
191
|
& .crisp-recordstable-sum-btn { display: flex; align-items: center; justify-content: flex-end; gap: var(--crisp-space-1-5); width: 100%; height: 100%; margin: 0; padding: 0 var(--crisp-space-3); border: none; background: none; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); cursor: pointer; white-space: nowrap; overflow: hidden; }
|
package/dist/settingsshell.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.crisp-settingsshell {
|
|
2
|
-
display: flex; min-height: 0; box-sizing: border-box; font-family: var(--crisp-font-sans); color: var(--crisp-fg-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
3
|
-
& .crisp-settingsshell-nav { display: flex; flex-direction: column; width:
|
|
2
|
+
display: flex; height: 100%; min-height: 0; box-sizing: border-box; font-family: var(--crisp-font-sans); color: var(--crisp-fg-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
3
|
+
& .crisp-settingsshell-nav { display: flex; flex-direction: column; width: 275px; flex-shrink: 0; min-height: 0; padding: var(--crisp-space-3); border-inline-end: 1px solid var(--crisp-border-subtle); }
|
|
4
4
|
& .crisp-settingsshell-back { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: 28px; padding: 0 var(--crisp-space-1); margin: 0 0 var(--crisp-space-2); border: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); color: var(--crisp-fg-primary); cursor: pointer; border-radius: var(--crisp-radius-md); }
|
|
5
5
|
& .crisp-settingsshell-back svg { color: var(--crisp-fg-muted); }
|
|
6
6
|
& .crisp-settingsshell-back:hover svg { color: var(--crisp-fg-primary); }
|