@crisp-ui-kit/crisp 0.57.2 → 0.57.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.
- package/dist/assigneepicker.css +13 -0
- package/dist/assigneepicker.d.ts +7 -0
- package/dist/assigneepicker.layered.css +15 -0
- package/dist/button.css +3 -0
- package/dist/button.d.ts +2 -2
- package/dist/button.layered.css +3 -0
- package/dist/chip.css +1 -1
- package/dist/chip.layered.css +1 -1
- package/dist/cjs/components/breadcrumb/breadcrumb.js +1 -1
- package/dist/cjs/components/button/button.recipe.js +33 -0
- package/dist/cjs/components/chip/chip.recipe.js +3 -1
- package/dist/cjs/components/datatable/datatable.js +6 -3
- package/dist/cjs/components/datatable/datatable.recipe.js +45 -6
- package/dist/cjs/components/datepickerfield/datepickerfield.js +2 -2
- package/dist/cjs/components/datepickerfield/datepickerfield.recipe.js +16 -3
- package/dist/cjs/components/menu/menu.js +65 -9
- package/dist/cjs/components/multiselect/multiselect.js +3 -0
- package/dist/cjs/components/multiselect/multiselect.recipe.js +18 -0
- package/dist/cjs/components/select/select.js +2 -2
- package/dist/cjs/components/select/select.recipe.js +19 -0
- package/dist/cjs/components/table/table.recipe.js +7 -1
- package/dist/cjs/core/floating-portal.js +7 -4
- package/dist/cjs/core/index.js +2 -1
- package/dist/cjs/core/place-floating.js +38 -0
- package/dist/cjs/index.js +8 -0
- package/dist/cjs/product/assigneepicker/assigneepicker.js +127 -0
- package/dist/cjs/product/assigneepicker/assigneepicker.recipe.js +36 -0
- package/dist/cjs/product/assigneepicker/index.js +7 -0
- package/dist/cjs/product/inbox/inbox.js +11 -3
- package/dist/cjs/product/notesgallery/index.js +7 -0
- package/dist/cjs/product/notesgallery/notesgallery.js +80 -0
- package/dist/cjs/product/notesgallery/notesgallery.recipe.js +46 -0
- package/dist/cjs/product/objectpagemenu/index.js +17 -0
- package/dist/cjs/product/objectpagemenu/objectpagemenu.js +26 -0
- package/dist/cjs/product/objectpagemenu/objectpagemenu.recipe.js +30 -0
- package/dist/cjs/product/objectsettings/objectsettings.js +107 -14
- package/dist/cjs/product/recordpage/index.js +2 -1
- package/dist/cjs/product/recordpage/recordpage.js +112 -7
- package/dist/cjs/product/recordpage/recordpage.recipe.js +63 -0
- package/dist/cjs/product/recordpicker/index.js +7 -0
- package/dist/cjs/product/recordpicker/recordpicker.js +100 -0
- package/dist/cjs/product/recordpicker/recordpicker.recipe.js +36 -0
- package/dist/cjs/product/savedviews/index.js +2 -1
- package/dist/cjs/product/savedviews/savedviews.js +22 -0
- package/dist/cjs/product/savedviews/savedviews.recipe.js +47 -0
- package/dist/cjs/product/share/index.js +7 -0
- package/dist/cjs/product/share/share.js +179 -0
- package/dist/cjs/product/share/share.recipe.js +114 -0
- package/dist/cjs/product/shortcutssheet/index.js +17 -0
- package/dist/cjs/product/shortcutssheet/shortcutssheet.js +125 -0
- package/dist/cjs/product/shortcutssheet/shortcutssheet.recipe.js +50 -0
- package/dist/cjs/product/taskeditpopover/index.js +7 -0
- package/dist/cjs/product/taskeditpopover/taskeditpopover.js +159 -0
- package/dist/cjs/product/taskeditpopover/taskeditpopover.recipe.js +68 -0
- package/dist/cjs/product/workspaceswitchermenu/index.js +17 -0
- package/dist/cjs/product/workspaceswitchermenu/workspaceswitchermenu.js +38 -0
- package/dist/cjs/product/workspaceswitchermenu/workspaceswitchermenu.recipe.js +34 -0
- package/dist/cjs/tokens/palette.js +27 -0
- package/dist/cjs/tokens/semantic.js +20 -0
- package/dist/datatable.css +50 -11
- package/dist/datatable.layered.css +50 -11
- package/dist/datepickerfield.css +8 -2
- package/dist/datepickerfield.d.ts +2 -2
- package/dist/datepickerfield.layered.css +8 -2
- package/dist/esm/components/breadcrumb/breadcrumb.js +1 -1
- package/dist/esm/components/button/button.recipe.js +33 -0
- package/dist/esm/components/chip/chip.recipe.js +3 -1
- package/dist/esm/components/datatable/datatable.js +6 -3
- package/dist/esm/components/datatable/datatable.recipe.js +45 -6
- package/dist/esm/components/datepickerfield/datepickerfield.js +2 -2
- package/dist/esm/components/datepickerfield/datepickerfield.recipe.js +16 -3
- package/dist/esm/components/menu/menu.js +64 -8
- package/dist/esm/components/multiselect/multiselect.js +3 -0
- package/dist/esm/components/multiselect/multiselect.recipe.js +18 -0
- package/dist/esm/components/select/select.js +2 -2
- package/dist/esm/components/select/select.recipe.js +19 -0
- package/dist/esm/components/table/table.recipe.js +7 -1
- package/dist/esm/core/floating-portal.js +7 -4
- package/dist/esm/core/index.js +1 -1
- package/dist/esm/core/place-floating.js +37 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/product/assigneepicker/assigneepicker.js +91 -0
- package/dist/esm/product/assigneepicker/assigneepicker.recipe.js +33 -0
- package/dist/esm/product/assigneepicker/index.js +2 -0
- package/dist/esm/product/inbox/inbox.js +11 -3
- package/dist/esm/product/notesgallery/index.js +2 -0
- package/dist/esm/product/notesgallery/notesgallery.js +44 -0
- package/dist/esm/product/notesgallery/notesgallery.recipe.js +43 -0
- package/dist/esm/product/objectpagemenu/index.js +1 -0
- package/dist/esm/product/objectpagemenu/objectpagemenu.js +23 -0
- package/dist/esm/product/objectpagemenu/objectpagemenu.recipe.js +27 -0
- package/dist/esm/product/objectsettings/objectsettings.js +106 -13
- package/dist/esm/product/recordpage/index.js +1 -1
- package/dist/esm/product/recordpage/recordpage.js +112 -8
- package/dist/esm/product/recordpage/recordpage.recipe.js +63 -0
- package/dist/esm/product/recordpicker/index.js +2 -0
- package/dist/esm/product/recordpicker/recordpicker.js +64 -0
- package/dist/esm/product/recordpicker/recordpicker.recipe.js +33 -0
- package/dist/esm/product/savedviews/index.js +1 -1
- package/dist/esm/product/savedviews/savedviews.js +22 -1
- package/dist/esm/product/savedviews/savedviews.recipe.js +47 -0
- package/dist/esm/product/share/index.js +2 -0
- package/dist/esm/product/share/share.js +143 -0
- package/dist/esm/product/share/share.recipe.js +111 -0
- package/dist/esm/product/shortcutssheet/index.js +1 -0
- package/dist/esm/product/shortcutssheet/shortcutssheet.js +88 -0
- package/dist/esm/product/shortcutssheet/shortcutssheet.recipe.js +47 -0
- package/dist/esm/product/taskeditpopover/index.js +2 -0
- package/dist/esm/product/taskeditpopover/taskeditpopover.js +123 -0
- package/dist/esm/product/taskeditpopover/taskeditpopover.recipe.js +65 -0
- package/dist/esm/product/workspaceswitchermenu/index.js +1 -0
- package/dist/esm/product/workspaceswitchermenu/workspaceswitchermenu.js +35 -0
- package/dist/esm/product/workspaceswitchermenu/workspaceswitchermenu.recipe.js +31 -0
- package/dist/esm/tokens/palette.js +27 -0
- package/dist/esm/tokens/semantic.js +20 -0
- package/dist/multiselect.css +18 -0
- package/dist/multiselect.layered.css +18 -0
- package/dist/native/tokens.d.ts +1 -1
- package/dist/native/tokens.js +56 -4
- package/dist/notesgallery.css +15 -0
- package/dist/notesgallery.d.ts +7 -0
- package/dist/notesgallery.layered.css +17 -0
- package/dist/objectpagemenu.css +3 -0
- package/dist/objectpagemenu.d.ts +7 -0
- package/dist/objectpagemenu.layered.css +5 -0
- package/dist/recordpage.css +59 -0
- package/dist/recordpage.layered.css +59 -0
- package/dist/recordpicker.css +13 -0
- package/dist/recordpicker.d.ts +7 -0
- package/dist/recordpicker.layered.css +15 -0
- package/dist/savedviews.css +47 -0
- package/dist/savedviews.layered.css +47 -0
- package/dist/select.css +19 -0
- package/dist/select.layered.css +19 -0
- package/dist/share.css +84 -0
- package/dist/share.d.ts +7 -0
- package/dist/share.layered.css +86 -0
- package/dist/shortcutssheet.css +24 -0
- package/dist/shortcutssheet.d.ts +7 -0
- package/dist/shortcutssheet.layered.css +26 -0
- package/dist/styles.css +438 -16
- package/dist/styles.layered.css +438 -16
- package/dist/table.css +7 -2
- package/dist/table.layered.css +7 -2
- package/dist/taskeditpopover.css +36 -0
- package/dist/taskeditpopover.d.ts +7 -0
- package/dist/taskeditpopover.layered.css +38 -0
- package/dist/tokens.css +26 -0
- package/dist/tokens.json +56 -4
- package/dist/types/components/breadcrumb/breadcrumb.d.ts +9 -1
- package/dist/types/components/button/button.d.ts +2 -0
- package/dist/types/components/button/button.recipe.d.ts +12 -0
- package/dist/types/components/chip/chip.recipe.d.ts +1 -1
- package/dist/types/components/datatable/datatable.d.ts +8 -0
- package/dist/types/components/datepickerfield/datepickerfield.d.ts +4 -1
- package/dist/types/components/datepickerfield/datepickerfield.recipe.d.ts +18 -3
- package/dist/types/components/menu/menu.d.ts +50 -7
- package/dist/types/components/multiselect/multiselect.d.ts +9 -0
- package/dist/types/components/select/select.d.ts +10 -0
- package/dist/types/core/floating-portal.d.ts +6 -5
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/place-floating.d.ts +37 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/product/assigneepicker/assigneepicker.d.ts +36 -0
- package/dist/types/product/assigneepicker/assigneepicker.recipe.d.ts +3 -0
- package/dist/types/product/assigneepicker/index.d.ts +2 -0
- package/dist/types/product/inbox/inbox.d.ts +13 -1
- package/dist/types/product/notesgallery/index.d.ts +2 -0
- package/dist/types/product/notesgallery/notesgallery.d.ts +54 -0
- package/dist/types/product/notesgallery/notesgallery.recipe.d.ts +3 -0
- package/dist/types/product/objectpagemenu/index.d.ts +1 -0
- package/dist/types/product/objectpagemenu/objectpagemenu.d.ts +40 -0
- package/dist/types/product/objectpagemenu/objectpagemenu.recipe.d.ts +17 -0
- package/dist/types/product/objectsettings/objectsettings.d.ts +71 -15
- package/dist/types/product/recordpage/index.d.ts +1 -1
- package/dist/types/product/recordpage/recordpage.d.ts +142 -1
- package/dist/types/product/recordpicker/index.d.ts +2 -0
- package/dist/types/product/recordpicker/recordpicker.d.ts +38 -0
- package/dist/types/product/recordpicker/recordpicker.recipe.d.ts +3 -0
- package/dist/types/product/savedviews/index.d.ts +1 -1
- package/dist/types/product/savedviews/savedviews.d.ts +36 -0
- package/dist/types/product/share/index.d.ts +2 -0
- package/dist/types/product/share/share.d.ts +85 -0
- package/dist/types/product/share/share.recipe.d.ts +3 -0
- package/dist/types/product/shortcutssheet/index.d.ts +1 -0
- package/dist/types/product/shortcutssheet/shortcutssheet.d.ts +49 -0
- package/dist/types/product/shortcutssheet/shortcutssheet.recipe.d.ts +3 -0
- package/dist/types/product/taskeditpopover/index.d.ts +2 -0
- package/dist/types/product/taskeditpopover/taskeditpopover.d.ts +67 -0
- package/dist/types/product/taskeditpopover/taskeditpopover.recipe.d.ts +3 -0
- package/dist/types/product/workspaceswitchermenu/index.d.ts +1 -0
- package/dist/types/product/workspaceswitchermenu/workspaceswitchermenu.d.ts +54 -0
- package/dist/types/product/workspaceswitchermenu/workspaceswitchermenu.recipe.d.ts +19 -0
- package/dist/types/tokens/contract.d.ts +13 -0
- package/dist/types/tokens/palette.d.ts +52 -0
- package/dist/types/tokens/semantic.d.ts +20 -0
- package/dist/workspaceswitchermenu.css +4 -0
- package/dist/workspaceswitchermenu.d.ts +7 -0
- package/dist/workspaceswitchermenu.layered.css +6 -0
- package/package.json +41 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.RecordPicker = RecordPicker;
|
|
37
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
|
+
const lucide_react_1 = require("lucide-react");
|
|
39
|
+
const React = __importStar(require("react"));
|
|
40
|
+
const select_1 = require("../../components/select");
|
|
41
|
+
const spinner_1 = require("../../components/spinner");
|
|
42
|
+
const core_1 = require("../../core");
|
|
43
|
+
const recordpicker_recipe_1 = require("./recordpicker.recipe");
|
|
44
|
+
/**
|
|
45
|
+
* The record-search picker behind a task's "Add record" chip -- measured
|
|
46
|
+
* live on app.attio.com's Tasks page ("Edit task" -> "Add record"): a
|
|
47
|
+
* "Search..." row, then a FLAT list mixed across every object type (a
|
|
48
|
+
* person result sat first, ahead of several companies, with no section
|
|
49
|
+
* headers -- unlike the mention picker's own grouped Users/Records shape,
|
|
50
|
+
* crisp#646). Attio's own live search took a moment to resolve, showing a
|
|
51
|
+
* centred spinner + "Loading..." row meanwhile; not independently
|
|
52
|
+
* re-measured against a second empty-results case, so `emptyLabel`'s
|
|
53
|
+
* default copy ("No records") is inferred by symmetry with
|
|
54
|
+
* `AssigneePicker`'s own measured "No users", not itself pixel-measured.
|
|
55
|
+
*/
|
|
56
|
+
function RecordPicker({ records, loading = false, onSelect, query: queryProp, onQueryChange, searchLabel: searchLabelProp, loadingLabel: loadingLabelProp, emptyLabel: emptyLabelProp, className, ...rest }) {
|
|
57
|
+
const searchLabel = (0, core_1.useCrispMessage)(searchLabelProp, "Search...");
|
|
58
|
+
const loadingLabel = (0, core_1.useCrispMessage)(loadingLabelProp, "Loading...");
|
|
59
|
+
// crisp/#471: `emptyLabel` is typed `React.ReactNode`, so it resolves by
|
|
60
|
+
// hand rather than through `useCrispMessage`, which is string-only --
|
|
61
|
+
// same reasoning as `Inbox`'s own `emptyTitle`/`emptySubtitle`.
|
|
62
|
+
const crispMessages = (0, core_1.useCrispMessages)();
|
|
63
|
+
const emptyLabel = emptyLabelProp ?? crispMessages["No records"] ?? "No records";
|
|
64
|
+
const [internalQuery, setInternalQuery] = React.useState("");
|
|
65
|
+
const query = queryProp ?? internalQuery;
|
|
66
|
+
const setQuery = (q) => {
|
|
67
|
+
if (queryProp === undefined)
|
|
68
|
+
setInternalQuery(q);
|
|
69
|
+
onQueryChange?.(q);
|
|
70
|
+
};
|
|
71
|
+
const [highlight, setHighlight] = React.useState(0);
|
|
72
|
+
const autoId = React.useId();
|
|
73
|
+
const listboxId = `${autoId}-listbox`;
|
|
74
|
+
const optionId = (i) => `${autoId}-opt-${i}`;
|
|
75
|
+
const select = (r) => {
|
|
76
|
+
onSelect?.(r);
|
|
77
|
+
};
|
|
78
|
+
const { onKeyDown } = (0, select_1.useListboxKeyboard)({
|
|
79
|
+
enabledIndexes: records.map((_, i) => i),
|
|
80
|
+
highlight,
|
|
81
|
+
setHighlight,
|
|
82
|
+
commit: () => {
|
|
83
|
+
const r = records[highlight];
|
|
84
|
+
if (r)
|
|
85
|
+
select(r);
|
|
86
|
+
},
|
|
87
|
+
close: () => { },
|
|
88
|
+
dismiss: () => { },
|
|
89
|
+
});
|
|
90
|
+
const activeId = !loading && highlight >= 0 && highlight < records.length
|
|
91
|
+
? optionId(highlight)
|
|
92
|
+
: undefined;
|
|
93
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpicker_recipe_1.recordpickerRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpicker-search", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { size: 16, strokeWidth: 1.75 }), (0, jsx_runtime_1.jsx)("input", { type: "text", className: "crisp-recordpicker-search-input", placeholder: searchLabel, value: query, onChange: (e) => {
|
|
94
|
+
setQuery(e.target.value);
|
|
95
|
+
setHighlight(0);
|
|
96
|
+
}, onKeyDown: onKeyDown, role: "combobox", "aria-expanded": "true", "aria-controls": listboxId, "aria-activedescendant": activeId,
|
|
97
|
+
// biome-ignore lint/a11y/noAutofocus: focus the search field the moment its enclosing popover opens
|
|
98
|
+
autoFocus: true })] }), loading ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpicker-loading", children: [(0, jsx_runtime_1.jsx)(spinner_1.Spinner, { size: 16 }), loadingLabel] })) : records.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpicker-empty", children: emptyLabel })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpicker-list", role: "listbox", id: listboxId, children: records.map((r, i) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", id: optionId(i), role: "option", tabIndex: -1, "aria-selected": i === highlight, "data-highlighted": i === highlight ? "" : undefined, className: "crisp-recordpicker-option", onMouseEnter: () => setHighlight(i), onClick: () => select(r), children: [r.icon, r.name] }, r.id))) }))] }));
|
|
99
|
+
}
|
|
100
|
+
RecordPicker.displayName = "RecordPicker";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordpickerRecipe = void 0;
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
const tokens_1 = require("../../tokens");
|
|
6
|
+
// The record picker behind a task's "Add record" chip -- measured live on
|
|
7
|
+
// app.attio.com's Tasks page ("Edit task" -> "Add record" -> its own
|
|
8
|
+
// sub-popover, same measured 350px width as `AssigneePicker`'s): a
|
|
9
|
+
// borderless "Search..." row, then a flat list mixed across every object
|
|
10
|
+
// type (not grouped into sections -- that's the *mention* picker's own
|
|
11
|
+
// shape, crisp#646, a different, still-ungrouped-by-default surface here),
|
|
12
|
+
// each row a consumer-supplied type icon + the record's name. A "Loading..."
|
|
13
|
+
// row appears while results are in flight (the same measured centred
|
|
14
|
+
// Spinner + text DataTable's own #826 loading state already uses).
|
|
15
|
+
const config = (0, core_1.defineRecipe)({
|
|
16
|
+
name: "recordpicker",
|
|
17
|
+
base: `display: flex; flex-direction: column; box-sizing: border-box; width: 350px; font-family: ${tokens_1.contract.font.sans};
|
|
18
|
+
|
|
19
|
+
& .crisp-recordpicker-search { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 36px; padding: 0 ${tokens_1.contract.space["3"]}; color: ${tokens_1.contract.fgMuted}; }
|
|
20
|
+
& .crisp-recordpicker-search svg { flex-shrink: 0; }
|
|
21
|
+
& .crisp-recordpicker-search-input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; line-height: 20px; color: ${tokens_1.contract.fgPrimary}; }
|
|
22
|
+
& .crisp-recordpicker-search-input::placeholder { color: ${tokens_1.contract.fgMuted}; }
|
|
23
|
+
|
|
24
|
+
& .crisp-recordpicker-loading { display: flex; align-items: center; justify-content: center; gap: 10px; padding: ${tokens_1.contract.space["8"]} ${tokens_1.contract.space["3"]}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; line-height: 20px; }
|
|
25
|
+
& .crisp-recordpicker-empty { padding: ${tokens_1.contract.space["4"]} ${tokens_1.contract.space["3"]}; text-align: center; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); }
|
|
26
|
+
|
|
27
|
+
& .crisp-recordpicker-list { display: flex; flex-direction: column; margin: 0; padding: ${tokens_1.contract.space["1"]}; list-style: none; max-height: 280px; overflow-y: auto; }
|
|
28
|
+
& .crisp-recordpicker-option { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; width: 100%; box-sizing: border-box; height: 32px; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; text-align: start; cursor: pointer; }
|
|
29
|
+
& .crisp-recordpicker-option svg { flex-shrink: 0; color: ${tokens_1.contract.fgMuted}; }
|
|
30
|
+
& .crisp-recordpicker-option:hover, & .crisp-recordpicker-option[data-highlighted] { background: ${tokens_1.contract.bgRaised}; }`,
|
|
31
|
+
variants: {},
|
|
32
|
+
defaultVariants: {},
|
|
33
|
+
compoundVariants: [],
|
|
34
|
+
});
|
|
35
|
+
exports.recordpickerRecipe = (0, core_1.resolveRecipe)(config);
|
|
36
|
+
exports.default = config;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.savedviewsRecipe = exports.SavedViews = void 0;
|
|
3
|
+
exports.savedviewsRecipe = exports.SavedViewsSaveBar = exports.SavedViews = void 0;
|
|
4
4
|
var savedviews_1 = require("./savedviews");
|
|
5
5
|
Object.defineProperty(exports, "SavedViews", { enumerable: true, get: function () { return savedviews_1.SavedViews; } });
|
|
6
|
+
Object.defineProperty(exports, "SavedViewsSaveBar", { enumerable: true, get: function () { return savedviews_1.SavedViewsSaveBar; } });
|
|
6
7
|
var savedviews_recipe_1 = require("./savedviews.recipe");
|
|
7
8
|
Object.defineProperty(exports, "savedviewsRecipe", { enumerable: true, get: function () { return savedviews_recipe_1.savedviewsRecipe; } });
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.SavedViews = SavedViews;
|
|
37
|
+
exports.SavedViewsSaveBar = SavedViewsSaveBar;
|
|
37
38
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
39
|
const lucide_react_1 = require("lucide-react");
|
|
39
40
|
const React = __importStar(require("react"));
|
|
@@ -236,3 +237,24 @@ function SavedViews({ label, icon, views, activeId, onSelect, onCreate, onRename
|
|
|
236
237
|
}, children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-savedviews-row-icon", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 16, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-savedviews-row-label", children: createLabel })] })] }) }))] }));
|
|
237
238
|
}
|
|
238
239
|
SavedViews.displayName = "SavedViews";
|
|
240
|
+
/**
|
|
241
|
+
* The "unsaved changes" bar for a currently loaded saved view — Attio's own
|
|
242
|
+
* "Discard changes" + a split "Save for everyone ▾" button, measured live
|
|
243
|
+
* (app.attio.com, a saved Companies view with its sort changed). Not a part
|
|
244
|
+
* of `SavedViews`' own trigger/panel: Attio renders this in the page
|
|
245
|
+
* toolbar's own trailing slot, replacing whatever sits there at rest
|
|
246
|
+
* (Import/Export, "+ New …") — the same slot `TableToolbar`'s own
|
|
247
|
+
* `children` prop already documents ("Right-aligned actions after the
|
|
248
|
+
* count"). A consumer swaps this in for that slot's usual content once its
|
|
249
|
+
* own dirty check (live filters/sort/columns vs. the loaded view's
|
|
250
|
+
* snapshot) is true, and swaps it back out once it's false — this
|
|
251
|
+
* component itself carries no dirty state or visibility toggle.
|
|
252
|
+
*/
|
|
253
|
+
function SavedViewsSaveBar({ onSave, onDiscard, onSaveAsNew, discardLabel: discardLabelProp, saveLabel: saveLabelProp, saveAsNewLabel: saveAsNewLabelProp, saveOptionsLabel: saveOptionsLabelProp, className, ...rest }) {
|
|
254
|
+
const discardLabel = (0, core_1.useCrispMessage)(discardLabelProp, "Discard changes");
|
|
255
|
+
const saveLabel = (0, core_1.useCrispMessage)(saveLabelProp, "Save for everyone");
|
|
256
|
+
const saveAsNewLabel = (0, core_1.useCrispMessage)(saveAsNewLabelProp, "Save as new view");
|
|
257
|
+
const saveOptionsLabel = (0, core_1.useCrispMessage)(saveOptionsLabelProp, "More save options");
|
|
258
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, core_1.cx)("crisp-savedviews-savebar", className), ...rest, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-savedviews-savebar-discard", onClick: onDiscard, children: discardLabel }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-savedviews-savebar-save-group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-savedviews-savebar-save", onClick: onSave, children: saveLabel }), onSaveAsNew && ((0, jsx_runtime_1.jsx)(menu_1.Menu, { align: "end", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-savedviews-savebar-save-chevron", "aria-label": saveOptionsLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: 16, strokeWidth: 1.75 }) }), children: (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { onSelect: onSaveAsNew, children: saveAsNewLabel }) }))] })] }));
|
|
259
|
+
}
|
|
260
|
+
SavedViewsSaveBar.displayName = "SavedViewsSaveBar";
|
|
@@ -123,6 +123,53 @@ const config = (0, core_1.defineRecipe)({
|
|
|
123
123
|
font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium};
|
|
124
124
|
color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 50%, transparent);
|
|
125
125
|
}
|
|
126
|
+
|
|
127
|
+
/* crisp#568: the "Discard changes" / "Save for everyone ▾" bar a
|
|
128
|
+
consumer swaps into its own toolbar's trailing slot (TableToolbar's
|
|
129
|
+
own children prop already documents "right-aligned actions after the
|
|
130
|
+
count") while the loaded view is dirty -- measured live on
|
|
131
|
+
app.attio.com replacing that exact slot's usual Import/Export + New
|
|
132
|
+
button. Not rendered inside SavedViews' own trigger/panel, which
|
|
133
|
+
stays untouched; this is its own export, SavedViewsSaveBar. */
|
|
134
|
+
.crisp-savedviews-savebar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; }
|
|
135
|
+
/* Rest-state color is a 55% color-mix of fgPrimary -- measured
|
|
136
|
+
identical to recordpanel's own ".crisp-recordpanel-section-action"
|
|
137
|
+
(its own comment: "measured 10px/400, a lighter mix..." -- font size
|
|
138
|
+
there was the SAME outer-vs-inner-div miss #688 corrected; the 55%
|
|
139
|
+
mix itself checks out independently here). Hover repeats crisp's own
|
|
140
|
+
already-measured Button ghost intent exactly (bgRaised + fgPrimary),
|
|
141
|
+
confirmed live (hover bg rgba(0,0,0,.04) + ink text matches bgRaised
|
|
142
|
+
+ fgPrimary bit for bit) -- reused, not re-derived. */
|
|
143
|
+
.crisp-savedviews-savebar-discard {
|
|
144
|
+
box-sizing: border-box; display: inline-flex; align-items: center; height: 28px;
|
|
145
|
+
margin: 0; padding-inline: ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md};
|
|
146
|
+
background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium};
|
|
147
|
+
color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 55%, transparent); cursor: pointer;
|
|
148
|
+
transition: background-color .12s ease, color .12s ease;
|
|
149
|
+
}
|
|
150
|
+
.crisp-savedviews-savebar-discard:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
|
|
151
|
+
/* the split "Save for everyone ▾" pill -- two adjacent buttons sharing
|
|
152
|
+
one visual pill (measured: label half rounds only its outer/left
|
|
153
|
+
corners, the chevron half only its outer/right corners, seamless
|
|
154
|
+
between). Fill is crisp's OWN measured bgBrandContrast, not Attio's
|
|
155
|
+
own literal button blue -- the owner's directive is Attio structure/
|
|
156
|
+
sizing, seed-identity color (crisp direction doc). Hover/active reuse
|
|
157
|
+
Button's own already-measured primary-intent brightness filter
|
|
158
|
+
(crisp#910) rather than Attio's own literal darker fill, for the
|
|
159
|
+
same reason. */
|
|
160
|
+
.crisp-savedviews-savebar-save-group { display: flex; }
|
|
161
|
+
.crisp-savedviews-savebar-save, .crisp-savedviews-savebar-save-chevron {
|
|
162
|
+
box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
|
|
163
|
+
height: 28px; margin: 0; border: none; background: ${tokens_1.contract.bgBrandContrast}; color: ${tokens_1.contract.fgOnBrand};
|
|
164
|
+
cursor: pointer; transition: filter .2s;
|
|
165
|
+
}
|
|
166
|
+
.crisp-savedviews-savebar-save:hover, .crisp-savedviews-savebar-save-chevron:hover { filter: brightness(0.96); }
|
|
167
|
+
.crisp-savedviews-savebar-save:active, .crisp-savedviews-savebar-save-chevron:active { filter: brightness(0.92); }
|
|
168
|
+
.crisp-savedviews-savebar-save {
|
|
169
|
+
padding-inline: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["1.5"]}; border-radius: ${tokens_1.contract.radius.md} 0 0 ${tokens_1.contract.radius.md};
|
|
170
|
+
font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium};
|
|
171
|
+
}
|
|
172
|
+
.crisp-savedviews-savebar-save-chevron { width: 28px; padding: 0; border-radius: 0 ${tokens_1.contract.radius.md} ${tokens_1.contract.radius.md} 0; }
|
|
126
173
|
`,
|
|
127
174
|
variants: {},
|
|
128
175
|
defaultVariants: {},
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shareRecipe = exports.SharePopover = void 0;
|
|
4
|
+
var share_1 = require("./share");
|
|
5
|
+
Object.defineProperty(exports, "SharePopover", { enumerable: true, get: function () { return share_1.SharePopover; } });
|
|
6
|
+
var share_recipe_1 = require("./share.recipe");
|
|
7
|
+
Object.defineProperty(exports, "shareRecipe", { enumerable: true, get: function () { return share_recipe_1.shareRecipe; } });
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SharePopover = SharePopover;
|
|
37
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
|
+
const lucide_react_1 = require("lucide-react");
|
|
39
|
+
const React = __importStar(require("react"));
|
|
40
|
+
const avatar_1 = require("../../components/avatar");
|
|
41
|
+
const input_1 = require("../../components/input");
|
|
42
|
+
const select_1 = require("../../components/select");
|
|
43
|
+
const tabs_1 = require("../../components/tabs");
|
|
44
|
+
const core_1 = require("../../core");
|
|
45
|
+
const share_recipe_1 = require("./share.recipe");
|
|
46
|
+
/**
|
|
47
|
+
* A Share/permissions popover — measured live on app.attio.com (both an
|
|
48
|
+
* object table's and a List's own "Share" trigger, techpartners workspace):
|
|
49
|
+
* Members/Automations pill tabs, a "Workspace access" row (avatar + label +
|
|
50
|
+
* a `Read and write ⌄`-style role select), an optional plan-gated upsell
|
|
51
|
+
* slot, a "Clear permissions" action, an "Individual members" list (one row
|
|
52
|
+
* per member, its own role select), and — on the Automations tab — a
|
|
53
|
+
* search box + role select + "Add" row. Both tabs share a trailing "Learn
|
|
54
|
+
* more about permissions" link.
|
|
55
|
+
*
|
|
56
|
+
* Its own floating shell (not the generic `Popover`): the measured surface
|
|
57
|
+
* is 440px wide, past `Popover`'s 360px content cap. See share.recipe.ts.
|
|
58
|
+
*/
|
|
59
|
+
function SharePopover({ trigger, align = "end", open: openProp, defaultOpen, onOpenChange, tab: tabProp, defaultTab = "members", onTabChange, membersTabLabel: membersTabLabelProp, automationsTabLabel: automationsTabLabelProp, workspaceIcon, workspaceAccessLabel: workspaceAccessLabelProp, workspaceAccessValue, workspaceAccessOptions, onWorkspaceAccessChange, advancedSharing, onClearPermissions, clearPermissionsLabel: clearPermissionsLabelProp, members, membersSectionLabel: membersSectionLabelProp, memberRoleOptions, onMemberAccessChange, automationSearchValue, defaultAutomationSearchValue, onAutomationSearchChange, automationSearchPlaceholder: automationSearchPlaceholderProp, automationRoleValue, automationRoleOptions, onAutomationRoleChange, onAddAutomation, addAutomationDisabled, addAutomationLabel: addAutomationLabelProp, learnMoreHref, learnMoreLabel: learnMoreLabelProp, "aria-label": ariaLabel, className, ...rest }) {
|
|
60
|
+
const membersTabLabel = (0, core_1.useCrispMessage)(membersTabLabelProp, "Members");
|
|
61
|
+
const automationsTabLabel = (0, core_1.useCrispMessage)(automationsTabLabelProp, "Automations");
|
|
62
|
+
const workspaceAccessLabel = (0, core_1.useCrispMessage)(workspaceAccessLabelProp, "Workspace access");
|
|
63
|
+
const clearPermissionsLabel = (0, core_1.useCrispMessage)(clearPermissionsLabelProp, "Clear permissions");
|
|
64
|
+
const membersSectionLabel = (0, core_1.useCrispMessage)(membersSectionLabelProp, "Individual members");
|
|
65
|
+
const automationSearchPlaceholder = (0, core_1.useCrispMessage)(automationSearchPlaceholderProp, "Search...");
|
|
66
|
+
const addAutomationLabel = (0, core_1.useCrispMessage)(addAutomationLabelProp, "Add");
|
|
67
|
+
const learnMoreLabel = (0, core_1.useCrispMessage)(learnMoreLabelProp, "Learn more about permissions");
|
|
68
|
+
const surfaceId = React.useId();
|
|
69
|
+
const triggerId = trigger.props.id ?? `${surfaceId}-trigger`;
|
|
70
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen ?? false);
|
|
71
|
+
const open = openProp ?? internalOpen;
|
|
72
|
+
const setOpen = React.useCallback((next) => {
|
|
73
|
+
if (openProp === undefined)
|
|
74
|
+
setInternalOpen(next);
|
|
75
|
+
onOpenChange?.(next);
|
|
76
|
+
}, [openProp, onOpenChange]);
|
|
77
|
+
const [internalTab, setInternalTab] = React.useState(defaultTab);
|
|
78
|
+
const activeTab = tabProp ?? internalTab;
|
|
79
|
+
const selectTab = (t) => {
|
|
80
|
+
if (tabProp === undefined)
|
|
81
|
+
setInternalTab(t);
|
|
82
|
+
onTabChange?.(t);
|
|
83
|
+
};
|
|
84
|
+
const [internalSearch, setInternalSearch] = React.useState(defaultAutomationSearchValue ?? "");
|
|
85
|
+
const searchValue = automationSearchValue ?? internalSearch;
|
|
86
|
+
const setSearch = (q) => {
|
|
87
|
+
if (automationSearchValue === undefined)
|
|
88
|
+
setInternalSearch(q);
|
|
89
|
+
onAutomationSearchChange?.(q);
|
|
90
|
+
};
|
|
91
|
+
const rootRef = React.useRef(null);
|
|
92
|
+
const triggerRef = React.useRef(null);
|
|
93
|
+
const contentRef = React.useRef(null);
|
|
94
|
+
const [pos, setPos] = React.useState({});
|
|
95
|
+
const [up, setUp] = React.useState(false);
|
|
96
|
+
const place = () => {
|
|
97
|
+
const el = triggerRef.current;
|
|
98
|
+
if (!el)
|
|
99
|
+
return;
|
|
100
|
+
const { style, up: flipUp } = (0, core_1.placeFloating)({
|
|
101
|
+
rect: el.getBoundingClientRect(),
|
|
102
|
+
align,
|
|
103
|
+
gap: 6,
|
|
104
|
+
flipBelow: 320,
|
|
105
|
+
anchor: el,
|
|
106
|
+
});
|
|
107
|
+
setUp(flipUp);
|
|
108
|
+
setPos(style);
|
|
109
|
+
};
|
|
110
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: reposition each time it opens
|
|
111
|
+
React.useLayoutEffect(() => {
|
|
112
|
+
if (open)
|
|
113
|
+
place();
|
|
114
|
+
}, [open]);
|
|
115
|
+
React.useEffect(() => {
|
|
116
|
+
if (!open || !contentRef.current)
|
|
117
|
+
return;
|
|
118
|
+
return (0, core_1.registerFloatingLayer)(contentRef.current);
|
|
119
|
+
}, [open]);
|
|
120
|
+
const close = React.useCallback(() => {
|
|
121
|
+
setOpen(false);
|
|
122
|
+
}, [setOpen]);
|
|
123
|
+
React.useEffect(() => {
|
|
124
|
+
if (!open)
|
|
125
|
+
return;
|
|
126
|
+
const onDown = (e) => {
|
|
127
|
+
const target = e.target;
|
|
128
|
+
if (rootRef.current?.contains(target))
|
|
129
|
+
return;
|
|
130
|
+
if (contentRef.current?.contains(target))
|
|
131
|
+
return;
|
|
132
|
+
if ((0, core_1.isInsideLaterFloatingLayer)(target, contentRef.current))
|
|
133
|
+
return;
|
|
134
|
+
close();
|
|
135
|
+
};
|
|
136
|
+
document.addEventListener("pointerdown", onDown);
|
|
137
|
+
return () => document.removeEventListener("pointerdown", onDown);
|
|
138
|
+
}, [open, close]);
|
|
139
|
+
React.useEffect(() => {
|
|
140
|
+
if (!open)
|
|
141
|
+
return;
|
|
142
|
+
const onKey = (e) => {
|
|
143
|
+
if (e.key !== "Escape")
|
|
144
|
+
return;
|
|
145
|
+
if ((0, core_1.hasNestedFloatingLayer)(contentRef.current))
|
|
146
|
+
return;
|
|
147
|
+
close();
|
|
148
|
+
};
|
|
149
|
+
document.addEventListener("keydown", onKey);
|
|
150
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
151
|
+
}, [open, close]);
|
|
152
|
+
const triggerEl = React.cloneElement(trigger, {
|
|
153
|
+
ref: triggerRef,
|
|
154
|
+
id: triggerId,
|
|
155
|
+
"aria-haspopup": "dialog",
|
|
156
|
+
"aria-expanded": open,
|
|
157
|
+
"aria-controls": open ? surfaceId : undefined,
|
|
158
|
+
onClick: (e) => {
|
|
159
|
+
trigger.props.onClick?.(e);
|
|
160
|
+
setOpen(!open);
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
const tablistRef = React.useRef(null);
|
|
164
|
+
const tabEntries = React.useMemo(() => [{ value: "members" }, { value: "automations" }], []);
|
|
165
|
+
const { onKeyDown: onTabKeyDown, tabIndexFor } = (0, tabs_1.useTablistKeyboard)({
|
|
166
|
+
tabs: tabEntries,
|
|
167
|
+
active: activeTab,
|
|
168
|
+
select: (v) => selectTab(v),
|
|
169
|
+
listRef: tablistRef,
|
|
170
|
+
});
|
|
171
|
+
return ((0, jsx_runtime_1.jsxs)("div", { ref: rootRef, className: (0, share_recipe_1.shareRecipe)({ className }), children: [triggerEl, open && ((0, jsx_runtime_1.jsx)(core_1.FloatingPortal, { sourceRef: rootRef, children: (0, jsx_runtime_1.jsxs)("div", { ref: contentRef, className: "crisp-share-content", role: "dialog", id: surfaceId, "aria-label": ariaLabel, "aria-labelledby": ariaLabel ? undefined : triggerId, "data-up": up ? "" : undefined, style: pos, ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { ref: tablistRef, className: "crisp-share-tabs", role: "tablist", onKeyDown: onTabKeyDown, children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", role: "tab", "data-value": "members", "aria-selected": activeTab === "members", tabIndex: tabIndexFor("members"), className: "crisp-share-tab", onClick: () => selectTab("members"), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Users, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }), membersTabLabel] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", role: "tab", "data-value": "automations", "aria-selected": activeTab === "automations", tabIndex: tabIndexFor("automations"), className: "crisp-share-tab", onClick: () => selectTab("automations"), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Play, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }), automationsTabLabel] })] }), activeTab === "members" ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-share-row", children: [workspaceIcon ?? ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", tone: "brand", children: typeof workspaceAccessLabel === "string"
|
|
172
|
+
? workspaceAccessLabel.charAt(0)
|
|
173
|
+
: null })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-share-row-label", children: workspaceAccessLabel }), (0, jsx_runtime_1.jsx)(select_1.Select, { variant: "ghost", width: "auto", options: workspaceAccessOptions, value: workspaceAccessValue, onValueChange: onWorkspaceAccessChange, "aria-label": workspaceAccessLabel })] }), advancedSharing, onClearPermissions && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-share-clear", onClick: onClearPermissions, children: clearPermissionsLabel })), members && members.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "crisp-share-section-label", children: membersSectionLabel }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-share-members", children: members.map((m) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-share-member", children: [m.avatar ?? ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", tone: "brand", children: typeof m.name === "string"
|
|
174
|
+
? m.name.charAt(0).toUpperCase()
|
|
175
|
+
: null })), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-share-member-text", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-share-member-name", children: m.name }), m.email && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-share-member-email", children: m.email }))] }), (0, jsx_runtime_1.jsx)(select_1.Select, { variant: "ghost", width: "auto", options: memberRoleOptions, value: m.access, disabled: m.accessDisabled, onValueChange: (v) => onMemberAccessChange?.(m.id, v), "aria-label": typeof m.name === "string"
|
|
176
|
+
? `${m.name}'s access`
|
|
177
|
+
: undefined })] }, m.id))) })] }))] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-share-automations-row", children: [(0, jsx_runtime_1.jsx)(input_1.Input, { value: searchValue, onChange: (e) => setSearch(e.target.value), placeholder: automationSearchPlaceholder, "aria-label": automationSearchPlaceholder }), (0, jsx_runtime_1.jsx)(select_1.Select, { variant: "ghost", width: "auto", options: automationRoleOptions, value: automationRoleValue, onValueChange: onAutomationRoleChange, "aria-label": automationsTabLabel }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-share-add", disabled: addAutomationDisabled, onClick: onAddAutomation, children: addAutomationLabel })] })), (0, jsx_runtime_1.jsxs)("a", { className: "crisp-share-learnmore", href: learnMoreHref, target: "_blank", rel: "noreferrer", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.HelpCircle, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }), learnMoreLabel] })] }) }))] }));
|
|
178
|
+
}
|
|
179
|
+
SharePopover.displayName = "SharePopover";
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shareRecipe = void 0;
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
const tokens_1 = require("../../tokens");
|
|
6
|
+
// SharePopover's shell — measured live on app.attio.com (both the object
|
|
7
|
+
// table's and a List's own "Share" trigger, techpartners workspace,
|
|
8
|
+
// 2026-09-27): a 440px-wide floating panel, radius 12 (xl), the same
|
|
9
|
+
// layered popover shadow every other floating surface uses (`e.floating`
|
|
10
|
+
// matched the measured box-shadow's four layers exactly, so no new shadow
|
|
11
|
+
// literal was needed).
|
|
12
|
+
//
|
|
13
|
+
// This is its own floating shell rather than a reuse of the generic
|
|
14
|
+
// `Popover` (components/popover): that recipe caps its content at
|
|
15
|
+
// `min(360px, 92vw)`, and 440px measured wider than that on every sample.
|
|
16
|
+
// `product/savedviews` already sets the precedent for a product surface
|
|
17
|
+
// owning its own portaled shell over the generic one when the measured
|
|
18
|
+
// geometry doesn't fit it.
|
|
19
|
+
//
|
|
20
|
+
// Three muted-text alphas were measured that don't match any existing
|
|
21
|
+
// color token: the workspace-access/role value text (`rgba(0,0,0,.55)`),
|
|
22
|
+
// the "Individual members" section label (`rgba(0,0,0,.5)`), and the
|
|
23
|
+
// inactive-tab/footer-link text (`rgba(0,0,0,.63)` — this one incidentally
|
|
24
|
+
// equals `fgAlertDescription`'s light value, but that token is Dialog's own
|
|
25
|
+
// alert-description colour, a different surface, so it is not reused here).
|
|
26
|
+
// Rather than add new palette entries for three one-off alphas (tokens/**
|
|
27
|
+
// is another lane's file), each is expressed as `color-mix(in srgb,
|
|
28
|
+
// fgPrimary N%, transparent)` — the same idiom `segmented`'s own track
|
|
29
|
+
// background already uses for its 5% tint — so the value is theme-reactive
|
|
30
|
+
// (it scales with fgPrimary's dark value too) without a new token or a
|
|
31
|
+
// flat literal that would go stale in dark mode.
|
|
32
|
+
const mutedText = (pct) => `color-mix(in srgb, ${tokens_1.contract.fgPrimary} ${pct}%, transparent)`;
|
|
33
|
+
const config = (0, core_1.defineRecipe)({
|
|
34
|
+
name: "share",
|
|
35
|
+
base: `display: contents; font-family: ${tokens_1.contract.font.sans};`,
|
|
36
|
+
globalCss: `
|
|
37
|
+
.crisp-share-content {
|
|
38
|
+
font-family: ${tokens_1.contract.font.sans}; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
39
|
+
position: fixed; z-index: 70; pointer-events: auto; box-sizing: border-box;
|
|
40
|
+
width: 440px; max-width: 92vw;
|
|
41
|
+
padding: ${tokens_1.contract.space["3"]}; display: flex; flex-direction: column; gap: ${tokens_1.contract.space["3"]};
|
|
42
|
+
border-radius: ${tokens_1.contract.radius.xl}; background: ${tokens_1.contract.bgPopover}; color: ${tokens_1.contract.fgPrimary};
|
|
43
|
+
box-shadow: ${tokens_1.elevation.floating};
|
|
44
|
+
opacity: 1; transform: none; transform-origin: top right;
|
|
45
|
+
transition: opacity 0.08s ease, transform 0.08s ease;
|
|
46
|
+
@starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); }
|
|
47
|
+
}
|
|
48
|
+
.crisp-share-content[data-up] { transform-origin: bottom right; }
|
|
49
|
+
|
|
50
|
+
.crisp-share-tabs { display: flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; }
|
|
51
|
+
.crisp-share-tab {
|
|
52
|
+
box-sizing: border-box; display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]};
|
|
53
|
+
height: ${tokens_1.contract.size.row}; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md};
|
|
54
|
+
background: transparent; color: ${mutedText(63)};
|
|
55
|
+
font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; letter-spacing: -0.07px;
|
|
56
|
+
cursor: pointer; transition: background-color .12s ease, color .12s ease;
|
|
57
|
+
}
|
|
58
|
+
.crisp-share-tab svg { flex-shrink: 0; }
|
|
59
|
+
.crisp-share-tab:hover { color: ${tokens_1.contract.fgPrimary}; }
|
|
60
|
+
.crisp-share-tab[aria-selected="true"] { background: ${tokens_1.contract.bgSurfaceMuted}; color: ${tokens_1.contract.fgPrimary}; }
|
|
61
|
+
|
|
62
|
+
.crisp-share-row { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; min-height: 34px; }
|
|
63
|
+
.crisp-share-row-label { flex: 1; min-width: 0; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; letter-spacing: -0.07px; }
|
|
64
|
+
.crisp-share-row .crisp-select { flex-shrink: 0; }
|
|
65
|
+
.crisp-share-row .crisp-select .crisp-select-value,
|
|
66
|
+
.crisp-share-row .crisp-select .crisp-select-chevron { color: ${mutedText(55)}; }
|
|
67
|
+
|
|
68
|
+
.crisp-share-clear {
|
|
69
|
+
align-self: flex-start; margin: 0; padding: 0; border: none; background: none;
|
|
70
|
+
font-family: inherit; font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium};
|
|
71
|
+
color: ${mutedText(63)}; cursor: pointer;
|
|
72
|
+
}
|
|
73
|
+
.crisp-share-clear:hover { color: ${tokens_1.contract.fgPrimary}; text-decoration: underline; }
|
|
74
|
+
|
|
75
|
+
.crisp-share-section-label {
|
|
76
|
+
margin: 0; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${mutedText(50)};
|
|
77
|
+
}
|
|
78
|
+
.crisp-share-members { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["2"]}; }
|
|
79
|
+
.crisp-share-member { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; }
|
|
80
|
+
.crisp-share-member-text { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: ${tokens_1.contract.space["1.5"]}; overflow: hidden; }
|
|
81
|
+
.crisp-share-member-name { flex-shrink: 0; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; letter-spacing: -0.07px; }
|
|
82
|
+
.crisp-share-member-email { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${mutedText(55)}; letter-spacing: -0.07px; }
|
|
83
|
+
.crisp-share-member .crisp-select { flex-shrink: 0; }
|
|
84
|
+
.crisp-share-member .crisp-select .crisp-select-value,
|
|
85
|
+
.crisp-share-member .crisp-select .crisp-select-chevron { color: ${mutedText(55)}; }
|
|
86
|
+
|
|
87
|
+
.crisp-share-automations-row { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; }
|
|
88
|
+
.crisp-share-automations-row .crisp-input { flex: 1; min-width: 0; }
|
|
89
|
+
.crisp-share-automations-row .crisp-select { flex-shrink: 0; }
|
|
90
|
+
|
|
91
|
+
.crisp-share-add {
|
|
92
|
+
flex-shrink: 0; box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
|
|
93
|
+
height: 32px; padding: 0 ${tokens_1.contract.space["2.5"]}; border: none; border-radius: ${tokens_1.contract.radius.lg};
|
|
94
|
+
background: ${tokens_1.contract.bgBrandSolid}; color: ${tokens_1.contract.fgOnBrand};
|
|
95
|
+
font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; letter-spacing: -0.07px;
|
|
96
|
+
cursor: pointer; transition: background-color .12s ease, opacity .12s ease;
|
|
97
|
+
}
|
|
98
|
+
.crisp-share-add:hover:not(:disabled) { background: ${tokens_1.contract.bgBrandSolidPressed}; }
|
|
99
|
+
.crisp-share-add:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
100
|
+
|
|
101
|
+
.crisp-share-learnmore {
|
|
102
|
+
display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]};
|
|
103
|
+
font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${mutedText(63)};
|
|
104
|
+
text-decoration: none;
|
|
105
|
+
}
|
|
106
|
+
.crisp-share-learnmore:hover { color: ${tokens_1.contract.fgPrimary}; }
|
|
107
|
+
.crisp-share-learnmore svg { flex-shrink: 0; }
|
|
108
|
+
`,
|
|
109
|
+
variants: {},
|
|
110
|
+
defaultVariants: {},
|
|
111
|
+
compoundVariants: [],
|
|
112
|
+
});
|
|
113
|
+
exports.shareRecipe = (0, core_1.resolveRecipe)(config);
|
|
114
|
+
exports.default = config;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./shortcutssheet"), exports);
|