@12-apps/ui 6.92.0 → 6.92.1
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/_internal/components/data-display/DataViews/DataViewsGrid.js +10 -10
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +11 -11
- package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +9 -9
- package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +7 -7
- package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +6 -6
- package/dist/_internal/components/data-display/DataViews/data-views-range-bounds.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-range-calendar.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +4 -4
- package/dist/_internal/components/data-display/DataViews/data-views-range-summary.js +1 -1
- package/dist/{chunk-3OHZAZEE.js → chunk-3WYEENUH.js} +9 -4
- package/dist/chunk-3WYEENUH.js.map +1 -0
- package/dist/{chunk-X3GD3TFI.js → chunk-BXZMV6QC.js} +3 -3
- package/dist/{chunk-FORAVDJF.js → chunk-FC7UCFFA.js} +35 -7
- package/dist/chunk-FC7UCFFA.js.map +1 -0
- package/dist/{chunk-CKQOYPH3.js → chunk-FYUNROLW.js} +2 -2
- package/dist/{chunk-MICX23P4.js → chunk-HRES2S3Q.js} +85 -8
- package/dist/chunk-HRES2S3Q.js.map +1 -0
- package/dist/{chunk-AI7XWBNG.js → chunk-IEUVP6UV.js} +3 -3
- package/dist/{chunk-R4LCPPKA.js → chunk-OCGPOACB.js} +2 -2
- package/dist/{chunk-HS662RLW.js → chunk-RZWU2KYP.js} +2 -2
- package/dist/{chunk-MZAYIG2I.js → chunk-VCJ72ODU.js} +2 -2
- package/dist/chunk-WLDP7C4K.js +44 -0
- package/dist/chunk-WLDP7C4K.js.map +1 -0
- package/dist/{chunk-W2KOP27S.js → chunk-ZVHHFLYY.js} +2 -2
- package/dist/data-display/DataViews.js +11 -11
- package/dist/types/components/data-display/DataViews/data-views-range-bounds.d.ts +6 -1
- package/dist/types/components/data-display/DataViews/data-views-range-bounds.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-range-calendar.d.ts +13 -1
- package/dist/types/components/data-display/DataViews/data-views-range-calendar.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-range-summary.d.ts +4 -5
- package/dist/types/components/data-display/DataViews/data-views-range-summary.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/data-display/DataViews/RESPONSIVE-BEHAVIOUR.md +8 -4
- package/src/components/data-display/DataViews/data-views-range-bounds.tsx +57 -3
- package/src/components/data-display/DataViews/data-views-range-calendar.tsx +122 -8
- package/src/components/data-display/DataViews/data-views-range-pill.tsx +5 -0
- package/src/components/data-display/DataViews/data-views-range-summary.tsx +9 -22
- package/dist/chunk-3OHZAZEE.js.map +0 -1
- package/dist/chunk-FORAVDJF.js.map +0 -1
- package/dist/chunk-J2AVWIMM.js +0 -60
- package/dist/chunk-J2AVWIMM.js.map +0 -1
- package/dist/chunk-MICX23P4.js.map +0 -1
- /package/dist/{chunk-X3GD3TFI.js.map → chunk-BXZMV6QC.js.map} +0 -0
- /package/dist/{chunk-CKQOYPH3.js.map → chunk-FYUNROLW.js.map} +0 -0
- /package/dist/{chunk-AI7XWBNG.js.map → chunk-IEUVP6UV.js.map} +0 -0
- /package/dist/{chunk-R4LCPPKA.js.map → chunk-OCGPOACB.js.map} +0 -0
- /package/dist/{chunk-HS662RLW.js.map → chunk-RZWU2KYP.js.map} +0 -0
- /package/dist/{chunk-MZAYIG2I.js.map → chunk-VCJ72ODU.js.map} +0 -0
- /package/dist/{chunk-W2KOP27S.js.map → chunk-ZVHHFLYY.js.map} +0 -0
|
@@ -114,6 +114,107 @@ function openingMonth(value: RangeValue, months: number): Date | undefined {
|
|
|
114
114
|
return new Date(anchor.getFullYear(), anchor.getMonth() - (months > 1 ? 1 : 0), 1);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* The line under the calendar: the next step ("Toque no primeiro e no último
|
|
119
|
+
* dia." / "Agora toque no último dia.") or, once a period is applied, the
|
|
120
|
+
* window, with "Limpar" at its end.
|
|
121
|
+
*
|
|
122
|
+
* ONE line whose words change, never a row held empty for later (FUT-4144
|
|
123
|
+
* follow-up): #932 kept an invisible summary row under the hint so the first
|
|
124
|
+
* tap would not grow the popover, and at 1280 that was 59px of white.
|
|
125
|
+
*
|
|
126
|
+
* Where the line can hold "Limpar" (the pill's popover) it is always as tall as
|
|
127
|
+
* its 40px target, so it keeps one height with the button and without it, and
|
|
128
|
+
* the popover does not move. Where it cannot (a panel, whose header has
|
|
129
|
+
* "Limpar") it stays a plain line of text: no row reserved for a button that
|
|
130
|
+
* never comes. The text keeps to one line, cut with an ellipsis and whole in
|
|
131
|
+
* its title, so a long label never grows the line on the closing tap. The target
|
|
132
|
+
* is its own box, not padding pushed out with a negative margin: that version
|
|
133
|
+
* ran under the calendar's last week, which took its top 10px at 320 (FUT-4144
|
|
134
|
+
* UI review). The window is said in the primary ink, the steps in the
|
|
135
|
+
* secondary one, so the result does not read as one more instruction.
|
|
136
|
+
*/
|
|
137
|
+
function HintLine({
|
|
138
|
+
text,
|
|
139
|
+
isWindow,
|
|
140
|
+
canClear,
|
|
141
|
+
onClear,
|
|
142
|
+
testId,
|
|
143
|
+
}: {
|
|
144
|
+
text: string;
|
|
145
|
+
/** `text` is the applied window, not a step. */
|
|
146
|
+
isWindow: boolean;
|
|
147
|
+
/** The line can hold "Limpar" at all — fixed per surface, not per state. */
|
|
148
|
+
canClear: boolean;
|
|
149
|
+
/** Shown now: "Limpar" empties the range; `fromKeyboard` is a click with `detail` 0 (Enter or Space). */
|
|
150
|
+
onClear: ((fromKeyboard: boolean) => void) | undefined;
|
|
151
|
+
testId: string;
|
|
152
|
+
}): React.JSX.Element {
|
|
153
|
+
const clear = useDataViewsCopy().filters.clear;
|
|
154
|
+
return (
|
|
155
|
+
<Box
|
|
156
|
+
data-testid={`${testId}-calendar-line`}
|
|
157
|
+
sx={{
|
|
158
|
+
display: 'flex',
|
|
159
|
+
alignItems: 'center',
|
|
160
|
+
justifyContent: 'space-between',
|
|
161
|
+
gap: 2,
|
|
162
|
+
mt: { xs: 0.25, sm: 1 },
|
|
163
|
+
minHeight: canClear ? sxRem(40) : undefined,
|
|
164
|
+
fontSize: sxRem(12),
|
|
165
|
+
lineHeight: 1.5,
|
|
166
|
+
}}
|
|
167
|
+
>
|
|
168
|
+
<Typography
|
|
169
|
+
component="p"
|
|
170
|
+
aria-live="polite"
|
|
171
|
+
data-testid={`${testId}-calendar-hint`}
|
|
172
|
+
title={text}
|
|
173
|
+
noWrap
|
|
174
|
+
sx={{ m: 0, minWidth: 0, font: 'inherit', color: isWindow ? 'text.primary' : 'text.secondary' }}
|
|
175
|
+
>
|
|
176
|
+
{text}
|
|
177
|
+
</Typography>
|
|
178
|
+
{onClear && (
|
|
179
|
+
<Box
|
|
180
|
+
component="button"
|
|
181
|
+
type="button"
|
|
182
|
+
onClick={(event) => onClear(event.detail === 0)}
|
|
183
|
+
data-testid={`${testId}-clear`}
|
|
184
|
+
sx={{
|
|
185
|
+
flexShrink: 0,
|
|
186
|
+
display: 'inline-flex',
|
|
187
|
+
alignItems: 'center',
|
|
188
|
+
minHeight: sxRem(40),
|
|
189
|
+
border: 0,
|
|
190
|
+
bgcolor: 'transparent',
|
|
191
|
+
cursor: 'pointer',
|
|
192
|
+
font: 'inherit',
|
|
193
|
+
fontWeight: 600,
|
|
194
|
+
color: 'primary.main',
|
|
195
|
+
px: 1,
|
|
196
|
+
py: 0,
|
|
197
|
+
// Its text lines up with the boxes' right edge; the side padding
|
|
198
|
+
// reaches into the popover's own.
|
|
199
|
+
mr: -1,
|
|
200
|
+
borderRadius: 1,
|
|
201
|
+
'&:hover': { bgcolor: 'action.hover' },
|
|
202
|
+
// The theme's focus ring for a keyboard, none for a tap.
|
|
203
|
+
'&:focus': { outline: 'none' },
|
|
204
|
+
'&:focus-visible': {
|
|
205
|
+
outline: (theme: Theme) => `${rem(theme, 2)} solid`,
|
|
206
|
+
outlineColor: 'primary.main',
|
|
207
|
+
outlineOffset: sxRem(1),
|
|
208
|
+
},
|
|
209
|
+
}}
|
|
210
|
+
>
|
|
211
|
+
{clear}
|
|
212
|
+
</Box>
|
|
213
|
+
)}
|
|
214
|
+
</Box>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
117
218
|
/** Props of {@link DayRangeCalendar}. */
|
|
118
219
|
export interface DayRangeCalendarProps {
|
|
119
220
|
/** The filter's own label ("Data"), which names the calendar. */
|
|
@@ -133,6 +234,18 @@ export interface DayRangeCalendarProps {
|
|
|
133
234
|
*/
|
|
134
235
|
viewKey: string;
|
|
135
236
|
testId: string;
|
|
237
|
+
/**
|
|
238
|
+
* The applied window in words ("Data: 01/10–15/10"), said on the hint's own
|
|
239
|
+
* line with "Limpar" at its end. Set by the pill, whose popover has no other
|
|
240
|
+
* place for them; a panel says them in its own header and leaves this unset.
|
|
241
|
+
*/
|
|
242
|
+
summary?: string;
|
|
243
|
+
/**
|
|
244
|
+
* Empties the range: the line's "Limpar", shown while `summary` is set. Set
|
|
245
|
+
* only where the line may hold it; the line reserves its 40px only then.
|
|
246
|
+
* `fromKeyboard` is true when it was pressed from the keyboard.
|
|
247
|
+
*/
|
|
248
|
+
onClear?: (fromKeyboard: boolean) => void;
|
|
136
249
|
}
|
|
137
250
|
|
|
138
251
|
export function DayRangeCalendar({
|
|
@@ -142,6 +255,8 @@ export function DayRangeCalendar({
|
|
|
142
255
|
months,
|
|
143
256
|
viewKey,
|
|
144
257
|
testId,
|
|
258
|
+
summary,
|
|
259
|
+
onClear,
|
|
145
260
|
}: DayRangeCalendarProps): React.JSX.Element {
|
|
146
261
|
const copy: DataViewsDayCalendarCopy =
|
|
147
262
|
useDataViewsCopy().filters.dayCalendar ?? (EN_US_DATA_VIEWS_COPY.filters.dayCalendar as DataViewsDayCalendarCopy);
|
|
@@ -172,14 +287,13 @@ export function DayRangeCalendar({
|
|
|
172
287
|
// tap that CLOSES a period, so the first tap would write nothing.
|
|
173
288
|
onIntermediateRangeChange={pick}
|
|
174
289
|
/>
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
</Typography>
|
|
290
|
+
<HintLine
|
|
291
|
+
text={waitingForEnd ? copy.pickEnd : (summary ?? copy.pickStart)}
|
|
292
|
+
isWindow={!waitingForEnd && summary !== undefined}
|
|
293
|
+
canClear={onClear !== undefined}
|
|
294
|
+
onClear={summary === undefined ? undefined : onClear}
|
|
295
|
+
testId={testId}
|
|
296
|
+
/>
|
|
183
297
|
</Box>
|
|
184
298
|
);
|
|
185
299
|
}
|
|
@@ -180,6 +180,10 @@ const DAY_PAPER_SX = (theme: Theme) => ({
|
|
|
180
180
|
// 280px seven 40px day columns need: at 320 it had 256 and every day was a
|
|
181
181
|
// 33px target (FUT-4144 UI review).
|
|
182
182
|
maxWidth: { xs: `calc(100% - ${rem(theme, 16)})`, sm: `calc(100% - ${rem(theme, 32)})` },
|
|
183
|
+
// And as tall as those same margins allow: MUI's default keeps 16px off the
|
|
184
|
+
// top and bottom, so a refused day's message at 320×568 made the popover
|
|
185
|
+
// 1px taller than its cap and it scrolled (FUT-4144 code review).
|
|
186
|
+
maxHeight: { xs: `calc(100% - ${rem(theme, 16)})`, sm: `calc(100% - ${rem(theme, 32)})` },
|
|
183
187
|
p: { xs: 1, sm: 2 },
|
|
184
188
|
});
|
|
185
189
|
|
|
@@ -232,6 +236,7 @@ export function RangePill<T extends Record<string, unknown>>({
|
|
|
232
236
|
onChange={onChange}
|
|
233
237
|
testId={testId}
|
|
234
238
|
calendarMonths={calendarMonths}
|
|
239
|
+
summaryOnHint
|
|
235
240
|
/>
|
|
236
241
|
<RangeSummary field={field} value={value} onClear={() => onChange({})} testId={testId} />
|
|
237
242
|
</Popover>
|
|
@@ -11,16 +11,15 @@ import type { RangeFieldConfig, RangeValue } from './data-views-types';
|
|
|
11
11
|
import { sxRem } from '../../../tokens/relative';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* The applied window in words, and "Limpar".
|
|
14
|
+
* The applied window in words, and "Limpar", under a NUMBER range's boxes.
|
|
15
15
|
*
|
|
16
16
|
* An inverted window is not an error the merchant must fix before the list
|
|
17
17
|
* responds — it simply matches nothing, and saying so beats an empty grid with
|
|
18
18
|
* no explanation (FUT-668).
|
|
19
19
|
*
|
|
20
|
-
* A DAY
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* (FUT-4144 UI review round 2). The held row is invisible and inert.
|
|
20
|
+
* A DAY range says these on its calendar's hint line instead (FUT-4144): a row
|
|
21
|
+
* of its own, held empty until the first tap so the popover would not grow,
|
|
22
|
+
* left 59px of white under the hint at 1280.
|
|
24
23
|
*/
|
|
25
24
|
export function RangeSummary<T extends Record<string, unknown>>({
|
|
26
25
|
field,
|
|
@@ -34,29 +33,17 @@ export function RangeSummary<T extends Record<string, unknown>>({
|
|
|
34
33
|
testId: string;
|
|
35
34
|
}): React.JSX.Element | null {
|
|
36
35
|
const copy = useDataViewsCopy();
|
|
37
|
-
|
|
38
|
-
if (!active && field.kind !== 'day') return null;
|
|
36
|
+
if (field.kind === 'day' || !isRangeSet(value)) return null;
|
|
39
37
|
return (
|
|
40
|
-
<Box
|
|
41
|
-
aria-hidden={active ? undefined : true}
|
|
42
|
-
sx={{
|
|
43
|
-
display: 'flex',
|
|
44
|
-
alignItems: 'center',
|
|
45
|
-
justifyContent: 'space-between',
|
|
46
|
-
gap: 2,
|
|
47
|
-
mt: { xs: 0.5, sm: 1.5 },
|
|
48
|
-
visibility: active ? undefined : 'hidden',
|
|
49
|
-
}}
|
|
50
|
-
>
|
|
38
|
+
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2, mt: { xs: 0.5, sm: 1.5 } }}>
|
|
51
39
|
<Typography component="span" sx={{ fontSize: sxRem(12), color: 'text.secondary' }}>
|
|
52
|
-
{
|
|
40
|
+
{rangeChipLabel(field, value)}
|
|
53
41
|
</Typography>
|
|
54
42
|
<Button
|
|
55
43
|
variant="text"
|
|
56
44
|
size="small"
|
|
57
|
-
onClick={
|
|
58
|
-
|
|
59
|
-
data-testid={active ? `${testId}-clear` : undefined}
|
|
45
|
+
onClick={onClear}
|
|
46
|
+
data-testid={`${testId}-clear`}
|
|
60
47
|
sx={{ textTransform: 'none' }}
|
|
61
48
|
>
|
|
62
49
|
{copy.filters.clear}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/data-views-range-pill.tsx"],"sourcesContent":["'use client';\n\n/**\n * A range filter as a PILL in the inline filter bar — the same affordance the\n * multi-select facets use, so \"Data\" and \"Valor\" sit in the filter row beside\n * \"Pagamento\"/\"Situação\"/\"Método\" instead of floating above the grid.\n *\n * Before this the inline bar rendered pills only, and `rangeFields` had a\n * surface on the slide-in panel alone — which `inlineFilters` REPLACES on a wide\n * screen. So a range filter was invisible on exactly the screens that use it,\n * and a page wanting one had to hang its own inputs outside the grid, outside\n * `DataViewState`, and outside the grid's \"Limpar filtros\" (FUT-668).\n */\nimport CloseIcon from '@mui/icons-material/Close';\nimport ChevronDownIcon from '@mui/icons-material/KeyboardArrowDown';\nimport Box from '@mui/material/Box/index.js';\nimport Button from '@mui/material/Button/index.js';\nimport Popover from '@mui/material/Popover/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport useMediaQuery from '@mui/material/useMediaQuery/index.js';\nimport { useTheme, type Theme } from '@mui/material/styles/index.js';\nimport React, { useContext } from 'react';\n\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\nimport { TableFilter } from '../../layout/TableFilter';\nimport { TableFilterContext } from '../../layout/TableFilter/TableFilterContext';\nimport { RangePresets } from './data-views-preset-chips';\nimport { RangeBounds } from './data-views-range-bounds';\nimport { RangeSummary } from './data-views-range-summary';\nimport { useStillAnchor } from './data-views-still-anchor';\nimport { presetsFor } from './data-views-range-presets';\nimport {\n isRangeInverted,\n isRangeSet,\n numericRange,\n rangeChipLabel,\n} from './data-views-range-values';\nimport type { RangeFieldConfig, RangeValue } from './data-views-types';\nimport { fieldRadiusPx } from '../../../tokens/field-radius';\nimport { fieldHeight } from '../../../tokens/field-height';\nimport { fieldEdge } from '../../../tokens/field-edge';\nimport { rem, remPx, sxRem } from '../../../tokens/relative';\n\n// Re-exported: the pair moved to its own file, and its importers keep their path.\nexport { RangeBounds };\n\n/**\n * The pill + its popover. Bounds commit on change (the list is server-driven, so\n * each edit is a query) and the popover stays open, which is what lets a\n * merchant set \"de\" and then \"até\" without re-opening it.\n */\n/** An applied range clears from the pill itself — re-opening to empty two fields is three gestures for one intent. */\nfunction ClearAffordance({\n label,\n onClear,\n testId,\n}: {\n label: string;\n onClear: () => void;\n testId: string;\n}): React.JSX.Element {\n const copy = useDataViewsCopy();\n const clear = (event: React.SyntheticEvent): void => {\n event.stopPropagation();\n onClear();\n };\n return (\n <Box\n component=\"span\"\n role=\"button\"\n tabIndex={0}\n aria-label={copy.filters.clearRange(label)}\n data-testid={testId}\n onClick={clear}\n onKeyDown={(event: React.KeyboardEvent) => {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n clear(event);\n }}\n sx={{ display: 'inline-flex', borderRadius: 999, p: 0.125, '&:hover': { bgcolor: 'action.selected' } }}\n >\n <CloseIcon sx={{ fontSize: sxRem(14) }} />\n </Box>\n );\n}\n\n/** The pill button: its label carries the applied window, and its tone the state. */\nfunction RangeTrigger<T extends Record<string, unknown>>({\n field,\n value,\n onChange,\n onOpen,\n open,\n testId,\n}: {\n field: RangeFieldConfig<T>;\n value: RangeValue;\n onChange: (range: RangeValue) => void;\n onOpen: (anchor: HTMLElement) => void;\n open: boolean;\n testId: string;\n}): React.JSX.Element {\n const active = isRangeSet(value);\n const inverted = isRangeInverted(value);\n // An INVERTED window gets its own tone rather than the ordinary \"applied\"\n // one: it is applied, and it matches nothing, and those are different states.\n // At rest the pill draws the one field border (`fieldEdge`).\n const tone = inverted ? 'error.main' : active ? 'primary.main' : null;\n return (\n <Button\n variant=\"outlined\"\n color=\"inherit\"\n size=\"small\"\n data-testid={testId}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={(event) => onOpen(event.currentTarget)}\n // ✕ FIRST, chevron LAST — the same shape as every other pill. It used to\n // replace the chevron at the end, so a range pill and a multi-select pill\n // put the clear in different places, and an applied range lost the\n // affordance that says it opens.\n startIcon={\n active ? (\n <ClearAffordance label={field.label} onClear={() => onChange({})} testId={`${testId}-clear-inline`} />\n ) : undefined\n }\n endIcon={<ChevronDownIcon sx={{ fontSize: sxRem(16) }} />}\n sx={{\n borderRadius: fieldRadiusPx,\n height: fieldHeight,\n px: 1.5,\n maxWidth: sxRem(280),\n color: inverted ? 'error.main' : 'text.primary',\n fontWeight: 600,\n fontSize: sxRem(13),\n textTransform: 'none',\n whiteSpace: 'nowrap',\n borderColor: (theme) => tone ?? fieldEdge(theme),\n bgcolor: active ? 'action.selected' : 'background.paper',\n '&:hover': {\n borderColor: active ? tone : 'text.primary',\n bgcolor: active ? 'action.selected' : 'action.hover',\n },\n }}\n >\n {/* The applied bounds, in the label — a pill reading only \"Valor\" hides\n the very thing that is narrowing the list. */}\n <Box component=\"span\" sx={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {active ? rangeChipLabel(field, value) : field.label}\n </Box>\n </Button>\n );\n}\n\n/**\n * How many months the pill's calendar shows: two from the theme's `md` up,\n * where the popover has the ~670px they take; one below it.\n *\n * A media query, not an `sx` breakpoint, because it decides what to RENDER —\n * CSS cannot un-render a second month. `up('md')` so that where nothing can be\n * measured (a test, the server) the answer is the one month that always fits.\n */\nfunction useCalendarMonths(): 1 | 2 {\n const theme = useTheme();\n return useMediaQuery(theme.breakpoints.up('md')) ? 2 : 1;\n}\n\n/**\n * The day popover's width. Below `sm` it takes the screen's (less the\n * popover's own 16px margins, which its `maxWidth` already keeps), so the boxes\n * and the month share it instead of leaving a strip of grid beside a narrow\n * card. From `sm` to `md` it holds one month, and sized to its content the\n * preset row alone stretched it to ~515px with the month hugging the left and\n * a band of nothing beside it; 400 keeps the month and the boxes one width.\n * From `md` its content — two months — sets it.\n */\nconst DAY_PAPER_SX = (theme: Theme) => ({\n width: { xs: '100%', sm: rem(theme, 400), md: 'auto' },\n // Below `sm` 8px from each edge and 8px of padding, so the month gets the\n // 280px seven 40px day columns need: at 320 it had 256 and every day was a\n // 33px target (FUT-4144 UI review).\n maxWidth: { xs: `calc(100% - ${rem(theme, 16)})`, sm: `calc(100% - ${rem(theme, 32)})` },\n p: { xs: 1, sm: 2 },\n});\n\n\nexport function RangePill<T extends Record<string, unknown>>({\n field,\n value,\n onChange,\n onOpenChange,\n testIdPrefix,\n}: {\n field: RangeFieldConfig<T>;\n value: RangeValue;\n onChange: (range: RangeValue) => void;\n /** So a measured toolbar can hold still while this is open. */\n onOpenChange?: (open: boolean) => void;\n testIdPrefix: string;\n}): React.JSX.Element {\n const still = useStillAnchor();\n const testId = `${testIdPrefix}-range-${field.id}`;\n const calendarMonths = useCalendarMonths();\n const theme = useTheme();\n const phone = useMediaQuery(theme.breakpoints.down('sm'));\n return (\n <>\n <RangeTrigger\n field={field}\n value={value}\n onChange={onChange}\n onOpen={(element) => {\n still.open(element);\n onOpenChange?.(true);\n }}\n open={Boolean(still.anchor)}\n testId={testId}\n />\n <Popover\n {...still.popoverProps}\n onClose={() => {\n still.close();\n onOpenChange?.(false);\n }}\n // Below `sm` a day popover keeps 8px from the screen's edges instead of 16.\n marginThreshold={field.kind === 'day' && phone ? remPx(theme, 8) : undefined}\n slotProps={{ paper: { ref: still.paperRef, sx: [{ p: 2, mt: 0.5 }, field.kind === 'day' && DAY_PAPER_SX] } }}\n >\n <RangeBounds\n field={field}\n value={value}\n onChange={onChange}\n testId={testId}\n calendarMonths={calendarMonths}\n />\n <RangeSummary field={field} value={value} onClear={() => onChange({})} testId={testId} />\n </Popover>\n </>\n );\n}\n\n\n/**\n * One range on the SLIDE-IN panel (and the narrow-screen modal): the numeric\n * control the panel already had, or — for a day range, which that control cannot\n * express — the same `De`/`Até` pair the pill's popover uses.\n */\nexport function PanelRangeField<T extends Record<string, unknown>>({\n field,\n value,\n onChange,\n testId,\n}: {\n field: RangeFieldConfig<T>;\n value: RangeValue;\n onChange: (range: RangeValue) => void;\n testId: string;\n}): React.JSX.Element {\n const copy = useDataViewsCopy();\n // The slide-in panel stays mounted while closed; its calendar does not.\n // Outside a `TableFilter` (the \"Mais\" sheet, a test) the pair is on screen.\n const panel = useContext(TableFilterContext);\n if (field.kind === \"day\") {\n return (\n <Box sx={{ display: \"flex\", flexDirection: \"column\", gap: 1 }}>\n <Typography component=\"span\" sx={{ fontSize: sxRem(12), fontWeight: 500, color: \"text.secondary\" }}>\n {field.label}\n </Typography>\n <RangeBounds\n field={field}\n value={value}\n onChange={onChange}\n testId={testId}\n showCalendar={panel ? panel.open : true}\n />\n </Box>\n );\n }\n return (\n <Box sx={{ display: \"flex\", flexDirection: \"column\", gap: 1 }}>\n <TableFilter.RangeField\n label={field.label}\n unit={field.unit}\n value={numericRange(value)}\n onChange={(range) => onChange(range)}\n testId={testId}\n />\n {/* Below the numeric control here, unlike the pill's popover: this one\n renders its own label, and chips above it would separate the label\n from the field it names. */}\n <RangePresets presets={presetsFor(field, copy)} value={value} onChange={onChange} testId={testId} />\n </Box>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/data-views-range-bounds.tsx"],"sourcesContent":["'use client';\n\n/**\n * The `De`/`Até` pair of a range filter, its preset chips, the line under it\n * and — for a day range — the calendar under that (FUT-4144). Shared by the\n * pill's popover, the slide-in panel and the \"Mais\" sheet, so the three cannot\n * drift on what a bound accepts or how it clears.\n */\nimport Box from '@mui/material/Box/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport React, { useState } from 'react';\n\nimport { useDataViewsCopy } from './data-views-copy-context';\nimport { DayBoundInput } from './data-views-day-input';\nimport { NumberBoundInput } from './data-views-number-input';\nimport { RangePresets } from './data-views-preset-chips';\nimport { DayRangeCalendar } from './data-views-range-calendar';\nimport { presetsFor } from './data-views-range-presets';\nimport { useOutsideResetKey } from './data-views-range-reset';\nimport { isRangeInverted } from './data-views-range-values';\nimport type { RangeFieldConfig, RangeValue } from './data-views-types';\nimport { sxRem } from '../../../tokens/relative';\n\n/**\n * One end of the range. A day keeps its `AAAA-MM-DD` string verbatim (the form\n * both the field and the backend speak) and is typed through the masked\n * `dd/mm/aaaa` field rather than a native date input — see\n * {@link DayBoundInput} for why. A number parses, and an unparseable/blank\n * entry CLEARS the bound rather than writing `NaN`.\n */\nfunction BoundField<T extends Record<string, unknown>>({\n field,\n label,\n value,\n onChange,\n testId,\n fill,\n}: {\n field: RangeFieldConfig<T>;\n label: string;\n value: number | string | undefined;\n onChange: (bound: number | string | undefined) => void;\n testId: string;\n /** A number box takes its cell's width; a day box always does. */\n fill: boolean;\n}): React.JSX.Element {\n const copy = useDataViewsCopy();\n if (field.kind === 'day') {\n return (\n <DayBoundInput\n fill\n mask={copy.filters.dayMask}\n invalidMessage={copy.filters.dayInvalid}\n label={label}\n value={value == null ? undefined : String(value)}\n onChange={onChange}\n testId={testId}\n />\n );\n }\n return (\n <NumberBoundInput\n fill={fill}\n label={label}\n value={value}\n unit={field.unit}\n onChange={onChange}\n testId={testId}\n />\n );\n}\n\n\n/** One box of the pair: an equal share of the row for a day, as it was for a number. */\nfunction BoundCell({ grow, children }: { grow: boolean; children: React.ReactNode }): React.JSX.Element {\n if (!grow) return <>{children}</>;\n return <Box sx={{ flex: '1 1 0', minWidth: 0 }}>{children}</Box>;\n}\n\n/**\n * The line under the pair: why an inverted window matches nothing, or — for a\n * day range — that BOTH days are in the result. Saying so is FUT-668's other\n * half: the bounds compare as ISO strings precisely so `até` keeps its whole\n * day, and nothing on screen would otherwise tell the merchant that.\n */\nfunction RangeNote({\n day,\n inverted,\n testId,\n}: {\n day: boolean;\n inverted: boolean;\n testId: string;\n}): React.JSX.Element | null {\n const copy = useDataViewsCopy();\n if (inverted) {\n return (\n <Typography\n component=\"p\"\n data-testid={`${testId}-inverted`}\n sx={{ mt: 0.75, fontSize: sxRem(12), color: 'error.main' }}\n >\n {copy.filters.rangeInvalid}\n </Typography>\n );\n }\n if (!day) return null;\n return (\n <Typography\n component=\"p\"\n data-testid={`${testId}-inclusive`}\n // `text.secondary`, not `disabled`: the note is read, and disabled grey\n // at 12px is 2.68:1 (FUT-4144 UI review).\n sx={{ mt: { xs: 0.25, sm: 0.75 }, fontSize: sxRem(12), color: 'text.secondary' }}\n >\n {copy.filters.rangeInclusiveNote}\n </Typography>\n );\n}\n\n/** Props of {@link RangeBounds}. */\ninterface RangeBoundsProps<T extends Record<string, unknown>> {\n field: RangeFieldConfig<T>;\n value: RangeValue;\n onChange: (range: RangeValue) => void;\n testId: string;\n /**\n * Months the day calendar shows side by side (FUT-4144). Two where the\n * popover has the room; one, with the month/year selectors, on a phone and\n * in the panels.\n */\n calendarMonths?: 1 | 2;\n /**\n * Whether the day calendar is mounted. A host that keeps the pair mounted\n * while hidden (the slide-in panel) passes its open state, so a closed panel\n * holds no calendar of its own.\n */\n showCalendar?: boolean;\n /**\n * A NUMBER pair splits the row equally too, as a day pair always does. Set\n * by the panels, whose width is the row's; the pill's popover sizes itself to\n * its content and keeps the boxes' own width.\n */\n fillRow?: boolean;\n}\n\n/**\n * The `De`/`Até` pair for a range — shared by the pill's popover and the\n * slide-in panel's day fields, so the two surfaces cannot drift on what a bound\n * accepts or how it clears.\n */\nexport function RangeBounds<T extends Record<string, unknown>>({\n field,\n value,\n onChange,\n testId,\n calendarMonths = 1,\n showCalendar = true,\n fillRow = false,\n}: RangeBoundsProps<T>): React.JSX.Element {\n const copy = useDataViewsCopy();\n const { key, emitted } = useOutsideResetKey(value);\n // Moves the calendar to a TYPED day. A typed write is the fields' own, so\n // the outside key above does not see it; a tap on the calendar moves\n // neither, which is what keeps it still under the finger.\n const [typed, setTyped] = useState(0);\n const typedChange = (range: RangeValue) => {\n setTyped((n) => n + 1);\n onChange(emitted(range));\n };\n const day = field.kind === 'day';\n return (\n <Box data-testid={`${testId}-panel`}>\n {/* Above the inputs, not below: the presets are the answer for most\n merchants, and the two date pickers are the escape hatch. */}\n <Box sx={{ '&:not(:empty)': { mb: { xs: 1, sm: 1.5 } } }}>\n <RangePresets presets={presetsFor(field, copy)} value={value} onChange={onChange} testId={testId} />\n </Box>\n {/* Top-aligned: a day that does not exist grows ITS field by a message\n line, and centring would push the other box half a line down. The two\n boxes are one height, so with no message this is the same row. */}\n <Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 1.5 }}>\n {/* A day pair shares the row equally, so it spans the calendar under\n it; a number pair keeps its own widths. */}\n <BoundCell grow={day || fillRow}>\n <BoundField\n key={`min-${key}`}\n field={field}\n label={copy.filters.rangeStart}\n value={value.min}\n onChange={(min) => typedChange({ ...value, min })}\n testId={`${testId}-min`}\n fill={fillRow}\n />\n </BoundCell>\n <BoundCell grow={day || fillRow}>\n <BoundField\n key={`max-${key}`}\n field={field}\n label={copy.filters.rangeEnd}\n value={value.max}\n onChange={(max) => typedChange({ ...value, max })}\n testId={`${testId}-max`}\n fill={fillRow}\n />\n </BoundCell>\n </Box>\n <RangeNote day={day} inverted={isRangeInverted(value)} testId={testId} />\n {/* Under the boxes and the note, with no button to reach it: the typed\n path stays as short as it was, and a period is two taps (FUT-4144). */}\n {day && showCalendar && (\n <DayRangeCalendar\n fieldLabel={field.label}\n value={value}\n onChange={(range) => onChange(emitted(range))}\n months={calendarMonths}\n viewKey={`${key}-${typed}`}\n testId={testId}\n />\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-J2AVWIMM.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isRangeSet,
|
|
3
|
-
rangeChipLabel
|
|
4
|
-
} from "./chunk-GCZJH4XL.js";
|
|
5
|
-
import {
|
|
6
|
-
useDataViewsCopy
|
|
7
|
-
} from "./chunk-KHG57NAE.js";
|
|
8
|
-
import {
|
|
9
|
-
sxRem
|
|
10
|
-
} from "./chunk-YKCAJ2TN.js";
|
|
11
|
-
|
|
12
|
-
// src/components/data-display/DataViews/data-views-range-summary.tsx
|
|
13
|
-
import Box from "@mui/material/Box/index.js";
|
|
14
|
-
import Button from "@mui/material/Button/index.js";
|
|
15
|
-
import Typography from "@mui/material/Typography/index.js";
|
|
16
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
17
|
-
function RangeSummary({
|
|
18
|
-
field,
|
|
19
|
-
value,
|
|
20
|
-
onClear,
|
|
21
|
-
testId
|
|
22
|
-
}) {
|
|
23
|
-
const copy = useDataViewsCopy();
|
|
24
|
-
const active = isRangeSet(value);
|
|
25
|
-
if (!active && field.kind !== "day") return null;
|
|
26
|
-
return /* @__PURE__ */ jsxs(
|
|
27
|
-
Box,
|
|
28
|
-
{
|
|
29
|
-
"aria-hidden": active ? void 0 : true,
|
|
30
|
-
sx: {
|
|
31
|
-
display: "flex",
|
|
32
|
-
alignItems: "center",
|
|
33
|
-
justifyContent: "space-between",
|
|
34
|
-
gap: 2,
|
|
35
|
-
mt: { xs: 0.5, sm: 1.5 },
|
|
36
|
-
visibility: active ? void 0 : "hidden"
|
|
37
|
-
},
|
|
38
|
-
children: [
|
|
39
|
-
/* @__PURE__ */ jsx(Typography, { component: "span", sx: { fontSize: sxRem(12), color: "text.secondary" }, children: active ? rangeChipLabel(field, value) : field.label }),
|
|
40
|
-
/* @__PURE__ */ jsx(
|
|
41
|
-
Button,
|
|
42
|
-
{
|
|
43
|
-
variant: "text",
|
|
44
|
-
size: "small",
|
|
45
|
-
onClick: active ? onClear : void 0,
|
|
46
|
-
tabIndex: active ? void 0 : -1,
|
|
47
|
-
"data-testid": active ? `${testId}-clear` : void 0,
|
|
48
|
-
sx: { textTransform: "none" },
|
|
49
|
-
children: copy.filters.clear
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
]
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export {
|
|
58
|
-
RangeSummary
|
|
59
|
-
};
|
|
60
|
-
//# sourceMappingURL=chunk-J2AVWIMM.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/data-views-range-summary.tsx"],"sourcesContent":["'use client';\n\nimport Box from '@mui/material/Box/index.js';\nimport Button from '@mui/material/Button/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport React from 'react';\n\nimport { useDataViewsCopy } from './data-views-copy-context';\nimport { isRangeSet, rangeChipLabel } from './data-views-range-values';\nimport type { RangeFieldConfig, RangeValue } from './data-views-types';\nimport { sxRem } from '../../../tokens/relative';\n\n/**\n * The applied window in words, and \"Limpar\".\n *\n * An inverted window is not an error the merchant must fix before the list\n * responds — it simply matches nothing, and saying so beats an empty grid with\n * no explanation (FUT-668).\n *\n * A DAY filter keeps the row's height while nothing is applied: its first tap\n * on the calendar applies a bound, and a row appearing then grew the popover\n * 26px and moved it 32px up at 320×568, the day under the finger with it\n * (FUT-4144 UI review round 2). The held row is invisible and inert.\n */\nexport function RangeSummary<T extends Record<string, unknown>>({\n field,\n value,\n onClear,\n testId,\n}: {\n field: RangeFieldConfig<T>;\n value: RangeValue;\n onClear: () => void;\n testId: string;\n}): React.JSX.Element | null {\n const copy = useDataViewsCopy();\n const active = isRangeSet(value);\n if (!active && field.kind !== 'day') return null;\n return (\n <Box\n aria-hidden={active ? undefined : true}\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 2,\n mt: { xs: 0.5, sm: 1.5 },\n visibility: active ? undefined : 'hidden',\n }}\n >\n <Typography component=\"span\" sx={{ fontSize: sxRem(12), color: 'text.secondary' }}>\n {active ? rangeChipLabel(field, value) : field.label}\n </Typography>\n <Button\n variant=\"text\"\n size=\"small\"\n onClick={active ? onClear : undefined}\n tabIndex={active ? undefined : -1}\n data-testid={active ? `${testId}-clear` : undefined}\n sx={{ textTransform: 'none' }}\n >\n {copy.filters.clear}\n </Button>\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAEA,OAAO,SAAS;AAChB,OAAO,YAAY;AACnB,OAAO,gBAAgB;AAmCnB,SAWE,KAXF;AAfG,SAAS,aAAgD;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAK6B;AAC3B,QAAM,OAAO,iBAAiB;AAC9B,QAAM,SAAS,WAAW,KAAK;AAC/B,MAAI,CAAC,UAAU,MAAM,SAAS,MAAO,QAAO;AAC5C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAa,SAAS,SAAY;AAAA,MAClC,IAAI;AAAA,QACF,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,KAAK;AAAA,QACL,IAAI,EAAE,IAAI,KAAK,IAAI,IAAI;AAAA,QACvB,YAAY,SAAS,SAAY;AAAA,MACnC;AAAA,MAEA;AAAA,4BAAC,cAAW,WAAU,QAAO,IAAI,EAAE,UAAU,MAAM,EAAE,GAAG,OAAO,iBAAiB,GAC7E,mBAAS,eAAe,OAAO,KAAK,IAAI,MAAM,OACjD;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,SAAS,UAAU;AAAA,YAC5B,UAAU,SAAS,SAAY;AAAA,YAC/B,eAAa,SAAS,GAAG,MAAM,WAAW;AAAA,YAC1C,IAAI,EAAE,eAAe,OAAO;AAAA,YAE3B,eAAK,QAAQ;AAAA;AAAA,QAChB;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/data-views-range-calendar.tsx"],"sourcesContent":["'use client';\n\n/**\n * The range calendar under a day filter's `De`/`Até` boxes (FUT-4144).\n *\n * The owner picked it ALWAYS OPEN (option B of the prototype): a period is\n * three taps — open the filter, the first day, the last day — against five for\n * a calendar button in each box and four for a link to a separate sheet. It\n * sits BELOW the boxes, with no button of its own, so the typed path is not one\n * keystroke longer than it was.\n *\n * The boxes and the calendar are two views of ONE range: a tap writes the\n * boxes, a typed day moves and repaints the calendar, an impossible typed day\n * (which writes nothing) leaves it alone, and \"Limpar\" empties both.\n *\n * It is `Calendar` in `selectionMode=\"range\"`, the same one `DateRangePicker`\n * mounts — not a second calendar. Its own rule picks the period: the first tap\n * starts it, the second closes it, and a second tap BEFORE the first swaps the\n * two, so the boxes never show a period backwards.\n */\nimport Box from '@mui/material/Box/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport React from 'react';\n\nimport { EN_US_DATA_VIEWS_COPY } from '../../../en-US.data-display';\nimport type { Theme } from '@mui/material/styles/index.js';\nimport { rem, sxRem } from '../../../tokens/relative';\nimport { Calendar, type DateRange } from '../../form/Calendar';\nimport { toDayString, toLocalDay } from '../../form/DateRangePicker/DateRangePicker.dates';\nimport type { DataViewsDayCalendarCopy } from './data-views-copy';\nimport { useDataViewsCopy } from './data-views-copy-context';\nimport type { RangeValue } from './data-views-types';\n\nconst CALENDAR_CLASS = 'data-views-range-calendar';\n\n/**\n * `Calendar` draws its own `Paper` with 24px of padding and a shadow. Inside\n * the filter's popover that reads as a card inside a card, so the inner frame\n * is flattened through the class hook the component offers for this — the\n * same thing `DateRangePicker` does.\n */\nconst ROOT_SX = (theme: Theme) => ({\n mt: { xs: 1, sm: 1.5 },\n // Below `sm` the caption and the weekday row give up their bottom margins,\n // so the whole popover fits a 320×568 screen under its pill (FUT-4144).\n '& :has(> * > [data-testid=\"calendar-month-select\"])': { mb: { xs: 0.5, sm: 2 } },\n '& :has(> [role=\"columnheader\"])': { mb: { xs: 0, sm: 1 } },\n '& [role=\"columnheader\"]': { height: { xs: rem(theme, 24), sm: rem(theme, 32) } },\n // The days carry no column gap of their own (`Calendar`, FUT-4162), so the\n // seven columns are what a day's 40px target is carved from below `sm`; the\n // range band and its round endpoints are the Calendar's, untouched here.\n // The month/year caption on ONE row at 320: the selectors give up the slack\n // around their text before the arrows are pushed onto a second row.\n '& [data-testid=\"calendar-month-select\"], & [data-testid=\"calendar-year-select\"]': { px: 0.5, minWidth: 0 },\n [`& .${CALENDAR_CLASS}`]: {\n p: 0,\n boxShadow: 'none',\n backgroundColor: 'transparent',\n backgroundImage: 'none',\n // A tapped day already rings itself; the whole grid framed in the primary\n // colour after every tap is noise in a popover. The frame stays for the\n // keyboard reaching the grid itself.\n '&:focus-within': { outline: 'none' },\n '&:focus-visible': {\n outline: (theme: Theme) => `${rem(theme, 2)} solid`,\n outlineColor: 'primary.main',\n outlineOffset: sxRem(2),\n },\n },\n});\n\n/** The two ends of a range, as `Calendar` reads them. */\nfunction rangeOf(value: RangeValue): DateRange {\n return {\n start: toLocalDay(typeof value.min === 'string' ? value.min : null),\n end: toLocalDay(typeof value.max === 'string' ? value.max : null),\n };\n}\n\n/**\n * What a tap on the calendar makes of the range.\n *\n * `Calendar` reports the period it holds after the tap: a fresh start (`end`\n * null) or a closed one, already in order. The one case it cannot see is a\n * range with only `Até` — typed, or left by a saved view — where its first tap\n * would drop that `Até`. A first day on or before it keeps it, so \"até 15/10\"\n * plus one tap on the 3rd is 03/10–15/10, as the prototype does.\n */\nexport function rangeFromCalendar(previous: RangeValue, picked: DateRange): RangeValue {\n const min = dayOf(picked.start);\n const max = dayOf(picked.end) ?? keptEnd(previous, min);\n return { ...(min ? { min } : {}), ...(max ? { max } : {}) };\n}\n\nconst dayOf = (date: Date | null | undefined): string | undefined => (date ? toDayString(date) : undefined);\n\n/** The `Até` of a range that has ONLY one, when the new first day is on or before it. */\nfunction keptEnd(previous: RangeValue, min: string | undefined): string | undefined {\n if (previous.min != null || typeof previous.max !== 'string') return undefined;\n return min && min <= previous.max ? previous.max : undefined;\n}\n\n/**\n * The month the calendar opens on while `De` is empty. With `De` set it opens\n * on De's month, which `Calendar` does by itself.\n *\n * With two months the current month sits on the RIGHT (setembro | outubro), so\n * the days a filter usually asks about — the ones just past — are on screen;\n * with only `Até` set, its month takes that place.\n */\nfunction openingMonth(value: RangeValue, months: number): Date | undefined {\n const end = toLocalDay(typeof value.max === 'string' ? value.max : null);\n const anchor = end ?? new Date();\n return new Date(anchor.getFullYear(), anchor.getMonth() - (months > 1 ? 1 : 0), 1);\n}\n\n/** Props of {@link DayRangeCalendar}. */\nexport interface DayRangeCalendarProps {\n /** The filter's own label (\"Data\"), which names the calendar. */\n fieldLabel: string;\n value: RangeValue;\n /** Called with the range a tap leaves; never for a typed day. */\n onChange: (range: RangeValue) => void;\n /**\n * Months side by side. Two read as a period at a glance where there is room;\n * one, with the month/year selectors, where there is not.\n */\n months: 1 | 2;\n /**\n * Changes when the range moved from OUTSIDE the calendar (typed, a preset,\n * \"Limpar\"), so the calendar re-opens on it. Never for its own taps: a\n * calendar that jumped under the finger picking in it would be unusable.\n */\n viewKey: string;\n testId: string;\n}\n\nexport function DayRangeCalendar({\n fieldLabel,\n value,\n onChange,\n months,\n viewKey,\n testId,\n}: DayRangeCalendarProps): React.JSX.Element {\n const copy: DataViewsDayCalendarCopy =\n useDataViewsCopy().filters.dayCalendar ?? (EN_US_DATA_VIEWS_COPY.filters.dayCalendar as DataViewsDayCalendarCopy);\n const range = rangeOf(value);\n const pick = (picked: DateRange) => onChange(rangeFromCalendar(value, picked));\n const waitingForEnd = Boolean(range.start && !range.end);\n\n return (\n <Box sx={ROOT_SX} data-testid={`${testId}-calendar`}>\n <Calendar\n key={viewKey}\n ariaLabel={copy.label(fieldLabel)}\n className={CALENDAR_CLASS}\n selectionMode=\"range\"\n locale={copy.locale}\n labels={copy.caption}\n // Sunday first, as a pt-BR calendar reads (`D S T Q Q S S`) and as the\n // presets' \"Esta semana\" counts.\n firstDayOfWeek={0}\n numberOfMonths={months}\n // Side by side, a day of the next month in this one is the same day\n // twice; one month alone keeps them, muted, as a six-week frame.\n showOutsideDays={months === 1}\n captionLayout={months > 1 ? 'arrows' : 'selectors'}\n defaultMonth={openingMonth(value, months)}\n range={range}\n // The intermediate callback does the work: the other fires only on the\n // tap that CLOSES a period, so the first tap would write nothing.\n onIntermediateRangeChange={pick}\n />\n <Typography\n component=\"p\"\n aria-live=\"polite\"\n data-testid={`${testId}-calendar-hint`}\n sx={{ mt: { xs: 0.25, sm: 1 }, fontSize: sxRem(12), color: 'text.secondary' }}\n >\n {waitingForEnd ? copy.pickEnd : copy.pickStart}\n </Typography>\n </Box>\n );\n}\n"],"mappings":"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","names":["theme"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|