@12-apps/ui 6.24.2 → 6.24.4
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/NATIVE.md +1 -1
- package/dist/_internal/components/data-display/Alert/Alert.js +5 -3
- package/dist/_internal/components/data-display/Alert/Alert.metrics.js +1 -1
- package/dist/_internal/components/data-display/Alert/Alert.styles.js +2 -2
- package/dist/_internal/components/data-display/Banner/Banner.js +7 -2
- package/dist/_internal/components/data-display/Banner/Banner.styles.js +10 -1
- package/dist/_internal/components/data-display/CardKit/card-actions-context.js +4 -4
- package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +5 -5
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +4 -4
- package/dist/_internal/components/data-display/index.js +5 -5
- package/dist/_internal/components/index.js +6 -6
- package/dist/_internal/components/navigation/AppHeader/AppHeader.identity.js +1 -1
- package/dist/_internal/components/navigation/index.js +1 -1
- package/dist/{chunk-7L6LAVJ7.js → chunk-4IVDVZZ2.js} +25 -11
- package/dist/chunk-4IVDVZZ2.js.map +1 -0
- package/dist/{chunk-U2YJCNRU.js → chunk-4T7TXRGM.js} +2 -2
- package/dist/{chunk-E27Y7FF2.js → chunk-57Z2ND3N.js} +9 -10
- package/dist/{chunk-E27Y7FF2.js.map → chunk-57Z2ND3N.js.map} +1 -1
- package/dist/{chunk-DI7HGYPX.js → chunk-JPV45AD6.js} +2 -2
- package/dist/{chunk-PRUSQQDT.js → chunk-KM5O4ICK.js} +2 -2
- package/dist/{chunk-2YEZONLX.js → chunk-M4LFDGI6.js} +30 -5
- package/dist/chunk-M4LFDGI6.js.map +1 -0
- package/dist/{chunk-O3336DJ6.js → chunk-SYJMI2NP.js} +2 -2
- package/dist/{chunk-W2YNUUVJ.js → chunk-TU6RNZUQ.js} +117 -78
- package/dist/chunk-TU6RNZUQ.js.map +1 -0
- package/dist/{chunk-B2Y3BABA.js → chunk-TXKZEKJN.js} +6 -9
- package/dist/chunk-TXKZEKJN.js.map +1 -0
- package/dist/{chunk-QFVFHIHE.js → chunk-WNMYWQ7D.js} +98 -30
- package/dist/chunk-WNMYWQ7D.js.map +1 -0
- package/dist/data-display/Alert.js +3 -3
- package/dist/data-display/Banner.js +7 -2
- package/dist/data-display/CardKit.js +5 -5
- package/dist/data-display/DataViews.js +5 -5
- package/dist/native/data-display/Alert.js +2 -5
- package/dist/native/data-display/Alert.js.map +1 -1
- package/dist/navigation/AppHeader.js +1 -1
- package/dist/types/components/data-display/Alert/Alert.d.ts +14 -0
- package/dist/types/components/data-display/Alert/Alert.d.ts.map +1 -1
- package/dist/types/components/data-display/Alert/Alert.metrics.d.ts +66 -23
- package/dist/types/components/data-display/Alert/Alert.metrics.d.ts.map +1 -1
- package/dist/types/components/data-display/Alert/Alert.styles.d.ts.map +1 -1
- package/dist/types/components/data-display/Banner/Banner.d.ts.map +1 -1
- package/dist/types/components/data-display/Banner/Banner.styles.d.ts +3 -0
- package/dist/types/components/data-display/Banner/Banner.styles.d.ts.map +1 -1
- package/dist/types/components/navigation/AppHeader/AppHeader.identity.d.ts +12 -5
- package/dist/types/components/navigation/AppHeader/AppHeader.identity.d.ts.map +1 -1
- package/dist/types/components/navigation/AppHeader/AppHeader.types.d.ts +12 -4
- package/dist/types/components/navigation/AppHeader/AppHeader.types.d.ts.map +1 -1
- package/dist/types-native/components/data-display/Alert/Alert.metrics.d.ts +66 -23
- package/dist/types-native/components/data-display/Alert/Alert.metrics.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/data-display/Alert/Alert.metrics.ts +66 -9
- package/src/components/data-display/Alert/Alert.styles.tsx +4 -5
- package/src/components/data-display/Alert/Alert.tsx +139 -21
- package/src/components/data-display/Alert/NATIVE-NOTES.md +1 -1
- package/src/components/data-display/Banner/Banner.styles.ts +40 -2
- package/src/components/data-display/Banner/Banner.tsx +22 -9
- package/src/components/navigation/AppHeader/AppHeader.identity.tsx +159 -86
- package/src/components/navigation/AppHeader/AppHeader.md +12 -5
- package/src/components/navigation/AppHeader/AppHeader.types.ts +12 -4
- package/dist/chunk-2YEZONLX.js.map +0 -1
- package/dist/chunk-7L6LAVJ7.js.map +0 -1
- package/dist/chunk-B2Y3BABA.js.map +0 -1
- package/dist/chunk-QFVFHIHE.js.map +0 -1
- package/dist/chunk-W2YNUUVJ.js.map +0 -1
- /package/dist/{chunk-U2YJCNRU.js.map → chunk-4T7TXRGM.js.map} +0 -0
- /package/dist/{chunk-DI7HGYPX.js.map → chunk-JPV45AD6.js.map} +0 -0
- /package/dist/{chunk-PRUSQQDT.js.map → chunk-KM5O4ICK.js.map} +0 -0
- /package/dist/{chunk-O3336DJ6.js.map → chunk-SYJMI2NP.js.map} +0 -0
|
@@ -87,46 +87,146 @@ export const AppHeaderStatus: React.FC<AppHeaderStatusProps> = ({
|
|
|
87
87
|
|
|
88
88
|
AppHeaderStatus.displayName = 'AppHeaderStatus';
|
|
89
89
|
|
|
90
|
-
/**
|
|
91
|
-
const
|
|
92
|
-
Pick<AppHeaderIdentityProps, 'title' | '
|
|
90
|
+
/** The name and, when the block opens onto something, the chevron beside it. */
|
|
91
|
+
const IdentityTitle: React.FC<
|
|
92
|
+
Pick<AppHeaderIdentityProps, 'title' | 'size'> & {
|
|
93
93
|
interactive: boolean;
|
|
94
94
|
disclosed: boolean;
|
|
95
95
|
dataTestId: string;
|
|
96
96
|
}
|
|
97
|
-
> = ({ title,
|
|
98
|
-
<Box sx={{
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
/>
|
|
119
|
-
)}
|
|
120
|
-
</Box>
|
|
121
|
-
{subtitle && (
|
|
122
|
-
<Typography variant="body2" color="text.secondary" component="span" sx={ONE_LINE}>
|
|
123
|
-
{subtitle}
|
|
124
|
-
</Typography>
|
|
97
|
+
> = ({ title, size = 'md', interactive, disclosed, dataTestId }) => (
|
|
98
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.25, minWidth: 0, width: '100%' }}>
|
|
99
|
+
<Typography
|
|
100
|
+
component="span"
|
|
101
|
+
data-testid={`${dataTestId}-title`}
|
|
102
|
+
sx={{ fontSize: TITLE_PX[size], fontWeight: 700, lineHeight: 1.2, ...ONE_LINE }}
|
|
103
|
+
>
|
|
104
|
+
{title}
|
|
105
|
+
</Typography>
|
|
106
|
+
{interactive && (
|
|
107
|
+
<KeyboardArrowDown
|
|
108
|
+
aria-hidden
|
|
109
|
+
data-testid={`${dataTestId}-chevron`}
|
|
110
|
+
sx={{
|
|
111
|
+
flex: '0 0 auto',
|
|
112
|
+
fontSize: 20,
|
|
113
|
+
opacity: 0.7,
|
|
114
|
+
transition: 'transform 150ms ease',
|
|
115
|
+
transform: disclosed ? 'rotate(180deg)' : 'none',
|
|
116
|
+
}}
|
|
117
|
+
/>
|
|
125
118
|
)}
|
|
126
|
-
{status}
|
|
127
119
|
</Box>
|
|
128
120
|
);
|
|
129
121
|
|
|
122
|
+
/**
|
|
123
|
+
* The disclosure, wrapping the NAME ROW and nothing else (12-63).
|
|
124
|
+
*
|
|
125
|
+
* The padding is cancelled by an equal negative margin, so the hover and the
|
|
126
|
+
* focus ring bleed outward while the title still starts on the same pixel as
|
|
127
|
+
* the lines under it. A padded button with no offset moves one of the two.
|
|
128
|
+
*/
|
|
129
|
+
const discloseSx = {
|
|
130
|
+
display: 'flex',
|
|
131
|
+
alignItems: 'center',
|
|
132
|
+
gap: 0.25,
|
|
133
|
+
width: '100%',
|
|
134
|
+
minWidth: 0,
|
|
135
|
+
appearance: 'none',
|
|
136
|
+
px: 0.5,
|
|
137
|
+
mx: -0.5,
|
|
138
|
+
py: 0.25,
|
|
139
|
+
my: -0.25,
|
|
140
|
+
border: 'none',
|
|
141
|
+
borderRadius: 1.5,
|
|
142
|
+
background: 'none',
|
|
143
|
+
color: 'inherit',
|
|
144
|
+
font: 'inherit',
|
|
145
|
+
textAlign: 'left',
|
|
146
|
+
cursor: 'pointer',
|
|
147
|
+
// Guarded: on a touch screen an unguarded `:hover` sticks after the tap that
|
|
148
|
+
// opened the panel, so the row stays highlighted behind it.
|
|
149
|
+
'@media (hover: hover)': { '&:hover': { backgroundColor: 'action.hover' } },
|
|
150
|
+
'&:focus-visible': { outline: '2px solid', outlineColor: 'primary.main', outlineOffset: 2 },
|
|
151
|
+
} as const;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The text column: the name row, then the quieter lines under it.
|
|
155
|
+
*
|
|
156
|
+
* ## `subtitle` and `status` are OUTSIDE the disclosure, on purpose (12-63)
|
|
157
|
+
*
|
|
158
|
+
* Both are `ReactNode`, and `AppHeaderStatus.items` is a `ReactNode[]` — so a
|
|
159
|
+
* segment of the state line is free to be a control, and consumers put controls
|
|
160
|
+
* there: a mesa chip, a service-mode picker. While the whole block was one
|
|
161
|
+
* `<button>` those were `<button>`s inside a `<button>`, which is invalid HTML
|
|
162
|
+
* (the content model of `button` excludes interactive content) and, more
|
|
163
|
+
* visibly, means one tap fires two handlers. An adopting storefront opened two
|
|
164
|
+
* popups on every tap of either control because of it, and had already
|
|
165
|
+
* hand-rolled this component at one tier to dodge the nesting — a consumer
|
|
166
|
+
* working around the component is the report.
|
|
167
|
+
*
|
|
168
|
+
* The target stays large. The button is the full-width NAME ROW, which is the
|
|
169
|
+
* thing a reader aims at — what it gives up is the mark beside it, and a mark
|
|
170
|
+
* that opens the panel is not worth a state line that cannot hold a control.
|
|
171
|
+
*/
|
|
172
|
+
const IdentityText: React.FC<
|
|
173
|
+
Pick<
|
|
174
|
+
AppHeaderIdentityProps,
|
|
175
|
+
'title' | 'subtitle' | 'status' | 'size' | 'discloseLabel' | 'className'
|
|
176
|
+
> & {
|
|
177
|
+
onDisclose: (() => void) | undefined;
|
|
178
|
+
disclosed: boolean;
|
|
179
|
+
dataTestId: string;
|
|
180
|
+
}
|
|
181
|
+
> = ({
|
|
182
|
+
title,
|
|
183
|
+
subtitle,
|
|
184
|
+
status,
|
|
185
|
+
size = 'md',
|
|
186
|
+
onDisclose,
|
|
187
|
+
disclosed,
|
|
188
|
+
discloseLabel,
|
|
189
|
+
className,
|
|
190
|
+
dataTestId,
|
|
191
|
+
}) => {
|
|
192
|
+
const name = (
|
|
193
|
+
<IdentityTitle
|
|
194
|
+
title={title}
|
|
195
|
+
size={size}
|
|
196
|
+
interactive={Boolean(onDisclose)}
|
|
197
|
+
disclosed={disclosed}
|
|
198
|
+
dataTestId={dataTestId}
|
|
199
|
+
/>
|
|
200
|
+
);
|
|
201
|
+
return (
|
|
202
|
+
<Box sx={{ minWidth: 0, flex: 1, display: 'flex', flexDirection: 'column', gap: 0.25 }}>
|
|
203
|
+
{onDisclose ? (
|
|
204
|
+
<Box
|
|
205
|
+
component="button"
|
|
206
|
+
type="button"
|
|
207
|
+
className={className}
|
|
208
|
+
data-testid={dataTestId}
|
|
209
|
+
onClick={onDisclose}
|
|
210
|
+
aria-haspopup="dialog"
|
|
211
|
+
aria-expanded={disclosed}
|
|
212
|
+
aria-label={discloseLabel ?? `Detalhes de ${title}`}
|
|
213
|
+
sx={discloseSx}
|
|
214
|
+
>
|
|
215
|
+
{name}
|
|
216
|
+
</Box>
|
|
217
|
+
) : (
|
|
218
|
+
name
|
|
219
|
+
)}
|
|
220
|
+
{subtitle && (
|
|
221
|
+
<Typography variant="body2" color="text.secondary" component="span" sx={ONE_LINE}>
|
|
222
|
+
{subtitle}
|
|
223
|
+
</Typography>
|
|
224
|
+
)}
|
|
225
|
+
{status}
|
|
226
|
+
</Box>
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
|
|
130
230
|
/** The placeholder held while the identity is still resolving. */
|
|
131
231
|
const IdentitySkeleton: React.FC<{ size: SizeValue; dataTestId: string }> = ({
|
|
132
232
|
size,
|
|
@@ -145,16 +245,13 @@ const IdentitySkeleton: React.FC<{ size: SizeValue; dataTestId: string }> = ({
|
|
|
145
245
|
);
|
|
146
246
|
|
|
147
247
|
/**
|
|
148
|
-
*
|
|
248
|
+
* The BLOCK's row: the mark, then the text column beside it.
|
|
149
249
|
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
* had a constraint to ellipsise against, and the title and state line ran
|
|
156
|
-
* straight under the actions — 327px of overlap at 320px wide. Filling the
|
|
157
|
-
* wrapper is what lets `minWidth: 0` bite and the ellipsis engage.
|
|
250
|
+
* Always a `Box` div now — since 12-63 the disclosure is the name row inside
|
|
251
|
+
* the text column ({@link discloseSx}), not this element. `width: '100%'` and
|
|
252
|
+
* `minWidth: 0` stay because the column below still has to ellipsise against
|
|
253
|
+
* something; the argument about a `<button>` sizing to max-content moved to
|
|
254
|
+
* `discloseSx`, which is where the button now is.
|
|
158
255
|
*/
|
|
159
256
|
const rowSx = {
|
|
160
257
|
display: 'flex',
|
|
@@ -166,12 +263,19 @@ const rowSx = {
|
|
|
166
263
|
} as const;
|
|
167
264
|
|
|
168
265
|
/**
|
|
169
|
-
* Mark + title + state line, and — when it can be opened —
|
|
170
|
-
*
|
|
266
|
+
* Mark + title + state line, and — when it can be opened — a name row that is
|
|
267
|
+
* the button.
|
|
171
268
|
*
|
|
172
|
-
* The
|
|
173
|
-
*
|
|
174
|
-
*
|
|
269
|
+
* The disclosure used to wrap EVERYTHING, on the argument that the chevron
|
|
270
|
+
* alone is a 20px target next to a 40px mark that does nothing. The target is
|
|
271
|
+
* still not the chevron: the button is the full-width NAME ROW, which is what a
|
|
272
|
+
* reader aims at. What it no longer swallows is the mark beside it and the
|
|
273
|
+
* quieter lines below — because those lines take `ReactNode`s, consumers put
|
|
274
|
+
* CONTROLS in them, and a control inside a button is invalid HTML whose every
|
|
275
|
+
* tap fires two handlers. See {@link IdentityText} (12-63).
|
|
276
|
+
*
|
|
277
|
+
* `className` and `dataTestId` stay on the same elements they always named: the
|
|
278
|
+
* block when it is static, the disclosure when there is one.
|
|
175
279
|
*/
|
|
176
280
|
export const AppHeaderIdentity: React.FC<AppHeaderIdentityProps> = ({
|
|
177
281
|
title,
|
|
@@ -190,8 +294,12 @@ export const AppHeaderIdentity: React.FC<AppHeaderIdentityProps> = ({
|
|
|
190
294
|
}) => {
|
|
191
295
|
if (loading) return <IdentitySkeleton size={size} dataTestId={dataTestId} />;
|
|
192
296
|
|
|
193
|
-
|
|
194
|
-
|
|
297
|
+
return (
|
|
298
|
+
<Box
|
|
299
|
+
className={onDisclose ? undefined : className}
|
|
300
|
+
data-testid={onDisclose ? undefined : dataTestId}
|
|
301
|
+
sx={rowSx}
|
|
302
|
+
>
|
|
195
303
|
{mark ?? (
|
|
196
304
|
<AppHeaderBrand
|
|
197
305
|
name={title}
|
|
@@ -206,47 +314,12 @@ export const AppHeaderIdentity: React.FC<AppHeaderIdentityProps> = ({
|
|
|
206
314
|
subtitle={subtitle}
|
|
207
315
|
status={status}
|
|
208
316
|
size={size}
|
|
209
|
-
|
|
317
|
+
onDisclose={onDisclose}
|
|
210
318
|
disclosed={disclosed}
|
|
319
|
+
discloseLabel={discloseLabel}
|
|
320
|
+
className={className}
|
|
211
321
|
dataTestId={dataTestId}
|
|
212
322
|
/>
|
|
213
|
-
</>
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
if (!onDisclose) {
|
|
217
|
-
return (
|
|
218
|
-
<Box className={className} data-testid={dataTestId} sx={rowSx}>
|
|
219
|
-
{body}
|
|
220
|
-
</Box>
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return (
|
|
225
|
-
<Box
|
|
226
|
-
component="button"
|
|
227
|
-
type="button"
|
|
228
|
-
className={className}
|
|
229
|
-
data-testid={dataTestId}
|
|
230
|
-
onClick={onDisclose}
|
|
231
|
-
aria-haspopup="dialog"
|
|
232
|
-
aria-expanded={disclosed}
|
|
233
|
-
aria-label={discloseLabel ?? `Detalhes de ${title}`}
|
|
234
|
-
sx={{
|
|
235
|
-
...rowSx,
|
|
236
|
-
appearance: 'none',
|
|
237
|
-
p: 0.5,
|
|
238
|
-
ml: -0.5,
|
|
239
|
-
border: 'none',
|
|
240
|
-
borderRadius: 1.5,
|
|
241
|
-
background: 'none',
|
|
242
|
-
color: 'inherit',
|
|
243
|
-
font: 'inherit',
|
|
244
|
-
cursor: 'pointer',
|
|
245
|
-
'&:hover': { backgroundColor: 'action.hover' },
|
|
246
|
-
'&:focus-visible': { outline: '2px solid', outlineColor: 'primary.main', outlineOffset: 2 },
|
|
247
|
-
}}
|
|
248
|
-
>
|
|
249
|
-
{body}
|
|
250
323
|
</Box>
|
|
251
324
|
);
|
|
252
325
|
};
|
|
@@ -118,11 +118,18 @@ throwing.
|
|
|
118
118
|
|
|
119
119
|
- The mark is `role="img"` labelled with the name, so a screen reader says
|
|
120
120
|
"Future Drink" rather than spelling out "F D".
|
|
121
|
-
- With `onDisclose`, the
|
|
122
|
-
`aria-haspopup="dialog"` and a live `aria-expanded`.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
121
|
+
- With `onDisclose`, the identity's **name row** is a `<button>` with
|
|
122
|
+
`aria-haspopup="dialog"` and a live `aria-expanded`. It is the full-width row,
|
|
123
|
+
chevron included, rather than the chevron alone — on a phone that would be a
|
|
124
|
+
20px target next to a 40px mark that does nothing, and a reader aiming at the
|
|
125
|
+
store's name expects the store's details.
|
|
126
|
+
- **`status` and `subtitle` render OUTSIDE that button, and must** (12-63). Both
|
|
127
|
+
are `ReactNode`, and `AppHeaderStatus.items` is a `ReactNode[]`, so a segment
|
|
128
|
+
of the state line is free to be a control — a mesa chip, a mode picker — and
|
|
129
|
+
consumers do exactly that. The disclosure used to wrap the whole block, which
|
|
130
|
+
made those `<button>`s inside a `<button>`: invalid HTML, and one tap firing
|
|
131
|
+
two handlers. Put controls in the state line freely; put nothing interactive
|
|
132
|
+
in `title`, which is a `string` and belongs to the button.
|
|
126
133
|
- The state line separates its segments with real whitespace, not CSS margin —
|
|
127
134
|
a screen reader reads `textContent`, and a margin-only gap runs "Aberto agora"
|
|
128
135
|
straight into "Retirada no balcão" as one word. The separator glyph itself is
|
|
@@ -62,20 +62,28 @@ export interface AppHeaderStatusProps {
|
|
|
62
62
|
* the consumer's own router in the `leading` slot, whereas an `href` prop would
|
|
63
63
|
* have to guess whose link component it is being handed — `to` for one router,
|
|
64
64
|
* `href` for another — and would half-work for everybody. `onDisclose` is the
|
|
65
|
-
* only interaction the block owns: with it the
|
|
66
|
-
* appears, without it the
|
|
65
|
+
* only interaction the block owns: with it the NAME ROW is a button and a
|
|
66
|
+
* chevron appears, without it the row is static text.
|
|
67
|
+
*
|
|
68
|
+
* The button stops at that row (12-63). `status` and `subtitle` render as its
|
|
69
|
+
* SIBLINGS, so a consumer may put controls in the state line — which they do,
|
|
70
|
+
* and which used to nest a `<button>` inside a `<button>`.
|
|
67
71
|
*/
|
|
68
72
|
export interface AppHeaderIdentityProps
|
|
69
73
|
extends Pick<AppHeaderBrandProps, 'logoUrl' | 'seedColor'> {
|
|
70
74
|
/** The name shown, and the one the mark derives its initials from. */
|
|
71
75
|
title: string;
|
|
72
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* A quieter line under the title — use `status` for the dotted state line.
|
|
78
|
+
*
|
|
79
|
+
* Rendered OUTSIDE the disclosure, like `status`, so it may hold a control.
|
|
80
|
+
*/
|
|
73
81
|
subtitle?: ReactNode;
|
|
74
82
|
/** The state line, usually an {@link AppHeaderStatusProps} element. */
|
|
75
83
|
status?: ReactNode;
|
|
76
84
|
/** Replaces the derived mark entirely (an icon, an `<img>`, nothing). */
|
|
77
85
|
mark?: ReactNode;
|
|
78
|
-
/** Opens the details panel. Renders the
|
|
86
|
+
/** Opens the details panel. Renders the NAME ROW as a button with a chevron. */
|
|
79
87
|
onDisclose?: () => void;
|
|
80
88
|
/** Whether the panel `onDisclose` opens is currently open (`aria-expanded`). */
|
|
81
89
|
disclosed?: boolean;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/Banner/Banner.styles.ts"],"sourcesContent":["import { alpha, keyframes } from '@mui/material/styles/index.js';\nimport type { CSSObject, PaletteColor, Theme } from '@mui/material/styles/index.js';\n\nimport type { BannerVariant } from './Banner.types';\n\n// Animations\nexport const fadeInSlide = keyframes`\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n`;\n\nconst pulseAnimation = keyframes`\n 0% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 0.7;\n }\n 70% {\n box-shadow: 0 0 0 8px currentColor;\n opacity: 0;\n }\n 100% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 0;\n }\n`;\n\nexport const getVariantColor = (theme: Theme, variant: BannerVariant) => {\n const colorMap = {\n info: theme.palette.info,\n success: theme.palette.success,\n warning: theme.palette.warning,\n critical: theme.palette.error,\n };\n return colorMap[variant];\n};\n\nexport const bannerPartStyles = (theme: Theme, colorPalette: PaletteColor): CSSObject => ({\n // Icon container\n '.banner-icon': {\n flexShrink: 0,\n marginTop: theme.spacing(0.25),\n color: colorPalette.main,\n fontSize: '1.25rem',\n display: 'flex',\n alignItems: 'center',\n position: 'relative',\n\n '&::before': {\n content: '\"\"',\n position: 'absolute',\n inset: -4,\n borderRadius: '50%',\n background: alpha(colorPalette.main, 0.1),\n animation: `${pulseAnimation} 3s infinite`,\n },\n },\n\n // Content area\n '.banner-content': {\n flex: 1,\n minWidth: 0, // Prevents flex item overflow\n },\n\n // Title styles\n '.banner-title': {\n fontWeight: 600,\n fontSize: '1rem',\n lineHeight: 1.4,\n marginBottom: theme.spacing(0.5),\n color: colorPalette.dark || colorPalette.main,\n },\n\n // Description styles \n '.banner-description': {\n fontSize: '0.875rem',\n lineHeight: 1.5,\n opacity: 0.9,\n color: 'inherit',\n },\n\n // Actions area\n '.banner-actions': {\n display: 'flex',\n flexShrink: 0,\n gap: theme.spacing(1),\n alignItems: 'center',\n marginTop: theme.spacing(1),\n\n [theme.breakpoints.up('sm')]: {\n marginTop: 0,\n marginLeft: theme.spacing(2),\n },\n },\n\n // Dismiss button\n '.banner-dismiss': {\n color: 'inherit',\n opacity: 0.7,\n marginLeft: theme.spacing(1),\n flexShrink: 0,\n\n '&:hover': {\n opacity: 1,\n backgroundColor: alpha(colorPalette.main, 0.1),\n transform: 'rotate(90deg)',\n },\n\n '&:focus': {\n opacity: 1,\n outline: `2px solid ${colorPalette.main}`,\n outlineOffset: '2px',\n },\n },\n});\n"],"mappings":";AAAA,SAAS,OAAO,iBAAiB;AAM1B,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAW3B,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAehB,IAAM,kBAAkB,CAAC,OAAc,YAA2B;AACvE,QAAM,WAAW;AAAA,IACf,MAAM,MAAM,QAAQ;AAAA,IACpB,SAAS,MAAM,QAAQ;AAAA,IACvB,SAAS,MAAM,QAAQ;AAAA,IACvB,UAAU,MAAM,QAAQ;AAAA,EAC1B;AACA,SAAO,SAAS,OAAO;AACzB;AAEO,IAAM,mBAAmB,CAAC,OAAc,kBAA2C;AAAA;AAAA,EAExF,gBAAgB;AAAA,IACd,YAAY;AAAA,IACZ,WAAW,MAAM,QAAQ,IAAI;AAAA,IAC7B,OAAO,aAAa;AAAA,IACpB,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IAEV,aAAa;AAAA,MACX,SAAS;AAAA,MACT,UAAU;AAAA,MACV,OAAO;AAAA,MACP,cAAc;AAAA,MACd,YAAY,MAAM,aAAa,MAAM,GAAG;AAAA,MACxC,WAAW,GAAG,cAAc;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA,EAGA,mBAAmB;AAAA,IACjB,MAAM;AAAA,IACN,UAAU;AAAA;AAAA,EACZ;AAAA;AAAA,EAGA,iBAAiB;AAAA,IACf,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc,MAAM,QAAQ,GAAG;AAAA,IAC/B,OAAO,aAAa,QAAQ,aAAa;AAAA,EAC3C;AAAA;AAAA,EAGA,uBAAuB;AAAA,IACrB,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA;AAAA,EAGA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK,MAAM,QAAQ,CAAC;AAAA,IACpB,YAAY;AAAA,IACZ,WAAW,MAAM,QAAQ,CAAC;AAAA,IAE1B,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG;AAAA,MAC5B,WAAW;AAAA,MACX,YAAY,MAAM,QAAQ,CAAC;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA,EAGA,mBAAmB;AAAA,IACjB,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY,MAAM,QAAQ,CAAC;AAAA,IAC3B,YAAY;AAAA,IAEZ,WAAW;AAAA,MACT,SAAS;AAAA,MACT,iBAAiB,MAAM,aAAa,MAAM,GAAG;AAAA,MAC7C,WAAW;AAAA,IACb;AAAA,IAEA,WAAW;AAAA,MACT,SAAS;AAAA,MACT,SAAS,aAAa,aAAa,IAAI;AAAA,MACvC,eAAe;AAAA,IACjB;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/Banner/Banner.tsx"],"sourcesContent":["import CheckCircle from '@mui/icons-material/CheckCircle';\nimport Close from '@mui/icons-material/Close';\nimport Error from '@mui/icons-material/Error';\nimport Info from '@mui/icons-material/Info';\nimport Warning from '@mui/icons-material/Warning';\nimport Box from '@mui/material/Box/index.js';\nimport Button from '@mui/material/Button/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { alpha, styled } from '@mui/material/styles/index.js';\nimport type { Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { bannerPartStyles, fadeInSlide, getVariantColor } from './Banner.styles';\nimport type { BannerProps, BannerVariant } from './Banner.types';\n\nconst StyledBanner = styled(Box, {\n shouldForwardProp: (prop) => !['variant', 'sticky', 'fullWidth'].includes(prop as string),\n})<{\n variant: BannerVariant;\n sticky: boolean;\n fullWidth: boolean;\n}>(({ theme, variant, sticky, fullWidth }) => {\n\n const colorPalette = getVariantColor(theme, variant);\n\n return {\n display: 'flex',\n alignItems: 'flex-start',\n gap: theme.spacing(1.5),\n padding: theme.spacing(1.5, 2),\n borderRadius: theme.spacing(1),\n backgroundColor: alpha(colorPalette.main, 0.1),\n border: `1px solid ${alpha(colorPalette.main, 0.2)}`,\n color: colorPalette.main,\n position: sticky ? 'sticky' : 'relative',\n top: sticky ? 0 : 'auto',\n zIndex: sticky ? theme.zIndex.appBar : 'auto',\n width: fullWidth ? '100vw' : '100%',\n marginLeft: fullWidth ? '50%' : 0,\n transform: fullWidth ? 'translateX(-50%)' : 'none',\n animation: `${fadeInSlide} 0.3s ease-out`,\n transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',\n\n // Enhanced accessibility and focus styles\n '&:focus-within': {\n outline: `3px solid ${alpha(colorPalette.main, 0.5)}`,\n outlineOffset: '2px',\n },\n\n ...bannerPartStyles(theme, colorPalette),\n\n // Responsive layout\n [theme.breakpoints.down('sm')]: {\n flexDirection: 'column',\n alignItems: 'stretch',\n gap: theme.spacing(1),\n \n '.banner-content': {\n order: 1,\n },\n\n '.banner-actions': {\n order: 2,\n justifyContent: 'flex-start',\n marginTop: theme.spacing(1),\n marginLeft: 0,\n },\n },\n\n // Glass effect variant (optional enhancement)\n '&.banner-glass': {\n backgroundColor: alpha(theme.palette.background.paper, 0.1),\n backdropFilter: 'blur(20px)',\n border: `1px solid ${alpha(theme.palette.divider, 0.2)}`,\n color: theme.palette.text.primary,\n \n '.banner-icon': {\n color: colorPalette.main,\n },\n },\n };\n});\n\nconst getVariantIcon = (variant: BannerVariant) => {\n const iconMap: Record<BannerVariant, React.ReactNode> = {\n info: <Info />,\n success: <CheckCircle />,\n warning: <Warning />,\n critical: <Error />,\n };\n return iconMap[variant];\n};\n\ntype BannerAction = NonNullable<BannerProps['actions']>[number];\n\n// Warnings and criticals interrupt the screen reader; the rest are announced\n// politely when it next pauses.\nconst resolveAriaAnnouncement = (variant: BannerVariant) => ({\n role: variant === 'warning' || variant === 'critical' ? 'alert' : 'status',\n live: (variant === 'critical' ? 'assertive' : 'polite') as 'assertive' | 'polite',\n});\n\nconst testIdFor = (base: string | undefined, suffix: string) =>\n base ? `${base}-${suffix}` : `banner-${suffix}`;\n\n// Resolves the banner's palette once, rather than per property as the inline\n// version did — getVariantColor was being called nine times to build one button.\nconst buildActionSx = (\n theme: Theme,\n variant: BannerVariant,\n actionVariant: BannerAction['variant'],\n) => {\n const palette = getVariantColor(theme, variant);\n\n return {\n minWidth: 'auto',\n px: 1.5,\n py: 0.5,\n fontSize: '0.8125rem',\n fontWeight: 500,\n borderRadius: 1,\n\n ...(actionVariant === 'primary' && {\n backgroundColor: palette.main,\n color: theme.palette.getContrastText(palette.main),\n\n '&:hover': {\n backgroundColor: palette.dark || palette.main,\n transform: 'translateY(-1px)',\n },\n }),\n\n ...(actionVariant === 'secondary' && {\n borderColor: palette.main,\n color: palette.main,\n\n '&:hover': {\n backgroundColor: alpha(palette.main, 0.1),\n borderColor: palette.main,\n transform: 'translateY(-1px)',\n },\n }),\n };\n};\n\nconst BannerActionButton: React.FC<{\n action: BannerAction;\n variant: BannerVariant;\n dataTestId?: string;\n}> = ({ action, variant, dataTestId }) => (\n <Button\n size=\"small\"\n variant={action.variant === 'primary' ? 'contained' : 'outlined'}\n onClick={action.onClick}\n data-testid={testIdFor(dataTestId, 'action')}\n sx={(theme) => buildActionSx(theme, variant, action.variant)}\n >\n {action.label}\n </Button>\n);\n\nconst BannerBody: React.FC<{\n displayIcon: React.ReactNode;\n title?: BannerProps['title'];\n description?: BannerProps['description'];\n dataTestId?: string;\n children?: React.ReactNode;\n}> = ({ displayIcon, title, description, dataTestId, children }) => (\n <>\n {displayIcon && (\n <Box className=\"banner-icon\" aria-hidden=\"true\" data-testid={testIdFor(dataTestId, 'icon')}>\n {displayIcon}\n </Box>\n )}\n\n <Box className=\"banner-content\">\n {title && (\n <Typography\n className=\"banner-title\"\n variant=\"subtitle2\"\n component=\"div\"\n data-testid={testIdFor(dataTestId, 'title')}\n >\n {title}\n </Typography>\n )}\n {description && (\n <Typography\n className=\"banner-description\"\n variant=\"body2\"\n component=\"div\"\n data-testid={testIdFor(dataTestId, 'message')}\n >\n {description}\n </Typography>\n )}\n {children}\n </Box>\n </>\n);\n\nconst BannerTrailing: React.FC<{\n actions?: BannerProps['actions'];\n variant: BannerVariant;\n dismissible: boolean;\n onDismissClick: () => void;\n dismissLabel: string;\n dataTestId?: string;\n}> = ({ actions, variant, dismissible, onDismissClick, dismissLabel, dataTestId }) => (\n <Box display=\"flex\" alignItems=\"center\" gap={1}>\n {actions && actions.length > 0 && (\n <Box className=\"banner-actions\">\n {actions.map((action, index) => (\n <BannerActionButton\n key={index}\n action={action}\n variant={variant}\n dataTestId={dataTestId}\n />\n ))}\n </Box>\n )}\n\n {dismissible && (\n <IconButton\n className=\"banner-dismiss\"\n size=\"small\"\n onClick={onDismissClick}\n aria-label={dismissLabel}\n data-testid={testIdFor(dataTestId, 'close')}\n sx={{ transition: 'all 0.2s ease' }}\n >\n <Close fontSize=\"small\" />\n </IconButton>\n )}\n </Box>\n);\n\nexport const Banner = React.forwardRef<HTMLDivElement, BannerProps>(\n (\n {\n variant = 'info',\n title,\n description,\n icon,\n dismissible = false,\n dismissLabel,\n onDismiss,\n actions,\n sticky = false,\n fullWidth = false,\n className,\n children,\n 'data-testid': dataTestId = 'banner',\n ...props\n },\n ref,\n ) => {\n const [visible, setVisible] = React.useState(true);\n\n const handleDismiss = React.useCallback(() => {\n setVisible(false);\n onDismiss?.();\n }, [onDismiss]);\n\n const displayIcon = icon || getVariantIcon(variant);\n\n const { role: ariaRole, live: ariaLive } = resolveAriaAnnouncement(variant);\n\n if (!visible) {\n return null;\n }\n\n return (\n <StyledBanner\n ref={ref}\n variant={variant}\n sticky={sticky}\n fullWidth={fullWidth}\n className={className}\n role={ariaRole}\n aria-live={ariaLive}\n aria-atomic=\"true\"\n tabIndex={0}\n data-testid={dataTestId}\n {...props}\n >\n <BannerBody\n displayIcon={displayIcon}\n title={title}\n description={description}\n dataTestId={dataTestId}\n >\n {children}\n </BannerBody>\n\n <BannerTrailing\n actions={actions}\n variant={variant}\n dismissible={dismissible}\n onDismissClick={handleDismiss}\n dismissLabel={dismissLabel}\n dataTestId={dataTestId}\n />\n </StyledBanner>\n );\n },\n);\n\nBanner.displayName = 'Banner';"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/Alert/Alert.metrics.ts"],"sourcesContent":["import type { AlertVariant } from './Alert.base';\nimport { alpha, darken, lighten } from '../../../tokens/color';\nimport { contrastText, type UiGreyStep, type UiTheme } from '../../../tokens/theme';\n\n/**\n * THE NUMBERS BOTH `Alert` RENDERERS DRAW WITH.\n *\n * `Alert.styles.tsx` / `Alert.tsx` (MUI) and `Alert.native.tsx` (React\n * Native) read this one table. Spacing is in SPACING UNITS where the web\n * writes `theme.spacing(n)`; durations are ms (the web turns them into `s`\n * through {@link seconds} so its emitted CSS is byte-for-byte what it was);\n * everything else is px, a ratio or an alpha. The hover, active and focus\n * numbers are here too although only the DOM can honour them — a number the\n * web draws with belongs in the table whether or not native can reach it.\n */\n\n/** The root: 12px corners, 14px 16px of padding, one 300ms curve for everything. */\nexport const ALERT_RADIUS_UNITS = 1.5;\nexport const ALERT_PADDING_UNITS = { vertical: 1.75, horizontal: 2 } as const;\nexport const ALERT_TRANSITION_MS = 300;\nexport const ALERT_EASING = 'cubic-bezier(0.4, 0, 0.2, 1)';\n\n/** Mount: the web's `fadeInScale` keyframes and the icon's `iconRotate`. */\nexport const FADE_IN = { ms: 300, scale: 0.95, lift: 10 } as const;\nexport const ICON_SPIN = { ms: 600, from: 0.8, mid: 1.1 } as const;\n/** Dismiss: MUI `Collapse` runs 300ms; `onClose` fires 200ms in. */\nexport const COLLAPSE_MS = 300;\nexport const CLOSE_DELAY_MS = 200;\n\n/** The message column: 8px between title, description and children; 0.95rem body on 1.5. */\nexport const MESSAGE_GAP_UNITS = 1;\nexport const MESSAGE_FONT_SIZE = 15.2;\nexport const MESSAGE_LINE_HEIGHT = 1.5;\n/** A control inside the message gets an edge: 4px above, a hairline at 0.45 of the hue. */\nexport const MESSAGE_BUTTON = { marginTopUnits: 0.5, borderAlpha: 0.45 } as const;\n\n/** The title: 1.05rem at 600; MUI's `AlertTitle` lifts it 2px; 4px below it when a description follows. */\nexport const TITLE = { fontSize: 16.8, fontWeight: 600, marginTop: -2, marginBottomUnits: 0.5 } as const;\n/** The description: 0.925rem, slightly faded. */\nexport const DESCRIPTION = { fontSize: 14.8, opacity: 0.9 } as const;\n\n/** The icon slot: MUI's 22px glyph at 0.9, 14px from the words, 2px down (MUI's 7px stays below). */\nexport const ICON_SLOT = { size: 22, opacity: 0.9, marginRightUnits: 1.75, paddingTopUnits: 0.25, paddingBottom: 7 } as const;\n/** The action slot: MUI's `4px 0 0 16px` with the 16px ours, pushed right, 8px into the padding. */\nexport const ACTION_SLOT = { paddingLeftUnits: 2, paddingTop: 4, marginRight: -8 } as const;\n/** The close button: MUI's small `IconButton` (5px padding, 18px glyph) at 0.7. */\nexport const CLOSE_BUTTON = { padding: 5, iconSize: 18, opacity: 0.7, hoverRotateDeg: 90, hoverScale: 1.1, washAlpha: 0.1 } as const;\n\n/**\n * A semantic Alert's surface and ink: an OPAQUE tint of the hue with a dark\n * ink of the same hue — MUI's own `standard` recipe, at its ratios. See\n * `semanticSurface` in `Alert.styles.tsx` for why not `alpha(main, 0.1)`.\n */\nexport const SEMANTIC_SURFACE = { tint: { light: 0.9, dark: 0.8 }, ink: 0.6, borderAlpha: 0.35 } as const;\n/** `glass`: 85% paper under a 20px blur, a 0.4 divider hairline. */\nexport const GLASS = { backgroundAlpha: 0.85, borderAlpha: 0.4, blur: 20, saturatePercent: 180 } as const;\n/** `gradient`: light→dark at 0.9 along 135°, a 0.2 white shimmer sweeping 1000px every 3s. */\nexport const GRADIENT = {\n angleDeg: 135,\n stopAlpha: 0.9,\n shimmerAlpha: 0.2,\n shimmerMs: 3000,\n shimmerTravel: 1000,\n hoverBrightness: 1.1,\n hoverLift: 2,\n hoverScale: 1.01,\n} as const;\n\n/** Emphasis: the glow's shadow and brightness, the pulse's wash. */\nexport const GLOW = { blur: 20, spread: 5, alpha: 0.3, brightness: 1.05 } as const;\nexport const PULSE = { alpha: 0.2, ms: 2000, spread: 10 } as const;\n\n/** Pointer states — DOM only, kept so the web derives them. */\nexport const HOVER = { lift: 3, scale: 1.01, shadowY: 8, shadowBlur: 20, shadowAlpha: 0.2, iconScale: 1.15, iconRotateDeg: 10 } as const;\nexport const ACTIVE = { lift: 1, scale: 0.99, ms: 100 } as const;\nexport const FOCUS = { ringWidth: 3, ringAlpha: 0.5, offset: 3, haloSpread: 6, haloAlpha: 0.1, ms: 200 } as const;\n\n/** `neutral` has no palette slot; the web has always drawn it from three greys. */\nexport const NEUTRAL_GREY: Record<'main' | 'light' | 'dark', UiGreyStep> = { main: 500, light: 300, dark: 700 };\n\n/** A duration as the CSS the web has always emitted: `2000` → `2s`, `300` → `0.3s`. */\nexport const seconds = (ms: number): string => `${ms / 1000}s`;\n\n/** The palette shape the web's `getColorFromTheme` returns — a main plus optional shades. */\nexport interface AlertPalette {\n main: string;\n light?: string;\n dark?: string;\n}\n\n/**\n * The renderer-free twin of the web's `getColorFromTheme`: a variant or\n * colour name to its palette, `neutral` from the greys, anything unknown\n * (`glass`, `gradient`) to `info`.\n */\nexport function alertPalette(theme: UiTheme, key: string | undefined): AlertPalette {\n switch (key) {\n case 'info':\n case 'success':\n case 'warning':\n case 'danger':\n case 'primary':\n case 'secondary':\n return theme.palette[key];\n case 'neutral':\n return {\n main: theme.palette.grey[NEUTRAL_GREY.main],\n light: theme.palette.grey[NEUTRAL_GREY.light],\n dark: theme.palette.grey[NEUTRAL_GREY.dark],\n };\n default:\n return theme.palette.info;\n }\n}\n\n/** What a variant paints: its fill, its ink, its hairline if any, and the colour of its glyph. */\nexport interface AlertSurface {\n backgroundColor: string;\n color: string;\n borderColor?: string;\n iconColor: string;\n}\n\nexport const SEMANTIC_VARIANTS: ReadonlySet<AlertVariant> = new Set(['info', 'success', 'warning', 'danger']);\n\n/** The opaque tint and same-hue ink, inverted for dark mode; the hairline keeps its alpha. */\nexport function semanticSurface(theme: UiTheme, palette: AlertPalette): AlertSurface {\n const dark = theme.mode === 'dark';\n return {\n backgroundColor: dark\n ? darken(palette.main, SEMANTIC_SURFACE.tint.dark)\n : lighten(palette.main, SEMANTIC_SURFACE.tint.light),\n color: dark ? lighten(palette.main, SEMANTIC_SURFACE.ink) : darken(palette.main, SEMANTIC_SURFACE.ink),\n borderColor: alpha(palette.main, SEMANTIC_SURFACE.borderAlpha),\n iconColor: palette.main,\n };\n}\n\nexport function glassSurface(theme: UiTheme): AlertSurface {\n return {\n backgroundColor: alpha(theme.palette.background.paper, GLASS.backgroundAlpha),\n color: theme.palette.text.primary,\n borderColor: alpha(theme.palette.divider, GLASS.borderAlpha),\n iconColor: theme.palette.primary.main,\n };\n}\n\n/** The gradient's two stops; a renderer with no gradient fill paints `from`. */\nexport function gradientStops(palette: AlertPalette): { from: string; to: string } {\n return {\n from: alpha(palette.light || palette.main, GRADIENT.stopAlpha),\n to: alpha(palette.dark || palette.main, GRADIENT.stopAlpha),\n };\n}\n\nexport function gradientSurface(palette: AlertPalette): AlertSurface {\n const ink = contrastText(palette.main);\n return { backgroundColor: gradientStops(palette).from, color: ink, iconColor: ink };\n}\n\n/** The surface for a variant, `glass` and `gradient` included. */\nexport function alertSurface(theme: UiTheme, variant: AlertVariant, palette: AlertPalette): AlertSurface {\n if (variant === 'glass') return glassSurface(theme);\n if (variant === 'gradient') return gradientSurface(palette);\n return semanticSurface(theme, palette);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/Alert/Alert.tsx"],"sourcesContent":["import Close from '@mui/icons-material/Close';\nimport MuiAlert from '@mui/material/Alert/index.js';\nimport AlertTitle from '@mui/material/AlertTitle/index.js';\nimport Box from '@mui/material/Box/index.js';\nimport Collapse from '@mui/material/Collapse/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport { alpha, styled } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { defaultAriaLive, resolveAlertProps, testIdFor } from './Alert.helpers';\nimport {\n ACTIVE,\n ALERT_EASING,\n ALERT_RADIUS_UNITS,\n ALERT_TRANSITION_MS,\n CLOSE_BUTTON,\n CLOSE_DELAY_MS,\n COLLAPSE_MS,\n DESCRIPTION,\n FADE_IN,\n FOCUS,\n HOVER,\n seconds,\n TITLE,\n} from './Alert.metrics';\nimport {\n alertEmphasisStyles,\n alertLayoutStyles,\n alertVariantStyles,\n fadeInScale,\n getColorFromTheme,\n getVariantIcon,\n} from './Alert.styles';\nimport type { AlertColor } from '@mui/material/Alert/index.js';\nimport type { AlertProps } from './Alert.types';\nimport { resolveTestId, withoutTestIdProps } from '../../../platform/test-id';\nimport { px } from '../../../tokens/theme';\n\nconst transition = `all ${seconds(ALERT_TRANSITION_MS)} ${ALERT_EASING}`;\n\n// Define animations\nconst StyledAlert = styled(MuiAlert, {\n shouldForwardProp: (prop) =>\n !['customVariant', 'customColor', 'glow', 'pulse', 'animate'].includes(prop as string),\n})<{\n customVariant?: string;\n customColor?: string;\n glow?: boolean;\n pulse?: boolean;\n animate?: boolean;\n}>(({ theme, customVariant, customColor, glow, pulse, animate }) => {\n const colorPalette = getColorFromTheme(theme, customColor || customVariant || 'info');\n\n return {\n borderRadius: theme.spacing(ALERT_RADIUS_UNITS),\n transition,\n position: 'relative',\n overflow: 'hidden',\n animation: animate ? `${fadeInScale} ${seconds(FADE_IN.ms)} ease-out` : 'none',\n willChange: 'transform, opacity',\n\n ...alertLayoutStyles(theme, colorPalette, animate),\n\n // Hover effects\n '&:hover': {\n transform: `translateY(-${HOVER.lift}px) scale(${HOVER.scale})`,\n boxShadow: `0 ${HOVER.shadowY}px ${HOVER.shadowBlur}px ${alpha(colorPalette.main, HOVER.shadowAlpha)}`,\n transition,\n\n '.MuiAlert-icon': {\n transform: `scale(${HOVER.iconScale}) rotate(${HOVER.iconRotateDeg}deg)`,\n },\n\n '&::before': {\n opacity: 1,\n },\n },\n\n // Active state\n '&:active': {\n transform: `translateY(-${ACTIVE.lift}px) scale(${ACTIVE.scale})`,\n transition: `transform ${seconds(ACTIVE.ms)} ease`,\n },\n\n // Focus styles for accessibility\n '&:focus-within': {\n outline: `${FOCUS.ringWidth}px solid ${alpha(colorPalette.main, FOCUS.ringAlpha)}`,\n outlineOffset: `${FOCUS.offset}px`,\n boxShadow: `0 0 0 ${FOCUS.haloSpread}px ${alpha(colorPalette.main, FOCUS.haloAlpha)}`,\n transition: `all ${seconds(FOCUS.ms)} ease`,\n },\n\n ...alertVariantStyles(theme, customVariant, colorPalette),\n ...alertEmphasisStyles(colorPalette, Boolean(glow), Boolean(pulse)),\n };\n});\n\n// glass and gradient are our own looks with no MUI severity of their own; both\n// borrow info's. danger is MUI's error.\nconst MUI_SEVERITY: Record<string, AlertColor> = {\n danger: 'error',\n glass: 'info',\n gradient: 'info',\n};\n\nconst toMuiSeverity = (variant: string): AlertColor =>\n MUI_SEVERITY[variant] ?? (variant as AlertColor);\n\nconst AlertContent: React.FC<{\n title?: AlertProps['title'];\n description?: AlertProps['description'];\n dataTestId?: string;\n children?: React.ReactNode;\n}> = ({ title, description, dataTestId, children }) => (\n <>\n {title && (\n <AlertTitle\n data-testid={testIdFor(dataTestId, 'title')}\n sx={{\n fontWeight: TITLE.fontWeight,\n fontSize: px(TITLE.fontSize),\n marginBottom: description ? TITLE.marginBottomUnits : 0,\n wordWrap: 'break-word',\n overflowWrap: 'break-word',\n wordBreak: 'break-word',\n }}\n >\n {title}\n </AlertTitle>\n )}\n {description && (\n <Box\n component=\"div\"\n data-testid={testIdFor(dataTestId, 'message')}\n sx={{\n opacity: DESCRIPTION.opacity,\n fontSize: px(DESCRIPTION.fontSize),\n wordWrap: 'break-word',\n overflowWrap: 'break-word',\n wordBreak: 'break-word',\n }}\n >\n {description}\n </Box>\n )}\n {children}\n </>\n);\n\nconst AlertCloseButton: React.FC<{ dataTestId?: string; label: string; onClose: () => void }> = ({\n dataTestId,\n label,\n onClose,\n}) => (\n <IconButton\n data-testid={testIdFor(dataTestId, 'close')}\n aria-label={label}\n color=\"inherit\"\n size=\"small\"\n onClick={onClose}\n sx={(theme) => ({\n transition,\n opacity: CLOSE_BUTTON.opacity,\n '&:hover': {\n transform: `rotate(${CLOSE_BUTTON.hoverRotateDeg}deg) scale(${CLOSE_BUTTON.hoverScale})`,\n opacity: 1,\n backgroundColor: alpha(theme.palette.action.hover, CLOSE_BUTTON.washAlpha),\n },\n '&:focus': {\n opacity: 1,\n outline: 'none',\n backgroundColor: alpha(theme.palette.action.focus, CLOSE_BUTTON.washAlpha),\n },\n })}\n >\n <Close fontSize=\"inherit\" />\n </IconButton>\n);\n\n/**\n * The dismiss button, or nothing.\n *\n * Reads `closeLabel` straight off the props rather than through the\n * `definedProps` merge, which would widen it to `string | undefined` and hand\n * the button an empty name. The UNION in `AlertProps` guarantees the label\n * wherever `closable` is true — that narrowing is gone inside the component,\n * which is why the fallback below exists and why it is unreachable.\n */\nfunction dismissButton(\n props: AlertProps,\n dataTestId: string | undefined,\n onClose: () => void,\n): React.JSX.Element | null {\n if (!props.closable) return null;\n return <AlertCloseButton dataTestId={dataTestId} label={props.closeLabel} onClose={onClose} />;\n}\n\nexport const Alert = React.forwardRef<HTMLDivElement, AlertProps>((alertProps, ref) => {\n const {\n variant,\n color,\n glow,\n pulse,\n icon,\n showIcon,\n onClose,\n title,\n description,\n children,\n animate,\n role,\n 'aria-atomic': ariaAtomic,\n ...others\n } = resolveAlertProps(alertProps);\n\n // Every spelling of the test id the shared contract allows, mapped to the\n // one the DOM reads and defaulted to `alert`; the native Alert does the same.\n const dataTestId = resolveTestId(others, 'alert');\n const props = withoutTestIdProps(others);\n\n // Depends on `variant`, so it cannot live in the static defaults above.\n const ariaLive = alertProps['aria-live'] ?? defaultAriaLive(variant);\n const [open, setOpen] = React.useState(true);\n const [isClosing, setIsClosing] = React.useState(false);\n\n const handleClose = () => {\n setIsClosing(true);\n window.setTimeout(() => {\n setOpen(false);\n onClose?.();\n }, CLOSE_DELAY_MS);\n };\n\n const severity = toMuiSeverity(variant);\n\n const displayIcon = showIcon ? (\n <Box component=\"span\" data-testid={testIdFor(dataTestId, 'icon')}>\n {icon || getVariantIcon(variant)}\n </Box>\n ) : (\n false\n );\n\n const content = (\n <AlertContent title={title} description={description} dataTestId={dataTestId}>\n {children}\n </AlertContent>\n );\n\n return (\n <Collapse in={open && !isClosing} timeout={COLLAPSE_MS}>\n <StyledAlert\n ref={ref}\n data-testid={dataTestId}\n severity={severity}\n customVariant={variant}\n customColor={color}\n glow={glow}\n pulse={pulse}\n animate={animate}\n icon={displayIcon}\n role={role}\n aria-live={ariaLive}\n aria-atomic={ariaAtomic}\n tabIndex={0}\n action={dismissButton(alertProps, dataTestId, handleClose)}\n {...props}\n >\n {content}\n </StyledAlert>\n </Collapse>\n );\n});\n\nAlert.displayName = 'Alert';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,WAAW;AAClB,OAAO,cAAc;AACrB,OAAO,gBAAgB;AACvB,OAAO,SAAS;AAChB,OAAO,cAAc;AACrB,OAAO,gBAAgB;AACvB,SAAS,OAAO,cAAc;AAC9B,OAAO,WAAW;AA2GhB,mBAEI,KAFJ;AA5EF,IAAM,aAAa,OAAO,QAAQ,mBAAmB,CAAC,IAAI,YAAY;AAGtE,IAAM,cAAc,OAAO,UAAU;AAAA,EACnC,mBAAmB,CAAC,SAClB,CAAC,CAAC,iBAAiB,eAAe,QAAQ,SAAS,SAAS,EAAE,SAAS,IAAc;AACzF,CAAC,EAME,CAAC,EAAE,OAAO,eAAe,aAAa,MAAM,OAAO,QAAQ,MAAM;AAClE,QAAM,eAAe,kBAAkB,OAAO,eAAe,iBAAiB,MAAM;AAEpF,SAAO;AAAA,IACL,cAAc,MAAM,QAAQ,kBAAkB;AAAA,IAC9C;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW,UAAU,GAAG,WAAW,IAAI,QAAQ,QAAQ,EAAE,CAAC,cAAc;AAAA,IACxE,YAAY;AAAA,IAEZ,GAAG,kBAAkB,OAAO,cAAc,OAAO;AAAA;AAAA,IAGjD,WAAW;AAAA,MACT,WAAW,eAAe,MAAM,IAAI,aAAa,MAAM,KAAK;AAAA,MAC5D,WAAW,KAAK,MAAM,OAAO,MAAM,MAAM,UAAU,MAAM,MAAM,aAAa,MAAM,MAAM,WAAW,CAAC;AAAA,MACpG;AAAA,MAEA,kBAAkB;AAAA,QAChB,WAAW,SAAS,MAAM,SAAS,YAAY,MAAM,aAAa;AAAA,MACpE;AAAA,MAEA,aAAa;AAAA,QACX,SAAS;AAAA,MACX;AAAA,IACF;AAAA;AAAA,IAGA,YAAY;AAAA,MACV,WAAW,eAAe,OAAO,IAAI,aAAa,OAAO,KAAK;AAAA,MAC9D,YAAY,aAAa,QAAQ,OAAO,EAAE,CAAC;AAAA,IAC7C;AAAA;AAAA,IAGA,kBAAkB;AAAA,MAChB,SAAS,GAAG,MAAM,SAAS,YAAY,MAAM,aAAa,MAAM,MAAM,SAAS,CAAC;AAAA,MAChF,eAAe,GAAG,MAAM,MAAM;AAAA,MAC9B,WAAW,SAAS,MAAM,UAAU,MAAM,MAAM,aAAa,MAAM,MAAM,SAAS,CAAC;AAAA,MACnF,YAAY,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,IACtC;AAAA,IAEA,GAAG,mBAAmB,OAAO,eAAe,YAAY;AAAA,IACxD,GAAG,oBAAoB,cAAc,QAAQ,IAAI,GAAG,QAAQ,KAAK,CAAC;AAAA,EACpE;AACF,CAAC;AAID,IAAM,eAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,UAAU;AACZ;AAEA,IAAM,gBAAgB,CAAC,YACrB,aAAa,OAAO,KAAM;AAE5B,IAAM,eAKD,CAAC,EAAE,OAAO,aAAa,YAAY,SAAS,MAC/C,iCACG;AAAA,WACC;AAAA,IAAC;AAAA;AAAA,MACC,eAAa,UAAU,YAAY,OAAO;AAAA,MAC1C,IAAI;AAAA,QACF,YAAY,MAAM;AAAA,QAClB,UAAU,GAAG,MAAM,QAAQ;AAAA,QAC3B,cAAc,cAAc,MAAM,oBAAoB;AAAA,QACtD,UAAU;AAAA,QACV,cAAc;AAAA,QACd,WAAW;AAAA,MACb;AAAA,MAEC;AAAA;AAAA,EACH;AAAA,EAED,eACC;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAa,UAAU,YAAY,SAAS;AAAA,MAC5C,IAAI;AAAA,QACF,SAAS,YAAY;AAAA,QACrB,UAAU,GAAG,YAAY,QAAQ;AAAA,QACjC,UAAU;AAAA,QACV,cAAc;AAAA,QACd,WAAW;AAAA,MACb;AAAA,MAEC;AAAA;AAAA,EACH;AAAA,EAED;AAAA,GACH;AAGF,IAAM,mBAA0F,CAAC;AAAA,EAC/F;AAAA,EACA;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA;AAAA,IACC,eAAa,UAAU,YAAY,OAAO;AAAA,IAC1C,cAAY;AAAA,IACZ,OAAM;AAAA,IACN,MAAK;AAAA,IACL,SAAS;AAAA,IACT,IAAI,CAAC,WAAW;AAAA,MACd;AAAA,MACA,SAAS,aAAa;AAAA,MACtB,WAAW;AAAA,QACT,WAAW,UAAU,aAAa,cAAc,cAAc,aAAa,UAAU;AAAA,QACrF,SAAS;AAAA,QACT,iBAAiB,MAAM,MAAM,QAAQ,OAAO,OAAO,aAAa,SAAS;AAAA,MAC3E;AAAA,MACA,WAAW;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,iBAAiB,MAAM,MAAM,QAAQ,OAAO,OAAO,aAAa,SAAS;AAAA,MAC3E;AAAA,IACF;AAAA,IAEA,8BAAC,SAAM,UAAS,WAAU;AAAA;AAC5B;AAYF,SAAS,cACP,OACA,YACA,SAC0B;AAC1B,MAAI,CAAC,MAAM,SAAU,QAAO;AAC5B,SAAO,oBAAC,oBAAiB,YAAwB,OAAO,MAAM,YAAY,SAAkB;AAC9F;AAEO,IAAM,QAAQ,MAAM,WAAuC,CAAC,YAAY,QAAQ;AACrF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,GAAG;AAAA,EACL,IAAI,kBAAkB,UAAU;AAIhC,QAAM,aAAa,cAAc,QAAQ,OAAO;AAChD,QAAM,QAAQ,mBAAmB,MAAM;AAGvC,QAAM,WAAW,WAAW,WAAW,KAAK,gBAAgB,OAAO;AACnE,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,IAAI;AAC3C,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AAEtD,QAAM,cAAc,MAAM;AACxB,iBAAa,IAAI;AACjB,WAAO,WAAW,MAAM;AACtB,cAAQ,KAAK;AACb,gBAAU;AAAA,IACZ,GAAG,cAAc;AAAA,EACnB;AAEA,QAAM,WAAW,cAAc,OAAO;AAEtC,QAAM,cAAc,WAClB,oBAAC,OAAI,WAAU,QAAO,eAAa,UAAU,YAAY,MAAM,GAC5D,kBAAQ,eAAe,OAAO,GACjC,IAEA;AAGF,QAAM,UACJ,oBAAC,gBAAa,OAAc,aAA0B,YACnD,UACH;AAGF,SACE,oBAAC,YAAS,IAAI,QAAQ,CAAC,WAAW,SAAS,aACzC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,eAAa;AAAA,MACb;AAAA,MACA,eAAe;AAAA,MACf,aAAa;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,aAAW;AAAA,MACX,eAAa;AAAA,MACb,UAAU;AAAA,MACV,QAAQ,cAAc,YAAY,YAAY,WAAW;AAAA,MACxD,GAAG;AAAA,MAEH;AAAA;AAAA,EACH,GACF;AAEJ,CAAC;AAED,MAAM,cAAc;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/navigation/AppHeader/AppHeader.identity.tsx"],"sourcesContent":["'use client';\n\nimport KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';\nimport Box from '@mui/material/Box/index.js';\nimport Skeleton from '@mui/material/Skeleton/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { accentFor, type SizeValue } from '../../../tokens/scales';\n\nimport { AppHeaderBrand } from './AppHeader.brand';\nimport type { AppHeaderIdentityProps, AppHeaderStatusProps } from './AppHeader.types';\n\n/** Title type scale, per house size step. */\nconst TITLE_PX: Record<SizeValue, number> = { xs: 14, sm: 15, md: 17, lg: 20, xl: 24 };\n\n/** One line, ellipsised — a long store name must not push the actions off-screen. */\nconst ONE_LINE = {\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n} as const;\n\n/**\n * The dotted state line: \"● Aberto agora · Retirada no balcão\".\n *\n * Segments are joined here rather than by the caller because the separator is a\n * presentational choice — a caller that pre-joins its own string can never be\n * restyled, and each segment loses the chance to carry its own markup.\n */\nexport const AppHeaderStatus: React.FC<AppHeaderStatusProps> = ({\n tone,\n items,\n separator = '·',\n className,\n dataTestId = 'app-header-status',\n}) => {\n const theme = useTheme();\n const visible = items.filter((item) => item !== null && item !== undefined && item !== '');\n if (visible.length === 0) return null;\n\n return (\n <Box\n className={className}\n data-testid={dataTestId}\n sx={{ display: 'flex', alignItems: 'center', gap: 0.75, ...ONE_LINE }}\n >\n {tone && (\n <Box\n aria-hidden\n data-testid={`${dataTestId}-dot`}\n sx={{\n width: 8,\n height: 8,\n flex: '0 0 auto',\n borderRadius: '50%',\n backgroundColor: accentFor(theme, tone).main,\n }}\n />\n )}\n <Typography variant=\"body2\" color=\"text.secondary\" component=\"span\" sx={ONE_LINE}>\n {visible.map((item, index) => (\n // Index keys: the segments are positional presentation, and nothing\n // here reorders or is keyed on identity elsewhere.\n <React.Fragment key={index}>\n {index > 0 && (\n <>\n {/* Real spaces, not margin. A screen reader reads `textContent`,\n and a CSS-only gap runs \"Aberto agora\" straight into\n \"Retirada no balcão\" as one word. The glyph itself is\n hidden — it is punctuation, not something to announce. */}\n {' '}\n <Box component=\"span\" aria-hidden>\n {separator}\n </Box>{' '}\n </>\n )}\n {item}\n </React.Fragment>\n ))}\n </Typography>\n </Box>\n );\n};\n\nAppHeaderStatus.displayName = 'AppHeaderStatus';\n\n/** Title + chevron + the quieter lines under them. */\nconst IdentityText: React.FC<\n Pick<AppHeaderIdentityProps, 'title' | 'subtitle' | 'status' | 'size'> & {\n interactive: boolean;\n disclosed: boolean;\n dataTestId: string;\n }\n> = ({ title, subtitle, status, size = 'md', interactive, disclosed, dataTestId }) => (\n <Box sx={{ minWidth: 0, display: 'flex', flexDirection: 'column', gap: 0.25 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.25, minWidth: 0 }}>\n <Typography\n component=\"span\"\n data-testid={`${dataTestId}-title`}\n sx={{ fontSize: TITLE_PX[size], fontWeight: 700, lineHeight: 1.2, ...ONE_LINE }}\n >\n {title}\n </Typography>\n {interactive && (\n <KeyboardArrowDown\n aria-hidden\n data-testid={`${dataTestId}-chevron`}\n sx={{\n flex: '0 0 auto',\n fontSize: 20,\n opacity: 0.7,\n transition: 'transform 150ms ease',\n transform: disclosed ? 'rotate(180deg)' : 'none',\n }}\n />\n )}\n </Box>\n {subtitle && (\n <Typography variant=\"body2\" color=\"text.secondary\" component=\"span\" sx={ONE_LINE}>\n {subtitle}\n </Typography>\n )}\n {status}\n </Box>\n);\n\n/** The placeholder held while the identity is still resolving. */\nconst IdentitySkeleton: React.FC<{ size: SizeValue; dataTestId: string }> = ({\n size,\n dataTestId,\n}) => (\n <Box\n data-testid={`${dataTestId}-loading`}\n sx={{ display: 'flex', alignItems: 'center', gap: 1.25, minWidth: 0 }}\n >\n <Skeleton variant=\"rounded\" width={40} height={40} sx={{ flex: '0 0 auto' }} />\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Skeleton variant=\"text\" width={140} height={TITLE_PX[size] * 1.4} />\n <Skeleton variant=\"text\" width={180} height={16} />\n </Box>\n </Box>\n);\n\n/**\n * Row styling shared by the static and the button rendering.\n *\n * `width: '100%'` is load-bearing, not cosmetic. A `<button>` sizes to\n * max-content and — unlike the `div` the non-interactive path renders — does\n * not stretch to fill its block container, so without it the DISCLOSING\n * identity measured its widest possible line at every viewport: the row's\n * right edge stayed pinned at 564px while the bar narrowed, `ONE_LINE` never\n * had a constraint to ellipsise against, and the title and state line ran\n * straight under the actions — 327px of overlap at 320px wide. Filling the\n * wrapper is what lets `minWidth: 0` bite and the ellipsis engage.\n */\nconst rowSx = {\n display: 'flex',\n alignItems: 'center',\n gap: 1.25,\n width: '100%',\n minWidth: 0,\n textAlign: 'left',\n} as const;\n\n/**\n * Mark + title + state line, and — when it can be opened — the whole block as\n * one button.\n *\n * The button wraps EVERYTHING rather than sitting next to the title, because on\n * a phone the chevron alone is a 20px target next to a 40px one that does\n * nothing. A shopper aiming at the store's name expects the store's details.\n */\nexport const AppHeaderIdentity: React.FC<AppHeaderIdentityProps> = ({\n title,\n subtitle,\n status,\n mark,\n logoUrl,\n seedColor,\n onDisclose,\n disclosed = false,\n discloseLabel,\n loading = false,\n size = 'md',\n className,\n dataTestId = 'app-header-identity',\n}) => {\n if (loading) return <IdentitySkeleton size={size} dataTestId={dataTestId} />;\n\n const body = (\n <>\n {mark ?? (\n <AppHeaderBrand\n name={title}\n logoUrl={logoUrl}\n seedColor={seedColor}\n size={size}\n dataTestId={`${dataTestId}-brand`}\n />\n )}\n <IdentityText\n title={title}\n subtitle={subtitle}\n status={status}\n size={size}\n interactive={Boolean(onDisclose)}\n disclosed={disclosed}\n dataTestId={dataTestId}\n />\n </>\n );\n\n if (!onDisclose) {\n return (\n <Box className={className} data-testid={dataTestId} sx={rowSx}>\n {body}\n </Box>\n );\n }\n\n return (\n <Box\n component=\"button\"\n type=\"button\"\n className={className}\n data-testid={dataTestId}\n onClick={onDisclose}\n aria-haspopup=\"dialog\"\n aria-expanded={disclosed}\n aria-label={discloseLabel ?? `Detalhes de ${title}`}\n sx={{\n ...rowSx,\n appearance: 'none',\n p: 0.5,\n ml: -0.5,\n border: 'none',\n borderRadius: 1.5,\n background: 'none',\n color: 'inherit',\n font: 'inherit',\n cursor: 'pointer',\n '&:hover': { backgroundColor: 'action.hover' },\n '&:focus-visible': { outline: '2px solid', outlineColor: 'primary.main', outlineOffset: 2 },\n }}\n >\n {body}\n </Box>\n );\n};\n\nAppHeaderIdentity.displayName = 'AppHeaderIdentity';\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|