@12-apps/ui 6.24.3 → 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.
@@ -88,7 +88,7 @@ import {
88
88
  import {
89
89
  AppHeaderIdentity,
90
90
  AppHeaderStatus
91
- } from "../../chunk-W2YNUUVJ.js";
91
+ } from "../../chunk-TU6RNZUQ.js";
92
92
  import {
93
93
  AppHeaderBrand
94
94
  } from "../../chunk-H37GIAAM.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  AppHeaderIdentity,
4
4
  AppHeaderStatus
5
- } from "../../../../chunk-W2YNUUVJ.js";
5
+ } from "../../../../chunk-TU6RNZUQ.js";
6
6
  import "../../../../chunk-H37GIAAM.js";
7
7
  import "../../../../chunk-IQU4HKND.js";
8
8
  import "../../../../chunk-V5IOLAIS.js";
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  AppHeaderIdentity,
14
14
  AppHeaderStatus
15
- } from "../../../chunk-W2YNUUVJ.js";
15
+ } from "../../../chunk-TU6RNZUQ.js";
16
16
  import {
17
17
  AppHeaderBrand
18
18
  } from "../../../chunk-H37GIAAM.js";
@@ -68,35 +68,95 @@ var AppHeaderStatus = ({
68
68
  );
69
69
  };
70
70
  AppHeaderStatus.displayName = "AppHeaderStatus";
