pixelize-design-library 2.4.2-beta.32 → 2.4.2-beta.33
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/README.md +21 -0
- package/dist/Components/Button/Button.styles.js +9 -8
- package/dist/Components/Card/PaymentCard/PaymentCard.js +14 -5
- package/dist/Components/Common/ErrorComponent.js +6 -5
- package/dist/Components/DatePicker/CalendarPanel.js +6 -7
- package/dist/Components/FilePreview/FilePreview.js +2 -1
- package/dist/Components/KanbanBoard/KanbanActions/KanbanActions.js +1 -2
- package/dist/Components/OrganizationDetails/OrganizationDetails.js +3 -2
- package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +4 -3
- package/dist/Components/ScrollToTop/ScrollToTop.js +3 -3
- package/dist/Components/SelectSearch/SelectSearch.js +1 -1
- package/dist/Components/SideBar/SideBar.js +4 -2
- package/dist/Components/StageProgress/StageProgressProps.js +6 -4
- package/dist/Components/Table/Table.js +2 -3
- package/dist/Components/Table/filters/LeftFilterPane.js +1 -1
- package/dist/Components/Tag/Tag.styles.js +13 -9
- package/dist/Theme/chakra/componentStyles.js +16 -9
- package/dist/Theme/chakra/createBrandTheme.js +15 -9
- package/dist/Theme/tokens/builders/filledSurface.d.ts +29 -0
- package/dist/Theme/tokens/builders/filledSurface.js +74 -0
- package/dist/Utils/table.js +5 -2
- package/dist/esm/Components/Button/Button.styles.js +10 -9
- package/dist/esm/Components/Card/PaymentCard/PaymentCard.js +14 -5
- package/dist/esm/Components/Common/ErrorComponent.js +6 -5
- package/dist/esm/Components/DatePicker/CalendarPanel.js +6 -7
- package/dist/esm/Components/FilePreview/FilePreview.js +2 -1
- package/dist/esm/Components/KanbanBoard/KanbanActions/KanbanActions.js +1 -2
- package/dist/esm/Components/OrganizationDetails/OrganizationDetails.js +4 -3
- package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +5 -4
- package/dist/esm/Components/ScrollToTop/ScrollToTop.js +3 -3
- package/dist/esm/Components/SelectSearch/SelectSearch.js +1 -1
- package/dist/esm/Components/SideBar/SideBar.js +4 -2
- package/dist/esm/Components/StageProgress/StageProgressProps.js +7 -5
- package/dist/esm/Components/Table/Table.js +2 -3
- package/dist/esm/Components/Table/filters/LeftFilterPane.js +1 -1
- package/dist/esm/Components/Tag/Tag.styles.js +14 -10
- package/dist/esm/Theme/chakra/componentStyles.js +16 -9
- package/dist/esm/Theme/chakra/createBrandTheme.js +15 -9
- package/dist/esm/Theme/tokens/builders/filledSurface.js +67 -0
- package/dist/esm/Utils/table.js +5 -2
- package/dist/esm/index.js +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -1
- package/package.json +1 -1
- package/dist/Theme/tokens/builders/scrollShadow.d.ts +0 -2
- package/dist/Theme/tokens/builders/scrollShadow.js +0 -16
- package/dist/Theme/tokens/builders/solidFillRung.d.ts +0 -4
- package/dist/Theme/tokens/builders/solidFillRung.js +0 -33
- package/dist/esm/Theme/tokens/builders/scrollShadow.js +0 -13
- package/dist/esm/Theme/tokens/builders/solidFillRung.js +0 -28
|
@@ -8,7 +8,7 @@ const react_1 = require("@chakra-ui/react");
|
|
|
8
8
|
const common_web_1 = __importDefault(require("./common.web"));
|
|
9
9
|
const fonts_web_1 = __importDefault(require("./fonts.web"));
|
|
10
10
|
const componentStyles_1 = require("./componentStyles");
|
|
11
|
-
const
|
|
11
|
+
const filledSurface_1 = require("../tokens/builders/filledSurface");
|
|
12
12
|
const scrollbar_1 = require("../tokens/builders/scrollbar");
|
|
13
13
|
const focusRing_styles_1 = require("./focusRing.styles");
|
|
14
14
|
/**
|
|
@@ -88,14 +88,20 @@ const createBrandTheme = (palette, options = {}) => {
|
|
|
88
88
|
// selecting text anywhere (e.g. a table cell) shows a stray white/lavender patch on
|
|
89
89
|
// the dark canvas. Brand it instead, with WCAG-safe ink via the same `onFilled` math
|
|
90
90
|
// used for buttons/badges.
|
|
91
|
-
"::selection": {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
"::selection": (() => {
|
|
92
|
+
const solid = (0, filledSurface_1.resolveFilledSurface)(palette.primary, palette);
|
|
93
|
+
return {
|
|
94
|
+
background: solid.fill,
|
|
95
|
+
color: solid.color,
|
|
96
|
+
};
|
|
97
|
+
})(),
|
|
98
|
+
"::-moz-selection": (() => {
|
|
99
|
+
const solid = (0, filledSurface_1.resolveFilledSurface)(palette.primary, palette);
|
|
100
|
+
return {
|
|
101
|
+
background: solid.fill,
|
|
102
|
+
color: solid.color,
|
|
103
|
+
};
|
|
104
|
+
})(),
|
|
99
105
|
// `color-scheme: dark` gives WebKit/Blink a dark scrollbar by default, but it's the
|
|
100
106
|
// OS's generic dark gray, not brand-aware.
|
|
101
107
|
...(0, scrollbar_1.globalScrollbarStyles)(palette),
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ColorScale, PaletteProps } from "../types";
|
|
2
|
+
/** Resolved fill + ink for a solid surface, including hover/active steps. */
|
|
3
|
+
export type FilledSurface = {
|
|
4
|
+
rung: keyof ColorScale;
|
|
5
|
+
fill: string;
|
|
6
|
+
color: string;
|
|
7
|
+
hoverRung: keyof ColorScale;
|
|
8
|
+
hoverFill: string;
|
|
9
|
+
hoverColor: string;
|
|
10
|
+
activeRung: keyof ColorScale;
|
|
11
|
+
activeFill: string;
|
|
12
|
+
activeColor: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Lightest rung on `scale` that still carries `white` at WCAG AA. Prefers [500] when it already
|
|
16
|
+
* passes; otherwise walks toward darker rungs. Used for solid fills on buttons, tags, badges and
|
|
17
|
+
* table status pills so consumers never get black ink on a saturated fill when white is achievable.
|
|
18
|
+
*/
|
|
19
|
+
export declare const solidFillRung: (scale: ColorScale, white: string) => keyof ColorScale;
|
|
20
|
+
/** Hover (step 0) or active (step 1) fill rung, one step darker than `solidFillRung`. */
|
|
21
|
+
export declare const darkerFillRung: (scale: ColorScale, canvas: string, white: string, step: 0 | 1) => keyof ColorScale;
|
|
22
|
+
/** Label ink for a specific fill swatch — always `onFilled`, exported for style configs. */
|
|
23
|
+
export declare const labelOnFill: (fill: string, white: string, black: string) => string;
|
|
24
|
+
/**
|
|
25
|
+
* Consumer-facing helper: given any `ColorScale` (primary, red, semantic.error, …), return the
|
|
26
|
+
* fill rung and matching ink for solid / hover / active states. Use this whenever you paint a
|
|
27
|
+
* `bg` from a scale — never pair `scale[500]` with `onFilled` or `colors.white` by hand.
|
|
28
|
+
*/
|
|
29
|
+
export declare const resolveFilledSurface: (scale: ColorScale, colors: Pick<PaletteProps, "white" | "black" | "backgroundColor">) => FilledSurface;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveFilledSurface = exports.labelOnFill = exports.darkerFillRung = exports.solidFillRung = void 0;
|
|
4
|
+
const color_1 = require("./color");
|
|
5
|
+
const accentText_1 = require("./accentText");
|
|
6
|
+
const RUNGS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
7
|
+
/**
|
|
8
|
+
* The rung one/two steps DARKER than the accent — what a filled button's hover/active needs so its
|
|
9
|
+
* white label stays legible.
|
|
10
|
+
*
|
|
11
|
+
* Every dark scale runs dark -> light across 50 -> 900 (brand scales are rebuilt that way, utility
|
|
12
|
+
* hues are reversed), the mirror of light mode. So "darker than [500]" is [600]/[700] in light but
|
|
13
|
+
* [400]/[300] in dark.
|
|
14
|
+
*/
|
|
15
|
+
const FILL_STEP_RUNGS = { light: [600, 700], dark: [400, 300] };
|
|
16
|
+
/**
|
|
17
|
+
* Lightest rung on `scale` that still carries `white` at WCAG AA. Prefers [500] when it already
|
|
18
|
+
* passes; otherwise walks toward darker rungs. Used for solid fills on buttons, tags, badges and
|
|
19
|
+
* table status pills so consumers never get black ink on a saturated fill when white is achievable.
|
|
20
|
+
*/
|
|
21
|
+
const solidFillRung = (scale, white) => {
|
|
22
|
+
if ((0, color_1.contrastRatio)(scale[500], white) >= accentText_1.AA_NORMAL_TEXT)
|
|
23
|
+
return 500;
|
|
24
|
+
const passing = RUNGS.filter((r) => scale[r] && (0, color_1.contrastRatio)(scale[r], white) >= accentText_1.AA_NORMAL_TEXT);
|
|
25
|
+
if (!passing.length)
|
|
26
|
+
return 500;
|
|
27
|
+
return passing.reduce((a, b) => (0, color_1.contrastRatio)(scale[a], white) <= (0, color_1.contrastRatio)(scale[b], white) ? a : b);
|
|
28
|
+
};
|
|
29
|
+
exports.solidFillRung = solidFillRung;
|
|
30
|
+
const steppedRung = (base, canvas, step) => {
|
|
31
|
+
const dir = (0, accentText_1.isDarkCanvas)(canvas) ? -100 : 100;
|
|
32
|
+
return Math.min(900, Math.max(50, base + dir * step));
|
|
33
|
+
};
|
|
34
|
+
/** Hover (step 0) or active (step 1) fill rung, one step darker than `solidFillRung`. */
|
|
35
|
+
const darkerFillRung = (scale, canvas, white, step) => {
|
|
36
|
+
const base = (0, exports.solidFillRung)(scale, white);
|
|
37
|
+
if (base === 500) {
|
|
38
|
+
const mode = (0, accentText_1.isDarkCanvas)(canvas) ? "dark" : "light";
|
|
39
|
+
return FILL_STEP_RUNGS[mode][step];
|
|
40
|
+
}
|
|
41
|
+
const stepped = steppedRung(base, canvas, step === 0 ? 1 : 2);
|
|
42
|
+
return stepped;
|
|
43
|
+
};
|
|
44
|
+
exports.darkerFillRung = darkerFillRung;
|
|
45
|
+
/** Label ink for a specific fill swatch — always `onFilled`, exported for style configs. */
|
|
46
|
+
const labelOnFill = (fill, white, black) => (0, accentText_1.onFilled)(fill, white, black);
|
|
47
|
+
exports.labelOnFill = labelOnFill;
|
|
48
|
+
/**
|
|
49
|
+
* Consumer-facing helper: given any `ColorScale` (primary, red, semantic.error, …), return the
|
|
50
|
+
* fill rung and matching ink for solid / hover / active states. Use this whenever you paint a
|
|
51
|
+
* `bg` from a scale — never pair `scale[500]` with `onFilled` or `colors.white` by hand.
|
|
52
|
+
*/
|
|
53
|
+
const resolveFilledSurface = (scale, colors) => {
|
|
54
|
+
const { white, black, backgroundColor } = colors;
|
|
55
|
+
const canvas = backgroundColor.main;
|
|
56
|
+
const rung = (0, exports.solidFillRung)(scale, white);
|
|
57
|
+
const fill = scale[rung];
|
|
58
|
+
const hoverRung = (0, exports.darkerFillRung)(scale, canvas, white, 0);
|
|
59
|
+
const hoverFill = scale[hoverRung];
|
|
60
|
+
const activeRung = (0, exports.darkerFillRung)(scale, canvas, white, 1);
|
|
61
|
+
const activeFill = scale[activeRung];
|
|
62
|
+
return {
|
|
63
|
+
rung,
|
|
64
|
+
fill,
|
|
65
|
+
color: (0, exports.labelOnFill)(fill, white, black),
|
|
66
|
+
hoverRung,
|
|
67
|
+
hoverFill,
|
|
68
|
+
hoverColor: (0, exports.labelOnFill)(hoverFill, white, black),
|
|
69
|
+
activeRung,
|
|
70
|
+
activeFill,
|
|
71
|
+
activeColor: (0, exports.labelOnFill)(activeFill, white, black),
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
exports.resolveFilledSurface = resolveFilledSurface;
|
package/dist/Utils/table.js
CHANGED
|
@@ -45,6 +45,7 @@ exports.useDebounce = useDebounce;
|
|
|
45
45
|
exports.globalSearchFilter = globalSearchFilter;
|
|
46
46
|
const react_1 = __importStar(require("react"));
|
|
47
47
|
const accentText_1 = require("../Theme/tokens/builders/accentText");
|
|
48
|
+
const filledSurface_1 = require("../Theme/tokens/builders/filledSurface");
|
|
48
49
|
const statusTone_1 = require("../Theme/tokens/builders/statusTone");
|
|
49
50
|
// Built once, not per comparison: sorting 10k rows runs this ~130k times, and constructing a
|
|
50
51
|
// collator is orders of magnitude dearer than using one.
|
|
@@ -117,11 +118,13 @@ function buildTablePalette(theme) {
|
|
|
117
118
|
];
|
|
118
119
|
return scales.map((scale) => {
|
|
119
120
|
const tone = (0, statusTone_1.resolveStatusTone)(scale, mode);
|
|
121
|
+
const solidRung = (0, filledSurface_1.solidFillRung)(scale, c.white);
|
|
122
|
+
const solid = scale[solidRung];
|
|
120
123
|
return {
|
|
121
|
-
solid
|
|
124
|
+
solid,
|
|
122
125
|
soft: tone.bg,
|
|
123
126
|
text: tone.fg,
|
|
124
|
-
onSolid: (0,
|
|
127
|
+
onSolid: (0, filledSurface_1.labelOnFill)(solid, c.white, c.black),
|
|
125
128
|
};
|
|
126
129
|
});
|
|
127
130
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { accentTextOnCanvas
|
|
2
|
-
import {
|
|
1
|
+
import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
|
|
2
|
+
import { darkerFillRung, labelOnFill, 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";
|
|
5
5
|
/**
|
|
@@ -19,14 +19,15 @@ const onCanvasHoverBg = (theme, colorScheme, step) => {
|
|
|
19
19
|
const scale = theme.colors[colorScheme];
|
|
20
20
|
return "opacity" in scale ? scale.opacity[step] : scale[50];
|
|
21
21
|
};
|
|
22
|
-
const
|
|
22
|
+
const swatch = (theme, colorScheme) => theme.colors[colorScheme];
|
|
23
|
+
const solidRung = (theme, colorScheme) => solidFillRung(swatch(theme, colorScheme), theme.colors.white);
|
|
23
24
|
const darkerFill = (theme, colorScheme, step) => {
|
|
24
|
-
const scale = theme
|
|
25
|
-
const
|
|
26
|
-
return scale[
|
|
25
|
+
const scale = swatch(theme, colorScheme);
|
|
26
|
+
const rung = darkerFillRung(scale, theme.colors.backgroundColor.main, theme.colors.white, step);
|
|
27
|
+
return scale[rung];
|
|
27
28
|
};
|
|
28
29
|
/** Label for the solid variant's filled bg — derived from THAT fill, since hover/active swap it. */
|
|
29
|
-
const labelFor = (theme, fill) =>
|
|
30
|
+
const labelFor = (theme, fill) => labelOnFill(fill, theme.colors.white, theme.colors.black);
|
|
30
31
|
/**
|
|
31
32
|
* The two-tone `:focus-visible` ring, from the palette's derived `focusRing` pair.
|
|
32
33
|
*
|
|
@@ -52,7 +53,7 @@ export const Button = {
|
|
|
52
53
|
}),
|
|
53
54
|
variants: {
|
|
54
55
|
solid: ({ theme, colorScheme = "primary" }) => {
|
|
55
|
-
const fill = theme.colors[colorScheme][
|
|
56
|
+
const fill = theme.colors[colorScheme][solidRung(theme, colorScheme)];
|
|
56
57
|
const hoverFill = darkerFill(theme, colorScheme, 0);
|
|
57
58
|
const activeFill = darkerFill(theme, colorScheme, 1);
|
|
58
59
|
const hoverLabel = labelFor(theme, hoverFill);
|
|
@@ -86,7 +87,7 @@ export const Button = {
|
|
|
86
87
|
},
|
|
87
88
|
outline: ({ theme, colorScheme = "primary" }) => {
|
|
88
89
|
// Same rung as `solid`'s fill, not raw [500] — keeps hover bg AA-safe for white text.
|
|
89
|
-
const hoverFill = theme.colors[colorScheme][
|
|
90
|
+
const hoverFill = theme.colors[colorScheme][solidRung(theme, colorScheme)];
|
|
90
91
|
const activeFill = darkerFill(theme, colorScheme, 0);
|
|
91
92
|
const ink = onCanvasText(theme, colorScheme);
|
|
92
93
|
return {
|
|
@@ -2,18 +2,24 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
import { Box, Badge, Flex, GridItem, Heading, Icon, Text, VStack, Skeleton, SkeletonText, } from "@chakra-ui/react";
|
|
3
3
|
import { Check } from "lucide-react";
|
|
4
4
|
import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveFilledSurface } from "../../../Theme/tokens/builders/filledSurface.js";
|
|
6
6
|
import Button from "../../Button/Button.js";
|
|
7
7
|
const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
|
|
8
|
-
const withOnButtonColor = (styles) =>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const withOnButtonColor = (styles) => {
|
|
9
|
+
const scale = theme.colors[styles.buttonScale];
|
|
10
|
+
const solid = resolveFilledSurface(scale, theme.colors);
|
|
11
|
+
return {
|
|
12
|
+
...styles,
|
|
13
|
+
buttonColor: solid.fill,
|
|
14
|
+
onButtonColor: solid.color,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
12
17
|
if (isActive) {
|
|
13
18
|
return withOnButtonColor({
|
|
14
19
|
badgeText: "Active Plan",
|
|
15
20
|
badgeColor: `0.125rem solid ${theme.colors.green[500]}`,
|
|
16
21
|
buttonColor: theme.colors.green[500],
|
|
22
|
+
buttonScale: "green",
|
|
17
23
|
buttonColor50: theme.colors.green[50],
|
|
18
24
|
colorScheme: "green",
|
|
19
25
|
});
|
|
@@ -23,6 +29,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
|
|
|
23
29
|
badgeText: "Upgrade Your Plan",
|
|
24
30
|
badgeColor: `0.125rem solid ${theme.colors.primary[500]}`,
|
|
25
31
|
buttonColor: theme.colors.primary[500],
|
|
32
|
+
buttonScale: "primary",
|
|
26
33
|
buttonColor50: theme.colors.primary[50],
|
|
27
34
|
colorScheme: "primary",
|
|
28
35
|
});
|
|
@@ -32,6 +39,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
|
|
|
32
39
|
badgeText: "Most Popular",
|
|
33
40
|
badgeColor: `0.125rem solid ${theme.colors.primary[500]}`,
|
|
34
41
|
buttonColor: theme.colors.primary[500],
|
|
42
|
+
buttonScale: "primary",
|
|
35
43
|
buttonColor50: theme.colors.primary[50],
|
|
36
44
|
colorScheme: "primary",
|
|
37
45
|
});
|
|
@@ -40,6 +48,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
|
|
|
40
48
|
badgeText: "",
|
|
41
49
|
badgeColor: "",
|
|
42
50
|
buttonColor: theme.colors.primary[500],
|
|
51
|
+
buttonScale: "primary",
|
|
43
52
|
buttonColor50: theme.colors.primary[50],
|
|
44
53
|
colorScheme: "primary",
|
|
45
54
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { HStack, Text } from "@chakra-ui/react";
|
|
3
3
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
|
|
5
5
|
const ErrorComponent = ({ error, errorClassName, }) => {
|
|
6
6
|
const { colors } = useCustomTheme();
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
7
|
+
const errorText = colors.semanticText.error;
|
|
8
|
+
const errorSolid = resolveFilledSurface(colors.semantic.error, colors);
|
|
9
|
+
const errorFill = errorSolid.fill;
|
|
10
|
+
const markInk = errorSolid.color;
|
|
11
|
+
return (_jsxs(HStack, { as: "p", align: "flex-start", spacing: 1, mt: 1, fontSize: "sm", color: errorText, className: errorClassName, children: [_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 100 100", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, children: [_jsx("circle", { cx: "50", cy: "50", r: "50", fill: errorFill }), _jsx("rect", { x: "46", y: "40", width: "8", height: "30", rx: "2", fill: markInk }), _jsx("circle", { cx: "50", cy: "28", r: "4", fill: markInk })] }), _jsx(Text, { as: "span", children: error })] }));
|
|
11
12
|
};
|
|
12
13
|
export default ErrorComponent;
|
|
@@ -4,7 +4,7 @@ import { format, startOfMonth, endOfMonth, startOfWeek, endOfWeek, addDays } fro
|
|
|
4
4
|
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
5
5
|
import Button from "../Button/Button.js";
|
|
6
6
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
7
|
-
import {
|
|
7
|
+
import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
|
|
8
8
|
import { DAY_CLASS, dayAccessibleName, dayStateClassName, resolveDayStateVisual, } from "./dayStates.js";
|
|
9
9
|
export const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, tempDate, tempRangeStart, tempRangeEnd, isSameDay, isBefore, isAfter, minDate, maxDate, disablePastDates, disableFutureDates, disableToday, onDaySelect, hoveredDate, onDayHover, renderWeekdays, dayStates, renderDayContent, }) => {
|
|
10
10
|
const theme = useCustomTheme();
|
|
@@ -95,16 +95,15 @@ export const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, t
|
|
|
95
95
|
// Solid fill (selected/range-endpoint) needs the ink checked against that
|
|
96
96
|
// specific fill — `primary[500]` doesn't reliably clear AA for white text on
|
|
97
97
|
// every brand/mode (same gap the solid Button variant already accounts for).
|
|
98
|
-
const
|
|
99
|
-
const
|
|
98
|
+
const primarySolid = resolveFilledSurface(theme.colors.primary, theme.colors);
|
|
99
|
+
const solidFill = primarySolid.fill;
|
|
100
|
+
const solidHoverFill = primarySolid.hoverFill;
|
|
100
101
|
const circleColor = circleSolid
|
|
101
|
-
?
|
|
102
|
+
? primarySolid.color
|
|
102
103
|
: isInCurrentMonth
|
|
103
104
|
? theme.colors.text[700]
|
|
104
105
|
: theme.colors.gray[400];
|
|
105
|
-
const circleHoverColor = circleSolid
|
|
106
|
-
? onFilled(solidHoverFill, theme.colors.white, theme.colors.black)
|
|
107
|
-
: circleColor;
|
|
106
|
+
const circleHoverColor = circleSolid ? primarySolid.hoverColor : circleColor;
|
|
108
107
|
const circleBorder = circleSolid
|
|
109
108
|
? "1px solid transparent"
|
|
110
109
|
: isTentativeEnd
|
|
@@ -4,6 +4,7 @@ import { Box, Flex, IconButton, Image, Modal, ModalBody, ModalCloseButton, Modal
|
|
|
4
4
|
import { motion } from "framer-motion";
|
|
5
5
|
import { Download, Eye, FileQuestion, Minus, Plus, RotateCw, } from "lucide-react";
|
|
6
6
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
7
|
+
import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
|
|
7
8
|
import ToolTip from "../ToolTip/ToolTip.js";
|
|
8
9
|
const MotionContent = motion(ModalContent);
|
|
9
10
|
const inferKind = (url, fileName) => {
|
|
@@ -56,7 +57,7 @@ export const FilePreview = ({ isOpen, onClose, fileUrl, fileName, fileType, hide
|
|
|
56
57
|
if (kind === "video") {
|
|
57
58
|
return (_jsx(Box, { as: "video", src: fileUrl, controls: true, width: "100%", borderRadius: "lg" }));
|
|
58
59
|
}
|
|
59
|
-
return (_jsxs(Flex, { direction: "column", align: "center", justify: "center", py: 12, gap: 3, children: [_jsx(FileQuestion, { size: 48, color: theme.colors.textMuted }), _jsx(Text, { color: theme.colors.textMuted, fontSize: "sm", children: "Preview isn't available for this file type." }), !hideDownload && (_jsxs(Flex, { as: "button", align: "center", gap: 2, px: 4, py: 2, borderRadius: "lg", bg: theme.colors.primary[
|
|
60
|
+
return (_jsxs(Flex, { direction: "column", align: "center", justify: "center", py: 12, gap: 3, children: [_jsx(FileQuestion, { size: 48, color: theme.colors.textMuted }), _jsx(Text, { color: theme.colors.textMuted, fontSize: "sm", children: "Preview isn't available for this file type." }), !hideDownload && (_jsxs(Flex, { as: "button", align: "center", gap: 2, px: 4, py: 2, borderRadius: "lg", bg: theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], color: labelOnFill(theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], theme.colors.white, theme.colors.black), fontSize: "sm", fontWeight: 500, onClick: () => downloadFile(fileUrl, fileName), children: [_jsx(Download, { size: 16 }), " Download file"] }))] }));
|
|
60
61
|
};
|
|
61
62
|
return (_jsxs(Modal, { isOpen: isOpen, onClose: handleClose, size: size, isCentered: true, children: [_jsx(ModalOverlay, { bg: "blackAlpha.600", backdropFilter: "blur(4px)" }), _jsxs(MotionContent
|
|
62
63
|
// Chakra's default Modal drives its bg off `--modal-bg`, which flips to
|
|
@@ -4,10 +4,9 @@ import Select from "../../Select/Select.js";
|
|
|
4
4
|
import { CirclePlus, SquarePen } from "lucide-react";
|
|
5
5
|
import VeritcalDivider from "../../Divider/Divider.js";
|
|
6
6
|
import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
|
|
7
|
-
import { onFilled } from "../../../Theme/tokens/builders/accentText.js";
|
|
8
7
|
import Button from "../../Button/Button.js";
|
|
9
8
|
const KanbanActions = ({ options, onSelectChange, onEdit, onCreate, }) => {
|
|
10
9
|
const { colors } = useCustomTheme();
|
|
11
|
-
return (_jsxs(Box, { display: "flex", alignItems: "center", gap: "0.625rem", children: [_jsx(Select, { options: options, placeholder: "Filter by Status", width: "12.5rem", onChange: (option) => onSelectChange && onSelectChange(option) }), _jsxs(Box, { display: "flex", alignItems: "center", gap: "0.5rem", children: [_jsx(Button, { size: "sm", variant: "ghost", leftIcon: _jsx(SquarePen, { size: 20, color: colors.text[500] }), onClick: () => onEdit === null || onEdit === void 0 ? void 0 : onEdit(), children: "Edit Layout" }), _jsx(VeritcalDivider, {}), _jsx(Button, { size: "sm", variant: "solid", leftIcon: _jsx(CirclePlus, { size: 20
|
|
10
|
+
return (_jsxs(Box, { display: "flex", alignItems: "center", gap: "0.625rem", children: [_jsx(Select, { options: options, placeholder: "Filter by Status", width: "12.5rem", onChange: (option) => onSelectChange && onSelectChange(option) }), _jsxs(Box, { display: "flex", alignItems: "center", gap: "0.5rem", children: [_jsx(Button, { size: "sm", variant: "ghost", leftIcon: _jsx(SquarePen, { size: 20, color: colors.text[500] }), onClick: () => onEdit === null || onEdit === void 0 ? void 0 : onEdit(), children: "Edit Layout" }), _jsx(VeritcalDivider, {}), _jsx(Button, { size: "sm", variant: "solid", leftIcon: _jsx(CirclePlus, { size: 20 }), onClick: () => onCreate === null || onCreate === void 0 ? void 0 : onCreate(), children: "Create New" })] })] }));
|
|
12
11
|
};
|
|
13
12
|
export default KanbanActions;
|
|
@@ -3,7 +3,8 @@ import { useMemo, useState } from "react";
|
|
|
3
3
|
import { Avatar, Badge, Box, Flex, Heading, HStack, IconButton, Input, Skeleton, SkeletonText, Spinner, Text, Tooltip, VStack, } from "@chakra-ui/react";
|
|
4
4
|
import { ArrowLeft, Building2, Check, CheckCircle2, Crown, Globe, Mail, Pencil, Plus, Trash2, Users, X, } from "lucide-react";
|
|
5
5
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
6
|
-
import { accentTextOnCanvas, isDarkCanvas
|
|
6
|
+
import { accentTextOnCanvas, isDarkCanvas } from "../../Theme/tokens/builders/accentText.js";
|
|
7
|
+
import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
|
|
7
8
|
import { resolveStatusTone } from "../../Theme/tokens/builders/statusTone.js";
|
|
8
9
|
import Button from "../Button/Button.js";
|
|
9
10
|
import EmptyState from "../EmptyState/EmptyState.js";
|
|
@@ -67,7 +68,7 @@ const OrganizationDetails = ({ activeOrganizations, invitedOrganizations, isLoad
|
|
|
67
68
|
const pageBg = colors.backgroundColor.main;
|
|
68
69
|
const primary50 = colors.primary[50];
|
|
69
70
|
const primary100 = colors.primary[100];
|
|
70
|
-
const
|
|
71
|
+
const primarySolid = resolveFilledSurface(colors.primary, colors);
|
|
71
72
|
const onPrimary50 = accentTextOnCanvas(colors.primary, colors.primary[50]);
|
|
72
73
|
const cardSx = {
|
|
73
74
|
backgroundColor: surface,
|
|
@@ -153,7 +154,7 @@ const OrganizationDetails = ({ activeOrganizations, invitedOrganizations, isLoad
|
|
|
153
154
|
width: "100%",
|
|
154
155
|
};
|
|
155
156
|
const hasOrganizations = activeOrganizations.length > 0 || invitedOrganizations.length > 0;
|
|
156
|
-
return (_jsxs(Box, { backgroundColor: pageBg, minHeight: "100%", p: { base: 2, md: 3 }, children: [_jsxs(Flex, { ...cardSx, px: 3, py: 2.5, mb: 3, alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 3, bgGradient: `linear(135deg, ${primary50} 0%, ${primary100} 100%)`, children: [_jsxs(Flex, { alignItems: "center", gap: 3, children: [onBack && (_jsx(IconButton, { "aria-label": "Go back", icon: _jsx(ArrowLeft, { size: 18 }), variant: "ghost", size: "sm", color: subtle, onClick: onBack })), _jsx(Flex, { align: "center", justify: "center", boxSize: "36px", borderRadius: "full", bg:
|
|
157
|
+
return (_jsxs(Box, { backgroundColor: pageBg, minHeight: "100%", p: { base: 2, md: 3 }, children: [_jsxs(Flex, { ...cardSx, px: 3, py: 2.5, mb: 3, alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 3, bgGradient: `linear(135deg, ${primary50} 0%, ${primary100} 100%)`, children: [_jsxs(Flex, { alignItems: "center", gap: 3, children: [onBack && (_jsx(IconButton, { "aria-label": "Go back", icon: _jsx(ArrowLeft, { size: 18 }), variant: "ghost", size: "sm", color: subtle, onClick: onBack })), _jsx(Flex, { align: "center", justify: "center", boxSize: "36px", borderRadius: "full", bg: primarySolid.fill, color: primarySolid.color, children: _jsx(Building2, { size: 18 }) }), _jsxs(Box, { children: [_jsxs(HStack, { spacing: 2, children: [_jsx(Heading, { size: "sm", color: heading, fontWeight: 700, children: userName
|
|
157
158
|
? `${labels.greeting.replace(/User!?/, "")}${userName}!`.trim()
|
|
158
159
|
: labels.greeting }), _jsx(Avatar, { size: "xs", name: userName, src: userAvatarUrl })] }), _jsx(Text, { fontSize: "xs", color: subtle, mt: 0.5, children: labels.manageSubtitle })] })] }), _jsx(Button, { label: labels.createNewOrganization, onClick: () => setCreateOpen(true), leftIcon: _jsx(Plus, { size: 16 }), colorScheme: "primary", size: "sm" })] }), isLoading ? (_jsx(Box, { ...gridSx, children: Array.from({ length: 6 }).map((_, idx) => (_jsxs(Box, { ...cardSx, p: 3, children: [_jsx(Skeleton, { boxSize: "36px", borderRadius: "lg", mb: 2 }), _jsx(SkeletonText, { noOfLines: 2, spacing: 2 })] }, idx))) })) : !hasOrganizations ? (_jsx(EmptyState, { icon: Building2, title: labels.noOrganizationsTitle, description: labels.noOrganizationsDescription, minH: "40vh", action: _jsx(Button, { label: labels.createOrganization, onClick: () => setCreateOpen(true), leftIcon: _jsx(Plus, { size: 16 }), colorScheme: "primary", size: "sm" }) })) : (_jsxs(VStack, { align: "stretch", spacing: 4, children: [activeOrganizations.length > 0 && (_jsxs(Box, { children: [_jsxs(Flex, { align: "center", gap: 2, mb: 2, children: [_jsx(Users, { size: 16, color: colors.accentText }), _jsx(Heading, { size: "sm", color: heading, fontWeight: 600, children: labels.activeOrganizations }), sectionBadge(activeOrganizations.length, "blue")] }), _jsx(Box, { ...gridSx, children: activeOrganizations.map(renderActiveCard) })] })), invitedOrganizations.length > 0 && (_jsxs(Box, { children: [_jsxs(Flex, { align: "center", gap: 2, mb: 2, children: [_jsx(Mail, { size: 16, color: colors.semanticText.warning }), _jsx(Heading, { size: "sm", color: heading, fontWeight: 600, children: labels.invitedOrganizations }), sectionBadge(invitedOrganizations.length, "yellow")] }), _jsx(Box, { ...gridSx, children: invitedOrganizations.map(renderInvitedCard) })] }))] })), footerSlot, _jsx(CreateOrgModal, { isOpen: isCreateOpen, onClose: () => setCreateOpen(false), isLoading: isCreating, onSubmit: async (values) => {
|
|
159
160
|
await (onCreateOrganization === null || onCreateOrganization === void 0 ? void 0 : onCreateOrganization(values));
|
|
@@ -3,7 +3,8 @@ import { useRef, useState } from "react";
|
|
|
3
3
|
import { Box, Image, IconButton, Input, Text, Tooltip, HStack, } from "@chakra-ui/react";
|
|
4
4
|
import { Eye, FileText, SquarePen, User } from "lucide-react";
|
|
5
5
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
6
|
-
import { accentTextOnCanvas
|
|
6
|
+
import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
|
|
7
|
+
import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
|
|
7
8
|
export default function ProfilePhotoViewer({ photoUrl, onPhotoChange, imageWidth = "100px", imageAlt = "Profile Photo", imageObjectFit = "cover", imageBorderRadius = "full", editIconSize = "sm", editIconPositionRight = "0px", editIconPositionBottom = "0px", isRound = true, boxStyle, isEditable = false, isView = false, style, handleIsView, fallbackText, revealOnHover = true, }) {
|
|
8
9
|
var _a, _b, _c, _d, _e;
|
|
9
10
|
const [photo, setPhoto] = useState(photoUrl);
|
|
@@ -57,14 +58,14 @@ export default function ProfilePhotoViewer({ photoUrl, onPhotoChange, imageWidth
|
|
|
57
58
|
"&:hover .ppv-media": {
|
|
58
59
|
boxShadow: `0 0 0 0.1875rem ${c.primary.opacity[24]}`,
|
|
59
60
|
},
|
|
60
|
-
}, children: [_jsx(Box, { className: "ppv-media", borderRadius: imageBorderRadius, transition: "box-shadow 0.2s ease", children: renderMedia() }), hasActions && (_jsxs(_Fragment, { children: [_jsx(Box, { className: "ppv-overlay", position: "absolute", inset: 0, borderRadius: imageBorderRadius, bg: "blackAlpha.300", opacity: 0, transition: "opacity 0.2s ease", pointerEvents: "none" }), _jsxs(HStack, { className: "ppv-actions", position: "absolute", right: editIconPositionRight, bottom: editIconPositionBottom, transform: "translate(-15%, -15%)", spacing: 1.5, opacity: revealOnHover ? 0 : 1, transition: "opacity 0.2s ease", children: [isEditable && (_jsx(Tooltip, { label: "Edit", "aria-label": "Edit", hasArrow: true, children: _jsx(IconButton, { icon: _jsx(SquarePen, { size: 14 }), isRound: isRound, size: editIconSize, onClick: handleClick, "aria-label": "Edit photo", bg: c.primary[
|
|
61
|
+
}, children: [_jsx(Box, { className: "ppv-media", borderRadius: imageBorderRadius, transition: "box-shadow 0.2s ease", children: renderMedia() }), hasActions && (_jsxs(_Fragment, { children: [_jsx(Box, { className: "ppv-overlay", position: "absolute", inset: 0, borderRadius: imageBorderRadius, bg: "blackAlpha.300", opacity: 0, transition: "opacity 0.2s ease", pointerEvents: "none" }), _jsxs(HStack, { className: "ppv-actions", position: "absolute", right: editIconPositionRight, bottom: editIconPositionBottom, transform: "translate(-15%, -15%)", spacing: 1.5, opacity: revealOnHover ? 0 : 1, transition: "opacity 0.2s ease", children: [isEditable && (_jsx(Tooltip, { label: "Edit", "aria-label": "Edit", hasArrow: true, children: _jsx(IconButton, { icon: _jsx(SquarePen, { size: 14 }), isRound: isRound, size: editIconSize, onClick: handleClick, "aria-label": "Edit photo", bg: c.primary[solidFillRung(c.primary, c.white)], color: labelOnFill(c.primary[solidFillRung(c.primary, c.white)], c.white, c.black), border: `0.125rem solid ${c.background[50]}`, boxShadow: (_b = theme.shadows) === null || _b === void 0 ? void 0 : _b.md, style: style, transition: "transform 0.2s ease, background 0.2s ease, box-shadow 0.2s ease", _hover: {
|
|
61
62
|
bg: c.primary[600],
|
|
62
|
-
color:
|
|
63
|
+
color: labelOnFill(c.primary[600], c.white, c.black),
|
|
63
64
|
transform: "scale(1.1)",
|
|
64
65
|
boxShadow: (_c = theme.shadows) === null || _c === void 0 ? void 0 : _c.lg,
|
|
65
66
|
}, _active: {
|
|
66
67
|
bg: c.primary[700],
|
|
67
|
-
color:
|
|
68
|
+
color: labelOnFill(c.primary[700], c.white, c.black),
|
|
68
69
|
} }) })), isView && (_jsx(Tooltip, { label: "View", "aria-label": "View", hasArrow: true, children: _jsx(IconButton, { icon: _jsx(Eye, { size: 14 }), isRound: isRound, size: editIconSize, onClick: handleIsView, "aria-label": "View photo", bg: c.background[50], color: c.text[700], border: `0.063rem solid ${border}`, boxShadow: (_d = theme.shadows) === null || _d === void 0 ? void 0 : _d.md, style: style, transition: "transform 0.2s ease, background 0.2s ease, box-shadow 0.2s ease", _hover: {
|
|
69
70
|
bg: c.gray[50],
|
|
70
71
|
color: accentTextOnCanvas(c.primary, c.gray[50]),
|
|
@@ -5,7 +5,7 @@ import { ChevronUp } from "lucide-react";
|
|
|
5
5
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
6
6
|
import ToolTip from "../ToolTip/ToolTip.js";
|
|
7
7
|
import { rafThrottle } from "../../Utils/rafThrottle.js";
|
|
8
|
-
import {
|
|
8
|
+
import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
|
|
9
9
|
const ScrollToTop = ({ children, tooltipLabel = "Scroll to top", threshold = 300, duration = 600, useWindow = false, bottom = "2rem", right = "2rem", }) => {
|
|
10
10
|
const [visible, setVisible] = useState(false);
|
|
11
11
|
const anchorRef = useRef(null);
|
|
@@ -58,9 +58,9 @@ const ScrollToTop = ({ children, tooltipLabel = "Scroll to top", threshold = 300
|
|
|
58
58
|
};
|
|
59
59
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
60
60
|
}, [useWindow, threshold]);
|
|
61
|
-
return (_jsxs(Box, { ref: anchorRef, position: "relative", children: [children, _jsx(ToolTip, { label: tooltipLabel, placement: "left", children: _jsx(Box, { as: "button", type: "button", onClick: scrollToTop, "aria-label": tooltipLabel, border: "none", position: "fixed", bottom: bottom, right: right, zIndex: 1000, display: "flex", alignItems: "center", justifyContent: "center", boxSize: "44px", borderRadius: "full", cursor: "pointer", bg: theme.colors.primary[
|
|
61
|
+
return (_jsxs(Box, { ref: anchorRef, position: "relative", children: [children, _jsx(ToolTip, { label: tooltipLabel, placement: "left", children: _jsx(Box, { as: "button", type: "button", onClick: scrollToTop, "aria-label": tooltipLabel, border: "none", position: "fixed", bottom: bottom, right: right, zIndex: 1000, display: "flex", alignItems: "center", justifyContent: "center", boxSize: "44px", borderRadius: "full", cursor: "pointer", bg: theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], color: labelOnFill(theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], theme.colors.white, theme.colors.black), boxShadow: "md", opacity: visible ? 1 : 0, transform: visible ? "translateY(0) scale(1)" : "translateY(16px) scale(0.85)", pointerEvents: visible ? "auto" : "none", transition: "all 0.25s cubic-bezier(0.16, 1, 0.3, 1)", _hover: {
|
|
62
62
|
bg: theme.colors.primary[600],
|
|
63
|
-
color:
|
|
63
|
+
color: labelOnFill(theme.colors.primary[600], theme.colors.white, theme.colors.black),
|
|
64
64
|
transform: "translateY(-2px) scale(1.05)",
|
|
65
65
|
boxShadow: "lg",
|
|
66
66
|
}, _active: { transform: "scale(0.95)" }, children: _jsx(ChevronUp, { size: 24, strokeWidth: 2.5 }) }) })] }));
|
|
@@ -243,7 +243,7 @@ BottomIcon = false, BottomText, handleBottomClick, BottomTextColor, isColorOptio
|
|
|
243
243
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
244
244
|
};
|
|
245
245
|
}, [isOpen]);
|
|
246
|
-
return (_jsx(_Fragment, { children: _jsx(FormControl, { isInvalid: error, children: _jsxs(Box, { display: "flex", flexDirection: "column", position: "relative", sx: boxStyle, children: [label && (_jsx(TextLabel, { label: label, id: id, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), isMultipleSelect && selectedOptions.length > 0 && (_jsx(HStack, { spacing: 2, mb: 2, children: selectedOptions.map((option) => (_jsxs(Tag, { size: "md", borderRadius: "full", variant: "solid",
|
|
246
|
+
return (_jsx(_Fragment, { children: _jsx(FormControl, { isInvalid: error, children: _jsxs(Box, { display: "flex", flexDirection: "column", position: "relative", sx: boxStyle, children: [label && (_jsx(TextLabel, { label: label, id: id, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), isMultipleSelect && selectedOptions.length > 0 && (_jsx(HStack, { spacing: 2, mb: 2, children: selectedOptions.map((option) => (_jsxs(Tag, { size: "md", borderRadius: "full", variant: "solid", colorScheme: "primary", children: [_jsx(TagLabel, { width: "50px", children: option.label }), _jsx(TagCloseButton, { onClick: () => handleRemoveOption(option) })] }, option.id))) })), _jsxs(InputGroup, { children: [_jsx(Input, { ref: inputRef, variant: "outline", borderRadius: FIELD_RADIUS, value: inputValue ? inputValue : "", onClick: () => setIsOpen(true), onFocus: () => {
|
|
247
247
|
if (skipNextInputFocusOpen.current) {
|
|
248
248
|
skipNextInputFocusOpen.current = false;
|
|
249
249
|
return;
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { Flex, Text, Image, Box, Skeleton, useBreakpointValue } from "@chakra-ui/react";
|
|
4
4
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
5
|
-
import {
|
|
5
|
+
import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
|
|
6
6
|
import { getSidebarActiveAccent } from "./sidebarAccentColors.js";
|
|
7
7
|
import { FlexCss, HEADER_HEIGHT } from "../../Constants/Sidebar.js";
|
|
8
8
|
import { ArrowLeftToLine, ArrowRightToLine, ChevronLeft, Maximize2, MoreVertical, PanelLeft, Plus, X } from "lucide-react";
|
|
@@ -27,7 +27,9 @@ const SidebarHeader = ({ logo, companyName, companySubtitle, toggle, isLoading,
|
|
|
27
27
|
if (isLoading) {
|
|
28
28
|
return (_jsx(Box, { w: "100%", px: toggle ? 2 : 4, py: 2, h: HEADER_HEIGHT, display: "flex", alignItems: "center", flexShrink: 0, children: toggle ? (_jsx(Flex, { align: "center", gap: 4, justifyContent: "center", w: "100%", children: _jsx(Skeleton, { w: "28px", h: "28px", borderRadius: "md", startColor: theme.colors.sidebar.background[400], endColor: theme.colors.sidebar.background[300] }) })) : (_jsxs(Flex, { align: "center", gap: 3, w: "100%", children: [_jsx(Skeleton, { w: "28px", h: "28px", borderRadius: "md", startColor: theme.colors.sidebar.background[400], endColor: theme.colors.sidebar.background[300] }), _jsx(Skeleton, { h: "1.25rem", w: "60%", borderRadius: "md", startColor: theme.colors.sidebar.background[400], endColor: theme.colors.sidebar.background[300] })] })) }));
|
|
29
29
|
}
|
|
30
|
-
const
|
|
30
|
+
const primaryFillRung = solidFillRung(theme.colors.primary, theme.colors.white);
|
|
31
|
+
const primaryFill = theme.colors.primary[primaryFillRung];
|
|
32
|
+
const logoNode = logo ? (_jsx(Image, { borderRadius: "md", boxSize: "1.75rem", src: logo, alt: "Company Logo", flexShrink: 0, cursor: toggle ? "pointer" : undefined, onClick: toggle ? onToggle : undefined })) : (_jsx(Box, { bg: primaryFill, color: labelOnFill(primaryFill, theme.colors.white, theme.colors.black), borderRadius: "md", boxSize: "1.75rem", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: "bold", flexShrink: 0, cursor: toggle ? "pointer" : undefined, onClick: toggle ? onToggle : undefined, children: _jsx(DefaultLogo, {}) }));
|
|
31
33
|
return (_jsxs(Flex, { h: HEADER_HEIGHT, w: "100%", alignItems: "center", justifyContent: toggle ? "center" : "flex-start", gap: "8px", px: toggle ? "8px" : "10px", borderBottom: "1px solid", borderColor: "whiteAlpha.100", minW: 0, overflow: "hidden", flexShrink: 0, children: [logoNode, !toggle && (_jsxs(Box, { flex: "1", minW: 0, children: [_jsx(OverflowTooltipText, { placement: "right", fontWeight: 600, fontSize: "12.5px", textAlign: "left", color: theme.colors.white, lineHeight: "1.3", as: "p", width: "100%", children: companyName !== null && companyName !== void 0 ? companyName : "" }), companySubtitle && (_jsx(Text, { fontSize: "10px", color: theme.colors.sidebar.mutedLabel, lineHeight: "1.3", isTruncated: true, children: companySubtitle }))] })), !toggle && (_jsx(Box, { as: "button", type: "button", onClick: overlay ? onClose : onToggle, "aria-label": overlay ? "Close menu" : "Collapse sidebar", w: "22px", h: "22px", borderRadius: "base", bg: "whiteAlpha.100", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, _hover: { bg: "whiteAlpha.300" }, transition: "background 0.15s", children: overlay ? (_jsx(X, { size: 15, color: theme.colors.sidebar.mutedIcon })) : (_jsx(ChevronLeft, { size: 14, color: theme.colors.sidebar.mutedIcon })) }))] }));
|
|
32
34
|
};
|
|
33
35
|
const SkeletonMenuRow = ({ toggle }) => {
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { accentTextOnCanvas
|
|
1
|
+
import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
|
|
2
|
+
import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
|
|
2
3
|
/** Exhaustive by construction: a new scheme that maps nowhere is a compile error. */
|
|
3
4
|
const scaleFor = (colors, scheme) => scheme === "primary" || scheme === "secondary" || scheme === "tertiary"
|
|
4
5
|
? colors[scheme]
|
|
5
6
|
: colors.semantic[scheme];
|
|
6
7
|
/** Resolve a chevron palette for a given color scheme from the theme. */
|
|
7
8
|
export const resolveStagePalette = (theme, colorScheme = "primary") => {
|
|
8
|
-
const { gray
|
|
9
|
+
const { gray } = theme.colors;
|
|
9
10
|
const scale = scaleFor(theme.colors, colorScheme);
|
|
10
|
-
const
|
|
11
|
-
const
|
|
11
|
+
const solid = resolveFilledSurface(scale, theme.colors);
|
|
12
|
+
const strong = solid.fill;
|
|
13
|
+
const onStrong = solid.color;
|
|
12
14
|
const soft = scale[100];
|
|
13
15
|
// A fixed [700] fails AA against [100] for some hues (orange 3.30, borderline green 3.58) —
|
|
14
16
|
// walk the scale's own rungs against this specific tint instead.
|
|
@@ -18,7 +20,7 @@ export const resolveStagePalette = (theme, colorScheme = "primary") => {
|
|
|
18
20
|
softText,
|
|
19
21
|
strong,
|
|
20
22
|
onStrong,
|
|
21
|
-
hover:
|
|
23
|
+
hover: solid.hoverFill,
|
|
22
24
|
muted: gray[100],
|
|
23
25
|
mutedText: gray[500],
|
|
24
26
|
};
|
|
@@ -7,12 +7,12 @@ import LeftFilterPane from "./filters/LeftFilterPane.js";
|
|
|
7
7
|
import { TABLE_VARIANTS } from "./variants/index.js";
|
|
8
8
|
import { TableVariantProvider } from "./variants/TableVariantContext.js";
|
|
9
9
|
import { isDarkCanvas } from "../../Theme/tokens/builders/accentText.js";
|
|
10
|
+
import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
|
|
10
11
|
import Pagination from "./components/Pagination.js";
|
|
11
12
|
import TableHeader from "./components/TableHeader.js";
|
|
12
13
|
import TableBody from "./components/TableBody.js";
|
|
13
14
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
14
15
|
import { scrollbarStyles, SCROLLBAR_WIDTH } from "../../Theme/tokens/builders/scrollbar.js";
|
|
15
|
-
import { scrollShadowStyles } from "../../Theme/tokens/builders/scrollShadow.js";
|
|
16
16
|
import useTable from "./hooks/useTable.js";
|
|
17
17
|
import { searchAndSortData, SortMultiColumnData, groupRows, buildTablePalette, pickTableColor } from "../../Utils/table.js";
|
|
18
18
|
import { useGetPreferences, useSavePreferences, } from "../../Hooks/usePreferences.js";
|
|
@@ -365,7 +365,7 @@ export default function Table({ data, columns, onSelection, isLoading, isCheckbo
|
|
|
365
365
|
// Square children poked past the rounded border, leaving a gap at each corner.
|
|
366
366
|
overflow: "hidden", children: [filterSidebar && filterMode === "modal" && (_jsxs(Modal, { isOpen: isFilterModalOpen, onClose: onFilterModalClose, size: "4xl", scrollBehavior: "inside", children: [_jsx(ModalOverlay, {}), _jsxs(ModalContent, { bg: theme.colors.background[50], my: 0, top: "10%", position: "fixed", left: "auto", right: "auto", children: [_jsx(ModalCloseButton, { size: "sm" }), _jsx(ModalBody, { p: 0, children: _jsx(LeftFilterPane, { theme: theme, sections: (_c = filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.sidebarOptions) !== null && _c !== void 0 ? _c : [], selected: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.selected, onApply: (sel) => { var _a; (_a = filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onApply) === null || _a === void 0 ? void 0 : _a.call(filterSidebar, sel); onFilterModalClose(); }, onClear: () => { var _a; (_a = filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onClearAllHandler) === null || _a === void 0 ? void 0 : _a.call(filterSidebar); }, isApplyLoading: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isApplyLoading, filterMode: filterMode }) })] })] })), _jsxs(Flex, { align: "start", children: [filterMode === "sidebar" && (_jsx(MotionBox, { "data-testid": "filter-sidebar-pane", initial: { width: 0 }, animate: { width: (filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isFilterSidebar) ? 180 : 0 }, transition: { type: "tween", duration: 0.5 }, overflow: "hidden", flexShrink: 0, borderRight: (filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isFilterSidebar) ? "1px solid" : "none", borderColor: theme.colors.boxborder[200], style: { height: controlsHeight + tableMaxH }, minHeight: (filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isFilterSidebar) ? "32rem" : "auto", children: _jsx(LeftFilterPane, { height: controlsHeight + tableMaxH, theme: theme, sections: (_d = filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.sidebarOptions) !== null && _d !== void 0 ? _d : [], selected: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.selected, onApply: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onApply, onClear: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onClearAllHandler, isApplyLoading: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isApplyLoading, filterMode: filterMode }) })), _jsxs(Box, { flex: "1", minW: 0, children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", px: 3, py: 0, height: controlsHeight, gap: 3, flexWrap: "nowrap", bg: theme.colors.background[50], borderBottom: `0.063rem solid ${theme.colors.boxborder[200]}`, children: [filterSidebar && (_jsxs(_Fragment, { children: [_jsx(ToolTip, { label: "Filter", placement: "top", children: _jsxs(Box, { position: "relative", display: "inline-block", children: [_jsx(Icon, { as: Filter, transform: "scaleX(-1)", cursor: "pointer", boxSize: 4, color: sidebarActiveCount > 0 ? theme.colors.accentText : theme.colors.text[500], onClick: filterMode === "modal" ? onFilterModalOpen : filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.filterSidebarToggle, _hover: {
|
|
367
367
|
color: theme.colors.accentText,
|
|
368
|
-
} }), sidebarActiveCount > 0 && (_jsx(Box, { position: "absolute", top: "-6px", right: "-10px", bg: theme.colors.primary[
|
|
368
|
+
} }), sidebarActiveCount > 0 && (_jsx(Box, { position: "absolute", top: "-6px", right: "-10px", bg: theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], color: labelOnFill(theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], theme.colors.white, theme.colors.black), borderRadius: "full", p: "1px", cursor: "pointer", onClick: (e) => {
|
|
369
369
|
var _a;
|
|
370
370
|
e.stopPropagation();
|
|
371
371
|
if (filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onClearAllHandler) {
|
|
@@ -394,7 +394,6 @@ export default function Table({ data, columns, onSelection, isLoading, isCheckbo
|
|
|
394
394
|
}, children: _jsx(RefreshCw, { size: 16 }) }) })] })), headerActions && (_jsxs(_Fragment, { children: [_jsx(VeritcalDivider, {}), _jsx(HeaderActions, { actions: headerActions, selections: selection })] })), _jsx(ActiveFilters, { columns: columnsList, columnsSearch: columnsSearch, setColumnsSearch: setColumnsSearch }), _jsxs(Box, { ml: "auto", display: "flex", alignItems: "center", gap: 2, children: [groupLoadMoreActive && loadMorePosition === "top" && (groupLoadMoreCaption || canGroupLoadMore) && (_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, flex: "0 0 auto", children: [groupLoadMoreCaption && (_jsx(Box, { fontSize: "0.75rem", color: theme.colors.text[500], whiteSpace: "nowrap", children: groupLoadMoreCaption })), canGroupLoadMore && (_jsx(Button, { size: "xs", variant: "outline", colorScheme: "gray", isLoading: isLoadingMore, loadingText: loadMoreText, onClick: handleGroupLoadMore, label: loadMoreText }))] })), (isPagination || isServerPagination) && !isGrouped && !canInfinite && !isCompactHeader && (_jsx("div", { children: _jsx(Pagination, { columns: columns, currentPage: currentPage, setCurrentPage: setCurrentPage, rowsPerPage: rowsPerPage, pages: pages, paginationText: tablePaginationText, handlePageSizeChange: handlePageSizeChange, dataLength: tableData.length, isServerPagination: isServerPagination, paginationSelectOptions: paginationSelectOptions, isVisiblity: true }) })), (isPagination || isServerPagination) && !isGrouped && !canInfinite && isCompactHeader && tableData.length > 0 && (_jsxs(Popover, { isOpen: isPaginationPopoverOpen, onClose: () => setIsPaginationPopoverOpen(false), placement: "bottom-end", children: [_jsx(PopoverTrigger, { children: _jsx(IconButton, { "aria-label": "Pagination", size: "sm", variant: "ghost", icon: _jsx(EllipsisVertical, { size: 18 }), color: theme.colors.text[500], _hover: {
|
|
395
395
|
color: theme.colors.accentText,
|
|
396
396
|
}, onClick: () => setIsPaginationPopoverOpen((open) => !open) }) }), _jsx(Portal, { children: _jsx(PopoverContent, { maxW: "22rem", p: 2, zIndex: 1600, bg: theme.colors.background[50], boxShadow: "lg", children: _jsx(PopoverBody, { p: 0, children: _jsx(Pagination, { columns: columns, currentPage: currentPage, setCurrentPage: setCurrentPage, rowsPerPage: rowsPerPage, pages: pages, paginationText: tablePaginationText, handlePageSizeChange: handlePageSizeChange, dataLength: tableData.length, isServerPagination: isServerPagination, paginationSelectOptions: paginationSelectOptions, isVisiblity: true }) }) }) })] }))] })] }), _jsxs(TableContainer, { ref: tableContainerRef, position: "relative", h: isTableLoading ? tableMaxH : undefined, maxH: !isTableLoading ? tableMaxH : undefined, pb: isTableLoading ? 0 : compactScrollbarPadding, overflowY: isCompactRows ? "hidden" : "auto", overflowX: "auto", sx: {
|
|
397
|
-
...scrollShadowStyles(theme.colors.background[50]),
|
|
398
397
|
...scrollbarStyles(theme.colors),
|
|
399
398
|
// Compact rows hide the horizontal bar until hover to keep the row height.
|
|
400
399
|
'&::-webkit-scrollbar': {
|
|
@@ -168,6 +168,6 @@ const LeftFilterPane = ({ title = "Filter", height = 300, sections, selected: se
|
|
|
168
168
|
}
|
|
169
169
|
return filteredSections.map((sec) => (_jsxs(Box, { children: [_jsx(Box, { px: 3, py: 2, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: _jsx(SectionLabel, { label: sec.label, theme: theme }) }), _jsx(Box, { px: 3, pt: 2, pb: 1, children: _jsx(SectionContent, { sec: sec, ...sectionContentProps }) })] }, sec.id)));
|
|
170
170
|
};
|
|
171
|
-
return (_jsxs(Box, { width: filterMode === "modal" ? "100%" : "180px", height: filterMode === "modal" ? "100%" : height, minHeight: "32rem", bg: theme.colors.background[50], borderRight: "1px solid", borderColor: theme.colors.boxborder[200], borderRadius: "md", overflow: "hidden", display: "flex", flexDirection: "column", marginBottom: filterMode === "modal" && hasActiveFilters ? '3.5rem' : 0, children: [_jsx(Box, { p: 3, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: !isSearching ? (_jsxs(Flex, { align: "center", justify: "space-between", children: [_jsx(Text, { fontWeight: "semibold", fontSize: "sm", children: title }), _jsx(IconButton, { "aria-label": "Search filters", icon: _jsx(Icon, { as: Search, transform: "scaleX(-1)", boxSize: 4 }), variant: "unstyled", minW: "auto", h: "auto", display: "flex", cursor: "pointer", color: theme.colors.text[500], onClick: () => setIsSearching(true), mr: filterMode === "modal" ? 8 : 2, mt: filterMode === "modal" ? -1 : 0 })] })) : (_jsx(motion.div, { ref: searchRef, initial: { opacity: 0, x: 40 }, animate: { opacity: 1, x: 0 }, transition: { type: "tween", duration: 0.2 }, children: _jsxs(InputGroup, { size: "sm", children: [_jsx(InputLeftElement, { pointerEvents: "none", children: _jsx(Search, { size: 16, color: theme.colors.text[500] }) }), _jsx(Input, { placeholder: "Search", value: search, onChange: (e) => setSearch(e.target.value), autoFocus: true }), search.length > 0 && (_jsx(InputRightElement, { children: _jsx(IconButton, { "aria-label": "Clear", size: "xs", variant: "ghost", icon: _jsx(X, { size: 14 }), onClick: () => { setSearch(""); setIsSearching(false); } }) }))] }) })) }), _jsx(Box, { flex: "1", overflowY: "auto", children: renderSections() }), hasActiveFilters && (_jsxs(HStack, { px: 2, py: 1, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], spacing: 2, position: filterMode === "modal" ? "absolute" : "relative", bottom: 0, left: 0, right: 0, bg: theme.colors.background[50], children: [_jsx(Button, { flex: 1, variant: "outline", size: "sm", onClick: handleClear, fontSize: "xs", colorScheme: "red", children: "Clear All" }), _jsx(Button, { flex: 1, colorScheme: "primary",
|
|
171
|
+
return (_jsxs(Box, { width: filterMode === "modal" ? "100%" : "180px", height: filterMode === "modal" ? "100%" : height, minHeight: "32rem", bg: theme.colors.background[50], borderRight: "1px solid", borderColor: theme.colors.boxborder[200], borderRadius: "md", overflow: "hidden", display: "flex", flexDirection: "column", marginBottom: filterMode === "modal" && hasActiveFilters ? '3.5rem' : 0, children: [_jsx(Box, { p: 3, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: !isSearching ? (_jsxs(Flex, { align: "center", justify: "space-between", children: [_jsx(Text, { fontWeight: "semibold", fontSize: "sm", children: title }), _jsx(IconButton, { "aria-label": "Search filters", icon: _jsx(Icon, { as: Search, transform: "scaleX(-1)", boxSize: 4 }), variant: "unstyled", minW: "auto", h: "auto", display: "flex", cursor: "pointer", color: theme.colors.text[500], onClick: () => setIsSearching(true), mr: filterMode === "modal" ? 8 : 2, mt: filterMode === "modal" ? -1 : 0 })] })) : (_jsx(motion.div, { ref: searchRef, initial: { opacity: 0, x: 40 }, animate: { opacity: 1, x: 0 }, transition: { type: "tween", duration: 0.2 }, children: _jsxs(InputGroup, { size: "sm", children: [_jsx(InputLeftElement, { pointerEvents: "none", children: _jsx(Search, { size: 16, color: theme.colors.text[500] }) }), _jsx(Input, { placeholder: "Search", value: search, onChange: (e) => setSearch(e.target.value), autoFocus: true }), search.length > 0 && (_jsx(InputRightElement, { children: _jsx(IconButton, { "aria-label": "Clear", size: "xs", variant: "ghost", icon: _jsx(X, { size: 14 }), onClick: () => { setSearch(""); setIsSearching(false); } }) }))] }) })) }), _jsx(Box, { flex: "1", overflowY: "auto", children: renderSections() }), hasActiveFilters && (_jsxs(HStack, { px: 2, py: 1, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], spacing: 2, position: filterMode === "modal" ? "absolute" : "relative", bottom: 0, left: 0, right: 0, bg: theme.colors.background[50], children: [_jsx(Button, { flex: 1, variant: "outline", size: "sm", onClick: handleClear, fontSize: "xs", colorScheme: "red", children: "Clear All" }), _jsx(Button, { flex: 1, colorScheme: "primary", size: "sm", onClick: handleApply, fontSize: "xs", isLoading: isApplyLoading, children: "Apply" })] }))] }));
|
|
172
172
|
};
|
|
173
173
|
export default LeftFilterPane;
|