@eifi1/ui-kit 0.9.0 → 0.11.0
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 +37 -23
- package/dist/components/alert-banner.d.ts +57 -5
- package/dist/components/alert-banner.js +63 -17
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +6 -0
- package/dist/components/breadcrumbs.d.ts +60 -0
- package/dist/components/breadcrumbs.js +88 -0
- package/dist/components/breadcrumbs.js.map +1 -0
- package/dist/components/bulk-action-bar.d.ts +112 -0
- package/dist/components/bulk-action-bar.js +196 -0
- package/dist/components/bulk-action-bar.js.map +1 -0
- package/dist/components/button-group.d.ts +58 -3
- package/dist/components/button-group.js +56 -5
- package/dist/components/button-group.js.map +1 -1
- package/dist/components/calculator.d.ts +6 -0
- package/dist/components/calendar-heatmap.d.ts +124 -0
- package/dist/components/calendar-heatmap.js +295 -0
- package/dist/components/calendar-heatmap.js.map +1 -0
- package/dist/components/chip.d.ts +31 -5
- package/dist/components/chip.js +85 -5
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +34 -2
- package/dist/components/choice-card.js +49 -0
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/copy-button.d.ts +14 -4
- package/dist/components/copy-button.js +17 -4
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/data-table.js +2 -0
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +22 -2
- package/dist/components/date-picker.js +11 -3
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +43 -6
- package/dist/components/description-list.js +91 -11
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +7 -0
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/disclosure.d.ts +57 -2
- package/dist/components/disclosure.js +24 -12
- package/dist/components/disclosure.js.map +1 -1
- package/dist/components/field.d.ts +43 -0
- package/dist/components/field.js +52 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/file-button.d.ts +1 -0
- package/dist/components/file-dropzone.d.ts +4 -4
- package/dist/components/file-dropzone.js +2 -1
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/floating-panel.d.ts +147 -4
- package/dist/components/floating-panel.js +188 -28
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/full-bleed-dialog.d.ts +23 -4
- package/dist/components/full-bleed-dialog.js +11 -2
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/list.d.ts +187 -0
- package/dist/components/list.js +221 -0
- package/dist/components/list.js.map +1 -0
- package/dist/components/menu-item.d.ts +109 -0
- package/dist/components/menu-item.js +88 -0
- package/dist/components/menu-item.js.map +1 -0
- package/dist/components/mini-calendar.d.ts +70 -5
- package/dist/components/mini-calendar.js +166 -62
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +23 -1
- package/dist/components/modal.js +36 -10
- package/dist/components/modal.js.map +1 -1
- package/dist/components/nav-pills.d.ts +66 -0
- package/dist/components/nav-pills.js +65 -0
- package/dist/components/nav-pills.js.map +1 -0
- package/dist/components/number-field.d.ts +6 -0
- package/dist/components/number-input.d.ts +6 -0
- package/dist/components/numpad-sheet.d.ts +6 -0
- package/dist/components/page-contents.js +1 -2
- package/dist/components/page-contents.js.map +1 -1
- package/dist/components/page-header.d.ts +37 -0
- package/dist/components/page-header.js +36 -0
- package/dist/components/page-header.js.map +1 -0
- package/dist/components/progress-bar.d.ts +31 -2
- package/dist/components/progress-bar.js +73 -7
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/series-chart-labels.d.ts +3 -0
- package/dist/components/series-chart-labels.js +2 -1
- package/dist/components/series-chart-labels.js.map +1 -1
- package/dist/components/series-chart.d.ts +32 -0
- package/dist/components/series-chart.js +141 -4
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/settings-fields.d.ts +1 -0
- package/dist/components/status-dot.d.ts +53 -0
- package/dist/components/status-dot.js +57 -0
- package/dist/components/status-dot.js.map +1 -0
- package/dist/components/table.d.ts +78 -13
- package/dist/components/table.js +84 -11
- package/dist/components/table.js.map +1 -1
- package/dist/components/text.d.ts +70 -0
- package/dist/components/text.js +24 -0
- package/dist/components/text.js.map +1 -0
- package/dist/components/time-input.d.ts +1 -0
- package/dist/components/toast.d.ts +167 -0
- package/dist/components/toast.js +226 -0
- package/dist/components/toast.js.map +1 -0
- package/dist/components/toggle-group.d.ts +44 -1
- package/dist/components/toggle-group.js +73 -4
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/tooltip.d.ts +46 -15
- package/dist/components/tooltip.js +87 -47
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/ui.d.ts +158 -7
- package/dist/components/ui.js +191 -10
- package/dist/components/ui.js.map +1 -1
- package/dist/components/user-avatar.d.ts +25 -3
- package/dist/components/user-avatar.js +32 -3
- package/dist/components/user-avatar.js.map +1 -1
- package/dist/hooks/use-close-transition.d.ts +7 -1
- package/dist/hooks/use-close-transition.js +5 -2
- package/dist/hooks/use-close-transition.js.map +1 -1
- package/dist/hooks/use-copy-to-clipboard.js +1 -1
- package/dist/hooks/use-copy-to-clipboard.js.map +1 -1
- package/dist/hooks/use-file-drop.d.ts +1 -0
- package/dist/i18n/defaults.d.ts +6 -0
- package/dist/i18n/defaults.js +11 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +11 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +6 -0
- package/dist/i18n/locales/de-CH.d.ts +6 -0
- package/dist/i18n/locales/de-informal.d.ts +6 -0
- package/dist/i18n/locales/de.d.ts +6 -0
- package/dist/i18n/locales/de.js +30 -2
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +6 -0
- package/dist/i18n/locales/es.js +30 -2
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +6 -0
- package/dist/i18n/locales/fr.js +30 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +6 -0
- package/dist/i18n/locales/hu.js +30 -2
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +6 -0
- package/dist/i18n/locales/it.js +30 -2
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +6 -0
- package/dist/i18n/locales/zh.js +30 -2
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.d.ts +27 -15
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/clipping.d.ts +25 -0
- package/dist/lib/clipping.js +17 -0
- package/dist/lib/clipping.js.map +1 -0
- package/dist/lib/dates.d.ts +17 -1
- package/dist/lib/dates.js +19 -0
- package/dist/lib/dates.js.map +1 -1
- package/dist/rhf/form.d.ts +1 -0
- package/dist/rhf/use-rhf-wizard-step.d.ts +22 -0
- package/dist/rhf/use-rhf-wizard-step.js +38 -0
- package/dist/rhf/use-rhf-wizard-step.js.map +1 -0
- package/dist/rhf.d.ts +2 -0
- package/dist/rhf.js +1 -0
- package/dist/rhf.js.map +1 -1
- package/dist/search/command-palette.d.ts +19 -2
- package/dist/search/command-palette.js +16 -5
- package/dist/search/command-palette.js.map +1 -1
- package/dist/search/global-search.d.ts +26 -1
- package/dist/search/global-search.js +29 -13
- package/dist/search/global-search.js.map +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/shell/topbar-action-menu.d.ts +73 -3
- package/dist/shell/topbar-action-menu.js +100 -27
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +2 -1
- package/dist/wizard/stepper-nav.d.ts +1 -0
- package/dist/wizard/stepper-nav.js +1 -1
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard/types.d.ts +2 -2
- package/dist/wizard/types.js.map +1 -1
- package/dist/wizard/use-wizard.js +1 -1
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/wizard-context.d.ts +7 -1
- package/dist/wizard/wizard-context.js +4 -0
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-summary.js +3 -3
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/dist/wizard.d.ts +2 -1
- package/package.json +16 -12
- package/src/components/alert-banner.tsx +149 -21
- package/src/components/breadcrumbs.tsx +168 -0
- package/src/components/bulk-action-bar.tsx +362 -0
- package/src/components/button-group.tsx +124 -4
- package/src/components/calendar-heatmap.tsx +504 -0
- package/src/components/chip.tsx +128 -7
- package/src/components/choice-card.tsx +97 -1
- package/src/components/copy-button.tsx +29 -7
- package/src/components/data-table.tsx +7 -0
- package/src/components/date-picker.tsx +49 -1
- package/src/components/description-list.tsx +168 -15
- package/src/components/dialog-frame.tsx +7 -0
- package/src/components/disclosure.tsx +93 -21
- package/src/components/field.tsx +137 -0
- package/src/components/file-dropzone.tsx +9 -10
- package/src/components/floating-panel.tsx +366 -15
- package/src/components/full-bleed-dialog.tsx +42 -5
- package/src/components/list.tsx +443 -0
- package/src/components/menu-item.tsx +235 -0
- package/src/components/mini-calendar.tsx +245 -54
- package/src/components/modal.tsx +80 -17
- package/src/components/nav-pills.tsx +145 -0
- package/src/components/page-contents.tsx +4 -4
- package/src/components/page-header.tsx +68 -0
- package/src/components/progress-bar.tsx +129 -11
- package/src/components/series-chart-labels.ts +4 -0
- package/src/components/series-chart.tsx +274 -3
- package/src/components/status-dot.tsx +107 -0
- package/src/components/table.tsx +176 -17
- package/src/components/text.tsx +97 -0
- package/src/components/toast.tsx +441 -0
- package/src/components/toggle-group.tsx +128 -4
- package/src/components/tooltip.tsx +200 -100
- package/src/components/ui.tsx +381 -14
- package/src/components/user-avatar.tsx +57 -3
- package/src/hooks/use-close-transition.ts +14 -5
- package/src/hooks/use-copy-to-clipboard.ts +1 -1
- package/src/i18n/defaults.ts +10 -0
- package/src/i18n/kit-labels.tsx +10 -0
- package/src/i18n/locales/de.ts +29 -0
- package/src/i18n/locales/es.ts +29 -0
- package/src/i18n/locales/fr.ts +29 -0
- package/src/i18n/locales/hu.ts +29 -0
- package/src/i18n/locales/it.ts +29 -0
- package/src/i18n/locales/zh.ts +29 -0
- package/src/index.ts +31 -0
- package/src/lib/clipping.ts +34 -0
- package/src/lib/dates.ts +37 -0
- package/src/rhf/use-rhf-wizard-step.ts +113 -0
- package/src/rhf.ts +2 -0
- package/src/search/command-palette.tsx +42 -5
- package/src/search/global-search.tsx +59 -18
- package/src/shell/topbar-action-menu.tsx +239 -49
- package/src/wizard/stepper-nav.tsx +2 -1
- package/src/wizard/types.ts +2 -2
- package/src/wizard/use-wizard.ts +3 -3
- package/src/wizard/wizard-context.tsx +9 -0
- package/src/wizard/wizard-summary.tsx +14 -10
- package/tokens.css +97 -0
package/src/components/chip.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { forwardRef, useId, useRef, useState } from "react";
|
|
2
2
|
import type { ComponentPropsWithoutRef, KeyboardEvent, MouseEvent, ReactElement, ReactNode, Ref } from "react";
|
|
3
|
-
import { X } from "lucide-react";
|
|
3
|
+
import { Check, X } from "lucide-react";
|
|
4
4
|
import type { LucideIcon } from "lucide-react";
|
|
5
5
|
import { cn } from "../lib/cn";
|
|
6
6
|
import { horizontalStep } from "../lib/direction";
|
|
@@ -30,9 +30,22 @@ export type ChipTone =
|
|
|
30
30
|
| "success"
|
|
31
31
|
| "info"
|
|
32
32
|
| "income"
|
|
33
|
-
| "expense"
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
| "expense"
|
|
34
|
+
| ChipHue;
|
|
35
|
+
/**
|
|
36
|
+
* Categorical hues (0.10.0): colour that says "a different value" and nothing more —
|
|
37
|
+
* kastlan's status-badge.tsx paints ~15 enums in 9 Tailwind hues by hand. Four of those
|
|
38
|
+
* nine are semantic and already tones (green = `success`, yellow = `warning`, red =
|
|
39
|
+
* `danger`, gray = `neutral`); these five are the rest, each a `--hue-*` token triple
|
|
40
|
+
* in tokens.css with a light and a dark value. Use a semantic tone when the value HAS a
|
|
41
|
+
* meaning (overdue is `danger`), a hue when it only needs telling apart (sent vs
|
|
42
|
+
* accepted vs invoiced).
|
|
43
|
+
*/
|
|
44
|
+
export type ChipHue = "blue" | "indigo" | "purple" | "teal" | "orange";
|
|
45
|
+
/** `lg` is the 44px touch target (`min-h-11`) a phone surface wants; `md` is ~28px.
|
|
46
|
+
* `xs` (0.10.0) is 11px type at `px-1.5` — keksdose's goal markers and budget-cell
|
|
47
|
+
* badges, which sit inside a figure's line and must not make it taller. */
|
|
48
|
+
export type ChipSize = "xs" | "sm" | "md" | "lg";
|
|
36
49
|
/**
|
|
37
50
|
* How much of the tone the chip wears.
|
|
38
51
|
*
|
|
@@ -43,8 +56,12 @@ export type ChipSize = "sm" | "md" | "lg";
|
|
|
43
56
|
* - `solid`: the tone as a fill under contrasting text — the "count" pill (unread
|
|
44
57
|
* messages, open tasks). It centres its content and sets figures tabular, so a
|
|
45
58
|
* one-digit count is a round dot and "9" → "10" does not jiggle the row.
|
|
59
|
+
* - `dot` (0.10.0): no pill at all — a dot in the tone's colour before plain text, for
|
|
60
|
+
* a status in a dense list or a table column where eight tinted pills in a column
|
|
61
|
+
* would outshout the figures beside them (kastlan's unit picker already draws its
|
|
62
|
+
* UnitStatus this way, from a separate `dotColor` map).
|
|
46
63
|
*/
|
|
47
|
-
export type ChipVariant = "soft" | "outline" | "solid";
|
|
64
|
+
export type ChipVariant = "soft" | "outline" | "solid" | "dot";
|
|
48
65
|
/** `pill` (default) is fully rounded; `square` has the small radius of a field or a
|
|
49
66
|
* button — for a chip that sits in a table cell or beside square controls. */
|
|
50
67
|
export type ChipShape = "pill" | "square";
|
|
@@ -86,6 +103,28 @@ const TONE: Record<ChipTone, { idle: string; selected: string }> = {
|
|
|
86
103
|
idle: "border-current/40 bg-[var(--bg-surface-2)] text-[var(--money-expense)]",
|
|
87
104
|
selected: "border-current bg-[var(--bg-active)] text-[var(--money-expense)]",
|
|
88
105
|
},
|
|
106
|
+
// The categorical hues: the `info` recipe with its own token triple, so a hue chip
|
|
107
|
+
// and a status chip in one row carry the same weight.
|
|
108
|
+
blue: {
|
|
109
|
+
idle: "border-[var(--hue-blue-border)] bg-[var(--hue-blue-bg)] text-[var(--hue-blue)]",
|
|
110
|
+
selected: "border-[var(--hue-blue)] bg-[var(--hue-blue-bg)] text-[var(--hue-blue)]",
|
|
111
|
+
},
|
|
112
|
+
indigo: {
|
|
113
|
+
idle: "border-[var(--hue-indigo-border)] bg-[var(--hue-indigo-bg)] text-[var(--hue-indigo)]",
|
|
114
|
+
selected: "border-[var(--hue-indigo)] bg-[var(--hue-indigo-bg)] text-[var(--hue-indigo)]",
|
|
115
|
+
},
|
|
116
|
+
purple: {
|
|
117
|
+
idle: "border-[var(--hue-purple-border)] bg-[var(--hue-purple-bg)] text-[var(--hue-purple)]",
|
|
118
|
+
selected: "border-[var(--hue-purple)] bg-[var(--hue-purple-bg)] text-[var(--hue-purple)]",
|
|
119
|
+
},
|
|
120
|
+
teal: {
|
|
121
|
+
idle: "border-[var(--hue-teal-border)] bg-[var(--hue-teal-bg)] text-[var(--hue-teal)]",
|
|
122
|
+
selected: "border-[var(--hue-teal)] bg-[var(--hue-teal-bg)] text-[var(--hue-teal)]",
|
|
123
|
+
},
|
|
124
|
+
orange: {
|
|
125
|
+
idle: "border-[var(--hue-orange-border)] bg-[var(--hue-orange-bg)] text-[var(--hue-orange)]",
|
|
126
|
+
selected: "border-[var(--hue-orange)] bg-[var(--hue-orange-bg)] text-[var(--hue-orange)]",
|
|
127
|
+
},
|
|
89
128
|
};
|
|
90
129
|
|
|
91
130
|
// `outline` idle looks: the tone's border and text, the surface left to whatever the
|
|
@@ -100,6 +139,11 @@ const OUTLINE: Record<ChipTone, string> = {
|
|
|
100
139
|
info: "border-[var(--info-border)] bg-transparent text-[var(--info)]",
|
|
101
140
|
income: "border-current/60 bg-transparent text-[var(--money-income)]",
|
|
102
141
|
expense: "border-current/60 bg-transparent text-[var(--money-expense)]",
|
|
142
|
+
blue: "border-[var(--hue-blue-border)] bg-transparent text-[var(--hue-blue)]",
|
|
143
|
+
indigo: "border-[var(--hue-indigo-border)] bg-transparent text-[var(--hue-indigo)]",
|
|
144
|
+
purple: "border-[var(--hue-purple-border)] bg-transparent text-[var(--hue-purple)]",
|
|
145
|
+
teal: "border-[var(--hue-teal-border)] bg-transparent text-[var(--hue-teal)]",
|
|
146
|
+
orange: "border-[var(--hue-orange-border)] bg-transparent text-[var(--hue-orange)]",
|
|
103
147
|
};
|
|
104
148
|
|
|
105
149
|
// `solid`: the fill under its contrast pair. Only brand and danger have a declared
|
|
@@ -116,12 +160,40 @@ const SOLID: Record<ChipTone, string> = {
|
|
|
116
160
|
info: "border-transparent bg-[var(--info)] text-[var(--text-inverse)]",
|
|
117
161
|
income: "border-transparent bg-[var(--money-income)] text-[var(--text-inverse)]",
|
|
118
162
|
expense: "border-transparent bg-[var(--money-expense)] text-[var(--text-inverse)]",
|
|
163
|
+
blue: "border-transparent bg-[var(--hue-blue)] text-[var(--text-inverse)]",
|
|
164
|
+
indigo: "border-transparent bg-[var(--hue-indigo)] text-[var(--text-inverse)]",
|
|
165
|
+
purple: "border-transparent bg-[var(--hue-purple)] text-[var(--text-inverse)]",
|
|
166
|
+
teal: "border-transparent bg-[var(--hue-teal)] text-[var(--text-inverse)]",
|
|
167
|
+
orange: "border-transparent bg-[var(--hue-orange)] text-[var(--text-inverse)]",
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/** `dot`: the fill of the dot itself — the tone's strongest colour, which is the one
|
|
171
|
+
* chosen to read on the page surface in both themes. Neutral takes the muted ink: a
|
|
172
|
+
* grey dot is "no particular state", not a darker black. */
|
|
173
|
+
const DOT: Record<ChipTone, string> = {
|
|
174
|
+
neutral: "bg-[var(--text-muted)]",
|
|
175
|
+
brand: "bg-[var(--brand)]",
|
|
176
|
+
danger: "bg-[var(--danger)]",
|
|
177
|
+
warning: "bg-[var(--warning)]",
|
|
178
|
+
success: "bg-[var(--success)]",
|
|
179
|
+
info: "bg-[var(--info)]",
|
|
180
|
+
income: "bg-[var(--money-income)]",
|
|
181
|
+
expense: "bg-[var(--money-expense)]",
|
|
182
|
+
blue: "bg-[var(--hue-blue)]",
|
|
183
|
+
indigo: "bg-[var(--hue-indigo)]",
|
|
184
|
+
purple: "bg-[var(--hue-purple)]",
|
|
185
|
+
teal: "bg-[var(--hue-teal)]",
|
|
186
|
+
orange: "bg-[var(--hue-orange)]",
|
|
119
187
|
};
|
|
120
188
|
|
|
189
|
+
/** Per size: the dot's diameter. */
|
|
190
|
+
const DOT_SIZE: Record<ChipSize, string> = { xs: "size-1.5", sm: "size-2", md: "size-2", lg: "size-2.5" };
|
|
191
|
+
|
|
121
192
|
/** The status-badge type (`caps`): a size step down, heavier and tracked, because
|
|
122
193
|
* capitals at body size shout and capitals untracked run together. Per size, so it
|
|
123
194
|
* replaces the size's own `text-*` through tailwind-merge. */
|
|
124
195
|
const CAPS: Record<ChipSize, string> = {
|
|
196
|
+
xs: "text-[10px] font-semibold uppercase tracking-wider",
|
|
125
197
|
sm: "text-[10px] font-semibold uppercase tracking-wider",
|
|
126
198
|
md: "text-[11px] font-semibold uppercase tracking-wider",
|
|
127
199
|
lg: "text-xs font-semibold uppercase tracking-wider",
|
|
@@ -129,6 +201,13 @@ const CAPS: Record<ChipSize, string> = {
|
|
|
129
201
|
|
|
130
202
|
function surfaceOf(tone: ChipTone, variant: ChipVariant, selected: boolean | undefined): string {
|
|
131
203
|
const palette = TONE[tone];
|
|
204
|
+
if (variant === "dot") {
|
|
205
|
+
// No surface and no border colour: the dot carries the tone, the text stays ink.
|
|
206
|
+
// The border goes transparent rather than away, so a dot chip lines up with a pill.
|
|
207
|
+
return selected
|
|
208
|
+
? "border-transparent bg-transparent font-medium text-[var(--text-primary)]"
|
|
209
|
+
: "border-transparent bg-transparent text-[var(--text-secondary)]";
|
|
210
|
+
}
|
|
132
211
|
if (variant === "solid") {
|
|
133
212
|
// A solid chip is already the strongest look there is, so "on" is a ring round it.
|
|
134
213
|
return cn(SOLID[tone], selected && "ring-2 ring-[var(--border-strong)] ring-offset-1 ring-offset-[var(--bg-surface)]");
|
|
@@ -172,6 +251,13 @@ const SIZE: Record<
|
|
|
172
251
|
ChipSize,
|
|
173
252
|
{ body: string; split: string; tail: string; icon: string; remove: string }
|
|
174
253
|
> = {
|
|
254
|
+
xs: {
|
|
255
|
+
body: "gap-1 px-1.5 py-0 text-[11px] leading-4",
|
|
256
|
+
split: "gap-1 ps-1.5 pe-0.5 py-0 text-[11px] leading-4",
|
|
257
|
+
tail: "pe-1",
|
|
258
|
+
icon: "size-3",
|
|
259
|
+
remove: "size-2.5",
|
|
260
|
+
},
|
|
175
261
|
sm: {
|
|
176
262
|
body: "gap-1 px-2 py-0.5 text-xs",
|
|
177
263
|
split: "gap-1 ps-2 pe-1 py-0.5 text-xs",
|
|
@@ -238,6 +324,16 @@ interface ChipBaseProps {
|
|
|
238
324
|
* it — "+ Outflow" in green next to an inflow (keksdose #417).
|
|
239
325
|
*/
|
|
240
326
|
selected?: boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Checkbox mode (0.10.0), for a toggle chip (`onClick` + `selected`): a small box
|
|
329
|
+
* at the start that shows a tick when `selected`, and the button reports
|
|
330
|
+
* `role="checkbox"` + `aria-checked` instead of `aria-pressed`. For a set of
|
|
331
|
+
* include/exclude choices where "on" must read as TICKED, not merely tinted —
|
|
332
|
+
* keksdose's add-group-card (the "which categories come along" pills), which put a
|
|
333
|
+
* real `<Checkbox>` inside a `<label>` pill by hand. The box is drawn in both
|
|
334
|
+
* states so ticking one never shifts its label.
|
|
335
|
+
*/
|
|
336
|
+
checkbox?: boolean;
|
|
241
337
|
/** Renders a dismiss affordance. Works alongside `href`/`onClick` — see the note below. */
|
|
242
338
|
onRemove?: () => void;
|
|
243
339
|
/** Accessible name for the dismiss button. Default: `common.remove` from the
|
|
@@ -341,6 +437,7 @@ export const Chip = forwardRef<HTMLElement, ChipProps>(function Chip(
|
|
|
341
437
|
caps = false,
|
|
342
438
|
icon: Icon,
|
|
343
439
|
selected,
|
|
440
|
+
checkbox = false,
|
|
344
441
|
href,
|
|
345
442
|
renderLink,
|
|
346
443
|
onClick,
|
|
@@ -362,7 +459,9 @@ export const Chip = forwardRef<HTMLElement, ChipProps>(function Chip(
|
|
|
362
459
|
const interactive = !!href || !!onClick;
|
|
363
460
|
// One radius for every rounded piece — the pill, the body inside a split pill, the ×
|
|
364
461
|
// — so a square chip has no round focus ring inside it.
|
|
365
|
-
const radius =
|
|
462
|
+
const radius =
|
|
463
|
+
shape === "square" ? (size === "sm" || size === "xs" ? "rounded" : "rounded-md") : "rounded-full";
|
|
464
|
+
const dot = variant === "dot";
|
|
366
465
|
const type = cn(caps && CAPS[size], variant === "solid" && "justify-center tabular-nums");
|
|
367
466
|
const surface = cn(
|
|
368
467
|
surfaceOf(tone, variant, selected),
|
|
@@ -375,11 +474,29 @@ export const Chip = forwardRef<HTMLElement, ChipProps>(function Chip(
|
|
|
375
474
|
radius,
|
|
376
475
|
surface,
|
|
377
476
|
interactive && !disabled && "cursor-pointer hover:brightness-[0.97] dark:hover:brightness-110",
|
|
477
|
+
// An inert dot chip is text in a column: no inset, so it aligns with the header.
|
|
478
|
+
dot && !interactive && "px-0",
|
|
378
479
|
className,
|
|
379
480
|
);
|
|
380
481
|
|
|
482
|
+
// The checkbox box, only on the toggle shape it has meaning on.
|
|
483
|
+
const isCheckbox = checkbox && !!onClick && !href;
|
|
381
484
|
const body = (
|
|
382
485
|
<>
|
|
486
|
+
{isCheckbox && (
|
|
487
|
+
<span
|
|
488
|
+
aria-hidden
|
|
489
|
+
data-chip-check=""
|
|
490
|
+
className={cn(
|
|
491
|
+
"flex shrink-0 items-center justify-center rounded-sm border",
|
|
492
|
+
s.icon,
|
|
493
|
+
selected ? "border-current bg-current/15" : "border-current/50",
|
|
494
|
+
)}
|
|
495
|
+
>
|
|
496
|
+
{selected && <Check className="size-full" strokeWidth={3} />}
|
|
497
|
+
</span>
|
|
498
|
+
)}
|
|
499
|
+
{dot && <span aria-hidden data-chip-dot="" className={cn("shrink-0 rounded-full", DOT_SIZE[size], DOT[tone])} />}
|
|
383
500
|
{Icon && <Icon className={cn(s.icon, "shrink-0")} aria-hidden />}
|
|
384
501
|
<span className="min-w-0 truncate">{children}</span>
|
|
385
502
|
</>
|
|
@@ -485,7 +602,11 @@ export const Chip = forwardRef<HTMLElement, ChipProps>(function Chip(
|
|
|
485
602
|
// Only when `selected` is PASSED: a chip with `onClick` and no `selected` is an
|
|
486
603
|
// action button (it does something), not a toggle (it is on or off), and
|
|
487
604
|
// announcing it "not pressed" would claim a state it does not have.
|
|
488
|
-
|
|
605
|
+
// A checkbox chip says "checked", not "pressed" — the same state in the words
|
|
606
|
+
// of the control it looks like.
|
|
607
|
+
role={isCheckbox ? "checkbox" : undefined}
|
|
608
|
+
aria-pressed={isCheckbox ? undefined : selected}
|
|
609
|
+
aria-checked={isCheckbox ? !!selected : undefined}
|
|
489
610
|
className={remove ? inner : look}
|
|
490
611
|
{...rest}
|
|
491
612
|
>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, forwardRef, useCallback, useContext, useEffect, useId, useRef } from "react";
|
|
2
|
-
import type { ChangeEvent, ComponentType, InputHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import type { ButtonHTMLAttributes, ChangeEvent, ComponentType, InputHTMLAttributes, ReactNode } from "react";
|
|
3
3
|
import { Check, Minus } from "lucide-react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
5
|
import { assignRef, hasMessage, mergeDescribedBy } from "./choice-parts";
|
|
@@ -218,6 +218,102 @@ export const ChoiceCard = forwardRef<HTMLInputElement, ChoiceCardProps>(function
|
|
|
218
218
|
});
|
|
219
219
|
ChoiceCard.displayName = "ChoiceCard";
|
|
220
220
|
|
|
221
|
+
/* ── ActionCard ──────────────────────────────────────────────────────────── */
|
|
222
|
+
|
|
223
|
+
/** The colour of {@link ActionCardProps.meta}. */
|
|
224
|
+
export type ActionCardMetaTone = "muted" | "warning" | "danger" | "info" | "success";
|
|
225
|
+
|
|
226
|
+
const META_TONE: Record<ActionCardMetaTone, string> = {
|
|
227
|
+
muted: "text-[var(--text-muted)]",
|
|
228
|
+
warning: "text-[var(--warning)]",
|
|
229
|
+
danger: "text-[var(--danger)]",
|
|
230
|
+
info: "text-[var(--info)]",
|
|
231
|
+
success: "text-[var(--success)]",
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
export interface ActionCardProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "title"> {
|
|
235
|
+
/** What the card does — the button's accessible name. */
|
|
236
|
+
title: ReactNode;
|
|
237
|
+
/** A line or two on what it means. Attached with `aria-describedby`. */
|
|
238
|
+
description?: ReactNode;
|
|
239
|
+
/**
|
|
240
|
+
* What it costs, or what else to know — a third line, said as prose and not as fine
|
|
241
|
+
* print (keksdose's custody choice: both options are legitimate and neither is free,
|
|
242
|
+
* so a card listing only benefits would be selling rather than explaining). Attached
|
|
243
|
+
* with `aria-describedby` after the description.
|
|
244
|
+
*/
|
|
245
|
+
meta?: ReactNode;
|
|
246
|
+
/** The meta line's colour. Default `muted`; keksdose's cost line is `warning`. */
|
|
247
|
+
metaTone?: ActionCardMetaTone;
|
|
248
|
+
/** A Lucide icon (or any component taking a `className`), shown at the card's start. */
|
|
249
|
+
icon?: ChoiceCardProps["icon"];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* A {@link ChoiceCard} that ACTS rather than holds a state: a `<button>` with the
|
|
254
|
+
* card's icon, title and description, plus a `meta` line, that runs `onClick` the
|
|
255
|
+
* moment it is pressed. keksdose's privacy enrolment (privacy-enroll-dialog:345,
|
|
256
|
+
* `CustodyOption`) offers two custody modes this way — picking one IS the next step,
|
|
257
|
+
* so there is no checked state to show and no "Continue" to press after it.
|
|
258
|
+
*
|
|
259
|
+
* A separate component rather than `ChoiceCard as="button"`: a ChoiceCard is an
|
|
260
|
+
* `<input>` (its ref, its `checked`, its form value), and a button shares none of it.
|
|
261
|
+
* Named by the title alone and described by the rest, so a screen reader hears
|
|
262
|
+
* "Keep the key yourself, button" and then the explanation, not one long name.
|
|
263
|
+
*/
|
|
264
|
+
export const ActionCard = forwardRef<HTMLButtonElement, ActionCardProps>(function ActionCard(
|
|
265
|
+
{ title, description, meta, metaTone = "muted", icon: Icon, className, id, type = "button", ...rest },
|
|
266
|
+
ref,
|
|
267
|
+
) {
|
|
268
|
+
const generated = useId();
|
|
269
|
+
const baseId = id ?? generated;
|
|
270
|
+
const titleId = `${baseId}-title`;
|
|
271
|
+
const descriptionId = `${baseId}-description`;
|
|
272
|
+
const metaId = `${baseId}-meta`;
|
|
273
|
+
const showDescription = hasMessage(description);
|
|
274
|
+
const showMeta = hasMessage(meta);
|
|
275
|
+
return (
|
|
276
|
+
<button
|
|
277
|
+
ref={ref}
|
|
278
|
+
id={id}
|
|
279
|
+
type={type}
|
|
280
|
+
{...rest}
|
|
281
|
+
aria-labelledby={rest["aria-labelledby"] ?? titleId}
|
|
282
|
+
aria-describedby={mergeDescribedBy(
|
|
283
|
+
rest["aria-describedby"],
|
|
284
|
+
showDescription && descriptionId,
|
|
285
|
+
showMeta && metaId,
|
|
286
|
+
)}
|
|
287
|
+
className={cn(
|
|
288
|
+
"flex w-full items-start gap-3 rounded-lg border border-[var(--border)] bg-[var(--bg-surface)] p-3 text-start shadow-sm transition-colors",
|
|
289
|
+
"hover:border-[var(--brand)] hover:bg-[var(--bg-hover)]",
|
|
290
|
+
// The outline, as on ChoiceCard: the card is what the eye is on.
|
|
291
|
+
"focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--brand)]",
|
|
292
|
+
"disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:border-[var(--border)] disabled:hover:bg-[var(--bg-surface)]",
|
|
293
|
+
className,
|
|
294
|
+
)}
|
|
295
|
+
>
|
|
296
|
+
{Icon && <Icon aria-hidden className="mt-0.5 size-5 shrink-0 text-[var(--text-secondary)]" />}
|
|
297
|
+
<span className="min-w-0 flex-1 space-y-1">
|
|
298
|
+
<span id={titleId} className="block text-sm font-medium leading-5 text-[var(--text-primary)]">
|
|
299
|
+
{title}
|
|
300
|
+
</span>
|
|
301
|
+
{showDescription && (
|
|
302
|
+
<span id={descriptionId} className="block text-sm text-[var(--text-secondary)]">
|
|
303
|
+
{description}
|
|
304
|
+
</span>
|
|
305
|
+
)}
|
|
306
|
+
{showMeta && (
|
|
307
|
+
<span id={metaId} className={cn("block text-sm", META_TONE[metaTone])}>
|
|
308
|
+
{meta}
|
|
309
|
+
</span>
|
|
310
|
+
)}
|
|
311
|
+
</span>
|
|
312
|
+
</button>
|
|
313
|
+
);
|
|
314
|
+
});
|
|
315
|
+
ActionCard.displayName = "ActionCard";
|
|
316
|
+
|
|
221
317
|
/* ── ChoiceCardGroup ─────────────────────────────────────────────────────── */
|
|
222
318
|
|
|
223
319
|
export interface ChoiceCardOption<T extends string> {
|
|
@@ -6,7 +6,7 @@ import { useAnnounce } from "../hooks/use-announce";
|
|
|
6
6
|
import { useCopyToClipboard } from "../hooks/use-copy-to-clipboard";
|
|
7
7
|
import type { CopyState } from "../hooks/use-copy-to-clipboard";
|
|
8
8
|
import { Button, IconButton } from "./ui";
|
|
9
|
-
import type { ButtonVariant, IconButtonSize } from "./ui";
|
|
9
|
+
import type { ButtonSize, ButtonTone, ButtonVariant, IconButtonSize, IconButtonTone } from "./ui";
|
|
10
10
|
import { Tooltip } from "./tooltip";
|
|
11
11
|
import type { TooltipSide } from "./tooltip";
|
|
12
12
|
|
|
@@ -43,8 +43,17 @@ export interface CopyButtonProps
|
|
|
43
43
|
label?: string;
|
|
44
44
|
/** The button's own look. Default: `ghost` for the icon, `secondary` for the label. */
|
|
45
45
|
buttonVariant?: ButtonVariant;
|
|
46
|
-
/**
|
|
47
|
-
size
|
|
46
|
+
/** The icon variant's IconButton size (default `sm`). The `label` variant takes a
|
|
47
|
+
* Button size, `sm` or `md` — passed only when given, so an existing label button
|
|
48
|
+
* keeps its look (keksdose budget-share-card and jobs-panel wanted the compact one). */
|
|
49
|
+
size?: IconButtonSize | ButtonSize;
|
|
50
|
+
/** The icon variant's IconButton tone (e.g. `muted`, so a row of copy icons is no
|
|
51
|
+
* heavier than the row's other actions); in the `label` variant a Button tone,
|
|
52
|
+
* which applies to `link` / `ghost`. The copied / failed colour still wins. */
|
|
53
|
+
tone?: IconButtonTone | ButtonTone;
|
|
54
|
+
/** Keep the click and Enter/Space from reaching a clickable row around the button,
|
|
55
|
+
* as IconButton's own `stopPropagation` does (keksdose feedback-page, users-panel). */
|
|
56
|
+
stopPropagation?: boolean;
|
|
48
57
|
/** Icon variant only: where the result tooltip opens. */
|
|
49
58
|
tooltipSide?: TooltipSide;
|
|
50
59
|
/** Pass through to the tooltip — needed inside a scroll container (see Tooltip). */
|
|
@@ -80,7 +89,9 @@ export function CopyButton({
|
|
|
80
89
|
variant = "icon",
|
|
81
90
|
label,
|
|
82
91
|
buttonVariant,
|
|
83
|
-
size
|
|
92
|
+
size,
|
|
93
|
+
tone,
|
|
94
|
+
stopPropagation,
|
|
84
95
|
tooltipSide = "top",
|
|
85
96
|
tooltipPortal = false,
|
|
86
97
|
resetAfter = 2000,
|
|
@@ -123,8 +134,17 @@ export function CopyButton({
|
|
|
123
134
|
{...rest}
|
|
124
135
|
disabled={disabled}
|
|
125
136
|
variant={buttonVariant ?? "secondary"}
|
|
137
|
+
size={size === "sm" || size === "md" ? size : undefined}
|
|
138
|
+
tone={tone === "default" || tone === "muted" || tone === "danger" ? tone : undefined}
|
|
126
139
|
data-state={state}
|
|
127
|
-
onClick={
|
|
140
|
+
onClick={(e) => {
|
|
141
|
+
if (stopPropagation) e.stopPropagation();
|
|
142
|
+
void onClick();
|
|
143
|
+
}}
|
|
144
|
+
onKeyDown={(e) => {
|
|
145
|
+
if (stopPropagation && (e.key === "Enter" || e.key === " ")) e.stopPropagation();
|
|
146
|
+
rest.onKeyDown?.(e);
|
|
147
|
+
}}
|
|
128
148
|
className={className}
|
|
129
149
|
>
|
|
130
150
|
<Icon aria-hidden className={cn("size-4 shrink-0", iconTone)} />
|
|
@@ -144,9 +164,11 @@ export function CopyButton({
|
|
|
144
164
|
disabled={disabled}
|
|
145
165
|
aria-label={idleText}
|
|
146
166
|
variant={buttonVariant ?? "ghost"}
|
|
147
|
-
size={size}
|
|
167
|
+
size={(size ?? "sm") as IconButtonSize}
|
|
168
|
+
tone={tone as IconButtonTone | undefined}
|
|
169
|
+
stopPropagation={stopPropagation}
|
|
148
170
|
data-state={state}
|
|
149
|
-
onClick={onClick}
|
|
171
|
+
onClick={() => void onClick()}
|
|
150
172
|
className={cn(iconTone, className)}
|
|
151
173
|
>
|
|
152
174
|
<Icon aria-hidden />
|
|
@@ -1427,6 +1427,11 @@ export function DataTable<T>({
|
|
|
1427
1427
|
// density (`group-data-[density=compact]/table:…`) without being told twice.
|
|
1428
1428
|
data-density={density}
|
|
1429
1429
|
data-frame={frame ? undefined : "none"}
|
|
1430
|
+
// The frame clips (`overflow-clip`), so it is a clipping container for a
|
|
1431
|
+
// Tooltip's auto-portal — said as an attribute as well, because jsdom computes no
|
|
1432
|
+
// classes and a table-cell tooltip must portal under test just as it does in the
|
|
1433
|
+
// browser (see `CLIPS_ATTRIBUTE`). The bare root clips nothing and is not marked.
|
|
1434
|
+
data-clips={frame ? "" : undefined}
|
|
1430
1435
|
className={cn(
|
|
1431
1436
|
"group/table",
|
|
1432
1437
|
frame ? "overflow-clip" : "min-w-0",
|
|
@@ -1535,6 +1540,8 @@ export function DataTable<T>({
|
|
|
1535
1540
|
other half of the `w-0 min-w-full` fix on the expansion cell below
|
|
1536
1541
|
(feedback #104: "expanding an item resizes the columns"). */}
|
|
1537
1542
|
<div
|
|
1543
|
+
// The scroller: marked for the Tooltip's auto-portal (see the root above).
|
|
1544
|
+
data-clips=""
|
|
1538
1545
|
className={cn("overflow-auto [scrollbar-gutter:stable]", fillHeight && "flex-1 min-h-0")}
|
|
1539
1546
|
style={fillHeight ? undefined : { maxHeight: maxBodyHeight }}
|
|
1540
1547
|
>
|
|
@@ -770,6 +770,27 @@ export interface DateRangePickerProps extends DatePickerBaseProps {
|
|
|
770
770
|
* would overwrite the sheet's history marker.
|
|
771
771
|
*/
|
|
772
772
|
sheetBackCloses?: boolean;
|
|
773
|
+
/**
|
|
774
|
+
* With `commit="apply"`: a line above the calendar saying what Apply would commit —
|
|
775
|
+
* keksdose's report range writes "Custom · 1 Mar 2026 – …" there
|
|
776
|
+
* (report-range-field.tsx), the one place a preset armed and then nudged by a day is
|
|
777
|
+
* seen to have become "Custom", and a half-made range to still lack its end. Called
|
|
778
|
+
* with the DRAFT on every change, in the popover and the phone sheet alike; `preset`
|
|
779
|
+
* is the preset the column marks for it (none once a day was picked by hand), `to` is
|
|
780
|
+
* `""` until the second click. The line is a polite live region, so a screen reader
|
|
781
|
+
* hears the draft change as the calendar is used.
|
|
782
|
+
*
|
|
783
|
+
* Ignored in `"immediate"` mode, where there is no draft: every click is the value.
|
|
784
|
+
*/
|
|
785
|
+
renderDraftSummary?: (draft: DateRangeDraftSummary) => ReactNode;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/** What {@link DateRangePickerProps.renderDraftSummary} is called with. */
|
|
789
|
+
export interface DateRangeDraftSummary {
|
|
790
|
+
from: string;
|
|
791
|
+
to: string;
|
|
792
|
+
/** The preset the column marks for the draft, if any. */
|
|
793
|
+
preset: DateRangePickerPreset | undefined;
|
|
773
794
|
}
|
|
774
795
|
|
|
775
796
|
/** What {@link DateRangePickerProps.renderTrigger} is called with. */
|
|
@@ -889,6 +910,7 @@ function RangePanel({
|
|
|
889
910
|
commitRange,
|
|
890
911
|
calendarProps,
|
|
891
912
|
labels,
|
|
913
|
+
renderDraftSummary,
|
|
892
914
|
}: {
|
|
893
915
|
from: string;
|
|
894
916
|
to: string;
|
|
@@ -903,6 +925,7 @@ function RangePanel({
|
|
|
903
925
|
commitRange: (from: string, to: string, presetId: string | undefined) => void;
|
|
904
926
|
calendarProps: Pick<MiniCalendarProps, "locale" | "min" | "max" | "labels">;
|
|
905
927
|
labels: DatePickerLabels;
|
|
928
|
+
renderDraftSummary?: DateRangePickerProps["renderDraftSummary"];
|
|
906
929
|
}) {
|
|
907
930
|
const drafting = commit === "apply";
|
|
908
931
|
const [draft, setDraft] = useState<RangeDraft>({
|
|
@@ -917,7 +940,12 @@ function RangePanel({
|
|
|
917
940
|
: -1;
|
|
918
941
|
const complete = Boolean(draft.from && draft.to);
|
|
919
942
|
|
|
920
|
-
const
|
|
943
|
+
const summary =
|
|
944
|
+
drafting && renderDraftSummary
|
|
945
|
+
? renderDraftSummary({ from: draft.from, to: draft.to, preset: presets?.[marked] })
|
|
946
|
+
: null;
|
|
947
|
+
|
|
948
|
+
const picker = (
|
|
921
949
|
<MiniCalendar
|
|
922
950
|
{...calendarProps}
|
|
923
951
|
focusOnOpen
|
|
@@ -934,6 +962,24 @@ function RangePanel({
|
|
|
934
962
|
}}
|
|
935
963
|
/>
|
|
936
964
|
);
|
|
965
|
+
// The summary heads the CALENDAR's column, not the panel: beside a preset column it
|
|
966
|
+
// reads as the calendar's caption, and in the sheet it sits between the presets and
|
|
967
|
+
// the month it describes. `null` renders no line — a caller may opt out per draft —
|
|
968
|
+
// but keeps the wrapper, so the calendar is not remounted (and its month and focus
|
|
969
|
+
// lost) when a line comes or goes.
|
|
970
|
+
const calendar =
|
|
971
|
+
drafting && renderDraftSummary ? (
|
|
972
|
+
<div className="flex flex-col gap-2">
|
|
973
|
+
{summary != null && (
|
|
974
|
+
<div aria-live="polite" data-draft-summary="" className="text-xs text-[var(--text-muted)]">
|
|
975
|
+
{summary}
|
|
976
|
+
</div>
|
|
977
|
+
)}
|
|
978
|
+
{picker}
|
|
979
|
+
</div>
|
|
980
|
+
) : (
|
|
981
|
+
picker
|
|
982
|
+
);
|
|
937
983
|
|
|
938
984
|
const body =
|
|
939
985
|
presets && presets.length > 0 ? (
|
|
@@ -1006,6 +1052,7 @@ export function DateRangePicker({
|
|
|
1006
1052
|
commit = "immediate",
|
|
1007
1053
|
renderTrigger,
|
|
1008
1054
|
sheetBackCloses,
|
|
1055
|
+
renderDraftSummary,
|
|
1009
1056
|
calendarLabels,
|
|
1010
1057
|
label,
|
|
1011
1058
|
clearable,
|
|
@@ -1082,6 +1129,7 @@ export function DateRangePicker({
|
|
|
1082
1129
|
commitRange={commitRange}
|
|
1083
1130
|
calendarProps={{ locale, min, max, labels: calendarLabels }}
|
|
1084
1131
|
labels={text}
|
|
1132
|
+
renderDraftSummary={renderDraftSummary}
|
|
1085
1133
|
/>
|
|
1086
1134
|
)}
|
|
1087
1135
|
</DateField>
|