71
- var IdentityText = ({ title, subtitle, status, size = "md", interactive, disclosed, dataTestId }) => /* @__PURE__ */ jsxs(Box, { sx: { minWidth: 0, display: "flex", flexDirection: "column", gap: 0.25 }, children: [
72
- /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.25, minWidth: 0 }, children: [
73
- /* @__PURE__ */ jsx(
74
- Typography,
75
- {
76
- component: "span",
77
- "data-testid": `${dataTestId}-title`,
78
- sx: { fontSize: TITLE_PX[size], fontWeight: 700, lineHeight: 1.2, ...ONE_LINE },
79
- children: title
71
+ var IdentityTitle = ({ title, size = "md", interactive, disclosed, dataTestId }) => /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.25, minWidth: 0, width: "100%" }, children: [
72
+ /* @__PURE__ */ jsx(
73
+ Typography,
74
+ {
75
+ component: "span",
76
+ "data-testid": `${dataTestId}-title`,
77
+ sx: { fontSize: TITLE_PX[size], fontWeight: 700, lineHeight: 1.2, ...ONE_LINE },
78
+ children: title
79
+ }
80
+ ),
81
+ interactive && /* @__PURE__ */ jsx(
82
+ KeyboardArrowDown,
83
+ {
84
+ "aria-hidden": true,
85
+ "data-testid": `${dataTestId}-chevron`,
86
+ sx: {
87
+ flex: "0 0 auto",
88
+ fontSize: 20,
89
+ opacity: 0.7,
90
+ transition: "transform 150ms ease",
91
+ transform: disclosed ? "rotate(180deg)" : "none"
80
92
  }
81
- ),
82
- interactive && /* @__PURE__ */ jsx(
83
- KeyboardArrowDown,
93
+ }
94
+ )
95
+ ] });
96
+ var discloseSx = {
97
+ display: "flex",
98
+ alignItems: "center",
99
+ gap: 0.25,
100
+ width: "100%",
101
+ minWidth: 0,
102
+ appearance: "none",
103
+ px: 0.5,
104
+ mx: -0.5,
105
+ py: 0.25,
106
+ my: -0.25,
107
+ border: "none",
108
+ borderRadius: 1.5,
109
+ background: "none",
110
+ color: "inherit",
111
+ font: "inherit",
112
+ textAlign: "left",
113
+ cursor: "pointer",
114
+ // Guarded: on a touch screen an unguarded `:hover` sticks after the tap that
115
+ // opened the panel, so the row stays highlighted behind it.
116
+ "@media (hover: hover)": { "&:hover": { backgroundColor: "action.hover" } },
117
+ "&:focus-visible": { outline: "2px solid", outlineColor: "primary.main", outlineOffset: 2 }
118
+ };
119
+ var IdentityText = ({
120
+ title,
121
+ subtitle,
122
+ status,
123
+ size = "md",
124
+ onDisclose,
125
+ disclosed,
126
+ discloseLabel,
127
+ className,
128
+ dataTestId
129
+ }) => {
130
+ const name = /* @__PURE__ */ jsx(
131
+ IdentityTitle,
132
+ {
133
+ title,
134
+ size,
135
+ interactive: Boolean(onDisclose),
136
+ disclosed,
137
+ dataTestId
138
+ }
139
+ );
140
+ return /* @__PURE__ */ jsxs(Box, { sx: { minWidth: 0, flex: 1, display: "flex", flexDirection: "column", gap: 0.25 }, children: [
141
+ onDisclose ? /* @__PURE__ */ jsx(
142
+ Box,
84
143
  {
85
- "aria-hidden": true,
86
- "data-testid": `${dataTestId}-chevron`,
87
- sx: {
88
- flex: "0 0 auto",
89
- fontSize: 20,
90
- opacity: 0.7,
91
- transition: "transform 150ms ease",
92
- transform: disclosed ? "rotate(180deg)" : "none"
93
- }
144
+ component: "button",
145
+ type: "button",
146
+ className,
147
+ "data-testid": dataTestId,
148
+ onClick: onDisclose,
149
+ "aria-haspopup": "dialog",
150
+ "aria-expanded": disclosed,
151
+ "aria-label": discloseLabel ?? `Detalhes de ${title}`,
152
+ sx: discloseSx,
153
+ children: name
94
154
  }
95
- )
96
- ] }),
97
- subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", component: "span", sx: ONE_LINE, children: subtitle }),
98
- status
99
- ] });
155
+ ) : name,
156
+ subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", component: "span", sx: ONE_LINE, children: subtitle }),
157
+ status
158
+ ] });
159
+ };
100
160
  var IdentitySkeleton = ({
101
161
  size,
102
162
  dataTestId
@@ -138,59 +198,38 @@ var AppHeaderIdentity = ({
138
198
  dataTestId = "app-header-identity"
139
199
  }) => {
140
200
  if (loading) return /* @__PURE__ */ jsx(IdentitySkeleton, { size, dataTestId });
141
- const body = /* @__PURE__ */ jsxs(Fragment, { children: [
142
- mark ?? /* @__PURE__ */ jsx(
143
- AppHeaderBrand,
144
- {
145
- name: title,
146
- logoUrl,
147
- seedColor,
148
- size,
149
- dataTestId: `${dataTestId}-brand`
150
- }
151
- ),
152
- /* @__PURE__ */ jsx(
153
- IdentityText,
154
- {
155
- title,
156
- subtitle,
157
- status,
158
- size,
159
- interactive: Boolean(onDisclose),
160
- disclosed,
161
- dataTestId
162
- }
163
- )
164
- ] });
165
- if (!onDisclose) {
166
- return /* @__PURE__ */ jsx(Box, { className, "data-testid": dataTestId, sx: rowSx, children: body });
167
- }
168
- return /* @__PURE__ */ jsx(
201
+ return /* @__PURE__ */ jsxs(
169
202
  Box,
170
203
  {
171
- component: "button",
172
- type: "button",
173
- className,
174
- "data-testid": dataTestId,
175
- onClick: onDisclose,
176
- "aria-haspopup": "dialog",
177
- "aria-expanded": disclosed,
178
- "aria-label": discloseLabel ?? `Detalhes de ${title}`,
179
- sx: {
180
- ...rowSx,
181
- appearance: "none",
182
- p: 0.5,
183
- ml: -0.5,
184
- border: "none",
185
- borderRadius: 1.5,
186
- background: "none",
187
- color: "inherit",
188
- font: "inherit",
189
- cursor: "pointer",
190
- "&:hover": { backgroundColor: "action.hover" },
191
- "&:focus-visible": { outline: "2px solid", outlineColor: "primary.main", outlineOffset: 2 }
192
- },
193
- children: body
204
+ className: onDisclose ? void 0 : className,
205
+ "data-testid": onDisclose ? void 0 : dataTestId,
206
+ sx: rowSx,
207
+ children: [
208
+ mark ?? /* @__PURE__ */ jsx(
209
+ AppHeaderBrand,
210
+ {
211
+ name: title,
212
+ logoUrl,
213
+ seedColor,
214
+ size,
215
+ dataTestId: `${dataTestId}-brand`
216
+ }
217
+ ),
218
+ /* @__PURE__ */ jsx(
219
+ IdentityText,
220
+ {
221
+ title,
222
+ subtitle,
223
+ status,
224
+ size,
225
+ onDisclose,
226
+ disclosed,
227
+ discloseLabel,
228
+ className,
229
+ dataTestId
230
+ }
231
+ )
232
+ ]
194
233
  }
195
234
  );
196
235
  };
@@ -200,4 +239,4 @@ export {
200
239
  AppHeaderStatus,
201
240
  AppHeaderIdentity
202
241
  };
203
- //# sourceMappingURL=chunk-W2YNUUVJ.js.map
242
+ //# sourceMappingURL=chunk-TU6RNZUQ.js.map
@@ -0,0 +1 @@
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/** The name and, when the block opens onto something, the chevron beside it. */\nconst IdentityTitle: React.FC<\n Pick<AppHeaderIdentityProps, 'title' | 'size'> & {\n interactive: boolean;\n disclosed: boolean;\n dataTestId: string;\n }\n> = ({ title, size = 'md', interactive, disclosed, dataTestId }) => (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.25, minWidth: 0, width: '100%' }}>\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);\n\n/**\n * The disclosure, wrapping the NAME ROW and nothing else (12-63).\n *\n * The padding is cancelled by an equal negative margin, so the hover and the\n * focus ring bleed outward while the title still starts on the same pixel as\n * the lines under it. A padded button with no offset moves one of the two.\n */\nconst discloseSx = {\n display: 'flex',\n alignItems: 'center',\n gap: 0.25,\n width: '100%',\n minWidth: 0,\n appearance: 'none',\n px: 0.5,\n mx: -0.5,\n py: 0.25,\n my: -0.25,\n border: 'none',\n borderRadius: 1.5,\n background: 'none',\n color: 'inherit',\n font: 'inherit',\n textAlign: 'left',\n cursor: 'pointer',\n // Guarded: on a touch screen an unguarded `:hover` sticks after the tap that\n // opened the panel, so the row stays highlighted behind it.\n '@media (hover: hover)': { '&:hover': { backgroundColor: 'action.hover' } },\n '&:focus-visible': { outline: '2px solid', outlineColor: 'primary.main', outlineOffset: 2 },\n} as const;\n\n/**\n * The text column: the name row, then the quieter lines under it.\n *\n * ## `subtitle` and `status` are OUTSIDE the disclosure, on purpose (12-63)\n *\n * Both are `ReactNode`, and `AppHeaderStatus.items` is a `ReactNode[]` — so a\n * segment of the state line is free to be a control, and consumers put controls\n * there: a mesa chip, a service-mode picker. While the whole block was one\n * `<button>` those were `<button>`s inside a `<button>`, which is invalid HTML\n * (the content model of `button` excludes interactive content) and, more\n * visibly, means one tap fires two handlers. An adopting storefront opened two\n * popups on every tap of either control because of it, and had already\n * hand-rolled this component at one tier to dodge the nesting — a consumer\n * working around the component is the report.\n *\n * The target stays large. The button is the full-width NAME ROW, which is the\n * thing a reader aims at — what it gives up is the mark beside it, and a mark\n * that opens the panel is not worth a state line that cannot hold a control.\n */\nconst IdentityText: React.FC<\n Pick<\n AppHeaderIdentityProps,\n 'title' | 'subtitle' | 'status' | 'size' | 'discloseLabel' | 'className'\n > & {\n onDisclose: (() => void) | undefined;\n disclosed: boolean;\n dataTestId: string;\n }\n> = ({\n title,\n subtitle,\n status,\n size = 'md',\n onDisclose,\n disclosed,\n discloseLabel,\n className,\n dataTestId,\n}) => {\n const name = (\n <IdentityTitle\n title={title}\n size={size}\n interactive={Boolean(onDisclose)}\n disclosed={disclosed}\n dataTestId={dataTestId}\n />\n );\n return (\n <Box sx={{ minWidth: 0, flex: 1, display: 'flex', flexDirection: 'column', gap: 0.25 }}>\n {onDisclose ? (\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={discloseSx}\n >\n {name}\n </Box>\n ) : (\n name\n )}\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\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 * The BLOCK's row: the mark, then the text column beside it.\n *\n * Always a `Box` div now — since 12-63 the disclosure is the name row inside\n * the text column ({@link discloseSx}), not this element. `width: '100%'` and\n * `minWidth: 0` stay because the column below still has to ellipsise against\n * something; the argument about a `<button>` sizing to max-content moved to\n * `discloseSx`, which is where the button now is.\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 — a name row that is\n * the button.\n *\n * The disclosure used to wrap EVERYTHING, on the argument that the chevron\n * alone is a 20px target next to a 40px mark that does nothing. The target is\n * still not the chevron: the button is the full-width NAME ROW, which is what a\n * reader aims at. What it no longer swallows is the mark beside it and the\n * quieter lines below — because those lines take `ReactNode`s, consumers put\n * CONTROLS in them, and a control inside a button is invalid HTML whose every\n * tap fires two handlers. See {@link IdentityText} (12-63).\n *\n * `className` and `dataTestId` stay on the same elements they always named: the\n * block when it is static, the disclosure when there is one.\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 return (\n <Box\n className={onDisclose ? undefined : className}\n data-testid={onDisclose ? undefined : dataTestId}\n sx={rowSx}\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 onDisclose={onDisclose}\n disclosed={disclosed}\n discloseLabel={discloseLabel}\n className={className}\n dataTestId={dataTestId}\n />\n </Box>\n );\n};\n\nAppHeaderIdentity.displayName = 'AppHeaderIdentity';\n"],"mappings":"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","names":[]}
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  AppHeaderIdentity,
8
8
  AppHeaderStatus
9
- } from "../chunk-W2YNUUVJ.js";
9
+ } from "../chunk-TU6RNZUQ.js";
10
10
  import {
11
11
  AppHeaderBrand
12
12
  } from "../chunk-H37GIAAM.js";
