@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
|
@@ -52,10 +52,11 @@ const react_dom_1 = require("react-dom");
|
|
|
52
52
|
* `Dialog` was rendering offset by the dialog's own box instead of anchored
|
|
53
53
|
* to its trigger.
|
|
54
54
|
*
|
|
55
|
-
* Every caller renders this conditionally on its own `open` state
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
55
|
+
* Every caller renders this conditionally on its own `open` state. A fixture
|
|
56
|
+
* CAN set that true at mount (crisp#964 needs exactly that, to give Menu's
|
|
57
|
+
* roving-tabindex guard something to inspect), so this checks for `window`
|
|
58
|
+
* itself rather than assuming the caller never does — the same guard
|
|
59
|
+
* `@zag-js/react`'s own `Portal` uses for the identical reason.
|
|
59
60
|
*
|
|
60
61
|
* `sourceRef` is the caller's own root — still in its original DOM position,
|
|
61
62
|
* never portaled — used to carry a `data-theme` set on some ancestor of it
|
|
@@ -71,6 +72,8 @@ const react_dom_1 = require("react-dom");
|
|
|
71
72
|
* element carrying that attribute.
|
|
72
73
|
*/
|
|
73
74
|
function FloatingPortal({ children, sourceRef, }) {
|
|
75
|
+
if (typeof window === "undefined")
|
|
76
|
+
return children;
|
|
74
77
|
const theme = sourceRef.current
|
|
75
78
|
?.closest("[data-theme]")
|
|
76
79
|
?.getAttribute("data-theme");
|
package/dist/cjs/core/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.usePrefersReducedMotion = exports.useMentionTrigger = exports.useLabelAssociation = exports.useFormReset = exports.useFocusAfterRemoval = exports.specToRecipe = exports.defineSpec = exports.resolveRecipe = exports.Primitive = exports.placeFloating = exports.matchMentionTrigger = exports.useCrispMessages = exports.useCrispMessage = exports.useCrispComponentDefaults = exports.CrispMessagesProvider = exports.formValueStyle = exports.registerFloatingLayer = exports.isInsideLaterFloatingLayer = exports.hasOpenFloatingLayer = exports.hasNestedFloatingLayer = exports.FloatingPortal = exports.isRtlElement = exports.withDescribedBy = exports.defineRecipe = exports.cx = exports.parseCellDate = exports.formatCellDate = exports.cellDatePrecision = exports.caretRectInField = void 0;
|
|
17
|
+
exports.usePrefersReducedMotion = exports.useMentionTrigger = exports.useLabelAssociation = exports.useFormReset = exports.useFocusAfterRemoval = exports.specToRecipe = exports.defineSpec = exports.resolveRecipe = exports.Primitive = exports.placeSubmenu = exports.placeFloating = exports.matchMentionTrigger = exports.useCrispMessages = exports.useCrispMessage = exports.useCrispComponentDefaults = exports.CrispMessagesProvider = exports.formValueStyle = exports.registerFloatingLayer = exports.isInsideLaterFloatingLayer = exports.hasOpenFloatingLayer = exports.hasNestedFloatingLayer = exports.FloatingPortal = exports.isRtlElement = exports.withDescribedBy = exports.defineRecipe = exports.cx = exports.parseCellDate = exports.formatCellDate = exports.cellDatePrecision = exports.caretRectInField = void 0;
|
|
18
18
|
var caret_rect_1 = require("./caret-rect");
|
|
19
19
|
Object.defineProperty(exports, "caretRectInField", { enumerable: true, get: function () { return caret_rect_1.caretRectInField; } });
|
|
20
20
|
var cell_date_1 = require("./cell-date");
|
|
@@ -47,6 +47,7 @@ var mention_1 = require("./mention");
|
|
|
47
47
|
Object.defineProperty(exports, "matchMentionTrigger", { enumerable: true, get: function () { return mention_1.matchMentionTrigger; } });
|
|
48
48
|
var place_floating_1 = require("./place-floating");
|
|
49
49
|
Object.defineProperty(exports, "placeFloating", { enumerable: true, get: function () { return place_floating_1.placeFloating; } });
|
|
50
|
+
Object.defineProperty(exports, "placeSubmenu", { enumerable: true, get: function () { return place_floating_1.placeSubmenu; } });
|
|
50
51
|
var primitive_1 = require("./primitive");
|
|
51
52
|
Object.defineProperty(exports, "Primitive", { enumerable: true, get: function () { return primitive_1.Primitive; } });
|
|
52
53
|
var resolve_1 = require("./resolve");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.placeFloating = placeFloating;
|
|
4
|
+
exports.placeSubmenu = placeSubmenu;
|
|
4
5
|
const direction_1 = require("./direction");
|
|
5
6
|
/**
|
|
6
7
|
* Where a floating layer goes, in logical terms.
|
|
@@ -36,3 +37,40 @@ function placeFloating({ rect, align = "start", gap, flipBelow, anchor, }) {
|
|
|
36
37
|
style.left = rect.left;
|
|
37
38
|
return { style, up };
|
|
38
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Where a cascading submenu goes, BESIDE the item that opens it — not below
|
|
42
|
+
* it, the way `placeFloating`'s own dropdown does. Opens toward the inline
|
|
43
|
+
* end by default (further into the reading direction) and flips to the
|
|
44
|
+
* inline start when the surface's measured width doesn't fit there.
|
|
45
|
+
*
|
|
46
|
+
* Live-measured on Attio's own object-page "…" menu (crisp#616): the
|
|
47
|
+
* Notifications submenu sits with NO gap against the item's opposite edge
|
|
48
|
+
* (its own edge lines up exactly with the item's), so callers pass `gap: 0`
|
|
49
|
+
* for this specific cascade rather than the 4px a dropdown uses against its
|
|
50
|
+
* trigger.
|
|
51
|
+
*/
|
|
52
|
+
function placeSubmenu({ rect, size, gap, anchor, }) {
|
|
53
|
+
const rtl = (0, direction_1.isRtlElement)(anchor);
|
|
54
|
+
// "end" here is the inline-end direction FROM the item, e.g. further
|
|
55
|
+
// right in LTR — the room available there is measured from whichever
|
|
56
|
+
// physical edge that is.
|
|
57
|
+
const roomTowardEnd = rtl ? rect.left : window.innerWidth - rect.right;
|
|
58
|
+
const opensEnd = roomTowardEnd >= size.width + gap;
|
|
59
|
+
const align = opensEnd ? "start" : "end";
|
|
60
|
+
const style = {};
|
|
61
|
+
// Same formula as `placeFloating`'s own `toRight`, applied to the opposite
|
|
62
|
+
// geometry: there `align` picks which of the TRIGGER's edges the layer's
|
|
63
|
+
// matching edge lines up with; here it picks which side of the ITEM the
|
|
64
|
+
// layer cascades toward.
|
|
65
|
+
const anchorRight = align === "end" ? !rtl : rtl;
|
|
66
|
+
if (anchorRight)
|
|
67
|
+
style.right = window.innerWidth - rect.left + gap;
|
|
68
|
+
else
|
|
69
|
+
style.left = rect.right + gap;
|
|
70
|
+
const up = rect.top + size.height > window.innerHeight;
|
|
71
|
+
if (up)
|
|
72
|
+
style.bottom = Math.max(0, window.innerHeight - rect.bottom);
|
|
73
|
+
else
|
|
74
|
+
style.top = rect.top;
|
|
75
|
+
return { style, align, up };
|
|
76
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -92,6 +92,7 @@ __exportStar(require("./core"), exports);
|
|
|
92
92
|
// the generic primitives (Table, DataTable, Button, …) to build your own UI from.
|
|
93
93
|
__exportStar(require("./product/activityfeed"), exports);
|
|
94
94
|
__exportStar(require("./product/appshell"), exports);
|
|
95
|
+
__exportStar(require("./product/assigneepicker"), exports);
|
|
95
96
|
__exportStar(require("./product/authshell"), exports);
|
|
96
97
|
__exportStar(require("./product/board"), exports);
|
|
97
98
|
__exportStar(require("./product/command"), exports);
|
|
@@ -105,21 +106,28 @@ __exportStar(require("./product/inbox"), exports);
|
|
|
105
106
|
__exportStar(require("./product/listpage"), exports);
|
|
106
107
|
__exportStar(require("./product/memberssettings"), exports);
|
|
107
108
|
__exportStar(require("./product/navitem"), exports);
|
|
109
|
+
__exportStar(require("./product/notesgallery"), exports);
|
|
108
110
|
__exportStar(require("./product/notificationssettings"), exports);
|
|
111
|
+
__exportStar(require("./product/objectpagemenu"), exports);
|
|
109
112
|
__exportStar(require("./product/objectsettings"), exports);
|
|
110
113
|
__exportStar(require("./product/onboarding"), exports);
|
|
111
114
|
__exportStar(require("./product/recordpage"), exports);
|
|
112
115
|
__exportStar(require("./product/recordpanel"), exports);
|
|
116
|
+
__exportStar(require("./product/recordpicker"), exports);
|
|
113
117
|
__exportStar(require("./product/richtext"), exports);
|
|
114
118
|
__exportStar(require("./product/savedviews"), exports);
|
|
115
119
|
__exportStar(require("./product/settingssection"), exports);
|
|
116
120
|
__exportStar(require("./product/settingsshell"), exports);
|
|
121
|
+
__exportStar(require("./product/share"), exports);
|
|
122
|
+
__exportStar(require("./product/shortcutssheet"), exports);
|
|
117
123
|
__exportStar(require("./product/sidebar"), exports);
|
|
118
124
|
__exportStar(require("./product/statlist"), exports);
|
|
125
|
+
__exportStar(require("./product/taskeditpopover"), exports);
|
|
119
126
|
__exportStar(require("./product/tasklist"), exports);
|
|
120
127
|
__exportStar(require("./product/themepicker"), exports);
|
|
121
128
|
__exportStar(require("./product/trialbanner"), exports);
|
|
122
129
|
__exportStar(require("./product/viewtoggle"), exports);
|
|
123
130
|
__exportStar(require("./product/workspacegeneralsettings"), exports);
|
|
131
|
+
__exportStar(require("./product/workspaceswitchermenu"), exports);
|
|
124
132
|
// design tokens + recipe core (for building custom components)
|
|
125
133
|
__exportStar(require("./tokens"), exports);
|
|
@@ -0,0 +1,127 @@
|
|
|
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.AssigneePicker = AssigneePicker;
|
|
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 personchip_1 = require("../../components/personchip");
|
|
42
|
+
const select_1 = require("../../components/select");
|
|
43
|
+
const core_1 = require("../../core");
|
|
44
|
+
const assigneepicker_recipe_1 = require("./assigneepicker.recipe");
|
|
45
|
+
// Same five hashed avatar tones as `PersonChip`'s own (transcribed, not
|
|
46
|
+
// imported -- PersonChip's are private to that file, and this is the same
|
|
47
|
+
// one-line pure function `personchip.tsx` itself transcribes from
|
|
48
|
+
// `datatable.tsx`'s `TAG_TONES` rather than sharing an import; see its own
|
|
49
|
+
// comment for why that's fine here).
|
|
50
|
+
const HASH_TONES = ["brand", "orange", "cyan", "purple", "green"];
|
|
51
|
+
function hashTone(name) {
|
|
52
|
+
let h = 0;
|
|
53
|
+
for (let i = 0; i < name.length; i++)
|
|
54
|
+
h = (h * 31 + name.charCodeAt(i)) >>> 0;
|
|
55
|
+
return HASH_TONES[h % HASH_TONES.length];
|
|
56
|
+
}
|
|
57
|
+
function initials(name) {
|
|
58
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
59
|
+
if (parts.length === 0)
|
|
60
|
+
return "?";
|
|
61
|
+
return (parts[0][0] + (parts[1]?.[0] ?? "")).toUpperCase();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The picker behind a task's "Assigned to" chip -- measured live on
|
|
65
|
+
* app.attio.com's Tasks page ("Edit task" -> "Assigned to You" -> its own
|
|
66
|
+
* sub-popover, `Popover`-sized at the same measured 350px): a "Find a
|
|
67
|
+
* user..." search, the current assignee as a removable pill, then a plain
|
|
68
|
+
* option list, or "No users" when nothing matches. Attio's task assignment
|
|
69
|
+
* is single-user (one pill, replaced by picking another), unlike a
|
|
70
|
+
* multi-value field.
|
|
71
|
+
*/
|
|
72
|
+
function AssigneePicker({ users, assignee = null, onAssigneeChange, query: queryProp, onQueryChange, searchLabel: searchLabelProp, removeLabel: removeLabelProp, emptyLabel: emptyLabelProp, className, ...rest }) {
|
|
73
|
+
const searchLabel = (0, core_1.useCrispMessage)(searchLabelProp, "Find a user...");
|
|
74
|
+
const removeLabel = (0, core_1.useCrispMessage)(removeLabelProp, "Remove assignee");
|
|
75
|
+
// crisp/#471: `emptyLabel` is typed `React.ReactNode`, so it resolves by
|
|
76
|
+
// hand rather than through `useCrispMessage`, which is string-only --
|
|
77
|
+
// same reasoning as `Inbox`'s own `emptyTitle`/`emptySubtitle`.
|
|
78
|
+
const crispMessages = (0, core_1.useCrispMessages)();
|
|
79
|
+
const emptyLabel = emptyLabelProp ?? crispMessages["No users"] ?? "No users";
|
|
80
|
+
const [internalQuery, setInternalQuery] = React.useState("");
|
|
81
|
+
const query = queryProp ?? internalQuery;
|
|
82
|
+
const setQuery = (q) => {
|
|
83
|
+
if (queryProp === undefined)
|
|
84
|
+
setInternalQuery(q);
|
|
85
|
+
onQueryChange?.(q);
|
|
86
|
+
};
|
|
87
|
+
const [highlight, setHighlight] = React.useState(0);
|
|
88
|
+
const autoId = React.useId();
|
|
89
|
+
const listboxId = `${autoId}-listbox`;
|
|
90
|
+
const optionId = (i) => `${autoId}-opt-${i}`;
|
|
91
|
+
const q = query.trim().toLowerCase();
|
|
92
|
+
const candidates = users.filter((u) => u.id !== assignee?.id);
|
|
93
|
+
const filtered = q
|
|
94
|
+
? candidates.filter((u) => u.name.toLowerCase().includes(q))
|
|
95
|
+
: candidates;
|
|
96
|
+
const select = (u) => {
|
|
97
|
+
onAssigneeChange?.(u);
|
|
98
|
+
setQuery("");
|
|
99
|
+
setHighlight(0);
|
|
100
|
+
};
|
|
101
|
+
// crisp's shared popup-listbox model (#198), same as Select/MultiSelect --
|
|
102
|
+
// arrows, Home/End and wrapping, instead of a second hand-rolled one.
|
|
103
|
+
const { onKeyDown } = (0, select_1.useListboxKeyboard)({
|
|
104
|
+
enabledIndexes: filtered.map((_, i) => i),
|
|
105
|
+
highlight,
|
|
106
|
+
setHighlight,
|
|
107
|
+
commit: () => {
|
|
108
|
+
const u = filtered[highlight];
|
|
109
|
+
if (u)
|
|
110
|
+
select(u);
|
|
111
|
+
},
|
|
112
|
+
// Escape/Tab are for the enclosing Popover to handle (it owns open/close
|
|
113
|
+
// here, this picker has no floating state of its own).
|
|
114
|
+
close: () => { },
|
|
115
|
+
dismiss: () => { },
|
|
116
|
+
});
|
|
117
|
+
const activeId = highlight >= 0 && highlight < filtered.length
|
|
118
|
+
? optionId(highlight)
|
|
119
|
+
: undefined;
|
|
120
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, assigneepicker_recipe_1.assigneepickerRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-assigneepicker-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-assigneepicker-search-input", placeholder: searchLabel, value: query, onChange: (e) => {
|
|
121
|
+
setQuery(e.target.value);
|
|
122
|
+
setHighlight(0);
|
|
123
|
+
}, onKeyDown: onKeyDown, role: "combobox", "aria-expanded": "true", "aria-controls": listboxId, "aria-activedescendant": activeId,
|
|
124
|
+
// biome-ignore lint/a11y/noAutofocus: focus the search field the moment its enclosing popover opens
|
|
125
|
+
autoFocus: true })] }), assignee != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-assigneepicker-pill", children: (0, jsx_runtime_1.jsx)(personchip_1.PersonChip, { name: assignee.name, avatar: assignee.avatar, trailing: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-assigneepicker-remove", "aria-label": removeLabel, onClick: () => onAssigneeChange?.(null), children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 10, strokeWidth: 2 }) }) }) })), filtered.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-assigneepicker-empty", children: emptyLabel })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-assigneepicker-list", role: "listbox", id: listboxId, children: filtered.map((u, 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-assigneepicker-option", onMouseEnter: () => setHighlight(i), onClick: () => select(u), children: [(0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "sm", shape: "circle", tone: u.avatar ? "neutral" : hashTone(u.name), style: { flexShrink: 0, marginInlineEnd: 8 }, children: u.avatar ? (0, jsx_runtime_1.jsx)("img", { src: u.avatar, alt: "" }) : initials(u.name) }), u.name] }, u.id))) }))] }));
|
|
126
|
+
}
|
|
127
|
+
AssigneePicker.displayName = "AssigneePicker";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assigneepickerRecipe = void 0;
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
const tokens_1 = require("../../tokens");
|
|
6
|
+
// The assignee picker behind a task's "Assigned to" chip -- measured live on
|
|
7
|
+
// app.attio.com's Tasks page (Edit task -> "Assigned to You" -> its own
|
|
8
|
+
// sub-popover): a borderless 14px/500 "Find a user..." search row, the
|
|
9
|
+
// current assignee as a removable pill below it, then a plain option list
|
|
10
|
+
// (32px rows, radius 8, the same measured hover crisp's other listboxes
|
|
11
|
+
// share -- see menu.recipe.ts's own comment) or a centred "No users" line.
|
|
12
|
+
// The popover shell itself (radius/shadow/width) is `Popover`'s own --
|
|
13
|
+
// this is only the 350px-wide content Attio's own picker measured at.
|
|
14
|
+
const config = (0, core_1.defineRecipe)({
|
|
15
|
+
name: "assigneepicker",
|
|
16
|
+
base: `display: flex; flex-direction: column; box-sizing: border-box; width: 350px; font-family: ${tokens_1.contract.font.sans};
|
|
17
|
+
|
|
18
|
+
& .crisp-assigneepicker-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}; }
|
|
19
|
+
& .crisp-assigneepicker-search svg { flex-shrink: 0; }
|
|
20
|
+
& .crisp-assigneepicker-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}; }
|
|
21
|
+
& .crisp-assigneepicker-search-input::placeholder { color: ${tokens_1.contract.fgMuted}; }
|
|
22
|
+
|
|
23
|
+
& .crisp-assigneepicker-pill { display: flex; padding: 0 ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["2"]}; }
|
|
24
|
+
& .crisp-assigneepicker-remove { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 14px; height: 14px; margin: 0; padding: 0; border: none; background: none; color: inherit; font-family: inherit; cursor: pointer; }
|
|
25
|
+
|
|
26
|
+
& .crisp-assigneepicker-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); }
|
|
27
|
+
|
|
28
|
+
& .crisp-assigneepicker-list { display: flex; flex-direction: column; margin: 0; padding: ${tokens_1.contract.space["1"]}; list-style: none; }
|
|
29
|
+
& .crisp-assigneepicker-option { display: flex; align-items: center; 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; text-align: start; cursor: pointer; }
|
|
30
|
+
& .crisp-assigneepicker-option:hover, & .crisp-assigneepicker-option[data-highlighted] { background: ${tokens_1.contract.bgRaised}; }`,
|
|
31
|
+
variants: {},
|
|
32
|
+
defaultVariants: {},
|
|
33
|
+
compoundVariants: [],
|
|
34
|
+
});
|
|
35
|
+
exports.assigneepickerRecipe = (0, core_1.resolveRecipe)(config);
|
|
36
|
+
exports.default = config;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assigneepickerRecipe = exports.AssigneePicker = void 0;
|
|
4
|
+
var assigneepicker_1 = require("./assigneepicker");
|
|
5
|
+
Object.defineProperty(exports, "AssigneePicker", { enumerable: true, get: function () { return assigneepicker_1.AssigneePicker; } });
|
|
6
|
+
var assigneepicker_recipe_1 = require("./assigneepicker.recipe");
|
|
7
|
+
Object.defineProperty(exports, "assigneepickerRecipe", { enumerable: true, get: function () { return assigneepicker_recipe_1.assigneepickerRecipe; } });
|
|
@@ -54,10 +54,18 @@ function Inbox({ notifications = [], title: titleProp, tabs, activeTab, onTabCha
|
|
|
54
54
|
// own `empty`.
|
|
55
55
|
const crispMessages = (0, core_1.useCrispMessages)();
|
|
56
56
|
const title = titleProp ?? crispMessages.Notifications ?? "Notifications";
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
// A tab's own empty copy wins over the instance-level prop, which wins
|
|
58
|
+
// over the built-in default — same precedence as `title`/`emptyAction`.
|
|
59
|
+
const activeTabDef = tabs?.find((t) => t.id === activeTab);
|
|
60
|
+
const emptyTitle = activeTabDef?.emptyTitle ??
|
|
61
|
+
emptyTitleProp ??
|
|
62
|
+
crispMessages["No notifications"] ??
|
|
63
|
+
"No notifications";
|
|
64
|
+
const emptySubtitle = activeTabDef?.emptySubtitle ??
|
|
65
|
+
emptySubtitleProp ??
|
|
59
66
|
crispMessages["Notifications such as mentions and important updates will be displayed here."] ??
|
|
60
67
|
"Notifications such as mentions and important updates will be displayed here.";
|
|
68
|
+
const resolvedEmptyAction = activeTabDef?.emptyAction ?? emptyAction;
|
|
61
69
|
const tabsLabel = (0, core_1.useCrispMessage)(tabsLabelProp, "Notification views");
|
|
62
70
|
// crisp's shared tablist model, the one `Tabs` runs (#195). Hand-rolling a
|
|
63
71
|
// second one is how Inbox ended up with no arrow keys, no roving tabindex
|
|
@@ -68,6 +76,6 @@ function Inbox({ notifications = [], title: titleProp, tabs, activeTab, onTabCha
|
|
|
68
76
|
select: (id) => onTabChange?.(id),
|
|
69
77
|
listRef,
|
|
70
78
|
});
|
|
71
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, inbox_recipe_1.inboxRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-inbox-head", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-inbox-title", children: title }), tabs && tabs.length > 0 && ((0, jsx_runtime_1.jsx)("div", { ref: listRef, className: "crisp-inbox-tabs", role: "tablist", "aria-label": tabsLabel, onKeyDown: onKeyDown, children: tabs.map((t) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "tab", "aria-selected": t.id === activeTab, tabIndex: tabIndexFor(t.id), "data-value": t.id, disabled: t.disabled, className: "crisp-inbox-tab", "data-active": t.id === activeTab ? "" : undefined, onClick: () => onTabChange?.(t.id), children: [t.label, t.count != null && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-inbox-tab-count", children: ["(", t.count, ")"] }))] }, t.id))) }))] }), notifications.length === 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-inbox-empty", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-inbox-empty-icon", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Bell, { size: 40, strokeWidth: 1.25 }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-inbox-empty-title", children: emptyTitle }), emptySubtitle != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-inbox-empty-sub", children: emptySubtitle })),
|
|
79
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, inbox_recipe_1.inboxRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-inbox-head", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-inbox-title", children: title }), tabs && tabs.length > 0 && ((0, jsx_runtime_1.jsx)("div", { ref: listRef, className: "crisp-inbox-tabs", role: "tablist", "aria-label": tabsLabel, onKeyDown: onKeyDown, children: tabs.map((t) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "tab", "aria-selected": t.id === activeTab, tabIndex: tabIndexFor(t.id), "data-value": t.id, disabled: t.disabled, className: "crisp-inbox-tab", "data-active": t.id === activeTab ? "" : undefined, onClick: () => onTabChange?.(t.id), children: [t.label, t.count != null && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-inbox-tab-count", children: ["(", t.count, ")"] }))] }, t.id))) }))] }), notifications.length === 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-inbox-empty", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-inbox-empty-icon", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Bell, { size: 40, strokeWidth: 1.25 }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-inbox-empty-title", children: emptyTitle }), emptySubtitle != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-inbox-empty-sub", children: emptySubtitle })), resolvedEmptyAction != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-inbox-empty-action", children: resolvedEmptyAction }))] })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-inbox-list", children: notifications.map((n) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-inbox-row", onClick: n.onClick, children: [n.avatar != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-inbox-row-avatar", children: n.avatar })), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-inbox-row-body", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-inbox-row-msg", children: n.message }), n.time != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-inbox-row-time", children: n.time }))] }), n.unread && (0, jsx_runtime_1.jsx)("span", { className: "crisp-inbox-row-unread" })] }, n.id))) }))] }));
|
|
72
80
|
}
|
|
73
81
|
Inbox.displayName = "Inbox";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.notesgalleryRecipe = exports.NotesGallery = void 0;
|
|
4
|
+
var notesgallery_1 = require("./notesgallery");
|
|
5
|
+
Object.defineProperty(exports, "NotesGallery", { enumerable: true, get: function () { return notesgallery_1.NotesGallery; } });
|
|
6
|
+
var notesgallery_recipe_1 = require("./notesgallery.recipe");
|
|
7
|
+
Object.defineProperty(exports, "notesgalleryRecipe", { enumerable: true, get: function () { return notesgallery_recipe_1.notesgalleryRecipe; } });
|
|
@@ -0,0 +1,80 @@
|
|
|
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.NotesGallery = NotesGallery;
|
|
37
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
|
+
const React = __importStar(require("react"));
|
|
39
|
+
const tabs_1 = require("../../components/tabs");
|
|
40
|
+
const core_1 = require("../../core");
|
|
41
|
+
const entitycard_1 = require("../entitycard");
|
|
42
|
+
const notesgallery_recipe_1 = require("./notesgallery.recipe");
|
|
43
|
+
function NoteCard({ note }) {
|
|
44
|
+
return ((0, jsx_runtime_1.jsx)(entitycard_1.EntityCard, { author: note.linkedRecord, title: note.title, excerpt: note.excerpt, footer: note.author, date: note.date, onClick: note.onClick }));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The standalone Notes gallery -- measured live on app.attio.com's Notes
|
|
48
|
+
* page: "Notes N"/"Templates N" sub-tabs, a toolbar (Sort/View
|
|
49
|
+
* toggle/settings/New note, all consumer-composed), a dashed "Favorites"
|
|
50
|
+
* region, and date-grouped card sections. The card itself is `EntityCard`
|
|
51
|
+
* (crisp#474's own "measured from a Notes grid" component) — this shell
|
|
52
|
+
* only adds the gallery chrome around it.
|
|
53
|
+
*/
|
|
54
|
+
function NotesGallery({ notesCount, templatesCount, activeTab: activeTabProp, defaultActiveTab = "notes", onActiveTabChange, notesLabel: notesLabelProp, templatesLabel: templatesLabelProp, leading, trailing, favoritesLabel: favoritesLabelProp, favorites, favoritesEmptyLabel: favoritesEmptyLabelProp, groups, emptyLabel: emptyLabelProp, className, ...rest }) {
|
|
55
|
+
const notesLabel = (0, core_1.useCrispMessage)(notesLabelProp, "Notes");
|
|
56
|
+
const templatesLabel = (0, core_1.useCrispMessage)(templatesLabelProp, "Templates");
|
|
57
|
+
const favoritesLabel = (0, core_1.useCrispMessage)(favoritesLabelProp, "Favorites");
|
|
58
|
+
const favoritesEmptyLabel = (0, core_1.useCrispMessage)(favoritesEmptyLabelProp, "Notes that you favorite will appear here");
|
|
59
|
+
// crisp/#471: `emptyLabel` is typed `React.ReactNode`, so it resolves by
|
|
60
|
+
// hand rather than through `useCrispMessage`, which is string-only.
|
|
61
|
+
const crispMessages = (0, core_1.useCrispMessages)();
|
|
62
|
+
const emptyLabel = emptyLabelProp ?? crispMessages["No notes"] ?? "No notes";
|
|
63
|
+
const [internalTab, setInternalTab] = React.useState(defaultActiveTab);
|
|
64
|
+
const activeTab = activeTabProp ?? internalTab;
|
|
65
|
+
const setActiveTab = (v) => {
|
|
66
|
+
if (activeTabProp === undefined)
|
|
67
|
+
setInternalTab(v);
|
|
68
|
+
onActiveTabChange?.(v);
|
|
69
|
+
};
|
|
70
|
+
const total = groups.reduce((s, g) => s + g.notes.length, 0);
|
|
71
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, notesgallery_recipe_1.notesgalleryRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-tabs", children: (0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: [
|
|
72
|
+
{ value: "notes", label: notesLabel, badge: notesCount },
|
|
73
|
+
{
|
|
74
|
+
value: "templates",
|
|
75
|
+
label: templatesLabel,
|
|
76
|
+
badge: templatesCount,
|
|
77
|
+
},
|
|
78
|
+
], value: activeTab, onValueChange: setActiveTab }) }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-notesgallery-toolbar", children: [leading, trailing != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-toolbar-trail", children: trailing }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-notesgallery-favorites-section", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-favorites-label", children: favoritesLabel }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-favorites", children: favorites != null && favorites.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-grid", children: favorites.map((n) => ((0, jsx_runtime_1.jsx)(NoteCard, { note: n }, n.id))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-favorites-empty", children: favoritesEmptyLabel })) })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-body", children: total === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-empty", children: emptyLabel })) : (groups.map((g) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-notesgallery-group", children: [g.label, (0, jsx_runtime_1.jsx)("span", { className: "crisp-notesgallery-group-count", children: g.count })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-notesgallery-grid", children: g.notes.map((n) => ((0, jsx_runtime_1.jsx)(NoteCard, { note: n }, n.id))) })] }, g.id)))) })] }));
|
|
79
|
+
}
|
|
80
|
+
NotesGallery.displayName = "NotesGallery";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.notesgalleryRecipe = void 0;
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
const tokens_1 = require("../../tokens");
|
|
6
|
+
// The standalone Notes gallery -- measured live on app.attio.com's Notes
|
|
7
|
+
// page: a toolbar (leading Sort control, trailing view toggle/View
|
|
8
|
+
// settings/New note, both consumer-composed slots -- crisp doesn't own the
|
|
9
|
+
// exact button set, same reasoning as `ListPage`'s own leading/trailing), a
|
|
10
|
+
// dashed "Favorites" region, then date-grouped sections (a group header +
|
|
11
|
+
// count badge, transcribed from `ListPage`'s own already-measured values
|
|
12
|
+
// rather than re-deriving them -- this IS the same Attio pattern, applied
|
|
13
|
+
// above a card grid instead of a row list) holding a responsive card grid of
|
|
14
|
+
// `EntityCard`s.
|
|
15
|
+
//
|
|
16
|
+
// The grid itself: a single real note card measured 356px wide -- with only
|
|
17
|
+
// one note in the workspace there was no second card to read a column gap or
|
|
18
|
+
// count from, so this uses a responsive `auto-fill` grid at that measured
|
|
19
|
+
// per-card width instead of inventing a fixed column count or gap.
|
|
20
|
+
const config = (0, core_1.defineRecipe)({
|
|
21
|
+
name: "notesgallery",
|
|
22
|
+
base: `display: flex; flex-direction: column; min-height: 0; box-sizing: border-box; font-family: ${tokens_1.contract.font.sans}; color: ${tokens_1.contract.fgPrimary};
|
|
23
|
+
-webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
24
|
+
|
|
25
|
+
& .crisp-notesgallery-tabs { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 44px; flex-shrink: 0; padding: 0 ${tokens_1.contract.space["3"]}; }
|
|
26
|
+
|
|
27
|
+
& .crisp-notesgallery-toolbar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: ${tokens_1.contract.size.header}; flex-shrink: 0; padding: 0 ${tokens_1.contract.space["3"]}; }
|
|
28
|
+
& .crisp-notesgallery-toolbar-trail { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; margin-inline-start: auto; }
|
|
29
|
+
|
|
30
|
+
& .crisp-notesgallery-favorites-section { background: ${tokens_1.contract.bgSubtle}; box-shadow: inset 0 -1px 0 ${tokens_1.contract.borderSubtle}; }
|
|
31
|
+
& .crisp-notesgallery-favorites-label { padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["4"]} 0; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
|
|
32
|
+
& .crisp-notesgallery-favorites { display: flex; align-items: center; justify-content: center; min-height: 200px; padding: ${tokens_1.contract.space["6"]}; }
|
|
33
|
+
& .crisp-notesgallery-favorites-empty { box-sizing: border-box; width: 100%; padding: ${tokens_1.contract.space["6"]}; border: 1px dashed ${tokens_1.contract.borderDefault}; border-radius: ${tokens_1.contract.radius.xl}; text-align: center; font-size: ${tokens_1.contract.text.md}; color: ${tokens_1.contract.fgMuted}; }
|
|
34
|
+
|
|
35
|
+
& .crisp-notesgallery-body { flex: 1; min-height: 0; overflow-y: auto; padding: 0 ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["3"]}; }
|
|
36
|
+
& .crisp-notesgallery-group { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: ${tokens_1.contract.size.menuRow}; padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["1"]}; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
|
|
37
|
+
& .crisp-notesgallery-group-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius.sm}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent); font-size: ${tokens_1.contract.text.xs}; color: ${tokens_1.contract.fgMuted}; }
|
|
38
|
+
& .crisp-notesgallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: ${tokens_1.contract.space["4"]}; padding-bottom: ${tokens_1.contract.space["4"]}; }
|
|
39
|
+
|
|
40
|
+
& .crisp-notesgallery-empty { padding: ${tokens_1.contract.space["8"]} ${tokens_1.contract.space["3"]}; text-align: center; font-size: ${tokens_1.contract.text.md}; color: ${tokens_1.contract.fgMuted}; }`,
|
|
41
|
+
variants: {},
|
|
42
|
+
defaultVariants: {},
|
|
43
|
+
compoundVariants: [],
|
|
44
|
+
});
|
|
45
|
+
exports.notesgalleryRecipe = (0, core_1.resolveRecipe)(config);
|
|
46
|
+
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("./objectpagemenu"), exports);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ObjectPageMenu = ObjectPageMenu;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const lucide_react_1 = require("lucide-react");
|
|
6
|
+
const button_1 = require("../../components/button");
|
|
7
|
+
const menu_1 = require("../../components/menu");
|
|
8
|
+
const core_1 = require("../../core");
|
|
9
|
+
/**
|
|
10
|
+
* The page-level "…" menu on Attio's object page: Object settings / Manage
|
|
11
|
+
* attributes / a Notifications submenu ("Connect Slack workspace") — crisp
|
|
12
|
+
* parity checklist rows G-020/P-005 (crisp#616). Live-measured on
|
|
13
|
+
* app.attio.com/techpartners/companies: 208×114 popover (12px radius, 4px
|
|
14
|
+
* padding, 32px rows), a hairline separator before Notifications, and its
|
|
15
|
+
* submenu opening flush against the item with no gap, flipping side when
|
|
16
|
+
* the measured width doesn't fit (`placeSubmenu`, core/place-floating.ts).
|
|
17
|
+
*/
|
|
18
|
+
function ObjectPageMenu({ trigger, onObjectSettings, onManageAttributes, onConnectSlack, objectSettingsLabel, manageAttributesLabel, notificationsLabel, connectSlackLabel, "aria-label": ariaLabelProp, align = "end", }) {
|
|
19
|
+
const objectSettings = (0, core_1.useCrispMessage)(objectSettingsLabel, "Object settings");
|
|
20
|
+
const manageAttributes = (0, core_1.useCrispMessage)(manageAttributesLabel, "Manage attributes");
|
|
21
|
+
const notifications = (0, core_1.useCrispMessage)(notificationsLabel, "Notifications");
|
|
22
|
+
const connectSlack = (0, core_1.useCrispMessage)(connectSlackLabel, "Connect Slack workspace");
|
|
23
|
+
const ariaLabel = (0, core_1.useCrispMessage)(ariaLabelProp, "Show menu");
|
|
24
|
+
return ((0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: align, "aria-label": ariaLabel, trigger: trigger ?? ((0, jsx_runtime_1.jsx)(button_1.Button, { intent: "ghost", size: "md", shape: "icon", "aria-label": ariaLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) })), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Settings, { size: 16, strokeWidth: 1.75 }), onSelect: onObjectSettings, children: objectSettings }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.LayoutGrid, { size: 16, strokeWidth: 1.75 }), onSelect: onManageAttributes, children: manageAttributes }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.Menu, { placement: "submenu", "aria-label": notifications, trigger: (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Bell, { size: 16, strokeWidth: 1.75 }), trailingIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { "data-rtl-flip": "", size: 16, strokeWidth: 1.75 }), closeOnSelect: false, children: notifications }), children: (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.MessageSquare, { size: 16, strokeWidth: 1.75 }), onSelect: onConnectSlack, children: connectSlack }) })] }));
|
|
25
|
+
}
|
|
26
|
+
ObjectPageMenu.displayName = "ObjectPageMenu";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.objectpagemenuRecipe = void 0;
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
/**
|
|
6
|
+
* `ObjectPageMenu` owns no styling of its own — every visible pixel is
|
|
7
|
+
* `Menu`/`MenuItem`'s own already-measured recipe. The one thing it DOES
|
|
8
|
+
* need is the RTL mirror for its Notifications submenu chevron (crisp#616):
|
|
9
|
+
* that icon is the first direction-bearing one ever passed as a `MenuItem`
|
|
10
|
+
* `trailingIcon`, so nothing already mirrors it.
|
|
11
|
+
*
|
|
12
|
+
* Not written as `${rtlFlipCss}` (core/rtl.ts): that string relies on native
|
|
13
|
+
* CSS nesting's `&` resolving to an ENCLOSING rule, which is exactly what
|
|
14
|
+
* `Menu`'s own recipe deliberately avoids for its portaled content (see its
|
|
15
|
+
* own doc comment) — nesting this under a `.crisp-objectpagemenu` root would
|
|
16
|
+
* need a root class this component doesn't have. A plain absolute selector,
|
|
17
|
+
* matching `Menu`'s own pattern for the identical reason.
|
|
18
|
+
*/
|
|
19
|
+
const config = (0, core_1.defineRecipe)({
|
|
20
|
+
name: "objectpagemenu",
|
|
21
|
+
base: "",
|
|
22
|
+
globalCss: `
|
|
23
|
+
[dir="rtl"] .crisp-menu-item svg[data-rtl-flip] { transform: scaleX(-1); }
|
|
24
|
+
`,
|
|
25
|
+
variants: {},
|
|
26
|
+
defaultVariants: {},
|
|
27
|
+
compoundVariants: [],
|
|
28
|
+
});
|
|
29
|
+
exports.objectpagemenuRecipe = (0, core_1.resolveRecipe)(config);
|
|
30
|
+
exports.default = config;
|