pixelize-design-library 2.4.2-beta.27 → 2.4.2-beta.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Components/Button/Button.styles.js +22 -2
- package/dist/Components/DatePicker/CalendarPanel.d.ts +5 -0
- package/dist/Components/DatePicker/CalendarPanel.js +23 -4
- package/dist/Components/DatePicker/DatePickerProps.d.ts +21 -0
- package/dist/Components/DatePicker/RangeDatePicker.js +2 -2
- package/dist/Components/DatePicker/dayStates.d.ts +56 -0
- package/dist/Components/DatePicker/dayStates.js +87 -0
- package/dist/Theme/assertPalette.d.ts +1 -1
- package/dist/Theme/assertPalette.js +3 -2
- package/dist/Theme/chakra/createBrandTheme.js +7 -0
- package/dist/Theme/chakra/focusRing.styles.d.ts +52 -0
- package/dist/Theme/chakra/focusRing.styles.js +46 -0
- package/dist/Theme/tokens/brands/index.js +6 -1
- package/dist/Theme/tokens/brands/zinc/palette.dark.d.ts +1 -0
- package/dist/Theme/tokens/builders/buildDarkPalette.js +6 -1
- package/dist/Theme/tokens/builders/focusRing.d.ts +52 -0
- package/dist/Theme/tokens/builders/focusRing.js +92 -0
- package/dist/Theme/tokens/builders/index.d.ts +1 -0
- package/dist/Theme/tokens/builders/index.js +1 -0
- package/dist/Theme/tokens/builders/outlineRung.d.ts +8 -2
- package/dist/Theme/tokens/builders/outlineRung.js +8 -2
- package/dist/Theme/tokens/types.d.ts +21 -1
- package/dist/esm/Components/Button/Button.styles.js +22 -2
- package/dist/esm/Components/DatePicker/CalendarPanel.js +23 -4
- package/dist/esm/Components/DatePicker/RangeDatePicker.js +2 -2
- package/dist/esm/Components/DatePicker/dayStates.js +79 -0
- package/dist/esm/Theme/assertPalette.js +3 -2
- package/dist/esm/Theme/chakra/createBrandTheme.js +7 -0
- package/dist/esm/Theme/chakra/focusRing.styles.js +40 -0
- package/dist/esm/Theme/tokens/brands/index.js +6 -1
- package/dist/esm/Theme/tokens/builders/buildDarkPalette.js +6 -1
- package/dist/esm/Theme/tokens/builders/focusRing.js +85 -0
- package/dist/esm/Theme/tokens/builders/index.js +1 -0
- package/dist/esm/Theme/tokens/builders/outlineRung.js +8 -2
- package/dist/esm/index.js +10 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +26 -2
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ exports.Button = void 0;
|
|
|
4
4
|
const accentText_1 = require("../../Theme/tokens/builders/accentText");
|
|
5
5
|
const color_1 = require("../../Theme/tokens/builders/color");
|
|
6
6
|
const gradientInk_1 = require("../../Theme/tokens/builders/gradientInk");
|
|
7
|
+
const focusRing_styles_1 = require("../../Theme/chakra/focusRing.styles");
|
|
7
8
|
/**
|
|
8
9
|
* Outline/ghost/link text sits ON the canvas, so it needs a rung that stays readable there —
|
|
9
10
|
* `[500]` is pinned dark enough to carry a white label on the solid variant and measures only
|
|
@@ -62,8 +63,19 @@ const darkerFill = (theme, colorScheme, step) => {
|
|
|
62
63
|
};
|
|
63
64
|
/** Label for the solid variant's filled bg — derived from THAT fill, since hover/active swap it. */
|
|
64
65
|
const labelFor = (theme, fill) => (0, accentText_1.onFilled)(fill, theme.colors.white, theme.colors.black);
|
|
66
|
+
/**
|
|
67
|
+
* The two-tone `:focus-visible` ring, from the palette's derived `focusRing` pair.
|
|
68
|
+
*
|
|
69
|
+
* Every variant spreads this. Before it, none of them defined `_focusVisible` at all, so every
|
|
70
|
+
* button in every consuming app fell through to Chakra's stock `shadows.outline` — one fixed blue
|
|
71
|
+
* that measured 1.83:1 on the canvas and 1.38:1 on a primary fill, failing WCAG 1.4.11 (3:1) on
|
|
72
|
+
* all nine brands. `focusRing.test.ts` is the gate that keeps this true.
|
|
73
|
+
*/
|
|
74
|
+
const focusRing = (theme) => (0, focusRing_styles_1.focusVisibleStyles)(theme.colors);
|
|
65
75
|
exports.Button = {
|
|
66
|
-
|
|
76
|
+
// The ring is repeated on every variant below AND here, so a variant name this file does not
|
|
77
|
+
// define (a consumer's own, or an `IconButton` falling through) still gets an indicator.
|
|
78
|
+
baseStyle: ({ theme }) => ({
|
|
67
79
|
borderRadius: "lg",
|
|
68
80
|
fontWeight: 500,
|
|
69
81
|
fontSize: "1rem",
|
|
@@ -72,6 +84,7 @@ exports.Button = {
|
|
|
72
84
|
opacity: 0.6,
|
|
73
85
|
cursor: "not-allowed",
|
|
74
86
|
},
|
|
87
|
+
...focusRing(theme),
|
|
75
88
|
}),
|
|
76
89
|
variants: {
|
|
77
90
|
solid: ({ theme, colorScheme = "primary" }) => {
|
|
@@ -104,6 +117,7 @@ exports.Button = {
|
|
|
104
117
|
color: hoverLabel,
|
|
105
118
|
},
|
|
106
119
|
},
|
|
120
|
+
...focusRing(theme),
|
|
107
121
|
};
|
|
108
122
|
},
|
|
109
123
|
outline: ({ theme, colorScheme = "primary" }) => {
|
|
@@ -133,6 +147,7 @@ exports.Button = {
|
|
|
133
147
|
// bg: theme.colors[colorScheme][500],
|
|
134
148
|
color: ink,
|
|
135
149
|
},
|
|
150
|
+
...focusRing(theme),
|
|
136
151
|
};
|
|
137
152
|
},
|
|
138
153
|
ghost: ({ theme, colorScheme = "primary" }) => ({
|
|
@@ -145,6 +160,7 @@ exports.Button = {
|
|
|
145
160
|
_active: {
|
|
146
161
|
bg: onCanvasHoverBg(theme, colorScheme, 24),
|
|
147
162
|
},
|
|
163
|
+
...focusRing(theme),
|
|
148
164
|
}),
|
|
149
165
|
link: ({ theme, colorScheme = "primary" }) => ({
|
|
150
166
|
color: onCanvasText(theme, colorScheme),
|
|
@@ -157,13 +173,16 @@ exports.Button = {
|
|
|
157
173
|
_active: {
|
|
158
174
|
color: onCanvasText(theme, colorScheme),
|
|
159
175
|
},
|
|
176
|
+
...focusRing(theme),
|
|
160
177
|
}),
|
|
161
|
-
unstyled:
|
|
178
|
+
// `unstyled` drops the fill, not the affordance: a focus indicator is not styling.
|
|
179
|
+
unstyled: ({ theme }) => ({
|
|
162
180
|
bg: "transparent",
|
|
163
181
|
color: "inherit",
|
|
164
182
|
_hover: {
|
|
165
183
|
bg: "transparent",
|
|
166
184
|
},
|
|
185
|
+
...focusRing(theme),
|
|
167
186
|
}),
|
|
168
187
|
// Theme-based two-tone gradient: each theme defines its own `gradient` {from,to} pair.
|
|
169
188
|
// Ignores colorScheme; hover/active shift brightness so it works for any pair.
|
|
@@ -190,6 +209,7 @@ exports.Button = {
|
|
|
190
209
|
filter: "brightness(0.92)",
|
|
191
210
|
_hover: { bgImage: bg, filter: "brightness(0.92)" },
|
|
192
211
|
},
|
|
212
|
+
...focusRing(theme),
|
|
193
213
|
};
|
|
194
214
|
},
|
|
195
215
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { type DayStates, type RenderDayContent } from "./dayStates";
|
|
2
3
|
export type CalendarPanelProps = {
|
|
3
4
|
currentMonth: Date;
|
|
4
5
|
setCurrentMonth: (updater: (prev: Date) => Date) => void;
|
|
@@ -19,6 +20,10 @@ export type CalendarPanelProps = {
|
|
|
19
20
|
hoveredDate?: Date | null;
|
|
20
21
|
onDayHover?: (d: Date | null) => void;
|
|
21
22
|
renderWeekdays?: React.ReactNode;
|
|
23
|
+
/** Marks individual days (weekly off, holiday, …). See `dayStates.ts`. Omit for the plain grid. */
|
|
24
|
+
dayStates?: DayStates;
|
|
25
|
+
/** Custom content inside a day cell, replacing that day's built-in marker dot. */
|
|
26
|
+
renderDayContent?: RenderDayContent;
|
|
22
27
|
};
|
|
23
28
|
export declare const CalendarPanel: React.FC<CalendarPanelProps>;
|
|
24
29
|
export default CalendarPanel;
|
|
@@ -11,7 +11,8 @@ const lucide_react_1 = require("lucide-react");
|
|
|
11
11
|
const Button_1 = __importDefault(require("../Button/Button"));
|
|
12
12
|
const useCustomTheme_1 = require("../../Theme/useCustomTheme");
|
|
13
13
|
const accentText_1 = require("../../Theme/tokens/builders/accentText");
|
|
14
|
-
const
|
|
14
|
+
const dayStates_1 = require("./dayStates");
|
|
15
|
+
const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, tempDate, tempRangeStart, tempRangeEnd, isSameDay, isBefore, isAfter, minDate, maxDate, disablePastDates, disableFutureDates, disableToday, onDaySelect, hoveredDate, onDayHover, renderWeekdays, dayStates, renderDayContent, }) => {
|
|
15
16
|
const theme = (0, useCustomTheme_1.useCustomTheme)();
|
|
16
17
|
const rangeBg = theme.colors.primary.opacity[16];
|
|
17
18
|
const isViewingCurrentMonth = currentMonth.getFullYear() === today.getFullYear() &&
|
|
@@ -51,6 +52,7 @@ const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, tempDate
|
|
|
51
52
|
},
|
|
52
53
|
};
|
|
53
54
|
const renderDays = () => {
|
|
55
|
+
var _a;
|
|
54
56
|
const monthStart = (0, date_fns_1.startOfMonth)(currentMonth);
|
|
55
57
|
const monthEnd = (0, date_fns_1.endOfMonth)(currentMonth);
|
|
56
58
|
const startDate = (0, date_fns_1.startOfWeek)(monthStart);
|
|
@@ -69,12 +71,17 @@ const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, tempDate
|
|
|
69
71
|
const isSelected = !!(!isRange && tempDate && isSameDay(thisDay, tempDate));
|
|
70
72
|
const isTentativeEnd = isEnd && isTentative;
|
|
71
73
|
const circleSolid = !!(isSelected || (isRange && isStart) || (isEnd && !isTentative));
|
|
74
|
+
// Marking is not disabling: only the `disabled` state key blocks selection, and only
|
|
75
|
+
// because the caller asked for it by name.
|
|
76
|
+
const states = (_a = dayStates === null || dayStates === void 0 ? void 0 : dayStates(thisDay)) !== null && _a !== void 0 ? _a : [];
|
|
77
|
+
const stateVisual = states.length ? (0, dayStates_1.resolveDayStateVisual)(states, theme.colors) : null;
|
|
72
78
|
const disabled = !isInCurrentMonth ||
|
|
73
79
|
!!(minDate && isBefore(thisDay, minDate)) ||
|
|
74
80
|
!!(maxDate && isAfter(thisDay, maxDate)) ||
|
|
75
81
|
!!(disablePastDates && isBefore(thisDay, today) && !isSameDay(thisDay, today)) ||
|
|
76
82
|
!!(disableFutureDates && isAfter(thisDay, today) && !isSameDay(thisDay, today)) ||
|
|
77
|
-
!!(disableToday && isToday)
|
|
83
|
+
!!(disableToday && isToday) ||
|
|
84
|
+
!!(stateVisual === null || stateVisual === void 0 ? void 0 : stateVisual.blocksSelection);
|
|
78
85
|
// Connected range band painted on the cell background; start/end use a
|
|
79
86
|
// half gradient so the band meets the solid day circle cleanly.
|
|
80
87
|
let cellBg;
|
|
@@ -88,6 +95,9 @@ const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, tempDate
|
|
|
88
95
|
else if (isEnd)
|
|
89
96
|
cellBg = `linear-gradient(to right, ${rangeBg} 50%, transparent 50%)`;
|
|
90
97
|
}
|
|
98
|
+
// Selection feedback outranks a state tint — the band is what tells the user what they picked.
|
|
99
|
+
if (!cellBg && (stateVisual === null || stateVisual === void 0 ? void 0 : stateVisual.cellBg))
|
|
100
|
+
cellBg = stateVisual.cellBg;
|
|
91
101
|
// Solid fill (selected/range-endpoint) needs the ink checked against that
|
|
92
102
|
// specific fill — `primary[500]` doesn't reliably clear AA for white text on
|
|
93
103
|
// every brand/mode (same gap the solid Button variant already accounts for).
|
|
@@ -108,11 +118,20 @@ const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, tempDate
|
|
|
108
118
|
: isToday
|
|
109
119
|
? `1px solid ${theme.colors.primary[300]}`
|
|
110
120
|
: "1px solid transparent";
|
|
111
|
-
|
|
121
|
+
// A filled circle owns its own ink (checked against that fill by `onFilled`), so a state
|
|
122
|
+
// never repaints a selected day — it would undo that contrast guarantee.
|
|
123
|
+
const dayColor = !circleSolid && (stateVisual === null || stateVisual === void 0 ? void 0 : stateVisual.color) ? stateVisual.color : circleColor;
|
|
124
|
+
const dayBorder = !circleSolid && (stateVisual === null || stateVisual === void 0 ? void 0 : stateVisual.border) ? stateVisual.border : circleBorder;
|
|
125
|
+
const customContent = renderDayContent ? renderDayContent(thisDay, states) : null;
|
|
126
|
+
const markerColor = customContent == null && (stateVisual === null || stateVisual === void 0 ? void 0 : stateVisual.markerColor) ? stateVisual.markerColor : null;
|
|
127
|
+
const hasDayOverlay = customContent != null || markerColor != null;
|
|
128
|
+
days.push((0, jsx_runtime_1.jsx)(react_1.Box, { h: "2rem", display: "flex", alignItems: "center", justifyContent: "center", style: cellBg ? { background: cellBg } : undefined, children: (0, jsx_runtime_1.jsxs)(react_1.Box, { as: "button", type: "button", disabled: disabled, className: dayStates ? (0, dayStates_1.dayStateClassName)(states) : undefined, "aria-label": dayStates ? (0, dayStates_1.dayAccessibleName)((0, date_fns_1.format)(thisDay, "d MMMM yyyy"), states) : undefined, onClick: () => !disabled && onDaySelect(new Date(thisDay)), onMouseEnter: () => !disabled && (onDayHover === null || onDayHover === void 0 ? void 0 : onDayHover(new Date(thisDay))), position: hasDayOverlay ? "relative" : undefined, w: "1.75rem", h: "1.75rem", borderRadius: "full", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "0.8125rem", fontWeight: circleSolid ? 600 : 500, lineHeight: "1", cursor: disabled ? "not-allowed" : "pointer", bg: circleSolid ? solidFill : "transparent", color: dayColor, textDecoration: (stateVisual === null || stateVisual === void 0 ? void 0 : stateVisual.strikethrough) ? "line-through" : undefined, border: dayBorder, transition: "background 0.12s, color 0.12s", _hover: disabled
|
|
112
129
|
? {}
|
|
113
130
|
: circleSolid
|
|
114
131
|
? { bg: solidHoverFill, color: circleHoverColor }
|
|
115
|
-
: { bg: rangeBg }, children: (0, date_fns_1.format)(thisDay, "d")
|
|
132
|
+
: { bg: rangeBg }, children: [(0, date_fns_1.format)(thisDay, "d"), hasDayOverlay && ((0, jsx_runtime_1.jsx)(react_1.Box, { as: "span", className: `${dayStates_1.DAY_CLASS}__content`, position: "absolute", left: 0, right: 0, bottom: "0.0625rem", display: "flex", alignItems: "flex-end", justifyContent: "center", lineHeight: "1", fontSize: "0.5rem",
|
|
133
|
+
// The overlay is decoration: clicks belong to the day button under it.
|
|
134
|
+
pointerEvents: "none", children: customContent !== null && customContent !== void 0 ? customContent : ((0, jsx_runtime_1.jsx)(react_1.Box, { as: "span", className: `${dayStates_1.DAY_CLASS}__marker`, w: "0.25rem", h: "0.25rem", borderRadius: "full", bg: markerColor })) }))] }) }, thisDay.toString()));
|
|
116
135
|
day = (0, date_fns_1.addDays)(day, 1);
|
|
117
136
|
}
|
|
118
137
|
rows.push((0, jsx_runtime_1.jsx)(react_1.Grid, { templateColumns: "repeat(7, 1fr)", gap: 0, children: days }, day.toString()));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DayStates, RenderDayContent } from "./dayStates";
|
|
1
2
|
export type PickerType = "date" | "time" | "datetime";
|
|
2
3
|
export type BaseDatePickerProps = {
|
|
3
4
|
id?: string;
|
|
@@ -40,6 +41,26 @@ export type RangeDatePickerProps = BaseDatePickerProps & {
|
|
|
40
41
|
/** Alias for `selectedDate` (legacy / form libraries). */
|
|
41
42
|
value?: RangeDate | null;
|
|
42
43
|
onChange: (range: RangeDate | null) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Marks individual days with zero or more state keys — `["weekly-off"]`, `["Onam", "holiday"]`,
|
|
46
|
+
* `["excluded"]`. The keys in `DAY_STATE_KEYS` (`weekly-off`, `holiday`, `optional-holiday`,
|
|
47
|
+
* `excluded`, `disabled`) carry built-in, token-driven styling; any other key is announced to a
|
|
48
|
+
* screen reader but left unstyled, which is how a day gets named without a second prop.
|
|
49
|
+
*
|
|
50
|
+
* Marking is not disabling: a marked day stays selectable unless the caller also returns
|
|
51
|
+
* `"disabled"`, or blocks the day with `minDate`/`maxDate`/`disablePastDates`/`disableFutureDates`.
|
|
52
|
+
*
|
|
53
|
+
* Supplying this also spells each day's accessible name out in full — "16 September 2025, Onam,
|
|
54
|
+
* holiday" instead of "16". Called once per rendered day (42 per month), so keep it cheap and pure.
|
|
55
|
+
*/
|
|
56
|
+
dayStates?: DayStates;
|
|
57
|
+
/**
|
|
58
|
+
* Custom content rendered inside the day cell, centred under the day number — a dot, a short
|
|
59
|
+
* label, a tooltip trigger. Receives that day's resolved state keys. Returning a node replaces
|
|
60
|
+
* the built-in marker dot for that day; the number, the accessible name and hit target are
|
|
61
|
+
* unchanged (the overlay does not take pointer events).
|
|
62
|
+
*/
|
|
63
|
+
renderDayContent?: RenderDayContent;
|
|
43
64
|
};
|
|
44
65
|
export type DatePickerProps = SingleDatePickerProps | RangeDatePickerProps;
|
|
45
66
|
export type TimePickerProps = {
|
|
@@ -25,7 +25,7 @@ const setTimeFrom = (base, time) => {
|
|
|
25
25
|
};
|
|
26
26
|
const RangeDatePicker = (props) => {
|
|
27
27
|
var _a, _b, _c, _d;
|
|
28
|
-
const { id, name, label, isRequired, isInformation, informationMessage, error, errorMessage, helperText, placeholderText, dateFormat = "dd/MM/yyyy", minDate, maxDate, disableFutureDates, disablePastDates, autoComplete = "off", disabled, width = "100%", disableToday = false, size = "md", } = props;
|
|
28
|
+
const { id, name, label, isRequired, isInformation, informationMessage, error, errorMessage, helperText, placeholderText, dateFormat = "dd/MM/yyyy", minDate, maxDate, disableFutureDates, disablePastDates, autoComplete = "off", disabled, width = "100%", disableToday = false, size = "md", dayStates, renderDayContent, } = props;
|
|
29
29
|
const theme = (0, useCustomTheme_1.useCustomTheme)();
|
|
30
30
|
const sizeKey = typeof size === "string" ? size : "md";
|
|
31
31
|
const calendarIconPx = (0, textInputIconSize_1.getTextInputIconSizePx)(sizeKey);
|
|
@@ -181,7 +181,7 @@ const RangeDatePicker = (props) => {
|
|
|
181
181
|
}, cursor: "pointer" }), (0, jsx_runtime_1.jsx)(react_2.InputRightElement, { height: "100%", display: "flex", alignItems: "center", pointerEvents: "auto", style: { cursor: "pointer" }, onClick: () => (isOpen ? onClose() : handleOpen()), children: (0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", sx: calendarIconWrapperSx, children: (0, jsx_runtime_1.jsx)(lucide_react_1.CalendarIcon, { size: calendarIconPx, color: theme.colors.textMuted }) }) })] }) }) }), (0, jsx_runtime_1.jsx)(react_2.PopoverContent, { w: "18rem", maxW: "18rem", p: 3, ref: popoverRef, boxShadow: "lg", borderRadius: "xl", bg: theme.colors.background[50], children: (0, jsx_runtime_1.jsxs)(react_2.PopoverBody, { p: 0, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { display: "flex", flexWrap: "wrap", gap: 2, mb: 3, children: presets.map((p) => ((0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "gray", sx: { flex: "1 1 auto" }, onClick: () => {
|
|
182
182
|
const [from, to] = p.getRange();
|
|
183
183
|
applyPreset(from, to);
|
|
184
|
-
}, children: p.label }, p.label))) }), (0, jsx_runtime_1.jsx)(CalendarPanel_1.default, { currentMonth: currentMonth, setCurrentMonth: (updater) => setCurrentMonthState((prev) => updater(prev)), today: today, isRange: true, tempDate: null, tempRangeStart: tempRangeStart, tempRangeEnd: tempRangeEnd, hoveredDate: hoveredDate, onDayHover: setHoveredDate, isSameDay: date_fns_1.isSameDay, isBefore: date_fns_1.isBefore, isAfter: date_fns_1.isAfter, minDate: minDate, maxDate: maxDate, disablePastDates: disablePastDates, disableFutureDates: disableFutureDates, disableToday: disableToday, onDaySelect: handleDaySelect }), formatHasTime && ((0, jsx_runtime_1.jsxs)(react_2.Box, { mt: 3, display: "grid", gridTemplateColumns: "1fr", gap: 2, children: [(0, jsx_runtime_1.jsxs)(react_2.Box, { children: [(0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "xs", color: theme.colors.textMuted, mb: 1, children: "Start time" }), shouldUseSelectTimePicker ? ((0, jsx_runtime_1.jsx)(TimePicker_1.default, { date: startTimeBaseDate, onChange: (updated) => {
|
|
184
|
+
}, children: p.label }, p.label))) }), (0, jsx_runtime_1.jsx)(CalendarPanel_1.default, { currentMonth: currentMonth, setCurrentMonth: (updater) => setCurrentMonthState((prev) => updater(prev)), today: today, isRange: true, tempDate: null, tempRangeStart: tempRangeStart, tempRangeEnd: tempRangeEnd, hoveredDate: hoveredDate, onDayHover: setHoveredDate, isSameDay: date_fns_1.isSameDay, isBefore: date_fns_1.isBefore, isAfter: date_fns_1.isAfter, minDate: minDate, maxDate: maxDate, disablePastDates: disablePastDates, disableFutureDates: disableFutureDates, disableToday: disableToday, onDaySelect: handleDaySelect, dayStates: dayStates, renderDayContent: renderDayContent }), formatHasTime && ((0, jsx_runtime_1.jsxs)(react_2.Box, { mt: 3, display: "grid", gridTemplateColumns: "1fr", gap: 2, children: [(0, jsx_runtime_1.jsxs)(react_2.Box, { children: [(0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "xs", color: theme.colors.textMuted, mb: 1, children: "Start time" }), shouldUseSelectTimePicker ? ((0, jsx_runtime_1.jsx)(TimePicker_1.default, { date: startTimeBaseDate, onChange: (updated) => {
|
|
185
185
|
if (!tempRangeStart) {
|
|
186
186
|
setTempRangeStart(updated);
|
|
187
187
|
return;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Day-state marking for the calendar grid.
|
|
3
|
+
*
|
|
4
|
+
* A *state* is a key describing what a single day MEANS in the caller's domain — a weekly off,
|
|
5
|
+
* a public holiday, a day excluded from a leave count. It is deliberately separate from
|
|
6
|
+
* disabling: a marked day stays selectable unless the caller also returns the `"disabled"` key
|
|
7
|
+
* (or blocks the day through `minDate`/`maxDate`/`disablePastDates`/`disableFutureDates`).
|
|
8
|
+
*
|
|
9
|
+
* Every key returned reaches a screen reader. Only the keys in `DAY_STATE_KEYS` also carry
|
|
10
|
+
* built-in styling, so a caller can return a free-text key ("Onam") purely to have it announced
|
|
11
|
+
* alongside the recognised one: `["Onam", "holiday"]` → "16 September 2025, Onam, holiday".
|
|
12
|
+
*
|
|
13
|
+
* Colour comes from the palette only — every visual below is a function of `PaletteProps`, so a
|
|
14
|
+
* marked day follows the active light/dark palette like the rest of `CalendarPanel`.
|
|
15
|
+
*/
|
|
16
|
+
import type { ReactNode } from "react";
|
|
17
|
+
import type { PaletteProps } from "../../Theme/tokens/types";
|
|
18
|
+
/**
|
|
19
|
+
* The keys with built-in styling, in ascending precedence — when a day carries several, a later
|
|
20
|
+
* key's visual overrides the fields an earlier one set.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DAY_STATE_KEYS: readonly ["weekly-off", "holiday", "optional-holiday", "excluded", "disabled"];
|
|
23
|
+
export type DayStateKey = (typeof DAY_STATE_KEYS)[number];
|
|
24
|
+
/** Returns zero or more state keys for a day. Unrecognised keys are announced, never styled. */
|
|
25
|
+
export type DayStates = (date: Date) => string[] | undefined;
|
|
26
|
+
/** Custom content rendered inside a day cell, beneath the day number. */
|
|
27
|
+
export type RenderDayContent = (date: Date, states: string[]) => ReactNode;
|
|
28
|
+
/** What a resolved set of states paints. Every field is optional — an absent field changes nothing. */
|
|
29
|
+
export type DayStateVisual = {
|
|
30
|
+
/** Tint painted across the whole cell. The range band always wins over it. */
|
|
31
|
+
cellBg?: string;
|
|
32
|
+
/** Ink for the day number. Never applied to a selected/endpoint day, whose fill owns its ink. */
|
|
33
|
+
color?: string;
|
|
34
|
+
/** `border` shorthand for the day circle, replacing the today/tentative ring. */
|
|
35
|
+
border?: string;
|
|
36
|
+
/** Fill of the small marker dot under the number. `renderDayContent` replaces it. */
|
|
37
|
+
markerColor?: string;
|
|
38
|
+
/** Strikes the day number through — the "counted, but not really" states. */
|
|
39
|
+
strikethrough?: boolean;
|
|
40
|
+
/** The one state that also blocks selection. Marking alone never does. */
|
|
41
|
+
blocksSelection?: boolean;
|
|
42
|
+
};
|
|
43
|
+
export declare const isDayStateKey: (key: string) => key is DayStateKey;
|
|
44
|
+
/** Merges every recognised state in `DAY_STATE_KEYS` order, so precedence never depends on caller order. */
|
|
45
|
+
export declare const resolveDayStateVisual: (states: string[], colors: PaletteProps) => DayStateVisual;
|
|
46
|
+
/** Base class on every day button once `dayStates` is supplied. Consumers may style off it. */
|
|
47
|
+
export declare const DAY_CLASS = "pxl-calendar-day";
|
|
48
|
+
/** `["Onam", "holiday"]` → `"pxl-calendar-day pxl-calendar-day--onam pxl-calendar-day--holiday"`. */
|
|
49
|
+
export declare const dayStateClassName: (states: string[]) => string;
|
|
50
|
+
/** Human phrasing for the accessible name — every key, styled or not, in the caller's own order. */
|
|
51
|
+
export declare const describeDayStates: (states: string[]) => string;
|
|
52
|
+
/**
|
|
53
|
+
* The day's accessible name. The date is spelled out because "16" alone tells a screen-reader
|
|
54
|
+
* user nothing, and the states follow it so the marking is heard, not only seen.
|
|
55
|
+
*/
|
|
56
|
+
export declare const dayAccessibleName: (formattedDate: string, states: string[]) => string;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dayAccessibleName = exports.describeDayStates = exports.dayStateClassName = exports.DAY_CLASS = exports.resolveDayStateVisual = exports.isDayStateKey = exports.DAY_STATE_KEYS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The keys with built-in styling, in ascending precedence — when a day carries several, a later
|
|
6
|
+
* key's visual overrides the fields an earlier one set.
|
|
7
|
+
*/
|
|
8
|
+
exports.DAY_STATE_KEYS = [
|
|
9
|
+
"weekly-off",
|
|
10
|
+
"holiday",
|
|
11
|
+
"optional-holiday",
|
|
12
|
+
"excluded",
|
|
13
|
+
"disabled",
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Token roles, not rungs (see `Theme/THEME-CONTRACT.md`):
|
|
17
|
+
* - a non-working day is a *surface* step down plus muted ink — `backgroundColor.muted` / `textMuted`
|
|
18
|
+
* - a holiday is *status ink*, so `semanticText.<tone>`, never the `semantic.<tone>[500]` fill rung
|
|
19
|
+
* - an optional holiday is the same tone family one step less certain: warning + a dashed ring
|
|
20
|
+
* - an unavailable day is the `disabled` ramp, the only ramp whose job is exactly this
|
|
21
|
+
*/
|
|
22
|
+
const VISUALS = {
|
|
23
|
+
"weekly-off": (colors) => ({
|
|
24
|
+
cellBg: colors.backgroundColor.muted,
|
|
25
|
+
color: colors.textMuted,
|
|
26
|
+
}),
|
|
27
|
+
holiday: (colors) => ({
|
|
28
|
+
color: colors.semanticText.info,
|
|
29
|
+
markerColor: colors.semanticText.info,
|
|
30
|
+
}),
|
|
31
|
+
"optional-holiday": (colors) => ({
|
|
32
|
+
color: colors.semanticText.warning,
|
|
33
|
+
markerColor: colors.semanticText.warning,
|
|
34
|
+
border: `1px dashed ${colors.semanticText.warning}`,
|
|
35
|
+
}),
|
|
36
|
+
excluded: (colors) => ({
|
|
37
|
+
color: colors.textMuted,
|
|
38
|
+
strikethrough: true,
|
|
39
|
+
}),
|
|
40
|
+
disabled: (colors) => ({
|
|
41
|
+
color: colors.disabled[500],
|
|
42
|
+
blocksSelection: true,
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
const isDayStateKey = (key) => exports.DAY_STATE_KEYS.includes(key);
|
|
46
|
+
exports.isDayStateKey = isDayStateKey;
|
|
47
|
+
/** Merges every recognised state in `DAY_STATE_KEYS` order, so precedence never depends on caller order. */
|
|
48
|
+
const resolveDayStateVisual = (states, colors) => {
|
|
49
|
+
const visual = {};
|
|
50
|
+
for (const key of exports.DAY_STATE_KEYS) {
|
|
51
|
+
if (states.includes(key))
|
|
52
|
+
Object.assign(visual, VISUALS[key](colors));
|
|
53
|
+
}
|
|
54
|
+
return visual;
|
|
55
|
+
};
|
|
56
|
+
exports.resolveDayStateVisual = resolveDayStateVisual;
|
|
57
|
+
/** Base class on every day button once `dayStates` is supplied. Consumers may style off it. */
|
|
58
|
+
exports.DAY_CLASS = "pxl-calendar-day";
|
|
59
|
+
const slug = (key) => key
|
|
60
|
+
.trim()
|
|
61
|
+
.toLowerCase()
|
|
62
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
63
|
+
.replace(/^-+|-+$/g, "");
|
|
64
|
+
/** `["Onam", "holiday"]` → `"pxl-calendar-day pxl-calendar-day--onam pxl-calendar-day--holiday"`. */
|
|
65
|
+
const dayStateClassName = (states) => [
|
|
66
|
+
exports.DAY_CLASS,
|
|
67
|
+
...states
|
|
68
|
+
.map(slug)
|
|
69
|
+
.filter(Boolean)
|
|
70
|
+
.map((key) => `${exports.DAY_CLASS}--${key}`),
|
|
71
|
+
].join(" ");
|
|
72
|
+
exports.dayStateClassName = dayStateClassName;
|
|
73
|
+
/** Human phrasing for the accessible name — every key, styled or not, in the caller's own order. */
|
|
74
|
+
const describeDayStates = (states) => states
|
|
75
|
+
.map((state) => ((0, exports.isDayStateKey)(state) ? state.replace(/-/g, " ") : state.trim()))
|
|
76
|
+
.filter(Boolean)
|
|
77
|
+
.join(", ");
|
|
78
|
+
exports.describeDayStates = describeDayStates;
|
|
79
|
+
/**
|
|
80
|
+
* The day's accessible name. The date is spelled out because "16" alone tells a screen-reader
|
|
81
|
+
* user nothing, and the states follow it so the marking is heard, not only seen.
|
|
82
|
+
*/
|
|
83
|
+
const dayAccessibleName = (formattedDate, states) => {
|
|
84
|
+
const described = (0, exports.describeDayStates)(states);
|
|
85
|
+
return described ? `${formattedDate}, ${described}` : formattedDate;
|
|
86
|
+
};
|
|
87
|
+
exports.dayAccessibleName = dayAccessibleName;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PaletteProps } from "./tokens/types";
|
|
2
|
-
declare const REQUIRED_GROUPS: readonly ["gradient", "primary", "secondary", "tertiary", "transparent", "black", "white", "semantic", "gray", "red", "orange", "yellow", "green", "teal", "blue", "cyan", "purple", "pink", "backgroundColor", "background", "text", "header", "placeholder", "boxShadow", "sidebar", "boxborder", "border", "table", "disabled", "accentText", "textMuted", "semanticText", "onPrimary", "onSemantic"];
|
|
2
|
+
declare const REQUIRED_GROUPS: readonly ["gradient", "primary", "secondary", "tertiary", "transparent", "black", "white", "semantic", "gray", "red", "orange", "yellow", "green", "teal", "blue", "cyan", "purple", "pink", "backgroundColor", "background", "text", "header", "placeholder", "boxShadow", "focusRing", "sidebar", "boxborder", "border", "table", "disabled", "accentText", "textMuted", "semanticText", "onPrimary", "onSemantic"];
|
|
3
3
|
type Unlisted = Exclude<keyof PaletteProps, (typeof REQUIRED_GROUPS)[number]>;
|
|
4
4
|
export type AllPaletteTokensListed = Unlisted extends never ? true : ["unlisted token", Unlisted];
|
|
5
5
|
export declare const allPaletteTokensListed: AllPaletteTokensListed;
|
|
@@ -5,8 +5,8 @@ const REQUIRED_GROUPS = [
|
|
|
5
5
|
"gradient", "primary", "secondary", "tertiary", "transparent", "black", "white",
|
|
6
6
|
"semantic", "gray", "red", "orange", "yellow", "green", "teal", "blue", "cyan",
|
|
7
7
|
"purple", "pink", "backgroundColor", "background", "text", "header", "placeholder",
|
|
8
|
-
"boxShadow", "sidebar", "boxborder", "border", "table", "disabled",
|
|
9
|
-
"textMuted", "semanticText", "onPrimary", "onSemantic",
|
|
8
|
+
"boxShadow", "focusRing", "sidebar", "boxborder", "border", "table", "disabled",
|
|
9
|
+
"accentText", "textMuted", "semanticText", "onPrimary", "onSemantic",
|
|
10
10
|
];
|
|
11
11
|
exports.allPaletteTokensListed = true;
|
|
12
12
|
const NESTED = [
|
|
@@ -17,6 +17,7 @@ const NESTED = [
|
|
|
17
17
|
]],
|
|
18
18
|
["semanticText", ["success", "error", "warning", "info"]],
|
|
19
19
|
["onSemantic", ["success", "error", "warning", "info"]],
|
|
20
|
+
["focusRing", ["ring", "halo"]],
|
|
20
21
|
["backgroundColor", ["main", "base"]],
|
|
21
22
|
["boxShadow", ["primary", "default"]],
|
|
22
23
|
];
|
|
@@ -10,6 +10,7 @@ const fonts_web_1 = __importDefault(require("./fonts.web"));
|
|
|
10
10
|
const componentStyles_1 = require("./componentStyles");
|
|
11
11
|
const accentText_1 = require("../tokens/builders/accentText");
|
|
12
12
|
const scrollbar_1 = require("../tokens/builders/scrollbar");
|
|
13
|
+
const focusRing_styles_1 = require("./focusRing.styles");
|
|
13
14
|
/**
|
|
14
15
|
* Builds a Chakra theme from a pure brand palette.
|
|
15
16
|
*
|
|
@@ -27,6 +28,12 @@ const createBrandTheme = (palette, options = {}) => {
|
|
|
27
28
|
colors: palette,
|
|
28
29
|
...fonts_web_1.default,
|
|
29
30
|
...common_web_1.default,
|
|
31
|
+
// `shadows.outline` is what Chakra's stock `_focusVisible` reaches for on EVERY component it
|
|
32
|
+
// themes. The primitive ships one hardcoded blue (`rgba(66,153,225,.6)`), which measured
|
|
33
|
+
// 1.83:1 on the lavender canvas and 1.38:1 on a primary button — below 1.4.11's 3:1 on all
|
|
34
|
+
// nine brands, in both modes. A primitive cannot know the palette; this is the first place
|
|
35
|
+
// that does, so the palette-derived ring is bound here and every stock focus state inherits it.
|
|
36
|
+
shadows: { ...common_web_1.default.shadows, outline: (0, focusRing_styles_1.focusRingShadow)(palette) },
|
|
30
37
|
};
|
|
31
38
|
return (0, react_1.extendTheme)({
|
|
32
39
|
...brand,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { FocusRingTokens } from "../tokens/types";
|
|
2
|
+
/**
|
|
3
|
+
* WEB binding for the `focusRing` token pair. The colours are derived in
|
|
4
|
+
* `tokens/builders/focusRing.ts` (pure, shared with the mobile library); the CSS shape —
|
|
5
|
+
* box-shadow bands, the forced-colors outline — is web-only and lives here.
|
|
6
|
+
*/
|
|
7
|
+
/** Inner band, in the surface tone: separates the ring from the control's own fill. */
|
|
8
|
+
export declare const FOCUS_HALO_WIDTH = 2;
|
|
9
|
+
/** Outer edge of the brand band. The band itself is the 2px between halo and ring. */
|
|
10
|
+
export declare const FOCUS_RING_WIDTH = 4;
|
|
11
|
+
type WithFocusRing = {
|
|
12
|
+
focusRing: FocusRingTokens;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The two-tone ring as a single `box-shadow`. Drawn OUTSIDE the border box, so it costs no
|
|
16
|
+
* layout and never resizes the control — the reason this is a shadow and not an outline.
|
|
17
|
+
*/
|
|
18
|
+
export declare const focusRingShadow: (colors: WithFocusRing) => string;
|
|
19
|
+
/**
|
|
20
|
+
* `:hover`, `:active` and `:focus-visible` all score the same specificity, so which one paints
|
|
21
|
+
* comes down to source order — and in the merged style object Chakra's own Button baseStyle
|
|
22
|
+
* registers `_focusVisible` BEFORE `_hover`. A focused button that is also hovered would then
|
|
23
|
+
* drop the ring for `_hover`'s `boxShadow: "sm"`. Stacking the pseudo-classes raises the
|
|
24
|
+
* specificity above both, so the ring survives whatever else the state repaints.
|
|
25
|
+
*/
|
|
26
|
+
export declare const FOCUS_VISIBLE_OVER_STATE = "&:hover:focus-visible, &:active:focus-visible, &[data-active]:focus-visible";
|
|
27
|
+
/**
|
|
28
|
+
* `:focus-visible`, never `:focus` — a mouse click must not draw a ring.
|
|
29
|
+
*
|
|
30
|
+
* The transparent outline is not decoration: in Windows High Contrast / `forced-colors` mode
|
|
31
|
+
* box-shadows are dropped entirely, and a transparent outline is the one thing the OS repaints
|
|
32
|
+
* in its own focus colour. Without it, forced-colors users get no indicator at all.
|
|
33
|
+
*/
|
|
34
|
+
export declare const focusVisibleRing: (colors: WithFocusRing) => {
|
|
35
|
+
outline: string;
|
|
36
|
+
outlineOffset: string;
|
|
37
|
+
boxShadow: string;
|
|
38
|
+
};
|
|
39
|
+
/** Both selectors a control needs to keep the ring on top of its own hover/active styling. */
|
|
40
|
+
export declare const focusVisibleStyles: (colors: WithFocusRing) => {
|
|
41
|
+
_focusVisible: {
|
|
42
|
+
outline: string;
|
|
43
|
+
outlineOffset: string;
|
|
44
|
+
boxShadow: string;
|
|
45
|
+
};
|
|
46
|
+
"&:hover:focus-visible, &:active:focus-visible, &[data-active]:focus-visible": {
|
|
47
|
+
outline: string;
|
|
48
|
+
outlineOffset: string;
|
|
49
|
+
boxShadow: string;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.focusVisibleStyles = exports.focusVisibleRing = exports.FOCUS_VISIBLE_OVER_STATE = exports.focusRingShadow = exports.FOCUS_RING_WIDTH = exports.FOCUS_HALO_WIDTH = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* WEB binding for the `focusRing` token pair. The colours are derived in
|
|
6
|
+
* `tokens/builders/focusRing.ts` (pure, shared with the mobile library); the CSS shape —
|
|
7
|
+
* box-shadow bands, the forced-colors outline — is web-only and lives here.
|
|
8
|
+
*/
|
|
9
|
+
/** Inner band, in the surface tone: separates the ring from the control's own fill. */
|
|
10
|
+
exports.FOCUS_HALO_WIDTH = 2;
|
|
11
|
+
/** Outer edge of the brand band. The band itself is the 2px between halo and ring. */
|
|
12
|
+
exports.FOCUS_RING_WIDTH = 4;
|
|
13
|
+
/**
|
|
14
|
+
* The two-tone ring as a single `box-shadow`. Drawn OUTSIDE the border box, so it costs no
|
|
15
|
+
* layout and never resizes the control — the reason this is a shadow and not an outline.
|
|
16
|
+
*/
|
|
17
|
+
const focusRingShadow = (colors) => `0 0 0 ${exports.FOCUS_HALO_WIDTH}px ${colors.focusRing.halo}, ` +
|
|
18
|
+
`0 0 0 ${exports.FOCUS_RING_WIDTH}px ${colors.focusRing.ring}`;
|
|
19
|
+
exports.focusRingShadow = focusRingShadow;
|
|
20
|
+
/**
|
|
21
|
+
* `:hover`, `:active` and `:focus-visible` all score the same specificity, so which one paints
|
|
22
|
+
* comes down to source order — and in the merged style object Chakra's own Button baseStyle
|
|
23
|
+
* registers `_focusVisible` BEFORE `_hover`. A focused button that is also hovered would then
|
|
24
|
+
* drop the ring for `_hover`'s `boxShadow: "sm"`. Stacking the pseudo-classes raises the
|
|
25
|
+
* specificity above both, so the ring survives whatever else the state repaints.
|
|
26
|
+
*/
|
|
27
|
+
exports.FOCUS_VISIBLE_OVER_STATE = "&:hover:focus-visible, &:active:focus-visible, &[data-active]:focus-visible";
|
|
28
|
+
/**
|
|
29
|
+
* `:focus-visible`, never `:focus` — a mouse click must not draw a ring.
|
|
30
|
+
*
|
|
31
|
+
* The transparent outline is not decoration: in Windows High Contrast / `forced-colors` mode
|
|
32
|
+
* box-shadows are dropped entirely, and a transparent outline is the one thing the OS repaints
|
|
33
|
+
* in its own focus colour. Without it, forced-colors users get no indicator at all.
|
|
34
|
+
*/
|
|
35
|
+
const focusVisibleRing = (colors) => ({
|
|
36
|
+
outline: "2px solid transparent",
|
|
37
|
+
outlineOffset: "2px",
|
|
38
|
+
boxShadow: (0, exports.focusRingShadow)(colors),
|
|
39
|
+
});
|
|
40
|
+
exports.focusVisibleRing = focusVisibleRing;
|
|
41
|
+
/** Both selectors a control needs to keep the ring on top of its own hover/active styling. */
|
|
42
|
+
const focusVisibleStyles = (colors) => {
|
|
43
|
+
const ring = (0, exports.focusVisibleRing)(colors);
|
|
44
|
+
return { _focusVisible: ring, [exports.FOCUS_VISIBLE_OVER_STATE]: ring };
|
|
45
|
+
};
|
|
46
|
+
exports.focusVisibleStyles = focusVisibleStyles;
|
|
@@ -46,6 +46,7 @@ const sidebarAccent_1 = require("../builders/sidebarAccent");
|
|
|
46
46
|
const mutedText_1 = require("../builders/mutedText");
|
|
47
47
|
const semanticText_1 = require("../builders/semanticText");
|
|
48
48
|
const resolvedRungs_1 = require("../builders/resolvedRungs");
|
|
49
|
+
const focusRing_1 = require("../builders/focusRing");
|
|
49
50
|
const surfaceRungs_1 = require("../builders/surfaceRungs");
|
|
50
51
|
/** Derived, never hand-written: a copied hex goes stale the moment a canvas moves. */
|
|
51
52
|
const finalizeLightPalette = (source) => ({
|
|
@@ -56,9 +57,13 @@ const finalizeLightPalette = (source) => ({
|
|
|
56
57
|
semanticText: (0, semanticText_1.buildSemanticText)(source.semantic, source.backgroundColor.main),
|
|
57
58
|
onPrimary: (0, accentText_1.onFilled)(source.primary[500], source.white, source.black),
|
|
58
59
|
onSemantic: (0, semanticText_1.buildOnSemantic)(source.semantic, source.white, source.black),
|
|
60
|
+
focusRing: (0, focusRing_1.buildFocusRing)(source),
|
|
59
61
|
});
|
|
60
62
|
exports.finalizeLightPalette = finalizeLightPalette;
|
|
61
|
-
|
|
63
|
+
// `withFocusRing` is outermost: it is the only step that reads `primary` and the surfaces
|
|
64
|
+
// TOGETHER, so it must see both after every earlier step — and after a brand file's own
|
|
65
|
+
// post-derivation overrides (zinc dark replaces `primary` and `background` wholesale).
|
|
66
|
+
const resolveRungs = (palette) => (0, focusRing_1.withFocusRing)((0, surfaceRungs_1.withSurfaceRungs)((0, resolvedRungs_1.withTableHoverRung)((0, resolvedRungs_1.withPlaceholderRung)((0, outlineRung_1.withOutlineRung)(palette)))));
|
|
62
67
|
const lightBrand = (source) => resolveRungs((0, exports.finalizeLightPalette)(source));
|
|
63
68
|
/** Light palette per brand. `lavender` is the base the other six extend. */
|
|
64
69
|
exports.lightPalettes = {
|
|
@@ -197,6 +197,7 @@ declare const palette: {
|
|
|
197
197
|
purple: import("../..").ColorScale;
|
|
198
198
|
pink: import("../..").ColorScale;
|
|
199
199
|
backgroundColor: import("../..").NamedSurfaces;
|
|
200
|
+
focusRing: import("../..").FocusRingTokens;
|
|
200
201
|
sidebar: import("../..").SidebarTokens;
|
|
201
202
|
semanticText: import("../..").SemanticTextTokens;
|
|
202
203
|
textMuted: string;
|
|
@@ -8,6 +8,7 @@ const accentText_1 = require("./accentText");
|
|
|
8
8
|
const sidebarAccent_1 = require("./sidebarAccent");
|
|
9
9
|
const mutedText_1 = require("./mutedText");
|
|
10
10
|
const semanticText_1 = require("./semanticText");
|
|
11
|
+
const focusRing_1 = require("./focusRing");
|
|
11
12
|
/**
|
|
12
13
|
* Derives a brand's dark palette from its light palette.
|
|
13
14
|
*
|
|
@@ -246,6 +247,7 @@ function buildDarkPalette(light) {
|
|
|
246
247
|
]));
|
|
247
248
|
const white = light.white;
|
|
248
249
|
const primary = liftBrand(light.primary, white);
|
|
250
|
+
const background = fromTargets(hueSource, SURFACE_TARGETS, SURFACE_SAT);
|
|
249
251
|
const semantic = {
|
|
250
252
|
success: liftAccent(light.semantic.success, white),
|
|
251
253
|
error: liftAccent(light.semantic.error, white),
|
|
@@ -276,7 +278,7 @@ function buildDarkPalette(light) {
|
|
|
276
278
|
purple: (0, exports.reverseScale)(light.purple),
|
|
277
279
|
pink: (0, exports.reverseScale)(light.pink),
|
|
278
280
|
backgroundColor: namedSurfaces,
|
|
279
|
-
background
|
|
281
|
+
background,
|
|
280
282
|
text: fromTargets(hueSource, TEXT_TARGETS, TEXT_SAT),
|
|
281
283
|
header: fromTargets(hueSource, TEXT_TARGETS, TEXT_SAT + 2),
|
|
282
284
|
placeholder: fromTargets(hueSource, PLACEHOLDER_TARGETS, PLACEHOLDER_SAT),
|
|
@@ -293,6 +295,9 @@ function buildDarkPalette(light) {
|
|
|
293
295
|
semanticText: (0, semanticText_1.buildSemanticText)(semantic, namedSurfaces.main),
|
|
294
296
|
onPrimary: (0, accentText_1.onFilled)(primary[500], light.white, light.black),
|
|
295
297
|
onSemantic: (0, semanticText_1.buildOnSemantic)(semantic, light.white, light.black),
|
|
298
|
+
// The dark ring is derived from the LIFTED accent against the dark canvas, not copied from
|
|
299
|
+
// light: the two modes squeeze it from opposite sides, so a shared value fails one of them.
|
|
300
|
+
focusRing: (0, focusRing_1.buildFocusRing)({ primary, background, backgroundColor: namedSurfaces }),
|
|
296
301
|
// Sidebar is already near-black in light mode, so it needs no inversion.
|
|
297
302
|
sidebar: (0, sidebarAccent_1.withSidebarTokens)(light),
|
|
298
303
|
boxShadow: {
|