@@ -9,12 +9,19 @@ import type { AppHeaderIdentityProps, AppHeaderStatusProps } from './AppHeader.t
9
9
  */
10
10
  export declare const AppHeaderStatus: React.FC<AppHeaderStatusProps>;
11
11
  /**
12
- * Mark + title + state line, and — when it can be opened — the whole block as
13
- * one button.
12
+ * Mark + title + state line, and — when it can be opened — a name row that is
13
+ * the button.
14
14
  *
15
- * The button wraps EVERYTHING rather than sitting next to the title, because on
16
- * a phone the chevron alone is a 20px target next to a 40px one that does
17
- * nothing. A shopper aiming at the store's name expects the store's details.
15
+ * The disclosure used to wrap EVERYTHING, on the argument that the chevron
16
+ * alone is a 20px target next to a 40px mark that does nothing. The target is
17
+ * still not the chevron: the button is the full-width NAME ROW, which is what a
18
+ * reader aims at. What it no longer swallows is the mark beside it and the
19
+ * quieter lines below — because those lines take `ReactNode`s, consumers put
20
+ * CONTROLS in them, and a control inside a button is invalid HTML whose every
21
+ * tap fires two handlers. See {@link IdentityText} (12-63).
22
+ *
23
+ * `className` and `dataTestId` stay on the same elements they always named: the
24
+ * block when it is static, the disclosure when there is one.
18
25
  */
