pixelize-design-library 2.4.2-beta.63 → 2.4.2-beta.65
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/CHANGELOG.md +130 -8
- package/COMPONENT-GOTCHAS.md +63 -7
- package/DESIGN-GUIDE.md +8 -3
- package/dist/Components/Button/Button.styles.js +7 -2
- package/dist/Components/CopyButton/CopyButton.d.ts +3 -1
- package/dist/Components/CopyButton/CopyButton.js +2 -2
- package/dist/Components/Drawer/Drawer.d.ts +1 -1
- package/dist/Components/Drawer/Drawer.js +6 -2
- package/dist/Components/Drawer/DrawerProps.d.ts +4 -0
- package/dist/Components/Dropdown/DropDown.js +2 -9
- package/dist/Components/FilePreview/FilePreview.js +2 -1
- package/dist/Components/FileUploader/FileUploader.js +4 -0
- package/dist/Components/FileUploader/FileUploaderProps.d.ts +1 -1
- package/dist/Components/FormDrawer/FormDrawer.d.ts +1 -1
- package/dist/Components/FormDrawer/FormDrawer.js +3 -3
- package/dist/Components/FormDrawer/FormDrawerProps.d.ts +2 -0
- package/dist/Components/Input/TextInput.styles.js +10 -6
- package/dist/Components/KanbanBoard/KanbanBoard.js +6 -5
- package/dist/Components/Modal/dialogNaming.d.ts +8 -0
- package/dist/Components/Modal/dialogNaming.js +21 -0
- package/dist/Components/NavLauncher/LauncherTabs.js +2 -2
- package/dist/Components/NavLauncher/NavLauncher.d.ts +1 -1
- package/dist/Components/NavLauncher/NavLauncher.js +257 -47
- package/dist/Components/NavLauncher/NavLauncherProps.d.ts +79 -3
- package/dist/Components/NavLauncher/ScopeBar.d.ts +14 -0
- package/dist/Components/NavLauncher/ScopeBar.js +137 -0
- package/dist/Components/NavLauncher/engine/distance.d.ts +4 -0
- package/dist/Components/NavLauncher/engine/distance.js +41 -0
- package/dist/Components/NavLauncher/engine/engine.d.ts +84 -0
- package/dist/Components/NavLauncher/engine/engine.js +471 -0
- package/dist/Components/NavLauncher/engine/fold.d.ts +15 -0
- package/dist/Components/NavLauncher/engine/fold.js +83 -0
- package/dist/Components/NavLauncher/engine/index.d.ts +21 -0
- package/dist/Components/NavLauncher/engine/index.js +17 -0
- package/dist/Components/NavLauncher/launcherParts.d.ts +2 -0
- package/dist/Components/NavLauncher/launcherParts.js +11 -7
- package/dist/Components/NavLauncher/match.d.ts +13 -2
- package/dist/Components/NavLauncher/match.js +26 -12
- package/dist/Components/NavLauncher/searchLayout.d.ts +60 -0
- package/dist/Components/NavLauncher/searchLayout.js +108 -0
- package/dist/Components/NavLauncher/spotlight.d.ts +39 -0
- package/dist/Components/NavLauncher/spotlight.js +202 -0
- package/dist/Components/NavLauncher/spotlightParts.d.ts +49 -0
- package/dist/Components/NavLauncher/spotlightParts.js +108 -0
- package/dist/Components/NavigationBar/NavigationBar.js +2 -1
- package/dist/Components/OrgSwitcher/OrgSwitcher.js +2 -4
- package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +6 -5
- package/dist/Components/ScrollToTop/ScrollToTop.js +4 -3
- package/dist/Components/SearchSelect/SearchSelect.js +4 -16
- package/dist/Components/Select/SelectPopup.js +1 -3
- package/dist/Components/Select/optionRowInk.d.ts +12 -0
- package/dist/Components/Select/optionRowInk.js +10 -1
- package/dist/Components/SelectSearch/SelectSearch.js +1 -10
- package/dist/Components/Table/Table.js +3 -2
- package/dist/Components/Table/TableProps.d.ts +1 -1
- package/dist/Components/Table/components/TableBody.js +9 -1
- package/dist/Components/Table/components/TableHeader.js +9 -2
- package/dist/Components/Table/components/TableLoading.d.ts +4 -1
- package/dist/Components/Table/components/TableLoading.js +13 -6
- package/dist/Components/Table/filters/CompactSelect.js +1 -10
- package/dist/Components/Table/variants/TableVariantContext.d.ts +1 -1
- package/dist/Components/Table/variants/TableVariantContext.js +3 -3
- package/dist/Components/WizardDialog/WizardDialog.d.ts +1 -1
- package/dist/Components/WizardDialog/WizardDialog.js +15 -3
- package/dist/Components/WizardDialog/WizardDialogProps.d.ts +5 -3
- package/dist/Components/WorkspaceWindow/WorkspaceTrayPreview.js +4 -0
- package/dist/Components/WorkspaceWindow/WorkspaceWindow.d.ts +2 -2
- package/dist/Components/WorkspaceWindow/WorkspaceWindow.js +26 -18
- package/dist/Components/WorkspaceWindow/WorkspaceWindowProps.d.ts +38 -8
- package/dist/Theme/chakra/Menu.styles.d.ts +8 -0
- package/dist/Theme/chakra/Menu.styles.js +7 -0
- package/dist/Theme/chakra/componentStyles.d.ts +8 -0
- package/dist/Theme/chakra/componentStyles.js +2 -2
- package/dist/Theme/chakra/ringShadow.d.ts +3 -0
- package/dist/Theme/chakra/ringShadow.js +7 -0
- package/dist/Theme/tokens/builders/accentText.d.ts +2 -0
- package/dist/Theme/tokens/builders/accentText.js +7 -1
- package/dist/Theme/tokens/builders/buildDarkPalette.d.ts +1 -1
- package/dist/Theme/tokens/builders/buildDarkPalette.js +5 -5
- package/dist/Theme/tokens/builders/filledSurface.d.ts +5 -1
- package/dist/Theme/tokens/builders/filledSurface.js +17 -4
- package/dist/Theme/tokens/builders/planeStep.d.ts +1 -0
- package/dist/Theme/tokens/builders/planeStep.js +5 -4
- package/dist/Utils/table.js +2 -2
- package/dist/esm/Components/Button/Button.styles.js +8 -3
- package/dist/esm/Components/CopyButton/CopyButton.js +2 -2
- package/dist/esm/Components/Drawer/Drawer.js +6 -2
- package/dist/esm/Components/Dropdown/DropDown.js +2 -9
- package/dist/esm/Components/FilePreview/FilePreview.js +3 -2
- package/dist/esm/Components/FileUploader/FileUploader.js +4 -0
- package/dist/esm/Components/FormDrawer/FormDrawer.js +3 -3
- package/dist/esm/Components/Input/TextInput.styles.js +10 -6
- package/dist/esm/Components/KanbanBoard/KanbanBoard.js +6 -5
- package/dist/esm/Components/Modal/dialogNaming.js +18 -0
- package/dist/esm/Components/NavLauncher/LauncherTabs.js +2 -2
- package/dist/esm/Components/NavLauncher/NavLauncher.js +259 -49
- package/dist/esm/Components/NavLauncher/ScopeBar.js +134 -0
- package/dist/esm/Components/NavLauncher/engine/distance.js +37 -0
- package/dist/esm/Components/NavLauncher/engine/engine.js +458 -0
- package/dist/esm/Components/NavLauncher/engine/fold.js +74 -0
- package/dist/esm/Components/NavLauncher/engine/index.js +14 -0
- package/dist/esm/Components/NavLauncher/launcherParts.js +10 -6
- package/dist/esm/Components/NavLauncher/match.js +25 -12
- package/dist/esm/Components/NavLauncher/searchLayout.js +100 -0
- package/dist/esm/Components/NavLauncher/spotlight.js +194 -0
- package/dist/esm/Components/NavLauncher/spotlightParts.js +95 -0
- package/dist/esm/Components/NavigationBar/NavigationBar.js +2 -1
- package/dist/esm/Components/OrgSwitcher/OrgSwitcher.js +2 -4
- package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +7 -6
- package/dist/esm/Components/ScrollToTop/ScrollToTop.js +5 -4
- package/dist/esm/Components/SearchSelect/SearchSelect.js +6 -18
- package/dist/esm/Components/Select/SelectPopup.js +2 -4
- package/dist/esm/Components/Select/optionRowInk.js +7 -0
- package/dist/esm/Components/SelectSearch/SelectSearch.js +2 -11
- package/dist/esm/Components/Table/Table.js +4 -3
- package/dist/esm/Components/Table/components/TableBody.js +10 -2
- package/dist/esm/Components/Table/components/TableHeader.js +10 -3
- package/dist/esm/Components/Table/components/TableLoading.js +10 -6
- package/dist/esm/Components/Table/filters/CompactSelect.js +2 -11
- package/dist/esm/Components/Table/variants/TableVariantContext.js +3 -3
- package/dist/esm/Components/WizardDialog/WizardDialog.js +15 -3
- package/dist/esm/Components/WorkspaceWindow/WorkspaceTrayPreview.js +4 -0
- package/dist/esm/Components/WorkspaceWindow/WorkspaceWindow.js +28 -20
- package/dist/esm/Theme/chakra/Menu.styles.js +7 -0
- package/dist/esm/Theme/chakra/componentStyles.js +2 -2
- package/dist/esm/Theme/chakra/ringShadow.js +3 -0
- package/dist/esm/Theme/tokens/builders/accentText.js +5 -0
- package/dist/esm/Theme/tokens/builders/buildDarkPalette.js +5 -5
- package/dist/esm/Theme/tokens/builders/filledSurface.js +18 -5
- package/dist/esm/Theme/tokens/builders/planeStep.js +3 -3
- package/dist/esm/Utils/table.js +2 -2
- package/dist/esm/index.js +6 -5
- package/dist/index.d.ts +10 -8
- package/dist/index.js +14 -6
- package/package.json +1 -1
|
@@ -5,13 +5,13 @@ exports.useTableVariant = useTableVariant;
|
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
|
|
7
7
|
const accentText_1 = require("../../../Theme/tokens/builders/accentText");
|
|
8
|
-
const
|
|
8
|
+
const studio_1 = require("./studio");
|
|
9
9
|
const TableVariantContext = (0, react_1.createContext)(null);
|
|
10
10
|
exports.TableVariantProvider = TableVariantContext.Provider;
|
|
11
|
-
/** No provider means the
|
|
11
|
+
/** No provider means the default variant — studio, the same preset `Table` falls back to. */
|
|
12
12
|
function useTableVariant() {
|
|
13
13
|
const provided = (0, react_1.useContext)(TableVariantContext);
|
|
14
14
|
const theme = (0, useCustomTheme_1.useCustomTheme)();
|
|
15
15
|
const isDark = (0, accentText_1.isDarkCanvas)(theme.colors.backgroundColor.main);
|
|
16
|
-
return (0, react_1.useMemo)(() => provided !== null && provided !== void 0 ? provided : (0,
|
|
16
|
+
return (0, react_1.useMemo)(() => provided !== null && provided !== void 0 ? provided : (0, studio_1.studioPreset)(theme.colors, isDark), [provided, theme.colors, isDark]);
|
|
17
17
|
}
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import type { WizardDialogProps, WizardProps } from "./WizardDialogProps";
|
|
3
3
|
export { wizardTransition, firstInvalidStep, INITIAL_WIZARD_STATE } from "./wizardSteps";
|
|
4
4
|
export type { WizardAction, WizardState, StepValidator } from "./wizardSteps";
|
|
5
|
-
/**
|
|
5
|
+
/** Wizard that owns step state: validated Continue, locked future steps, error summary, review on the last step. A Modal by default; `chrome="inline"` draws it in place. */
|
|
6
6
|
export declare const WizardDialog: React.FC<WizardDialogProps>;
|
|
7
7
|
/** The same wizard inline, for a full-page flow rather than a modal. */
|
|
8
8
|
export declare const Wizard: React.FC<WizardProps>;
|
|
@@ -41,6 +41,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
41
41
|
const react_1 = require("react");
|
|
42
42
|
const react_2 = require("@chakra-ui/react");
|
|
43
43
|
const useCustomTheme_1 = require("../../Theme/useCustomTheme");
|
|
44
|
+
const surfaceRaised_1 = require("../../Theme/tokens/builders/surfaceRaised");
|
|
44
45
|
const Modal_1 = __importStar(require("../Modal/Modal"));
|
|
45
46
|
const Button_1 = __importDefault(require("../Button/Button"));
|
|
46
47
|
const StageProgress_1 = __importDefault(require("../StageProgress/StageProgress"));
|
|
@@ -86,15 +87,26 @@ const WizardFooter = ({ flow, labels, isFinishing, finishDisabled, finishBlocked
|
|
|
86
87
|
const reason = finishDisabled && !isFinishing ? finishBlockedReason : undefined;
|
|
87
88
|
return ((0, jsx_runtime_1.jsxs)(react_2.Flex, { w: "100%", justify: "space-between", gap: 2, wrap: "wrap", children: [onCancel ? ((0, jsx_runtime_1.jsx)(Button_1.default, { variant: "ghost", colorScheme: "gray", label: labels.cancel, onClick: onCancel, isDisabled: isFinishing, "data-testid": "wizard-cancel" })) : ((0, jsx_runtime_1.jsx)("span", {})), (0, jsx_runtime_1.jsxs)(react_2.Flex, { gap: 2, align: reason ? "center" : undefined, children: [!flow.isFirst ? ((0, jsx_runtime_1.jsx)(Button_1.default, { variant: "outline", colorScheme: "gray", label: labels.back, onClick: flow.back, isDisabled: isFinishing, "data-testid": "wizard-back" })) : null, flow.isLast && reason ? ((0, jsx_runtime_1.jsx)(react_2.Text, { id: reasonId, fontSize: "xs", color: colors.textMuted, "data-testid": "wizard-finish-reason", children: reason })) : null, flow.isLast ? ((0, jsx_runtime_1.jsx)(Button_1.default, { variant: "solid", colorScheme: "primary", label: labels.finish, onClick: flow.finish, isLoading: isFinishing, isDisabled: finishDisabled, "aria-describedby": reason ? reasonId : undefined, loadingText: labels.finish, "data-testid": "wizard-finish" })) : ((0, jsx_runtime_1.jsx)(Button_1.default, { variant: "solid", colorScheme: "primary", label: labels.next, onClick: flow.next, "data-testid": "wizard-next" }))] })] }));
|
|
88
89
|
};
|
|
89
|
-
|
|
90
|
-
const
|
|
90
|
+
const WizardInlineFrame = ({ title, subtitle, testId, footer, children }) => {
|
|
91
|
+
const { colors } = (0, useCustomTheme_1.useCustomTheme)();
|
|
92
|
+
return ((0, jsx_runtime_1.jsxs)(react_2.Flex, { direction: "column", gap: 4, "data-testid": testId, children: [(0, jsx_runtime_1.jsxs)(react_2.Box, { children: [(0, jsx_runtime_1.jsx)(react_2.Heading, { as: "h2", fontSize: "md", fontWeight: 600, color: colors.header[900], children: title }), subtitle ? ((0, jsx_runtime_1.jsx)(react_2.Text, { mt: 0.5, fontSize: "sm", color: colors.textMuted, children: subtitle })) : null] }), children, (0, jsx_runtime_1.jsx)(react_2.Box, { position: "sticky", bottom: 0, pt: 3, borderTopWidth: "1px", borderColor: (0, surfaceRaised_1.raisedRule)(colors), bg: colors.surfaceRaised, children: footer })] }));
|
|
93
|
+
};
|
|
94
|
+
/** Wizard that owns step state: validated Continue, locked future steps, error summary, review on the last step. A Modal by default; `chrome="inline"` draws it in place. */
|
|
95
|
+
const WizardDialog = ({ isOpen, onClose, title, subtitle, steps, onFinish, isFinishing = false, finishDisabled = false, finishBlockedReason, stepId, onStepChange, size = "3xl", chrome = "modal", labels, "data-testid": testId, }) => {
|
|
91
96
|
const flow = (0, useWizardFlow_1.useWizardFlow)({ steps, stepId, onStepChange, onFinish, resetWhen: !isOpen });
|
|
92
97
|
const resolved = { ...DEFAULT_LABELS, ...labels };
|
|
93
98
|
const guardedClose = () => {
|
|
94
99
|
if (!isFinishing)
|
|
95
100
|
onClose();
|
|
96
101
|
};
|
|
97
|
-
|
|
102
|
+
const body = ((0, jsx_runtime_1.jsx)(WizardBody, { flow: flow, steps: steps, labels: resolved, testId: testId !== null && testId !== void 0 ? testId : "wizard-dialog" }));
|
|
103
|
+
const footer = ((0, jsx_runtime_1.jsx)(WizardFooter, { flow: flow, labels: resolved, isFinishing: isFinishing, finishDisabled: finishDisabled, finishBlockedReason: finishBlockedReason, onCancel: guardedClose }));
|
|
104
|
+
if (chrome === "inline") {
|
|
105
|
+
if (!isOpen)
|
|
106
|
+
return null;
|
|
107
|
+
return ((0, jsx_runtime_1.jsx)(WizardInlineFrame, { title: title, subtitle: subtitle, testId: testId ? `${testId}-inline` : "wizard-inline", footer: footer, children: body }));
|
|
108
|
+
}
|
|
109
|
+
return ((0, jsx_runtime_1.jsxs)(Modal_1.default, { isOpen: isOpen, onClose: guardedClose, size: size, isCentered: true, scrollBehavior: "inside", title: title, subtitle: subtitle, closeOnOverlayClick: false, closeOnEsc: !isFinishing, hideCloseButton: isFinishing, children: [(0, jsx_runtime_1.jsx)(Modal_1.ModalBody, { children: body }), (0, jsx_runtime_1.jsx)(Modal_1.ModalFooter, { children: footer })] }));
|
|
98
110
|
};
|
|
99
111
|
exports.WizardDialog = WizardDialog;
|
|
100
112
|
/** The same wizard inline, for a full-page flow rather than a modal. */
|
|
@@ -20,7 +20,7 @@ export type WizardLabels = Partial<{
|
|
|
20
20
|
fixErrors: string;
|
|
21
21
|
review: string;
|
|
22
22
|
}>;
|
|
23
|
-
/** Props for the
|
|
23
|
+
/** Props for the wizard dialog: Modal (or inline with `chrome`) + stepper + per-step validation + review on the last step. */
|
|
24
24
|
export interface WizardDialogProps {
|
|
25
25
|
isOpen: boolean;
|
|
26
26
|
/** Ignored while `isFinishing`. */
|
|
@@ -40,13 +40,15 @@ export interface WizardDialogProps {
|
|
|
40
40
|
stepId?: string;
|
|
41
41
|
/** Fires whenever the visible step changes, controlled or not. */
|
|
42
42
|
onStepChange?: (stepId: string) => void;
|
|
43
|
-
/** Modal width; default "3xl". */
|
|
43
|
+
/** Modal width; default "3xl". Ignored when `chrome` is "inline". */
|
|
44
44
|
size?: "lg" | "xl" | "2xl" | "3xl" | "4xl";
|
|
45
|
+
/** "inline" draws the wizard in place with no Modal (no overlay, focus trap, close X, Esc or dialog role) for a host that is already the dialog, such as a WorkspaceWindow; it renders nothing while closed and Cancel still calls `onClose`. Default "modal". */
|
|
46
|
+
chrome?: "modal" | "inline";
|
|
45
47
|
labels?: WizardLabels;
|
|
46
48
|
"data-testid"?: string;
|
|
47
49
|
}
|
|
48
50
|
/** Same flow inline (a page section, not a modal) — for full-page wizards. */
|
|
49
|
-
export interface WizardProps extends Omit<WizardDialogProps, "isOpen" | "onClose" | "title" | "subtitle" | "size"> {
|
|
51
|
+
export interface WizardProps extends Omit<WizardDialogProps, "isOpen" | "onClose" | "title" | "subtitle" | "size" | "chrome"> {
|
|
50
52
|
/** Renders a Cancel button in the footer when provided. */
|
|
51
53
|
onCancel?: () => void;
|
|
52
54
|
}
|
|
@@ -21,7 +21,11 @@ function WorkspaceTrayPreview({ children, preview, enabled = true, openDelayMs =
|
|
|
21
21
|
const [open, setOpen] = (0, react_1.useState)(false);
|
|
22
22
|
const openTimer = (0, react_1.useRef)(null);
|
|
23
23
|
const closeTimer = (0, react_1.useRef)(null);
|
|
24
|
+
const openRef = (0, react_1.useRef)(false);
|
|
24
25
|
const setOpenState = (0, react_1.useCallback)((next) => {
|
|
26
|
+
if (openRef.current === next)
|
|
27
|
+
return;
|
|
28
|
+
openRef.current = next;
|
|
25
29
|
setOpen(next);
|
|
26
30
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(next);
|
|
27
31
|
}, [onOpenChange]);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { WorkspaceTrayProps, WorkspaceWindowProps } from "./WorkspaceWindowProps";
|
|
2
|
-
export default function WorkspaceWindow({ title, state, children, onMinimize, onClose, onOpenFullPage, onOverlayClick, headerActions, testId, }: WorkspaceWindowProps): import("react/jsx-runtime").JSX.Element | null;
|
|
3
|
-
export declare function WorkspaceTray({ items, onRestore, onClose, testId, renderItem, }: WorkspaceTrayProps): import("react/jsx-runtime").JSX.Element | null;
|
|
2
|
+
export default function WorkspaceWindow({ title, state, children, onMinimize, onClose, onOpenFullPage, onOverlayClick, headerActions, labels, finalFocusRef, testId, }: WorkspaceWindowProps): import("react/jsx-runtime").JSX.Element | null;
|
|
3
|
+
export declare function WorkspaceTray({ items, onRestore, onClose, testId, placement, offset, closeLabel, dirtyLabel, label, renderItem, }: WorkspaceTrayProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -12,7 +12,7 @@ const lucide_react_1 = require("lucide-react");
|
|
|
12
12
|
const useCustomTheme_1 = require("../../Theme/useCustomTheme");
|
|
13
13
|
const zIndices_1 = __importDefault(require("../../Theme/tokens/primitives/zIndices"));
|
|
14
14
|
const accentText_1 = require("../../Theme/tokens/builders/accentText");
|
|
15
|
-
// NOTE: no maximize/restore toggle (removed by product decision)
|
|
15
|
+
// NOTE: no maximize/restore toggle (removed by product decision); onMedium/onMaximize stay as deprecated no-ops.
|
|
16
16
|
const WINDOW_SIZE = { maxW: "88rem", h: "92vh" };
|
|
17
17
|
const WindowTitle = ({ testId, color, children }) => {
|
|
18
18
|
const { headerId, setHeaderMounted } = (0, react_1.useModalContext)();
|
|
@@ -23,7 +23,8 @@ const WindowTitle = ({ testId, color, children }) => {
|
|
|
23
23
|
return ((0, jsx_runtime_1.jsx)(react_1.Text, { id: headerId, fontSize: "sm", fontWeight: 600, color: color, noOfLines: 1, "data-testid": `${testId}-title`, children: children }));
|
|
24
24
|
};
|
|
25
25
|
// Presentational floating "workspace window" (Jira-style dialog), headless — the parent owns window state.
|
|
26
|
-
function WorkspaceWindow({ title, state, children, onMinimize, onClose, onOpenFullPage, onOverlayClick, headerActions, testId = "workspace-window", }) {
|
|
26
|
+
function WorkspaceWindow({ title, state, children, onMinimize, onClose, onOpenFullPage, onOverlayClick, headerActions, labels, finalFocusRef, testId = "workspace-window", }) {
|
|
27
|
+
var _a, _b, _c;
|
|
27
28
|
// Must run before the early return: a minimized render would otherwise skip the hook
|
|
28
29
|
// and change hook order when the window reopens.
|
|
29
30
|
const theme = (0, useCustomTheme_1.useCustomTheme)();
|
|
@@ -33,28 +34,35 @@ function WorkspaceWindow({ title, state, children, onMinimize, onClose, onOpenFu
|
|
|
33
34
|
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",
|
|
34
35
|
// Don't discard unsaved work on an accidental overlay click / Esc — the
|
|
35
36
|
// parent decides via the explicit Close control.
|
|
36
|
-
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",
|
|
37
|
+
closeOnOverlayClick: false, closeOnEsc: false, finalFocusRef: finalFocusRef, 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",
|
|
37
38
|
// NOTE: size="full" blocks Chakra's own closeOnOverlayClick — detect the outside click ourselves instead.
|
|
38
39
|
onMouseDown: (e) => {
|
|
39
40
|
if (e.target === e.currentTarget)
|
|
40
41
|
onOverlayClick === null || onOverlayClick === void 0 ? void 0 : onOverlayClick();
|
|
41
|
-
}, "data-testid": `${testId}-backdrop`, children: (0, jsx_runtime_1.jsxs)(react_1.Box, { bg: theme.colors.surfaceRaised, borderRadius: "xl", 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: theme.colors.boxborder[200], bg: theme.colors.background[100], flexShrink: 0, children: [(0, jsx_runtime_1.jsx)(WindowTitle, { testId: testId, color: theme.colors.text[700], 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 })] }) })] }));
|
|
42
|
+
}, "data-testid": `${testId}-backdrop`, children: (0, jsx_runtime_1.jsxs)(react_1.Box, { bg: theme.colors.surfaceRaised, borderRadius: "xl", 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: theme.colors.boxborder[200], bg: theme.colors.background[100], flexShrink: 0, children: [(0, jsx_runtime_1.jsx)(WindowTitle, { testId: testId, color: theme.colors.text[700], 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": (_a = labels === null || labels === void 0 ? void 0 : labels.openFullPage) !== null && _a !== void 0 ? _a : "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": (_b = labels === null || labels === void 0 ? void 0 : labels.minimize) !== null && _b !== void 0 ? _b : "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": (_c = labels === null || labels === void 0 ? void 0 : labels.close) !== null && _c !== void 0 ? _c : "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 })] }) })] }));
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
const cssLength = (value) => (typeof value === "number" ? `${value}px` : value);
|
|
45
|
+
// Portalled above modal overlays; aria-live keeps Chakra's modal aria-hidden off it, data-no-focus-lock keeps the focus trap off it.
|
|
46
|
+
function WorkspaceTray({ items, onRestore, onClose, testId = "workspace-tray", placement = "bottom-end", offset, closeLabel, dirtyLabel = "Unsaved changes", label = "Minimized windows", renderItem, }) {
|
|
47
|
+
var _a, _b;
|
|
45
48
|
const theme = (0, useCustomTheme_1.useCustomTheme)();
|
|
46
49
|
if (!items.length)
|
|
47
50
|
return null;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
const atEnd = placement === "bottom-end";
|
|
52
|
+
const inset = {
|
|
53
|
+
bottom: cssLength((_a = offset === null || offset === void 0 ? void 0 : offset.y) !== null && _a !== void 0 ? _a : "1rem"),
|
|
54
|
+
[atEnd ? "right" : "left"]: cssLength((_b = offset === null || offset === void 0 ? void 0 : offset.x) !== null && _b !== void 0 ? _b : "1rem"),
|
|
55
|
+
};
|
|
56
|
+
const ink = (0, accentText_1.accentTextOnCanvas)(theme.colors.primary, theme.colors.primary[100]);
|
|
57
|
+
return ((0, jsx_runtime_1.jsx)(react_1.Portal, { children: (0, jsx_runtime_1.jsx)(react_1.Flex, { role: "region", "aria-label": label, "aria-live": "polite", "data-no-focus-lock": "true", position: "fixed", ...inset, zIndex: zIndices_1.default.modal + 1, direction: atEnd ? "row-reverse" : "row", wrap: "wrap-reverse", justify: "flex-start", gap: 2, maxW: { base: "calc(100vw - 2rem)", md: "36rem" }, "data-testid": testId, children: items.map((item) => {
|
|
58
|
+
const api = {
|
|
59
|
+
restore: () => onRestore === null || onRestore === void 0 ? void 0 : onRestore(item.id),
|
|
60
|
+
close: () => onClose === null || onClose === void 0 ? void 0 : onClose(item.id),
|
|
61
|
+
};
|
|
62
|
+
const pill = ((0, jsx_runtime_1.jsxs)(react_1.HStack, { spacing: 1, pl: 3, pr: 1, py: 1, borderRadius: "full", bg: theme.colors.primary[100], color: ink, boxShadow: "md", borderWidth: "1px", borderColor: theme.colors.primary[200], "data-testid": `${testId}-pill`, children: [item.isDirty ? ((0, jsx_runtime_1.jsx)(react_1.Box, { role: "img", "aria-label": dirtyLabel, boxSize: "0.5rem", borderRadius: "full", bg: "currentColor", flexShrink: 0, "data-testid": `${testId}-dirty` })) : null, (0, jsx_runtime_1.jsxs)(react_1.Box, { as: "button", type: "button", fontSize: "sm", onClick: api.restore, "data-testid": `${testId}-restore`, maxW: "16rem", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: [item.title, item.subtitle ? ((0, jsx_runtime_1.jsx)(react_1.Box, { as: "span", fontWeight: 400, ml: 1.5, children: item.subtitle })) : null] }), onClose ? ((0, jsx_runtime_1.jsx)(react_1.IconButton, { "aria-label": closeLabel ? closeLabel(item) : "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: api.close, "data-testid": `${testId}-close` })) : null] }));
|
|
63
|
+
if (renderItem) {
|
|
64
|
+
return (0, jsx_runtime_1.jsx)(react_1.Box, { children: renderItem(item, api, pill) }, item.id);
|
|
65
|
+
}
|
|
66
|
+
return (0, jsx_runtime_1.jsx)(react_2.Fragment, { children: pill }, item.id);
|
|
67
|
+
}) }) }));
|
|
60
68
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
1
|
+
import type { ReactNode, RefObject } from "react";
|
|
2
2
|
/**
|
|
3
3
|
* Window state for a WorkspaceWindow.
|
|
4
4
|
* - "medium": default centered dialog (Jira-style)
|
|
@@ -6,6 +6,15 @@ import type { ReactNode } from "react";
|
|
|
6
6
|
* - "minimized": collapsed to a tray pill (rendered by WorkspaceTray, not the window)
|
|
7
7
|
*/
|
|
8
8
|
export type WorkspaceWindowState = "medium" | "maximized" | "minimized";
|
|
9
|
+
/** Accessible names of the window's icon controls; omitted keys keep the English default. */
|
|
10
|
+
export interface WorkspaceWindowLabels {
|
|
11
|
+
/** Default "Minimize". */
|
|
12
|
+
minimize?: string;
|
|
13
|
+
/** Default "Close". */
|
|
14
|
+
close?: string;
|
|
15
|
+
/** Default "Open full page". */
|
|
16
|
+
openFullPage?: string;
|
|
17
|
+
}
|
|
9
18
|
/** Props for one WorkspaceWindow instance; minimized windows render separately via WorkspaceTrayProps below. */
|
|
10
19
|
export interface WorkspaceWindowProps {
|
|
11
20
|
/** Title shown in the window's control bar. */
|
|
@@ -29,6 +38,13 @@ export interface WorkspaceWindowProps {
|
|
|
29
38
|
* itself (e.g. minimize-on-backdrop-click) via this callback.
|
|
30
39
|
*/
|
|
31
40
|
onOverlayClick?: () => void;
|
|
41
|
+
/** Translated names for the Minimize, Close and Open full page buttons. */
|
|
42
|
+
labels?: WorkspaceWindowLabels;
|
|
43
|
+
/**
|
|
44
|
+
* Where focus lands when the window closes or minimizes. Without it focus returns to whatever opened the
|
|
45
|
+
* window, which is gone once it was restored from the tray; point it at a stable element (e.g. the page's main region).
|
|
46
|
+
*/
|
|
47
|
+
finalFocusRef?: RefObject<HTMLElement>;
|
|
32
48
|
/** Extra controls rendered in the control bar, left of the window buttons. */
|
|
33
49
|
headerActions?: ReactNode;
|
|
34
50
|
/** data-testid for the window container. */
|
|
@@ -38,8 +54,12 @@ export interface WorkspaceWindowProps {
|
|
|
38
54
|
export interface WorkspaceTrayItem {
|
|
39
55
|
id: string;
|
|
40
56
|
title: ReactNode;
|
|
57
|
+
/** Shows an unsaved-changes dot on the built-in pill; named for screen readers by the tray's `dirtyLabel`. */
|
|
58
|
+
isDirty?: boolean;
|
|
59
|
+
/** Secondary text after the title on the built-in pill, e.g. a record type or id. */
|
|
60
|
+
subtitle?: ReactNode;
|
|
41
61
|
}
|
|
42
|
-
/** Props for the
|
|
62
|
+
/** Props for the cluster of minimized-window pills; renders nothing when items is empty. */
|
|
43
63
|
export interface WorkspaceTrayProps {
|
|
44
64
|
/** Minimized items rendered as restore pills along the bottom. */
|
|
45
65
|
items: WorkspaceTrayItem[];
|
|
@@ -47,16 +67,26 @@ export interface WorkspaceTrayProps {
|
|
|
47
67
|
onClose?: (id: string) => void;
|
|
48
68
|
testId?: string;
|
|
49
69
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* generic pill doesn't know about. Receives the item plus ready-bound
|
|
53
|
-
* restore/close callbacks; when provided, the built-in pill is skipped for
|
|
54
|
-
* that item and this renders in its place inside the same positioned tray.
|
|
70
|
+
* Which bottom corner the tray sits in. Default "bottom-end". The tray is portalled above modals and stays
|
|
71
|
+
* reachable while a modal is open.
|
|
55
72
|
*/
|
|
73
|
+
placement?: "bottom-end" | "bottom-start";
|
|
74
|
+
/** Distance from the viewport edges, to clear a sticky bar. Numbers are px, strings any CSS length. Default 1rem each. */
|
|
75
|
+
offset?: {
|
|
76
|
+
x?: number | string;
|
|
77
|
+
y?: number | string;
|
|
78
|
+
};
|
|
79
|
+
/** Accessible name for each pill's close button. Default "Close"; pass one that names the item for non-English or per-window labels. */
|
|
80
|
+
closeLabel?: (item: WorkspaceTrayItem) => string;
|
|
81
|
+
/** Accessible name of the unsaved dot on a pill with `isDirty`. Default "Unsaved changes". */
|
|
82
|
+
dirtyLabel?: string;
|
|
83
|
+
/** Accessible name of the tray region. Default "Minimized windows". */
|
|
84
|
+
label?: string;
|
|
85
|
+
/** Replaces one item's pill inside the same tray; gets the item, bound restore/close and `pill`, the built-in pill (dot, subtitle, close button) to return as is or wrap, e.g. in WorkspaceTrayPreview. */
|
|
56
86
|
renderItem?: (item: WorkspaceTrayItem, api: {
|
|
57
87
|
restore: () => void;
|
|
58
88
|
close: () => void;
|
|
59
|
-
}) => ReactNode;
|
|
89
|
+
}, pill: ReactNode) => ReactNode;
|
|
60
90
|
}
|
|
61
91
|
/** Props for WorkspaceTrayPreview — despite the name, works for any hover trigger, not just tray pills. */
|
|
62
92
|
export interface WorkspaceTrayPreviewProps {
|
|
@@ -15,6 +15,7 @@ export declare const Menu: {
|
|
|
15
15
|
borderColor: string;
|
|
16
16
|
};
|
|
17
17
|
item: {
|
|
18
|
+
color: string;
|
|
18
19
|
minH: string;
|
|
19
20
|
px: string;
|
|
20
21
|
py: string;
|
|
@@ -39,6 +40,13 @@ export declare const Menu: {
|
|
|
39
40
|
[$itemBg.variable]: string;
|
|
40
41
|
bg: string;
|
|
41
42
|
};
|
|
43
|
+
"&[aria-checked=true]": {
|
|
44
|
+
color: string;
|
|
45
|
+
fontWeight: number;
|
|
46
|
+
"& .chakra-menu__icon-wrapper": {
|
|
47
|
+
color: string;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
42
50
|
};
|
|
43
51
|
}) | undefined;
|
|
44
52
|
sizes?: {
|
|
@@ -4,6 +4,7 @@ exports.Menu = void 0;
|
|
|
4
4
|
const react_1 = require("@chakra-ui/react");
|
|
5
5
|
const anatomy_1 = require("@chakra-ui/anatomy");
|
|
6
6
|
const rowStates_1 = require("../tokens/builders/rowStates");
|
|
7
|
+
const optionRowInk_1 = require("../../Components/Select/optionRowInk");
|
|
7
8
|
const optionRowSizes_1 = require("../tokens/primitives/optionRowSizes");
|
|
8
9
|
const paletteFromTheme_1 = require("./paletteFromTheme");
|
|
9
10
|
const overlay_styles_1 = require("./overlay.styles");
|
|
@@ -28,6 +29,7 @@ const baseStyle = definePartsStyle(({ theme }) => {
|
|
|
28
29
|
...overlay_styles_1.POPUP_SURFACE,
|
|
29
30
|
},
|
|
30
31
|
item: {
|
|
32
|
+
color: (0, optionRowInk_1.optionRowInk)(colors, false),
|
|
31
33
|
minH: itemRowSpec.minH,
|
|
32
34
|
px: itemRowSpec.px,
|
|
33
35
|
py: itemRowSpec.py,
|
|
@@ -40,6 +42,11 @@ const baseStyle = definePartsStyle(({ theme }) => {
|
|
|
40
42
|
_hover: { [$itemBg.variable]: hoverBg, bg: $itemBg.reference },
|
|
41
43
|
_active: { [$itemBg.variable]: activeBg, bg: $itemBg.reference },
|
|
42
44
|
_expanded: { [$itemBg.variable]: hoverBg, bg: $itemBg.reference },
|
|
45
|
+
"&[aria-checked=true]": {
|
|
46
|
+
color: (0, optionRowInk_1.optionRowInk)(colors, true),
|
|
47
|
+
fontWeight: (0, optionRowInk_1.optionRowWeight)(true),
|
|
48
|
+
"& .chakra-menu__icon-wrapper": { color: colors.accentText },
|
|
49
|
+
},
|
|
43
50
|
},
|
|
44
51
|
};
|
|
45
52
|
});
|
|
@@ -182,6 +182,7 @@ export declare const componentStyles: {
|
|
|
182
182
|
borderColor: string;
|
|
183
183
|
};
|
|
184
184
|
item: {
|
|
185
|
+
color: string;
|
|
185
186
|
minH: string;
|
|
186
187
|
px: string;
|
|
187
188
|
py: string;
|
|
@@ -206,6 +207,13 @@ export declare const componentStyles: {
|
|
|
206
207
|
[x: string]: string;
|
|
207
208
|
bg: string;
|
|
208
209
|
};
|
|
210
|
+
"&[aria-checked=true]": {
|
|
211
|
+
color: string;
|
|
212
|
+
fontWeight: number;
|
|
213
|
+
"& .chakra-menu__icon-wrapper": {
|
|
214
|
+
color: string;
|
|
215
|
+
};
|
|
216
|
+
};
|
|
209
217
|
};
|
|
210
218
|
}) | undefined;
|
|
211
219
|
sizes?: {
|
|
@@ -26,7 +26,7 @@ const Card_styles_1 = require("./Card.styles");
|
|
|
26
26
|
// NOTE: guards untethemed scales (blackAlpha/whiteAlpha) whose rgba() rungs would throw in hexToRgb.
|
|
27
27
|
const isHexColor = (color) => typeof color === "string" && /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(color);
|
|
28
28
|
const solidFillStyle = (palette, swatch) => {
|
|
29
|
-
const rung = (0, filledSurface_1.solidFillRung)(swatch, palette.white);
|
|
29
|
+
const rung = (0, filledSurface_1.solidFillRung)(swatch, palette.white, palette.backgroundColor.main);
|
|
30
30
|
const bg = swatch[rung];
|
|
31
31
|
return {
|
|
32
32
|
bg,
|
|
@@ -161,7 +161,7 @@ const Radio = {
|
|
|
161
161
|
baseStyle: ({ theme, colorScheme }) => {
|
|
162
162
|
const palette = (0, paletteFromTheme_1.paletteOf)(theme);
|
|
163
163
|
const swatch = (0, paletteFromTheme_1.scaleFor)(palette, colorScheme);
|
|
164
|
-
const fill = swatch[(0, filledSurface_1.solidFillRung)(swatch, palette.white)];
|
|
164
|
+
const fill = swatch[(0, filledSurface_1.solidFillRung)(swatch, palette.white, palette.backgroundColor.main)];
|
|
165
165
|
const dot = (0, filledSurface_1.labelOnFill)(fill, palette.white, palette.black);
|
|
166
166
|
const hoverFill = (0, outlineRung_1.resolveHoverTint)(fill, fill);
|
|
167
167
|
return {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.insetRingShadow = void 0;
|
|
4
|
+
const borderWidths_1 = require("../tokens/primitives/borderWidths");
|
|
5
|
+
/** A stroke drawn inside the border box as a box-shadow, so it never costs layout. */
|
|
6
|
+
const insetRingShadow = (color, width = "hairline") => `inset 0 0 0 ${borderWidths_1.BORDER_WIDTHS[width]} ${color}`;
|
|
7
|
+
exports.insetRingShadow = insetRingShadow;
|
|
@@ -12,6 +12,8 @@ declare const DARK_CANVAS_LUMINANCE = 0.2;
|
|
|
12
12
|
/** True when `canvas` is a dark surface. Lets style configs branch without threading color mode. */
|
|
13
13
|
export declare const isDarkCanvas: (canvas: string) => boolean;
|
|
14
14
|
export declare const accentTextOnCanvas: (scale: ColorScale, canvas: string) => string;
|
|
15
|
+
/** Accent ink for chrome that can land on any plane (canvas, card, overlay): the first rung clearing AA on all. */
|
|
16
|
+
export declare const accentTextOnPlanes: (scale: ColorScale, planes: readonly string[]) => string;
|
|
15
17
|
export declare const onFilled: (fill: string, white: string, black: string) => string;
|
|
16
18
|
export declare const onGradient: (from: string, to: string, white: string, black: string) => string;
|
|
17
19
|
export { AA_NORMAL_TEXT, DARK_CANVAS_LUMINANCE };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DARK_CANVAS_LUMINANCE = exports.AA_NORMAL_TEXT = exports.onGradient = exports.onFilled = exports.accentTextOnCanvas = exports.isDarkCanvas = exports.DEFAULT_BLACK = exports.DEFAULT_WHITE = exports.DEFAULT_CANVAS = exports.pickAccentText = void 0;
|
|
3
|
+
exports.DARK_CANVAS_LUMINANCE = exports.AA_NORMAL_TEXT = exports.onGradient = exports.onFilled = exports.accentTextOnPlanes = exports.accentTextOnCanvas = exports.isDarkCanvas = exports.DEFAULT_BLACK = exports.DEFAULT_WHITE = exports.DEFAULT_CANVAS = exports.pickAccentText = void 0;
|
|
4
4
|
const color_1 = require("./color");
|
|
5
5
|
/** WCAG AA for normal-size text. Accent-as-text must clear this against the canvas. */
|
|
6
6
|
const AA_NORMAL_TEXT = 4.5;
|
|
@@ -27,6 +27,12 @@ exports.isDarkCanvas = isDarkCanvas;
|
|
|
27
27
|
// NOTE: held to AA in both modes now — some brands' light [500] no longer passes through untouched.
|
|
28
28
|
const accentTextOnCanvas = (scale, canvas) => (0, exports.pickAccentText)(scale, canvas);
|
|
29
29
|
exports.accentTextOnCanvas = accentTextOnCanvas;
|
|
30
|
+
/** Accent ink for chrome that can land on any plane (canvas, card, overlay): the first rung clearing AA on all. */
|
|
31
|
+
const accentTextOnPlanes = (scale, planes) => {
|
|
32
|
+
const found = SEARCH_ORDER.find((rung) => planes.every((plane) => (0, color_1.contrastRatio)(scale[rung], plane) >= AA_NORMAL_TEXT));
|
|
33
|
+
return scale[found !== null && found !== void 0 ? found : SEARCH_ORDER[SEARCH_ORDER.length - 1]];
|
|
34
|
+
};
|
|
35
|
+
exports.accentTextOnPlanes = accentTextOnPlanes;
|
|
30
36
|
// NOTE: white/black must be the mode-stable absolutes, not an adaptive token — always clears AA.
|
|
31
37
|
const onFilled = (fill, white, black) => (0, color_1.contrastRatio)(white, fill) >= AA_NORMAL_TEXT ? white : black;
|
|
32
38
|
exports.onFilled = onFilled;
|
|
@@ -6,7 +6,7 @@ export declare const shiftLighter: (scale: ColorScale) => ColorScale;
|
|
|
6
6
|
export declare const accentLightnessDelta: (accent500: string, white: string) => number;
|
|
7
7
|
/** Raises every rung by the same lightness delta, preserving the ramp's shape and hue. */
|
|
8
8
|
export declare const liftScale: (scale: ColorScale, delta: number) => ColorScale;
|
|
9
|
-
/** `lifted`:
|
|
9
|
+
/** `lifted`: the card sits a CARD_LIFT step above the canvas. `flat`: the card is the canvas. */
|
|
10
10
|
export type DarkPlanes = "lifted" | "flat";
|
|
11
11
|
export interface DarkPaletteOptions {
|
|
12
12
|
planes?: DarkPlanes;
|
|
@@ -151,7 +151,8 @@ const NAMED_SURFACE_L = {
|
|
|
151
151
|
accent: 17,
|
|
152
152
|
muted: 18,
|
|
153
153
|
};
|
|
154
|
-
|
|
154
|
+
// NOTE: surfaces are hue-neutral on every brand; brand hue stays on accents, ink and rules.
|
|
155
|
+
const SURFACE_SAT = 0;
|
|
155
156
|
const TEXT_SAT = 12;
|
|
156
157
|
const PLACEHOLDER_SAT = 10;
|
|
157
158
|
const BORDER_SAT = 12;
|
|
@@ -182,16 +183,15 @@ const cardPlane = (canvas, white, planes) => {
|
|
|
182
183
|
function buildDarkPalette(light, { planes = "lifted" } = {}) {
|
|
183
184
|
const hueSource = light.primary[500];
|
|
184
185
|
const { h } = (0, color_1.hexToHsl)(hueSource);
|
|
185
|
-
const surfaceSat = SURFACE_SAT[planes];
|
|
186
186
|
const namedSurfaces = Object.fromEntries(Object.entries(NAMED_SURFACE_L).map(([key, l]) => [
|
|
187
187
|
key,
|
|
188
|
-
(0, color_1.hslToHex)({ h, s:
|
|
188
|
+
(0, color_1.hslToHex)({ h, s: SURFACE_SAT, l }),
|
|
189
189
|
]));
|
|
190
190
|
const white = light.white;
|
|
191
191
|
const { card, rise, tableHover } = cardPlane(namedSurfaces.main, white, planes);
|
|
192
192
|
const primary = liftBrand(light.primary, white);
|
|
193
193
|
const background = {
|
|
194
|
-
...fromTargets(hueSource, raise(SURFACE_TARGETS, BACKGROUND_FILLS, rise),
|
|
194
|
+
...fromTargets(hueSource, raise(SURFACE_TARGETS, BACKGROUND_FILLS, rise), SURFACE_SAT),
|
|
195
195
|
50: card,
|
|
196
196
|
};
|
|
197
197
|
const semantic = {
|
|
@@ -231,7 +231,7 @@ function buildDarkPalette(light, { planes = "lifted" } = {}) {
|
|
|
231
231
|
border: dividerRamp,
|
|
232
232
|
boxborder: dividerRamp,
|
|
233
233
|
table: {
|
|
234
|
-
hover: fromTargets(hueSource, tableHover,
|
|
234
|
+
hover: fromTargets(hueSource, tableHover, SURFACE_SAT),
|
|
235
235
|
},
|
|
236
236
|
disabled: fromTargets(hueSource, DISABLED_TARGETS, DISABLED_SAT),
|
|
237
237
|
accentText: (0, accentText_1.pickAccentText)(primary, namedSurfaces.main),
|
|
@@ -12,7 +12,11 @@ export type FilledSurface = {
|
|
|
12
12
|
activeColor: string;
|
|
13
13
|
};
|
|
14
14
|
export declare const solidFillRung: (scale: ColorScale, white: string, canvas?: string) => keyof ColorScale;
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Hover (step 0) or active (step 1) fill rung, one step darker than `solidFillRung`. A step may not
|
|
17
|
+
* flip the label's side of AA (zinc dark: near-white fill, black ink) or fall below `CHROME_BORDER`
|
|
18
|
+
* against the canvas (a pressed warning solid used to reach 1.00:1 on the card).
|
|
19
|
+
*/
|
|
16
20
|
export declare const darkerFillRung: (scale: ColorScale, canvas: string, white: string, step: 0 | 1) => keyof ColorScale;
|
|
17
21
|
/** Label ink for a specific fill swatch — always `onFilled`, exported for style configs. */
|
|
18
22
|
export declare const labelOnFill: (fill: string, white: string, black: string) => string;
|
|
@@ -44,15 +44,28 @@ const steppedRung = (base, canvas, step) => {
|
|
|
44
44
|
const dir = (0, accentText_1.isDarkCanvas)(canvas) ? -100 : 100;
|
|
45
45
|
return Math.min(900, Math.max(50, base + dir * step));
|
|
46
46
|
};
|
|
47
|
-
|
|
47
|
+
const steppedTowardBase = (from, base) => RUNGS[RUNGS.indexOf(from) + (from > base ? -1 : 1)];
|
|
48
|
+
/**
|
|
49
|
+
* Hover (step 0) or active (step 1) fill rung, one step darker than `solidFillRung`. A step may not
|
|
50
|
+
* flip the label's side of AA (zinc dark: near-white fill, black ink) or fall below `CHROME_BORDER`
|
|
51
|
+
* against the canvas (a pressed warning solid used to reach 1.00:1 on the card).
|
|
52
|
+
*/
|
|
48
53
|
const darkerFillRung = (scale, canvas, white, step) => {
|
|
49
54
|
const base = (0, exports.solidFillRung)(scale, white, canvas);
|
|
55
|
+
const wantsWhite = (0, color_1.contrastRatio)(white, scale[base]) >= accentText_1.AA_NORMAL_TEXT;
|
|
56
|
+
const holds = (rung) => (0, color_1.contrastRatio)(scale[rung], canvas) >= outlineRung_1.CHROME_BORDER &&
|
|
57
|
+
((0, color_1.contrastRatio)(white, scale[rung]) >= accentText_1.AA_NORMAL_TEXT) === wantsWhite;
|
|
58
|
+
let rung;
|
|
50
59
|
if (base === 500) {
|
|
51
60
|
const mode = (0, accentText_1.isDarkCanvas)(canvas) ? "dark" : "light";
|
|
52
|
-
|
|
61
|
+
rung = FILL_STEP_RUNGS[mode][step];
|
|
53
62
|
}
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
else {
|
|
64
|
+
rung = steppedRung(base, canvas, step === 0 ? 1 : 2);
|
|
65
|
+
}
|
|
66
|
+
while (rung !== base && !holds(rung))
|
|
67
|
+
rung = steppedTowardBase(rung, base);
|
|
68
|
+
return rung;
|
|
56
69
|
};
|
|
57
70
|
exports.darkerFillRung = darkerFillRung;
|
|
58
71
|
/** Label ink for a specific fill swatch — always `onFilled`, exported for style configs. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PaletteProps } from "../types";
|
|
2
2
|
export declare const bandOn: (fill: string, plane: string) => string;
|
|
3
3
|
export declare const recessOn: (fill: string, plane: string) => string;
|
|
4
|
+
export declare const ruleOn: (colors: Pick<PaletteProps, "boxborder">, plane: string) => string;
|
|
4
5
|
export declare const cardRule: (colors: Pick<PaletteProps, "boxborder" | "background">) => string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.cardRule = exports.recessOn = exports.bandOn = void 0;
|
|
3
|
+
exports.cardRule = exports.ruleOn = exports.recessOn = exports.bandOn = void 0;
|
|
4
4
|
const accentText_1 = require("./accentText");
|
|
5
5
|
const color_1 = require("./color");
|
|
6
6
|
const outlineRung_1 = require("./outlineRung");
|
|
@@ -12,9 +12,10 @@ const recessOn = (fill, plane) => holds(fill, plane, outlineRung_1.MIN_PERCEPTIB
|
|
|
12
12
|
? fill
|
|
13
13
|
: (0, planes_1.lift)(accentText_1.DEFAULT_BLACK, plane, outlineRung_1.MIN_PERCEPTIBLE_STEP);
|
|
14
14
|
exports.recessOn = recessOn;
|
|
15
|
-
const
|
|
15
|
+
const ruleOn = (colors, plane) => {
|
|
16
16
|
const rule = colors.boxborder[200];
|
|
17
|
-
|
|
18
|
-
return holds(rule, card, outlineRung_1.CHROME_RULE) ? rule : (0, outlineRung_1.liftToContrast)(rule, card, outlineRung_1.CHROME_RULE);
|
|
17
|
+
return holds(rule, plane, outlineRung_1.CHROME_RULE) ? rule : (0, outlineRung_1.liftToContrast)(rule, plane, outlineRung_1.CHROME_RULE);
|
|
19
18
|
};
|
|
19
|
+
exports.ruleOn = ruleOn;
|
|
20
|
+
const cardRule = (colors) => (0, exports.ruleOn)(colors, colors.background[50]);
|
|
20
21
|
exports.cardRule = cardRule;
|
package/dist/Utils/table.js
CHANGED
|
@@ -81,7 +81,7 @@ function buildSemanticStatusPalette(toneByValue, theme) {
|
|
|
81
81
|
return Object.fromEntries(Object.entries(toneByValue).map(([value, key]) => {
|
|
82
82
|
const scale = scales[key];
|
|
83
83
|
const tone = (0, tone_1.resolveSoftTone)(c, scale);
|
|
84
|
-
const solidRung = (0, filledSurface_1.solidFillRung)(scale, c.white);
|
|
84
|
+
const solidRung = (0, filledSurface_1.solidFillRung)(scale, c.white, c.backgroundColor.main);
|
|
85
85
|
const solid = scale[solidRung];
|
|
86
86
|
return [
|
|
87
87
|
value,
|
|
@@ -123,7 +123,7 @@ function buildTablePalette(theme) {
|
|
|
123
123
|
];
|
|
124
124
|
return scales.map((scale) => {
|
|
125
125
|
const tone = (0, tone_1.resolveSoftTone)(c, scale);
|
|
126
|
-
const solidRung = (0, filledSurface_1.solidFillRung)(scale, c.white);
|
|
126
|
+
const solidRung = (0, filledSurface_1.solidFillRung)(scale, c.white, c.backgroundColor.main);
|
|
127
127
|
const solid = scale[solidRung];
|
|
128
128
|
return {
|
|
129
129
|
solid,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { accentTextOnPlanes } from "../../Theme/tokens/builders/accentText.js";
|
|
2
2
|
import { darkerFillRung, labelOnFill, resolveFilledSurface, solidFillRung, } from "../../Theme/tokens/builders/filledSurface.js";
|
|
3
3
|
import { resolveGradient, gradientCss } from "../../Theme/tokens/builders/gradientInk.js";
|
|
4
4
|
import { focusVisibleStyles } from "../../Theme/chakra/focusRing.styles.js";
|
|
@@ -21,7 +21,12 @@ const controlSize = (size) => {
|
|
|
21
21
|
return { h: height, minW: height, fontSize, px: paddingX };
|
|
22
22
|
};
|
|
23
23
|
// NOTE: [500] alone measures ~4.2 on a dark canvas — resolved per-mode so outline/ghost/link text stays readable.
|
|
24
|
-
|
|
24
|
+
// NOTE: a bare button sits on the canvas, a card or an overlay; dark overlays are the hardest plane.
|
|
25
|
+
const onCanvasText = (theme, colorScheme) => accentTextOnPlanes(theme.colors[colorScheme], [
|
|
26
|
+
theme.colors.backgroundColor.main,
|
|
27
|
+
theme.colors.background[50],
|
|
28
|
+
theme.colors.surfaceRaised,
|
|
29
|
+
]);
|
|
25
30
|
// NOTE: [50] alone measured ~1.04 (invisible) in both modes — gray borrows the row-state steps.
|
|
26
31
|
const onCanvasHoverBg = (theme, colorScheme, step) => {
|
|
27
32
|
const scale = theme.colors[colorScheme];
|
|
@@ -33,7 +38,7 @@ const onCanvasHoverBg = (theme, colorScheme, step) => {
|
|
|
33
38
|
return step === 16 ? rows.active : rows.selectedActive;
|
|
34
39
|
};
|
|
35
40
|
const swatch = (theme, colorScheme) => theme.colors[colorScheme];
|
|
36
|
-
const buttonSolidRung = (theme, colorScheme) => solidFillRung(swatch(theme, colorScheme), theme.colors.white);
|
|
41
|
+
const buttonSolidRung = (theme, colorScheme) => solidFillRung(swatch(theme, colorScheme), theme.colors.white, theme.colors.backgroundColor.main);
|
|
37
42
|
const darkerFill = (theme, colorScheme, step) => {
|
|
38
43
|
const scale = swatch(theme, colorScheme);
|
|
39
44
|
const rung = darkerFillRung(scale, theme.colors.backgroundColor.main, theme.colors.white, step);
|