pixelize-design-library 2.3.19 → 2.3.21
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/.cursor/modules/overlays/MODULE.md +18 -1
- package/.cursor/modules/utils-hooks/MODULE.md +12 -2
- package/dist/Components/Toaster/Toaster.d.ts.map +1 -1
- package/dist/Components/Toaster/Toaster.js +54 -12
- package/dist/Components/Toaster/ToasterProps.d.ts +7 -0
- package/dist/Components/Toaster/ToasterProps.d.ts.map +1 -1
- package/dist/Components/ToolTip/OverflowToolTip.d.ts +18 -0
- package/dist/Components/ToolTip/OverflowToolTip.d.ts.map +1 -0
- package/dist/Components/ToolTip/OverflowToolTip.js +26 -0
- package/dist/Components/ToolTip/ToolTip.d.ts +1 -1
- package/dist/Components/ToolTip/ToolTip.d.ts.map +1 -1
- package/dist/Components/ToolTip/ToolTip.js +21 -3
- package/dist/Components/ToolTip/ToolTipProps.d.ts +9 -0
- package/dist/Components/ToolTip/ToolTipProps.d.ts.map +1 -1
- package/dist/Components/WorkspaceWindow/WorkspaceTrayPreview.d.ts +16 -0
- package/dist/Components/WorkspaceWindow/WorkspaceTrayPreview.d.ts.map +1 -0
- package/dist/Components/WorkspaceWindow/WorkspaceTrayPreview.js +83 -0
- package/dist/Components/WorkspaceWindow/WorkspaceWindow.d.ts +15 -0
- package/dist/Components/WorkspaceWindow/WorkspaceWindow.d.ts.map +1 -0
- package/dist/Components/WorkspaceWindow/WorkspaceWindow.js +40 -0
- package/dist/Components/WorkspaceWindow/WorkspaceWindowProps.d.ts +72 -0
- package/dist/Components/WorkspaceWindow/WorkspaceWindowProps.d.ts.map +1 -0
- package/dist/Components/WorkspaceWindow/WorkspaceWindowProps.js +2 -0
- package/dist/Hooks/useIsTruncated.d.ts +36 -0
- package/dist/Hooks/useIsTruncated.d.ts.map +1 -0
- package/dist/Hooks/useIsTruncated.js +57 -0
- package/dist/Utils/mergeRefs.d.ts +11 -0
- package/dist/Utils/mergeRefs.d.ts.map +1 -0
- package/dist/Utils/mergeRefs.js +20 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -2
- package/package.json +1 -1
- package/dist/Assets/defaultLogo.tsx +0 -30
- package/dist/Components/Input/textInputIconSize.test.d.ts +0 -1
- package/dist/Components/Input/textInputIconSize.test.js +0 -27
- package/dist/Components/KanbanBoard/AccountCard.test.d.ts +0 -1
- package/dist/Components/KanbanBoard/AccountCard.test.js +0 -68
- package/dist/Components/KanbanBoard/KanbanActions/KanbanActions.test.d.ts +0 -1
- package/dist/Components/KanbanBoard/KanbanActions/KanbanActions.test.js +0 -49
- package/dist/Components/KanbanBoard/KanbanBoard.test.d.ts +0 -1
- package/dist/Components/KanbanBoard/KanbanBoard.test.js +0 -185
- package/dist/Components/SearchSelect/searchSelectSize.test.d.ts +0 -1
- package/dist/Components/SearchSelect/searchSelectSize.test.js +0 -22
- package/dist/Components/SideBar/components/OtherApps.test.d.ts +0 -1
- package/dist/Components/SideBar/components/OtherApps.test.js +0 -111
- package/dist/Components/Table/components/TableBody.virtualize.test.d.ts +0 -1
- package/dist/Components/Table/components/TableBody.virtualize.test.js +0 -93
- package/dist/Components/Table/settings/ManageColumns.test.d.ts +0 -1
- package/dist/Components/Table/settings/ManageColumns.test.js +0 -146
- package/dist/Theme/buildBrandTokens.test.d.ts +0 -1
- package/dist/Theme/buildBrandTokens.test.js +0 -31
- package/dist/Theme/chartColorsFromTheme.test.d.ts +0 -1
- package/dist/Theme/chartColorsFromTheme.test.js +0 -35
- package/dist/Utils/tableNormalizeCellValue.test.d.ts +0 -1
- package/dist/Utils/tableNormalizeCellValue.test.js +0 -41
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
Modal, AlertDialog, ToolTip, Toaster (+ `useToaster` hook).
|
|
5
|
+
Modal, AlertDialog, ToolTip / OverflowToolTip, Toaster (+ `useToaster` hook).
|
|
6
6
|
|
|
7
7
|
## Key paths
|
|
8
8
|
|
|
@@ -10,4 +10,21 @@ Modal, AlertDialog, ToolTip, Toaster (+ `useToaster` hook).
|
|
|
10
10
|
|
|
11
11
|
## Key rules
|
|
12
12
|
|
|
13
|
+
- **Toaster `showToast({ actions })`:** optional `actions?: (onClose) => ReactNode`
|
|
14
|
+
renders action buttons under the message (e.g. Jira-style "View" / "Copy link").
|
|
15
|
+
The render-prop receives the toast's own `onClose` so an action can dismiss it;
|
|
16
|
+
callers style the buttons with their app theme. Prefer this over a bespoke Chakra
|
|
17
|
+
`useToast` in a consumer app — a second `useToast` renders into a *different* toast
|
|
18
|
+
portal that a `Modal`'s overlay/focus-trap can hide, so the toast silently never
|
|
19
|
+
appears. The toast card slides in (framer tween), pulses the status icon once on
|
|
20
|
+
mount, and **pauses the auto-dismiss countdown on hover** so the user can read and
|
|
21
|
+
click an action before it dismisses.
|
|
13
22
|
- Modal exports ModalHeader, ModalBody, ModalFooter subcomponents
|
|
23
|
+
- **ToolTip `overflowOnly`:** pass `overflowOnly` to show the tooltip **only**
|
|
24
|
+
when the child text is actually truncated (ellipsis active) — no tooltip when
|
|
25
|
+
it fits. The child must be the single clamping element (e.g. `Text` with
|
|
26
|
+
`noOfLines`); its ref is managed internally. Works for single- and multi-line
|
|
27
|
+
clamps and combines with `isDisabled`. **`OverflowToolTip`** is sugar for
|
|
28
|
+
`<ToolTip overflowOnly>`. Powered by the `useIsTruncated` hook (see
|
|
29
|
+
`utils-hooks`). Inert unless `overflowOnly` is set — no measurement/observer
|
|
30
|
+
for ordinary tooltips, and it never measures on hover/scroll.
|
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
Shared utilities and hooks: debounce, table helpers, preferences
|
|
5
|
+
Shared utilities and hooks: debounce, table helpers, preferences, ref merging,
|
|
6
|
+
truncation detection.
|
|
6
7
|
|
|
7
8
|
## Key paths
|
|
8
9
|
|
|
9
|
-
- `src/Utils/table.ts`, `src/
|
|
10
|
+
- `src/Utils/table.ts`, `src/Utils/mergeRefs.ts`, `src/Hooks/usePreferences.ts`,
|
|
11
|
+
`src/Hooks/useIsTruncated.ts`, `src/services/feedback.ts`
|
|
10
12
|
|
|
11
13
|
## Key rules
|
|
12
14
|
|
|
13
15
|
- `debounce` exported from index.ts
|
|
16
|
+
- **`useIsTruncated(content?, enabled?)`** (exported) — returns `{ ref, isTruncated }`;
|
|
17
|
+
attach `ref` to a clamped element to detect real overflow (`scrollWidth/Height`
|
|
18
|
+
vs `clientWidth/Height`, single- and multi-line). Re-measures on mount, element
|
|
19
|
+
resize (`ResizeObserver`), and `content` change — never on hover/scroll. Pass
|
|
20
|
+
`enabled=false` to make it fully inert. Powers `ToolTip overflowOnly` (see
|
|
21
|
+
`overlays`).
|
|
22
|
+
- **`mergeRefs(...refs)`** (internal) — combine a caller ref with an injected one
|
|
23
|
+
when cloning an element.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../src/Components/Toaster/Toaster.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../src/Components/Toaster/Toaster.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAqB,MAAM,gBAAgB,CAAC;AAyKxF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAE,EAAE,eAAe,2CAkEpE;AAED,eAAO,MAAM,UAAU,0BAMtB,CAAC"}
|
|
@@ -6,20 +6,68 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const react_2 = require("@chakra-ui/react");
|
|
8
8
|
const react_3 = require("@emotion/react");
|
|
9
|
+
const framer_motion_1 = require("framer-motion");
|
|
9
10
|
const lucide_react_1 = require("lucide-react");
|
|
10
11
|
const ToasterContext = (0, react_1.createContext)(undefined);
|
|
11
12
|
const shrink = (0, react_3.keyframes) `
|
|
12
13
|
from { transform: scaleX(1); }
|
|
13
14
|
to { transform: scaleX(0); }
|
|
14
15
|
`;
|
|
16
|
+
// One-shot ring pulse on the status icon — a subtle "just happened" beat.
|
|
17
|
+
const iconPulse = (0, react_3.keyframes) `
|
|
18
|
+
0% { box-shadow: 0 0 0 0 var(--toast-pulse-color); }
|
|
19
|
+
70% { box-shadow: 0 0 0 0.5rem transparent; }
|
|
20
|
+
100% { box-shadow: 0 0 0 0 transparent; }
|
|
21
|
+
`;
|
|
22
|
+
const MotionBox = (0, framer_motion_1.motion)(react_2.Box);
|
|
23
|
+
/**
|
|
24
|
+
* Presentational toast card. Owns hover state so the auto-dismiss countdown
|
|
25
|
+
* pauses while the pointer is over the toast — the user can read and click an
|
|
26
|
+
* action without the toast vanishing mid-reach.
|
|
27
|
+
*/
|
|
28
|
+
function ToastCard({ onClose, title, description, actions, isClosable, duration, meta, colors: c, shadowLg, }) {
|
|
29
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
|
|
30
|
+
const [paused, setPaused] = (0, react_1.useState)(false);
|
|
31
|
+
const solid = (_d = (_b = (_a = meta.scale) === null || _a === void 0 ? void 0 : _a[500]) !== null && _b !== void 0 ? _b : (_c = c === null || c === void 0 ? void 0 : c.gray) === null || _c === void 0 ? void 0 : _c[500]) !== null && _d !== void 0 ? _d : "#718096";
|
|
32
|
+
const soft = (_h = (_f = (_e = meta.scale) === null || _e === void 0 ? void 0 : _e[50]) !== null && _f !== void 0 ? _f : (_g = c === null || c === void 0 ? void 0 : c.gray) === null || _g === void 0 ? void 0 : _g[50]) !== null && _h !== void 0 ? _h : "#f7fafc";
|
|
33
|
+
const accent = (_k = (_j = meta.scale) === null || _j === void 0 ? void 0 : _j[600]) !== null && _k !== void 0 ? _k : solid;
|
|
34
|
+
const ringTint = (_m = (_l = meta.scale) === null || _l === void 0 ? void 0 : _l[200]) !== null && _m !== void 0 ? _m : soft;
|
|
35
|
+
const showProgress = typeof duration === "number" && duration > 0;
|
|
36
|
+
return ((0, jsx_runtime_1.jsxs)(MotionBox
|
|
37
|
+
// Refined entrance — slides in from the right and settles, never a hard pop.
|
|
38
|
+
// framer owns ALL transform animation; the CSS transition below is limited to
|
|
39
|
+
// box-shadow so it never tweens the same `transform` framer is driving frame
|
|
40
|
+
// by frame (that double-drive is what caused the ~200ms entry flicker). A
|
|
41
|
+
// tween (not spring) lands on an exact end transform, so there's no residual
|
|
42
|
+
// sub-pixel settle to shimmer.
|
|
43
|
+
, {
|
|
44
|
+
// Refined entrance — slides in from the right and settles, never a hard pop.
|
|
45
|
+
// framer owns ALL transform animation; the CSS transition below is limited to
|
|
46
|
+
// box-shadow so it never tweens the same `transform` framer is driving frame
|
|
47
|
+
// by frame (that double-drive is what caused the ~200ms entry flicker). A
|
|
48
|
+
// tween (not spring) lands on an exact end transform, so there's no residual
|
|
49
|
+
// sub-pixel settle to shimmer.
|
|
50
|
+
initial: { opacity: 0, x: 24 }, animate: { opacity: 1, x: 0 }, exit: { opacity: 0, x: 24 }, transition: { duration: 0.24, ease: [0.22, 1, 0.36, 1] }, onHoverStart: () => setPaused(true), onHoverEnd: () => setPaused(false), position: "relative", bg: (_o = c === null || c === void 0 ? void 0 : c.white) !== null && _o !== void 0 ? _o : "#fff", border: `0.063rem solid ${(_s = (_q = (_p = c === null || c === void 0 ? void 0 : c.boxborder) === null || _p === void 0 ? void 0 : _p[300]) !== null && _q !== void 0 ? _q : (_r = c === null || c === void 0 ? void 0 : c.gray) === null || _r === void 0 ? void 0 : _r[200]) !== null && _s !== void 0 ? _s : "#e2e8f0"}`, boxShadow: shadowLg !== null && shadowLg !== void 0 ? shadowLg : "lg", borderRadius: "0.875rem", overflow: "hidden", minW: "22.5rem", maxW: "26rem", willChange: "transform, opacity", sx: {
|
|
51
|
+
transition: "box-shadow 0.18s ease",
|
|
52
|
+
_hover: { boxShadow: "xl" },
|
|
53
|
+
}, children: [(0, jsx_runtime_1.jsxs)(react_2.Flex, { p: 3.5, gap: 3, align: actions ? "flex-start" : "center", children: [(0, jsx_runtime_1.jsx)(react_2.Flex, { align: "center", justify: "center", boxSize: "2rem", minW: "2rem", borderRadius: "full", bg: soft, color: accent, sx: {
|
|
54
|
+
["--toast-pulse-color"]: ringTint,
|
|
55
|
+
animation: `${iconPulse} 900ms ease-out 1`,
|
|
56
|
+
}, children: meta.icon }), (0, jsx_runtime_1.jsxs)(react_2.Box, { flex: "1", minW: 0, children: [title && ((0, jsx_runtime_1.jsx)(react_2.Text, { fontWeight: 600, fontSize: "0.875rem", lineHeight: "1.3", color: (_w = (_u = (_t = c === null || c === void 0 ? void 0 : c.text) === null || _t === void 0 ? void 0 : _t[800]) !== null && _u !== void 0 ? _u : (_v = c === null || c === void 0 ? void 0 : c.gray) === null || _v === void 0 ? void 0 : _v[800]) !== null && _w !== void 0 ? _w : "#2d3748", children: title })), description && ((0, jsx_runtime_1.jsx)(react_2.Text, { fontSize: "0.8125rem", lineHeight: "1.45", color: (_0 = (_y = (_x = c === null || c === void 0 ? void 0 : c.gray) === null || _x === void 0 ? void 0 : _x[600]) !== null && _y !== void 0 ? _y : (_z = c === null || c === void 0 ? void 0 : c.text) === null || _z === void 0 ? void 0 : _z[600]) !== null && _0 !== void 0 ? _0 : "#718096", mt: title ? "0.125rem" : 0, children: description })), actions && ((0, jsx_runtime_1.jsx)(react_2.Flex, { gap: 2, mt: 2.5, align: "center", wrap: "wrap", children: actions(onClose) }))] }), isClosable && ((0, jsx_runtime_1.jsx)(react_2.CloseButton, { onClick: onClose, size: "sm", color: (_2 = (_1 = c === null || c === void 0 ? void 0 : c.gray) === null || _1 === void 0 ? void 0 : _1[400]) !== null && _2 !== void 0 ? _2 : "#a0aec0", borderRadius: "md", alignSelf: "flex-start", _hover: {
|
|
57
|
+
bg: (_4 = (_3 = c === null || c === void 0 ? void 0 : c.gray) === null || _3 === void 0 ? void 0 : _3[100]) !== null && _4 !== void 0 ? _4 : "#edf2f7",
|
|
58
|
+
color: (_6 = (_5 = c === null || c === void 0 ? void 0 : c.gray) === null || _5 === void 0 ? void 0 : _5[700]) !== null && _6 !== void 0 ? _6 : "#4a5568",
|
|
59
|
+
} }))] }), showProgress && ((0, jsx_runtime_1.jsx)(react_2.Box, { position: "absolute", bottom: 0, left: 0, right: 0, h: "0.1875rem", bg: solid, opacity: 0.85, transformOrigin: "left", sx: {
|
|
60
|
+
animation: `${shrink} ${duration}ms linear forwards`,
|
|
61
|
+
animationPlayState: paused ? "paused" : "running",
|
|
62
|
+
} }))] }));
|
|
63
|
+
}
|
|
15
64
|
function ToasterProvider({ children }) {
|
|
16
65
|
var _a;
|
|
17
66
|
const toast = (0, react_2.useToast)();
|
|
18
67
|
const theme = (0, react_2.useTheme)();
|
|
19
68
|
const c = (_a = theme.colors) !== null && _a !== void 0 ? _a : {};
|
|
20
|
-
const showToast = ({ title, description, status = "info", duration = 5000, isClosable = true, position = "top-right", onClose, }) => {
|
|
21
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l
|
|
22
|
-
// Status → semantic color scale + icon (falls back to legacy palettes).
|
|
69
|
+
const showToast = ({ title, description, status = "info", duration = 5000, isClosable = true, position = "top-right", onClose, actions, }) => {
|
|
70
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
23
71
|
const statusConfig = {
|
|
24
72
|
success: {
|
|
25
73
|
scale: (_b = (_a = c.semantic) === null || _a === void 0 ? void 0 : _a.success) !== null && _b !== void 0 ? _b : c.green,
|
|
@@ -42,21 +90,15 @@ function ToasterProvider({ children }) {
|
|
|
42
90
|
icon: (0, jsx_runtime_1.jsx)(react_2.Spinner, { size: "sm", thickness: "0.125rem", speed: "0.7s" }),
|
|
43
91
|
},
|
|
44
92
|
};
|
|
45
|
-
const
|
|
46
|
-
const solid = (_m = scale === null || scale === void 0 ? void 0 : scale[500]) !== null && _m !== void 0 ? _m : (_o = c.gray) === null || _o === void 0 ? void 0 : _o[500];
|
|
47
|
-
const soft = (_p = scale === null || scale === void 0 ? void 0 : scale[50]) !== null && _p !== void 0 ? _p : (_q = c.gray) === null || _q === void 0 ? void 0 : _q[50];
|
|
48
|
-
const accent = (_r = scale === null || scale === void 0 ? void 0 : scale[600]) !== null && _r !== void 0 ? _r : solid;
|
|
49
|
-
const showProgress = typeof duration === "number" && duration > 0;
|
|
93
|
+
const meta = (_l = statusConfig[status]) !== null && _l !== void 0 ? _l : statusConfig.info;
|
|
50
94
|
toast({
|
|
51
95
|
duration,
|
|
52
96
|
isClosable,
|
|
53
97
|
position,
|
|
54
98
|
onCloseComplete: onClose,
|
|
55
99
|
render: ({ onClose }) => {
|
|
56
|
-
var _a
|
|
57
|
-
return ((0, jsx_runtime_1.
|
|
58
|
-
animation: `${shrink} ${duration}ms linear forwards`,
|
|
59
|
-
} }))] }));
|
|
100
|
+
var _a;
|
|
101
|
+
return ((0, jsx_runtime_1.jsx)(ToastCard, { onClose: onClose, title: title, description: description, actions: actions, isClosable: isClosable, duration: duration, meta: meta, colors: c, shadowLg: (_a = theme.shadows) === null || _a === void 0 ? void 0 : _a.lg }));
|
|
60
102
|
},
|
|
61
103
|
});
|
|
62
104
|
};
|
|
@@ -3,6 +3,13 @@ import { ReactNode } from "react";
|
|
|
3
3
|
export type ToasterToastProps = Pick<ToastProps, 'description' | 'title' | 'isClosable' | 'duration' | 'children' | 'onClose'> & {
|
|
4
4
|
position?: "top" | "bottom" | "top-right" | "top-left" | "bottom-right" | "bottom-left";
|
|
5
5
|
status?: "success" | "error" | "warning" | "info" | "loading";
|
|
6
|
+
/**
|
|
7
|
+
* Optional action buttons rendered under the message (Jira-style "View" /
|
|
8
|
+
* "Copy link" affordances). Receives the toast's own `onClose` so an action
|
|
9
|
+
* can dismiss the toast. Kept a render-prop so callers style buttons with
|
|
10
|
+
* their app theme; the Toaster only positions them.
|
|
11
|
+
*/
|
|
12
|
+
actions?: (onClose: () => void) => ReactNode;
|
|
6
13
|
};
|
|
7
14
|
export interface ToasterContextType {
|
|
8
15
|
showToast: (children: ToasterToastProps) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToasterProps.d.ts","sourceRoot":"","sources":["../../../src/Components/Toaster/ToasterProps.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,GAAG,OAAO,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC,GAAG;IAC7H,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAA;IACvF,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"ToasterProps.d.ts","sourceRoot":"","sources":["../../../src/Components/Toaster/ToasterProps.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,GAAG,OAAO,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC,GAAG;IAC7H,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAA;IACvF,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAA;IAC7D;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,SAAS,CAAA;CAC/C,CAAA;AAED,MAAM,WAAW,kBAAkB;IAC/B,SAAS,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,CAAA;CACnD;AAED,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,SAAS,CAAC;CACvB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ToolTipProps } from "./ToolTipProps";
|
|
2
|
+
/**
|
|
3
|
+
* A tooltip that only appears when its child text is actually truncated
|
|
4
|
+
* (ellipsis active) — no tooltip when the text fully fits. Thin sugar over
|
|
5
|
+
* `<ToolTip overflowOnly>`; use it wherever you clamp text with `noOfLines` /
|
|
6
|
+
* ellipsis and want the full text revealed only when it's cut off.
|
|
7
|
+
*
|
|
8
|
+
* The child must be the single element that clamps the text (e.g. a Chakra
|
|
9
|
+
* `Text` with `noOfLines`); its ref is managed internally. Works for both
|
|
10
|
+
* single-line and multi-line clamps.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <OverflowToolTip label={title}>
|
|
14
|
+
* <Text noOfLines={1}>{title}</Text>
|
|
15
|
+
* </OverflowToolTip>
|
|
16
|
+
*/
|
|
17
|
+
export default function OverflowToolTip(props: ToolTipProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=OverflowToolTip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OverflowToolTip.d.ts","sourceRoot":"","sources":["../../../src/Components/ToolTip/OverflowToolTip.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,KAAK,EAAE,YAAY,2CAE1D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = OverflowToolTip;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const ToolTip_1 = __importDefault(require("./ToolTip"));
|
|
9
|
+
/**
|
|
10
|
+
* A tooltip that only appears when its child text is actually truncated
|
|
11
|
+
* (ellipsis active) — no tooltip when the text fully fits. Thin sugar over
|
|
12
|
+
* `<ToolTip overflowOnly>`; use it wherever you clamp text with `noOfLines` /
|
|
13
|
+
* ellipsis and want the full text revealed only when it's cut off.
|
|
14
|
+
*
|
|
15
|
+
* The child must be the single element that clamps the text (e.g. a Chakra
|
|
16
|
+
* `Text` with `noOfLines`); its ref is managed internally. Works for both
|
|
17
|
+
* single-line and multi-line clamps.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <OverflowToolTip label={title}>
|
|
21
|
+
* <Text noOfLines={1}>{title}</Text>
|
|
22
|
+
* </OverflowToolTip>
|
|
23
|
+
*/
|
|
24
|
+
function OverflowToolTip(props) {
|
|
25
|
+
return (0, jsx_runtime_1.jsx)(ToolTip_1.default, { ...props, overflowOnly: true });
|
|
26
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ToolTipProps } from "./ToolTipProps";
|
|
2
|
-
export default function ToolTip({ placement, label, children, hasArrow, fontSize, bg, color, isDisabled, isOpen, defaultIsOpen, openDelay, closeDelay, arrowSize, closeOnClick, size, width, height, arrowPadding, arrowShadowColor, direction, gutter, onClose, modifiers, closeOnPointerDown, styles, }: ToolTipProps): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export default function ToolTip({ placement, label, children, hasArrow, fontSize, bg, color, isDisabled, overflowOnly, isOpen, defaultIsOpen, openDelay, closeDelay, arrowSize, closeOnClick, size, width, height, arrowPadding, arrowShadowColor, direction, gutter, onClose, modifiers, closeOnPointerDown, styles, }: ToolTipProps): import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
//# sourceMappingURL=ToolTip.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolTip.d.ts","sourceRoot":"","sources":["../../../src/Components/ToolTip/ToolTip.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ToolTip.d.ts","sourceRoot":"","sources":["../../../src/Components/ToolTip/ToolTip.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI9C,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAC9B,SAAiB,EACjB,KAAK,EACL,QAAQ,EACR,QAAe,EACf,QAAiB,EACjB,EAAc,EACd,KAAe,EACf,UAAU,EACV,YAAoB,EACpB,MAAM,EACN,aAAa,EACb,SAAa,EACb,UAAc,EACd,SAAc,EACd,YAAoB,EACpB,IAAI,EACJ,KAAK,EACL,MAAM,EACN,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,MAAU,EACV,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,MAAM,GACP,EAAE,YAAY,2CA4Dd"}
|
|
@@ -2,7 +2,25 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = ToolTip;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
-
const react_1 = require("
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const react_2 = require("@chakra-ui/react");
|
|
7
|
+
const useIsTruncated_1 = require("../../Hooks/useIsTruncated");
|
|
8
|
+
const mergeRefs_1 = require("../../Utils/mergeRefs");
|
|
9
|
+
function ToolTip({ placement = "top", label, children, hasArrow = true, fontSize = "14px", bg = "#12161B", color = "white", isDisabled, overflowOnly = false, isOpen, defaultIsOpen, openDelay = 0, closeDelay = 0, arrowSize = 10, closeOnClick = false, size, width, height, arrowPadding, arrowShadowColor, direction, gutter = 8, onClose, modifiers, closeOnPointerDown, styles, }) {
|
|
10
|
+
// Measure the child for `overflowOnly`. The hook is always called (Rules of
|
|
11
|
+
// Hooks) but is fully inert unless `overflowOnly` is set — no layout reads,
|
|
12
|
+
// no ResizeObserver, no re-renders for ordinary tooltips. Measurement never
|
|
13
|
+
// runs on hover/scroll, so showing the tooltip stays as cheap as before.
|
|
14
|
+
const { ref, isTruncated } = (0, useIsTruncated_1.useIsTruncated)(label, overflowOnly && (0, react_1.isValidElement)(children));
|
|
15
|
+
let content = children;
|
|
16
|
+
let effectiveDisabled = isDisabled;
|
|
17
|
+
if (overflowOnly && (0, react_1.isValidElement)(children)) {
|
|
18
|
+
const child = children;
|
|
19
|
+
const childRef = child.ref;
|
|
20
|
+
content = (0, react_1.cloneElement)(child, {
|
|
21
|
+
ref: (0, mergeRefs_1.mergeRefs)(ref, childRef),
|
|
22
|
+
});
|
|
23
|
+
effectiveDisabled = Boolean(isDisabled) || !isTruncated;
|
|
24
|
+
}
|
|
25
|
+
return ((0, jsx_runtime_1.jsx)(react_2.Tooltip, { label: label, placement: placement, hasArrow: hasArrow, fontSize: fontSize, bg: bg, color: color, isDisabled: effectiveDisabled, isOpen: isOpen, defaultIsOpen: defaultIsOpen, openDelay: openDelay, closeDelay: closeDelay, arrowSize: arrowSize, closeOnClick: closeOnClick, size: size, width: width, height: height, arrowPadding: arrowPadding, arrowShadowColor: arrowShadowColor, direction: direction, gutter: gutter, onClose: onClose, modifiers: modifiers, closeOnPointerDown: closeOnPointerDown, style: styles, px: 3, py: 2, borderRadius: "8px", fontWeight: "400", lineHeight: "1.5", maxW: "300px", children: content }));
|
|
8
26
|
}
|
|
@@ -2,6 +2,15 @@ import { TooltipProps as ChakraTooltip } from "@chakra-ui/react";
|
|
|
2
2
|
export type ToolTipProps = Pick<ChakraTooltip, "placement" | "label" | "hasArrow" | "fontSize" | "bg" | "color" | "isDisabled" | "isOpen" | "defaultIsOpen" | "openDelay" | "closeDelay" | "arrowSize" | "closeOnClick" | "size" | "width" | "height" | "arrowPadding" | "arrowShadowColor" | "direction" | "gutter" | "onClose" | "modifiers" | "closeOnPointerDown"> & {
|
|
3
3
|
children: React.ReactNode;
|
|
4
4
|
styles?: React.CSSProperties;
|
|
5
|
+
/**
|
|
6
|
+
* When `true`, the tooltip is shown **only** while its child is actually
|
|
7
|
+
* truncated (ellipsis active) — no tooltip when the text fully fits. The
|
|
8
|
+
* child must be the single element that clamps the text (e.g. a `Text` with
|
|
9
|
+
* `noOfLines` / `isTruncated`); its ref is managed internally. Combines with
|
|
10
|
+
* `isDisabled` (either disabling condition hides the tooltip). Works for both
|
|
11
|
+
* single-line and multi-line clamps.
|
|
12
|
+
*/
|
|
13
|
+
overflowOnly?: boolean;
|
|
5
14
|
placement?: "auto" | "auto-start" | "auto-end" | "top" | "top-start" | "top-end" | "right" | "right-start" | "right-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end";
|
|
6
15
|
};
|
|
7
16
|
//# sourceMappingURL=ToolTipProps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolTipProps.d.ts","sourceRoot":"","sources":["../../../src/Components/ToolTip/ToolTipProps.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,aAAa,EACX,WAAW,GACX,OAAO,GACP,UAAU,GACV,UAAU,GACV,IAAI,GACJ,OAAO,GACP,YAAY,GACZ,QAAQ,GACR,eAAe,GACf,WAAW,GACX,YAAY,GACZ,WAAW,GACX,cAAc,GACd,MAAM,GACN,OAAO,GACP,QAAQ,GACR,cAAc,GACd,kBAAkB,GAClB,WAAW,GACX,QAAQ,GACR,SAAS,GACT,WAAW,GACX,oBAAoB,CACvB,GAAG;IACF,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC7B,SAAS,CAAC,EACN,MAAM,GACN,YAAY,GACZ,UAAU,GACV,KAAK,GACL,WAAW,GACX,SAAS,GACT,OAAO,GACP,aAAa,GACb,WAAW,GACX,QAAQ,GACR,cAAc,GACd,YAAY,GACZ,MAAM,GACN,YAAY,GACZ,UAAU,CAAC;CAChB,CAAC"}
|
|
1
|
+
{"version":3,"file":"ToolTipProps.d.ts","sourceRoot":"","sources":["../../../src/Components/ToolTip/ToolTipProps.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,aAAa,EACX,WAAW,GACX,OAAO,GACP,UAAU,GACV,UAAU,GACV,IAAI,GACJ,OAAO,GACP,YAAY,GACZ,QAAQ,GACR,eAAe,GACf,WAAW,GACX,YAAY,GACZ,WAAW,GACX,cAAc,GACd,MAAM,GACN,OAAO,GACP,QAAQ,GACR,cAAc,GACd,kBAAkB,GAClB,WAAW,GACX,QAAQ,GACR,SAAS,GACT,WAAW,GACX,oBAAoB,CACvB,GAAG;IACF,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC7B;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EACN,MAAM,GACN,YAAY,GACZ,UAAU,GACV,KAAK,GACL,WAAW,GACX,SAAS,GACT,OAAO,GACP,aAAa,GACb,WAAW,GACX,QAAQ,GACR,cAAc,GACd,YAAY,GACZ,MAAM,GACN,YAAY,GACZ,UAAU,CAAC;CAChB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { WorkspaceTrayPreviewProps } from "./WorkspaceWindowProps";
|
|
2
|
+
/**
|
|
3
|
+
* Presentational, app-agnostic hover-preview for a "workspace tray" pill (or any
|
|
4
|
+
* trigger). Headless of any data: the consumer passes the trigger as `children`
|
|
5
|
+
* and the card body as `preview` (node or render-prop receiving `close()`), so
|
|
6
|
+
* this can preview a ticket, a doc, a chat — anything — with the same intent-safe
|
|
7
|
+
* hover behavior.
|
|
8
|
+
*
|
|
9
|
+
* Intent-safe hover (hover-bridge): hovering the trigger opens the card after a
|
|
10
|
+
* short delay (anti-flash); a shared open/close timer + small gap let the cursor
|
|
11
|
+
* travel trigger ⇄ card without the card closing; leaving both (with a grace
|
|
12
|
+
* delay) closes it; Escape dismisses. Fetch/render the preview lazily via
|
|
13
|
+
* `onOpenChange`.
|
|
14
|
+
*/
|
|
15
|
+
export default function WorkspaceTrayPreview({ children, preview, enabled, openDelayMs, closeDelayMs, placement, onOpenChange, width, testId, }: WorkspaceTrayPreviewProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=WorkspaceTrayPreview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkspaceTrayPreview.d.ts","sourceRoot":"","sources":["../../../src/Components/WorkspaceWindow/WorkspaceTrayPreview.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAcxE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,QAAQ,EACR,OAAO,EACP,OAAc,EACd,WAAiB,EACjB,YAAkB,EAClB,SAAqB,EACrB,YAAY,EACZ,KAAe,EACf,MAAiC,GAClC,EAAE,yBAAyB,2CAuG3B"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = WorkspaceTrayPreview;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const react_2 = require("@chakra-ui/react");
|
|
7
|
+
const PLACEMENT_STYLE = {
|
|
8
|
+
"top-end": { bottom: "100%", right: 0, marginBottom: "6px" },
|
|
9
|
+
"top-start": { bottom: "100%", left: 0, marginBottom: "6px" },
|
|
10
|
+
"bottom-end": { top: "100%", right: 0, marginTop: "6px" },
|
|
11
|
+
"bottom-start": { top: "100%", left: 0, marginTop: "6px" },
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Presentational, app-agnostic hover-preview for a "workspace tray" pill (or any
|
|
15
|
+
* trigger). Headless of any data: the consumer passes the trigger as `children`
|
|
16
|
+
* and the card body as `preview` (node or render-prop receiving `close()`), so
|
|
17
|
+
* this can preview a ticket, a doc, a chat — anything — with the same intent-safe
|
|
18
|
+
* hover behavior.
|
|
19
|
+
*
|
|
20
|
+
* Intent-safe hover (hover-bridge): hovering the trigger opens the card after a
|
|
21
|
+
* short delay (anti-flash); a shared open/close timer + small gap let the cursor
|
|
22
|
+
* travel trigger ⇄ card without the card closing; leaving both (with a grace
|
|
23
|
+
* delay) closes it; Escape dismisses. Fetch/render the preview lazily via
|
|
24
|
+
* `onOpenChange`.
|
|
25
|
+
*/
|
|
26
|
+
function WorkspaceTrayPreview({ children, preview, enabled = true, openDelayMs = 350, closeDelayMs = 200, placement = "top-end", onOpenChange, width = "340px", testId = "workspace-tray-preview", }) {
|
|
27
|
+
const [open, setOpen] = (0, react_1.useState)(false);
|
|
28
|
+
const openTimer = (0, react_1.useRef)(null);
|
|
29
|
+
const closeTimer = (0, react_1.useRef)(null);
|
|
30
|
+
const setOpenState = (0, react_1.useCallback)((next) => {
|
|
31
|
+
setOpen(next);
|
|
32
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(next);
|
|
33
|
+
}, [onOpenChange]);
|
|
34
|
+
const clearOpenTimer = (0, react_1.useCallback)(() => {
|
|
35
|
+
if (openTimer.current) {
|
|
36
|
+
clearTimeout(openTimer.current);
|
|
37
|
+
openTimer.current = null;
|
|
38
|
+
}
|
|
39
|
+
}, []);
|
|
40
|
+
const clearCloseTimer = (0, react_1.useCallback)(() => {
|
|
41
|
+
if (closeTimer.current) {
|
|
42
|
+
clearTimeout(closeTimer.current);
|
|
43
|
+
closeTimer.current = null;
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
const scheduleOpen = (0, react_1.useCallback)(() => {
|
|
47
|
+
if (!enabled)
|
|
48
|
+
return;
|
|
49
|
+
clearCloseTimer();
|
|
50
|
+
if (open || openTimer.current)
|
|
51
|
+
return;
|
|
52
|
+
openTimer.current = setTimeout(() => {
|
|
53
|
+
openTimer.current = null;
|
|
54
|
+
setOpenState(true);
|
|
55
|
+
}, openDelayMs);
|
|
56
|
+
}, [enabled, clearCloseTimer, open, openDelayMs, setOpenState]);
|
|
57
|
+
const scheduleClose = (0, react_1.useCallback)(() => {
|
|
58
|
+
clearOpenTimer();
|
|
59
|
+
if (closeTimer.current)
|
|
60
|
+
return;
|
|
61
|
+
closeTimer.current = setTimeout(() => {
|
|
62
|
+
closeTimer.current = null;
|
|
63
|
+
setOpenState(false);
|
|
64
|
+
}, closeDelayMs);
|
|
65
|
+
}, [clearOpenTimer, closeDelayMs, setOpenState]);
|
|
66
|
+
const closeNow = (0, react_1.useCallback)(() => {
|
|
67
|
+
clearOpenTimer();
|
|
68
|
+
clearCloseTimer();
|
|
69
|
+
setOpenState(false);
|
|
70
|
+
}, [clearOpenTimer, clearCloseTimer, setOpenState]);
|
|
71
|
+
(0, react_1.useEffect)(() => () => {
|
|
72
|
+
clearOpenTimer();
|
|
73
|
+
clearCloseTimer();
|
|
74
|
+
}, [clearOpenTimer, clearCloseTimer]);
|
|
75
|
+
return ((0, jsx_runtime_1.jsxs)(react_2.Box, { position: "relative", onMouseEnter: scheduleOpen, onMouseLeave: scheduleClose, onFocus: scheduleOpen, onBlur: scheduleClose, onKeyDown: (e) => {
|
|
76
|
+
if (e.key === "Escape" && open) {
|
|
77
|
+
e.stopPropagation();
|
|
78
|
+
closeNow();
|
|
79
|
+
}
|
|
80
|
+
}, children: [children, open && ((0, jsx_runtime_1.jsx)(react_2.Box, { position: "absolute", ...PLACEMENT_STYLE[placement], w: typeof width === "number" ? `${width}px` : width, maxW: "min(360px, calc(100vw - 2rem))", bg: "white", borderWidth: "1px", borderColor: "gray.200", borderRadius: "lg", boxShadow: "xl", zIndex: 1500, pointerEvents: "auto", p: 3, textAlign: "left", color: "gray.800", cursor: "default", onMouseEnter: clearCloseTimer, onMouseLeave: scheduleClose, "data-testid": testId, children: typeof preview === "function"
|
|
81
|
+
? preview({ close: closeNow })
|
|
82
|
+
: preview }))] }));
|
|
83
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { WorkspaceTrayProps, WorkspaceWindowProps } from "./WorkspaceWindowProps";
|
|
2
|
+
/**
|
|
3
|
+
* Presentational floating "workspace window" — a Jira-style dialog with
|
|
4
|
+
* minimize / close controls and an optional "open full page" affordance, at a
|
|
5
|
+
* single fixed size (no maximize/restore toggle). Headless of any state
|
|
6
|
+
* management: the parent owns the window state and passes callbacks. Render
|
|
7
|
+
* minimized windows with the companion WorkspaceTray.
|
|
8
|
+
*/
|
|
9
|
+
export default function WorkspaceWindow({ title, state, children, onMinimize, onClose, onOpenFullPage, headerActions, testId, }: WorkspaceWindowProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
/**
|
|
11
|
+
* Bottom tray of restore pills for minimized WorkspaceWindows. Presentational —
|
|
12
|
+
* the parent supplies the minimized items and restore/close handlers.
|
|
13
|
+
*/
|
|
14
|
+
export declare function WorkspaceTray({ items, onRestore, onClose, testId, }: WorkspaceTrayProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
|
+
//# sourceMappingURL=WorkspaceWindow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkspaceWindow.d.ts","sourceRoot":"","sources":["../../../src/Components/WorkspaceWindow/WorkspaceWindow.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAOhC;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,KAAK,EACL,KAAK,EACL,QAAQ,EACR,UAAU,EACV,OAAO,EACP,cAAc,EACd,aAAa,EACb,MAA2B,GAC5B,EAAE,oBAAoB,kDAqGtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,SAAS,EACT,OAAO,EACP,MAAyB,GAC1B,EAAE,kBAAkB,kDAkEpB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = WorkspaceWindow;
|
|
4
|
+
exports.WorkspaceTray = WorkspaceTray;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const react_1 = require("@chakra-ui/react");
|
|
7
|
+
const lucide_react_1 = require("lucide-react");
|
|
8
|
+
// One in-between windowed size — wider than a cramped dialog but not near-full
|
|
9
|
+
// screen. There is no maximize/restore toggle (removed by product decision); the
|
|
10
|
+
// `onMedium`/`onMaximize` props are kept optional for back-compat but unused.
|
|
11
|
+
const WINDOW_SIZE = { maxW: "88rem", h: "92vh" };
|
|
12
|
+
/**
|
|
13
|
+
* Presentational floating "workspace window" — a Jira-style dialog with
|
|
14
|
+
* minimize / close controls and an optional "open full page" affordance, at a
|
|
15
|
+
* single fixed size (no maximize/restore toggle). Headless of any state
|
|
16
|
+
* management: the parent owns the window state and passes callbacks. Render
|
|
17
|
+
* minimized windows with the companion WorkspaceTray.
|
|
18
|
+
*/
|
|
19
|
+
function WorkspaceWindow({ title, state, children, onMinimize, onClose, onOpenFullPage, headerActions, testId = "workspace-window", }) {
|
|
20
|
+
if (state === "minimized")
|
|
21
|
+
return null;
|
|
22
|
+
const size = WINDOW_SIZE;
|
|
23
|
+
return ((0, jsx_runtime_1.jsxs)(react_1.Modal, { isOpen: true, onClose: () => onClose === null || onClose === void 0 ? void 0 : onClose(), size: "full", isCentered: true, scrollBehavior: "inside",
|
|
24
|
+
// Don't discard unsaved work on an accidental overlay click / Esc — the
|
|
25
|
+
// parent decides via the explicit Close control.
|
|
26
|
+
closeOnOverlayClick: false, closeOnEsc: false, children: [(0, jsx_runtime_1.jsx)(react_1.ModalOverlay, { backdropFilter: "blur(3px)" }), (0, jsx_runtime_1.jsx)(react_1.ModalContent, { bg: "transparent", boxShadow: "none", m: 0, display: "flex", alignItems: "center", justifyContent: "center", children: (0, jsx_runtime_1.jsxs)(react_1.Box, { bg: "white", borderRadius: "0.75rem", boxShadow: "2xl", overflow: "hidden", w: "100%", maxW: size.maxW, h: size.h, display: "flex", flexDirection: "column", "data-testid": testId, "data-window-state": state, children: [(0, jsx_runtime_1.jsxs)(react_1.Flex, { align: "center", justify: "space-between", px: 3, py: 2, borderBottomWidth: "1px", borderColor: "gray.100", bg: "gray.50", flexShrink: 0, children: [(0, jsx_runtime_1.jsx)(react_1.Text, { fontSize: "sm", fontWeight: 600, color: "gray.700", noOfLines: 1, "data-testid": `${testId}-title`, children: title }), (0, jsx_runtime_1.jsxs)(react_1.HStack, { spacing: 1, children: [headerActions, onOpenFullPage ? ((0, jsx_runtime_1.jsx)(react_1.IconButton, { "aria-label": "Open full page", size: "xs", variant: "ghost", icon: (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { size: 14 }), onClick: onOpenFullPage, "data-testid": `${testId}-fullpage` })) : null, onMinimize ? ((0, jsx_runtime_1.jsx)(react_1.IconButton, { "aria-label": "Minimize", size: "xs", variant: "ghost", icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Minus, { size: 15 }), onClick: onMinimize, "data-testid": `${testId}-minimize` })) : null, onClose ? ((0, jsx_runtime_1.jsx)(react_1.IconButton, { "aria-label": "Close", size: "xs", variant: "ghost", colorScheme: "red", icon: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15 }), onClick: onClose, "data-testid": `${testId}-close` })) : null] })] }), (0, jsx_runtime_1.jsx)(react_1.Box, { flex: "1", overflow: "auto", px: { base: 3, md: 5 }, py: 4, children: children })] }) })] }));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Bottom tray of restore pills for minimized WorkspaceWindows. Presentational —
|
|
30
|
+
* the parent supplies the minimized items and restore/close handlers.
|
|
31
|
+
*/
|
|
32
|
+
function WorkspaceTray({ items, onRestore, onClose, testId = "workspace-tray", }) {
|
|
33
|
+
if (!items.length)
|
|
34
|
+
return null;
|
|
35
|
+
return (
|
|
36
|
+
// Floating bottom-right cluster (Gmail/Jira minimized-window pattern) rather
|
|
37
|
+
// than a full-width docked bar, so it never covers the bottom strip of page
|
|
38
|
+
// content and needs no reserved page gutter. Pills wrap upward.
|
|
39
|
+
(0, jsx_runtime_1.jsx)(react_1.Flex, { position: "fixed", bottom: 4, right: 4, zIndex: 1400, direction: "row-reverse", wrap: "wrap-reverse", justify: "flex-start", gap: 2, maxW: { base: "calc(100vw - 2rem)", md: "36rem" }, "data-testid": testId, children: items.map((item) => ((0, jsx_runtime_1.jsxs)(react_1.HStack, { spacing: 1, pl: 3, pr: 1, py: 1, borderRadius: "full", bg: "blue.100", color: "blue.700", boxShadow: "md", borderWidth: "1px", borderColor: "blue.200", "data-testid": `${testId}-pill`, children: [(0, jsx_runtime_1.jsx)(react_1.Box, { as: "button", type: "button", fontSize: "sm", onClick: () => onRestore === null || onRestore === void 0 ? void 0 : onRestore(item.id), "data-testid": `${testId}-restore`, maxW: "16rem", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: item.title }), onClose ? ((0, jsx_runtime_1.jsx)(react_1.IconButton, { "aria-label": "Close", size: "xs", variant: "ghost", borderRadius: "full", minW: "auto", h: "auto", p: 1, color: "inherit", icon: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 13 }), onClick: () => onClose(item.id), "data-testid": `${testId}-close` })) : null] }, item.id))) }));
|
|
40
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Window state for a WorkspaceWindow.
|
|
4
|
+
* - "medium": default centered dialog (Jira-style)
|
|
5
|
+
* - "maximized": near-full-screen
|
|
6
|
+
* - "minimized": collapsed to a tray pill (rendered by WorkspaceTray, not the window)
|
|
7
|
+
*/
|
|
8
|
+
export type WorkspaceWindowState = "medium" | "maximized" | "minimized";
|
|
9
|
+
export interface WorkspaceWindowProps {
|
|
10
|
+
/** Title shown in the window's control bar. */
|
|
11
|
+
title: ReactNode;
|
|
12
|
+
/** Current window state. When "minimized", the window renders nothing. */
|
|
13
|
+
state: WorkspaceWindowState;
|
|
14
|
+
/** Window body. */
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
onMinimize?: () => void;
|
|
17
|
+
onMedium?: () => void;
|
|
18
|
+
onMaximize?: () => void;
|
|
19
|
+
onClose?: () => void;
|
|
20
|
+
/** Optional "pop out to full page" affordance; hidden when omitted. */
|
|
21
|
+
onOpenFullPage?: () => void;
|
|
22
|
+
/** Extra controls rendered in the control bar, left of the window buttons. */
|
|
23
|
+
headerActions?: ReactNode;
|
|
24
|
+
/** data-testid for the window container. */
|
|
25
|
+
testId?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface WorkspaceTrayItem {
|
|
28
|
+
id: string;
|
|
29
|
+
title: ReactNode;
|
|
30
|
+
}
|
|
31
|
+
export interface WorkspaceTrayProps {
|
|
32
|
+
/** Minimized items rendered as restore pills along the bottom. */
|
|
33
|
+
items: WorkspaceTrayItem[];
|
|
34
|
+
onRestore?: (id: string) => void;
|
|
35
|
+
onClose?: (id: string) => void;
|
|
36
|
+
testId?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface WorkspaceTrayPreviewProps {
|
|
39
|
+
/**
|
|
40
|
+
* The trigger markup (typically a tray pill). The preview + trigger share one
|
|
41
|
+
* open/close timer so the cursor can travel pill ⇄ preview without the card
|
|
42
|
+
* closing (hover-bridge pattern).
|
|
43
|
+
*/
|
|
44
|
+
children: ReactNode;
|
|
45
|
+
/**
|
|
46
|
+
* The preview body, rendered inside the floating card. Headless: the consumer
|
|
47
|
+
* supplies whatever it wants to show (ticket summary, chips, actions, etc.).
|
|
48
|
+
* A render-prop form receives the card's own `close()` so an action inside
|
|
49
|
+
* the preview can dismiss it.
|
|
50
|
+
*/
|
|
51
|
+
preview: ReactNode | ((api: {
|
|
52
|
+
close: () => void;
|
|
53
|
+
}) => ReactNode);
|
|
54
|
+
/** Whether the preview is enabled at all (e.g. disable on touch devices). */
|
|
55
|
+
enabled?: boolean;
|
|
56
|
+
/** ms before the card opens on hover/focus (anti-flash). Default 350. */
|
|
57
|
+
openDelayMs?: number;
|
|
58
|
+
/** ms grace before the card closes on leave (bridge). Default 200. */
|
|
59
|
+
closeDelayMs?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Where the card opens relative to the trigger. Default "top-end" (above,
|
|
62
|
+
* right-aligned) — matches a bottom-right tray.
|
|
63
|
+
*/
|
|
64
|
+
placement?: "top-start" | "top-end" | "bottom-start" | "bottom-end";
|
|
65
|
+
/** Fires when the card actually opens — use to lazy-load the preview data. */
|
|
66
|
+
onOpenChange?: (open: boolean) => void;
|
|
67
|
+
/** Card width. Default 340px, capped to the viewport on small screens. */
|
|
68
|
+
width?: string | number;
|
|
69
|
+
/** data-testid for the floating card. */
|
|
70
|
+
testId?: string;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=WorkspaceWindowProps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkspaceWindowProps.d.ts","sourceRoot":"","sources":["../../../src/Components/WorkspaceWindow/WorkspaceWindowProps.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AAExE,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,KAAK,EAAE,SAAS,CAAC;IACjB,0EAA0E;IAC1E,KAAK,EAAE,oBAAoB,CAAC;IAC5B,mBAAmB;IACnB,QAAQ,EAAE,SAAS,CAAC;IAEpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B,8EAA8E;IAC9E,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;;OAKG;IACH,OAAO,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,SAAS,CAAC,CAAC;IACjE,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,cAAc,GAAG,YAAY,CAAC;IACpE,8EAA8E;IAC9E,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detects whether an element's text is *actually* visually truncated — i.e. the
|
|
3
|
+
* ellipsis is active. Works for both single-line clamps
|
|
4
|
+
* (`overflow: hidden; white-space: nowrap; text-overflow: ellipsis`) and
|
|
5
|
+
* multi-line clamps (`-webkit-line-clamp` / Chakra `noOfLines`), by comparing
|
|
6
|
+
* the scroll size against the visible client size.
|
|
7
|
+
*
|
|
8
|
+
* Attach the returned `ref` to the element that clamps the text, then read
|
|
9
|
+
* `isTruncated` to decide whether a tooltip is worth showing. Re-measures on
|
|
10
|
+
* element resize (via `ResizeObserver`) and whenever `content` changes.
|
|
11
|
+
*
|
|
12
|
+
* @param content Pass the rendered text (or anything that changes with it) so
|
|
13
|
+
* the measurement re-runs when the content changes — the clamp box can keep
|
|
14
|
+
* the same size while the text length changes, which a `ResizeObserver` alone
|
|
15
|
+
* would not catch.
|
|
16
|
+
* @param enabled Set to `false` to fully disable measurement — no layout reads,
|
|
17
|
+
* no `ResizeObserver`, no state updates. Use it to keep the hook cheap when
|
|
18
|
+
* the caller isn't in truncation mode (`isTruncated` stays `false`).
|
|
19
|
+
*
|
|
20
|
+
* Performance: measurement runs only on mount, on element **resize**, and when
|
|
21
|
+
* `content` changes — never on hover, scroll, or re-render. Each run does a
|
|
22
|
+
* single batched layout read (four properties) on one element. When `enabled`
|
|
23
|
+
* is `false` the hook does nothing at all.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const { ref, isTruncated } = useIsTruncated(title);
|
|
27
|
+
* <ToolTip label={title} isDisabled={!isTruncated}>
|
|
28
|
+
* <Text ref={ref} noOfLines={1}>{title}</Text>
|
|
29
|
+
* </ToolTip>
|
|
30
|
+
*/
|
|
31
|
+
export declare function useIsTruncated<T extends HTMLElement = HTMLElement>(content?: unknown, enabled?: boolean): {
|
|
32
|
+
ref: React.MutableRefObject<T | null>;
|
|
33
|
+
isTruncated: boolean;
|
|
34
|
+
};
|
|
35
|
+
export default useIsTruncated;
|
|
36
|
+
//# sourceMappingURL=useIsTruncated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIsTruncated.d.ts","sourceRoot":"","sources":["../../src/Hooks/useIsTruncated.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAChE,OAAO,CAAC,EAAE,OAAO,EACjB,OAAO,GAAE,OAAc,GACtB;IAAE,GAAG,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAuBjE;AAED,eAAe,cAAc,CAAC"}
|