19
26
  export declare const AppHeaderIdentity: React.FC<AppHeaderIdentityProps>;
20
27
  //# sourceMappingURL=AppHeader.identity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppHeader.identity.d.ts","sourceRoot":"","sources":["../../../../../src/components/navigation/AppHeader/AppHeader.identity.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAatF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAqD1D,CAAC;AAkFF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA4E9D,CAAC"}
1
+ {"version":3,"file":"AppHeader.identity.d.ts","sourceRoot":"","sources":["../../../../../src/components/navigation/AppHeader/AppHeader.identity.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAatF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAqD1D,CAAC;AAmLF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA6C9D,CAAC"}
@@ -56,19 +56,27 @@ export interface AppHeaderStatusProps {
56
56
  * the consumer's own router in the `leading` slot, whereas an `href` prop would
57
57
  * have to guess whose link component it is being handed — `to` for one router,
58
58
  * `href` for another — and would half-work for everybody. `onDisclose` is the
59
- * only interaction the block owns: with it the block is a button and a chevron
60
- * appears, without it the block is static text.
59
+ * only interaction the block owns: with it the NAME ROW is a button and a
60
+ * chevron appears, without it the row is static text.
61
+ *
62
+ * The button stops at that row (12-63). `status` and `subtitle` render as its
63
+ * SIBLINGS, so a consumer may put controls in the state line — which they do,
64
+ * and which used to nest a `<button>` inside a `<button>`.
61
65
  */
62
66
  export interface AppHeaderIdentityProps extends Pick<AppHeaderBrandProps, 'logoUrl' | 'seedColor'> {
63
67
  /** The name shown, and the one the mark derives its initials from. */
64
68
  title: string;
65
- /** A quieter line under the title — use `status` for the dotted state line. */
69
+ /**
70
+ * A quieter line under the title — use `status` for the dotted state line.
71
+ *
72
+ * Rendered OUTSIDE the disclosure, like `status`, so it may hold a control.
73
+ */
66
74
  subtitle?: ReactNode;
67
75
  /** The state line, usually an {@link AppHeaderStatusProps} element. */
68
76
  status?: ReactNode;
69
77
  /** Replaces the derived mark entirely (an icon, an `<img>`, nothing). */
70
78
  mark?: ReactNode;
71
- /** Opens the details panel. Renders the block as a button with a chevron. */
79
+ /** Opens the details panel. Renders the NAME ROW as a button with a chevron. */
72
80
  onDisclose?: () => void;
73
81
  /** Whether the panel `onDisclose` opens is currently open (`aria-expanded`). */
74
82
  disclosed?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"AppHeader.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/navigation/AppHeader/AppHeader.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AppHeader.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/navigation/AppHeader/AppHeader.types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/ui",
3
- "version": "6.24.3",
3
+ "version": "6.24.4",
4
4
  "license": "MIT",
5
5
  "packageManager": "pnpm@10.34.5",
6
6
  "type": "module",
@@ -87,46 +87,146 @@ export const AppHeaderStatus: React.FC<AppHeaderStatusProps> = ({
87
87
 
88
88
  AppHeaderStatus.displayName = 'AppHeaderStatus';
89
89
 
90
- /** Title + chevron + the quieter lines under them. */
91
- const IdentityText: React.FC<
92
- Pick<AppHeaderIdentityProps, 'title' | 'subtitle' | 'status' | 'size'> & {
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, subtitle, status, size = 'md', interactive, disclosed, dataTestId }) => (
98
- <Box sx={{ minWidth: 0, display: 'flex', flexDirection: 'column', gap: 0.25 }}>
99
- <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.25, minWidth: 0 }}>
100
- <Typography
101
- component="span"
102
- data-testid={`${dataTestId}-title`}
103
- sx={{ fontSize: TITLE_PX[size], fontWeight: 700, lineHeight: 1.2, ...ONE_LINE }}
104
- >
105
- {title}
106
- </Typography>
107
- {interactive && (
108
- <KeyboardArrowDown
109
- aria-hidden
110
- data-testid={`${dataTestId}-chevron`}
111
- sx={{
112
- flex: '0 0 auto',
113
- fontSize: 20,
114
- opacity: 0.7,
115
- transition: 'transform 150ms ease',
116
- transform: disclosed ? 'rotate(180deg)' : 'none',
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
- * Row styling shared by the static and the button rendering.
248
+ * The BLOCK's row: the mark, then the text column beside it.
149
249
  *
150
- * `width: '100%'` is load-bearing, not cosmetic. A `<button>` sizes to
151
- * max-content and — unlike the `div` the non-interactive path renders — does
152
- * not stretch to fill its block container, so without it the DISCLOSING
153
- * identity measured its widest possible line at every viewport: the row's
154
- * right edge stayed pinned at 564px while the bar narrowed, `ONE_LINE` never
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 — the whole block as
170
- * one button.
266
+ * Mark + title + state line, and — when it can be opened — a name row that is
267
+ * the button.
171
268
  *
172
- * The button wraps EVERYTHING rather than sitting next to the title, because on
173
- * a phone the chevron alone is a 20px target next to a 40px one that does
174
- * nothing. A shopper aiming at the store's name expects the store's details.
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
- const body = (
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
- interactive={Boolean(onDisclose)}
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 whole identity block is one `<button>` with
122
- `aria-haspopup="dialog"` and a live `aria-expanded`. The button wraps
123
- everything rather than sitting beside the title: on a phone the chevron alone
124
- is a 20px target next to a 40px one that does nothing, and a shopper aiming at
125
- the store's name expects the store's details.
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 block is a button and a chevron
66
- * appears, without it the block is static text.
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
- /** A quieter line under the title — use `status` for the dotted state line. */
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 block as a button with a chevron. */
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/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":[]}