@12-apps/ui 5.5.0 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -167,12 +167,24 @@ function backdropSxOf(theme, glass) {
167
167
 
168
168
  // src/components/feedback/Dialog/Dialog.tsx
169
169
  import { jsx, jsxs } from "react/jsx-runtime";
170
+ function hasSpacingSlot(children) {
171
+ return React.Children.toArray(children).some((child) => {
172
+ if (!React.isValidElement(child)) return false;
173
+ if (child.type === DialogContent || child.type === DialogActions) return true;
174
+ if (child.type !== React.Fragment) return false;
175
+ return hasSpacingSlot(child.props.children);
176
+ });
177
+ }
178
+ var BODY_SX = {
179
+ px: 3,
180
+ pb: 2.5,
181
+ "&:has(> .MuiDialogContent-root), &:has(> .MuiDialogActions-root)": {
182
+ display: "contents"
183
+ }
184
+ };
170
185
  function bodyOf(children, hasTitle) {
171
- const managesOwnSpacing = React.Children.toArray(children).some(
172
- (child) => React.isValidElement(child) && (child.type === DialogContent || child.type === DialogActions)
173
- );
174
- if (managesOwnSpacing) return children;
175
- return /* @__PURE__ */ jsx(Box, { sx: { px: 3, pb: 2.5, pt: hasTitle ? 0.5 : 2.5 }, children });
186
+ if (hasSpacingSlot(children)) return children;
187
+ return /* @__PURE__ */ jsx(Box, { sx: { ...BODY_SX, pt: hasTitle ? 0.5 : 2.5 }, children });
176
188
  }
177
189
  var DIALOG_DEFAULTS = {
178
190
  variant: "default",
@@ -387,4 +399,4 @@ export {
387
399
  DialogContent,
388
400
  DialogActions
389
401
  };
390
- //# sourceMappingURL=chunk-U3J55YPN.js.map
402
+ //# sourceMappingURL=chunk-GSEAUMCS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/feedback/Dialog/Dialog.tsx","../src/components/feedback/Dialog/Dialog.styles.ts"],"sourcesContent":["import CloseIcon from '@mui/icons-material/Close';\nimport {\n Backdrop,\n Box,\n Dialog as MuiDialog,\n DialogActions as MuiDialogActions,\n DialogContent as MuiDialogContent,\n DialogTitle as MuiDialogTitle,\n Drawer,\n IconButton,\n Typography,\n useTheme,\n} from '@mui/material';\nimport React from 'react';\n\nimport { backdropSxOf, variantStylesOf } from './Dialog.styles';\nimport type {\n DialogActionsProps,\n DialogContentProps,\n DialogHeaderProps,\n DialogProps,\n} from './Dialog.types';\n\n/**\n * Does this hand us a spacing slot? Fragments are transparent: `<>` is a way of\n * passing several children, not a child that owns them, and a consumer who\n * groups a `DialogContent` and a `DialogActions` in one has still passed both.\n *\n * Only the slots themselves count, and only at the top. A `DialogContent`\n * genuinely nested inside a `<div>` is that div's content, and the dialog\n * padding the div is right.\n */\nfunction hasSpacingSlot(children: React.ReactNode): boolean {\n return React.Children.toArray(children).some((child) => {\n if (!React.isValidElement(child)) return false;\n if (child.type === DialogContent || child.type === DialogActions) return true;\n if (child.type !== React.Fragment) return false;\n return hasSpacingSlot((child.props as { children?: React.ReactNode }).children);\n });\n}\n\n/**\n * The padding a dialog gives children that are not managing their own — and the\n * rule that takes it back when it turns out they are.\n *\n * `:has()` is doing what {@link hasSpacingSlot} cannot. A slot passed through a\n * COMPONENT (`<Body />` rendering a `DialogContent`) is invisible to any check\n * on element type: React does not know what a component renders until it has\n * rendered it, and by then the wrapper is already in the tree. The selector\n * asks the question one step later, of the DOM, where the answer exists.\n *\n * `display: contents` rather than `padding: 0`, because the padding is only\n * half of what a wrapper does. The other half is standing between the paper and\n * its children: MUI's `scroll=\"paper\"` makes the paper a flex column with\n * `overflow-y: auto`, so a `DialogContent` that is no longer its direct child\n * cannot be the thing that scrolls — the whole dialog scrolls instead and\n * carries the `DialogActions` off the bottom with it. An element with\n * `display: contents` generates no box at all: its children become the paper's\n * flex items, and its padding is never applied. Both halves, one declaration.\n *\n * A browser without `:has()` falls back to the padded box — the layout this\n * had before, not a broken one.\n */\nconst BODY_SX = {\n px: 3,\n pb: 2.5,\n '&:has(> .MuiDialogContent-root), &:has(> .MuiDialogActions-root)': {\n display: 'contents',\n },\n} as const;\n\n/**\n * The dialog body. Consumers that pass raw children (no <DialogContent>) used\n * to render them flush against the paper edges — give them comfortable default\n * padding; <DialogContent>/<DialogActions> users keep managing their own\n * spacing.\n */\nfunction bodyOf(children: React.ReactNode, hasTitle: boolean): React.ReactNode {\n if (hasSpacingSlot(children)) return children;\n return <Box sx={{ ...BODY_SX, pt: hasTitle ? 0.5 : 2.5 }}>{children}</Box>;\n}\n\nconst DIALOG_DEFAULTS = {\n variant: 'default',\n size: 'md',\n showCloseButton: true,\n backdrop: true,\n persistent: false,\n glass: false,\n gradient: false,\n glow: false,\n pulse: false,\n borderRadius: 'lg',\n} as const satisfies Partial<DialogProps>;\n\n/** DialogProps with every defaulted field guaranteed present (wide types). */\ntype DialogPropsWithDefaults = DialogProps &\n Required<Pick<DialogProps, keyof typeof DIALOG_DEFAULTS>>;\n\n/**\n * Apply {@link DIALOG_DEFAULTS} exactly like parameter defaults would: only a\n * missing/`undefined` prop falls back (a loop, so the component's cyclomatic\n * complexity doesn't pay one branch per defaulted prop).\n */\nfunction withDialogDefaults(props: DialogProps): DialogPropsWithDefaults {\n const merged: Record<string, unknown> = { ...props };\n for (const [key, value] of Object.entries(DIALOG_DEFAULTS)) {\n if (merged[key] === undefined) merged[key] = value;\n }\n return merged as unknown as DialogPropsWithDefaults;\n}\n\nexport const Dialog: React.FC<DialogProps> = (rawProps) => {\n const {\n children,\n variant,\n size,\n title,\n description,\n showCloseButton,\n backdrop,\n persistent,\n glass,\n gradient,\n glow,\n pulse,\n borderRadius,\n onClose,\n open,\n dataTestId,\n ...props\n } = withDialogDefaults(rawProps);\n const theme = useTheme();\n const testId = dataTestId || 'dialog';\n const paperSx = variantStylesOf(theme, {\n variant, size, borderRadius, glass, gradient, glow, pulse,\n });\n\n const handleClose = (event: object, reason: 'backdropClick' | 'escapeKeyDown') => {\n if (persistent && (reason === 'backdropClick' || reason === 'escapeKeyDown')) {\n return;\n }\n onClose?.();\n };\n\n const header = title ? (\n <DialogHeader\n title={title}\n subtitle={description}\n showCloseButton={showCloseButton}\n onClose={onClose}\n dataTestId={dataTestId}\n />\n ) : null;\n const body = bodyOf(children, Boolean(title));\n\n if (variant === 'drawer') {\n return (\n <Drawer\n anchor=\"right\"\n open={open}\n onClose={onClose}\n data-testid={testId}\n {...props}\n >\n <Box sx={{ ...paperSx, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>\n {header}\n {body}\n </Box>\n </Drawer>\n );\n }\n\n return (\n <MuiDialog\n open={open}\n onClose={handleClose}\n fullScreen={variant === 'fullscreen'}\n BackdropComponent={backdrop ? Backdrop : undefined}\n BackdropProps={{ sx: backdropSxOf(theme, glass) }}\n PaperProps={{ sx: paperSx, 'data-testid': testId }}\n {...props}\n >\n {header}\n {body}\n </MuiDialog>\n );\n};\n\nexport const DialogHeader: React.FC<DialogHeaderProps> = ({\n children,\n title,\n subtitle,\n showCloseButton = true,\n onClose,\n dataTestId,\n}) => {\n if (children) {\n return (\n <Box sx={{ p: 2, borderBottom: '1px solid', borderColor: 'divider' }}>\n {children}\n </Box>\n );\n }\n\n return (\n <MuiDialogTitle\n data-testid={dataTestId ? `${dataTestId}-title` : 'dialog-title'}\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n pb: subtitle ? 1 : 2,\n }}\n >\n <Box>\n <Typography variant=\"h6\" component=\"div\">\n {title}\n </Typography>\n {subtitle && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {subtitle}\n </Typography>\n )}\n </Box>\n {showCloseButton && onClose && (\n <IconButton\n aria-label=\"close\"\n onClick={onClose}\n data-testid={dataTestId ? `${dataTestId}-close` : 'dialog-close'}\n sx={{\n color: 'text.secondary',\n '&:hover': {\n backgroundColor: 'action.hover',\n },\n }}\n >\n <CloseIcon />\n </IconButton>\n )}\n </MuiDialogTitle>\n );\n};\n\n/**\n * Top padding for a body that sits directly under the title.\n *\n * MUI zeroes it there (`.MuiDialogTitle-root + &` on a non-`dividers` content),\n * assuming the title's own bottom padding is the whole gap. That assumption\n * breaks for a body opening with an outlined field: a filled field floats its\n * label ABOVE the input's border box, and `DialogContent` is `overflow-y: auto`\n * — a clipping box — so the label gets sliced in half (FUT-544: \"Tipo\" in the\n * \"Novo insumo\" dialog).\n *\n * Reserve the overhang rather than restore the full 24px: the title already\n * contributes its bottom padding, so a shrunk label's `translate(…, -9px)` is\n * all that is missing. 12px clears it and leaves the gap visually tight.\n */\nconst TITLED_BODY_PADDING_TOP = 1.5;\n\n/**\n * `.MuiDialogTitle-root + &` is `(0,2,0)`-specific and a plain `sx` entry is\n * `(0,1,0)`, so the padding above only survives the cascade by naming the class\n * again — `(0,3,0)`. Scoped to the title-following case so an untitled dialog\n * keeps MUI's roomier default.\n */\nconst TITLED_BODY_SELECTOR = '.MuiDialogTitle-root + &.MuiDialogContent-root';\n\nexport const DialogContent: React.FC<DialogContentProps> = ({\n children,\n dividers = false,\n dense = false,\n dataTestId,\n ...props\n}) => (\n <MuiDialogContent\n data-testid={dataTestId ? `${dataTestId}-content` : 'dialog-content'}\n dividers={dividers}\n sx={{\n padding: dense ? 1.5 : 3,\n [TITLED_BODY_SELECTOR]: { paddingTop: TITLED_BODY_PADDING_TOP },\n '&.MuiDialogContent-dividers': {\n borderTop: dividers ? '1px solid' : 'none',\n borderBottom: dividers ? '1px solid' : 'none',\n borderColor: 'divider',\n },\n }}\n {...props}\n >\n {children}\n </MuiDialogContent>\n );\n\nexport const DialogActions: React.FC<DialogActionsProps> = ({\n children,\n alignment = 'right',\n spacing = 1,\n dataTestId,\n ...props\n}) => {\n const getJustifyContent = () => {\n switch (alignment) {\n case 'left': return 'flex-start';\n case 'center': return 'center';\n case 'right': return 'flex-end';\n case 'space-between': return 'space-between';\n default: return 'flex-end';\n }\n };\n\n return (\n <MuiDialogActions\n data-testid={dataTestId ? `${dataTestId}-actions` : 'dialog-actions'}\n sx={{\n justifyContent: getJustifyContent(),\n gap: spacing,\n p: 2,\n }}\n {...props}\n >\n {children}\n </MuiDialogActions>\n );\n};","import type { SxProps, Theme } from '@mui/material';\nimport { alpha, keyframes } from '@mui/material';\n\nimport { dynamicViewportHeight } from '../../../utils/viewport';\nimport type { DialogProps } from './Dialog.types';\n\n/**\n * Paper/backdrop styling for the Dialog component (FUT-181 gate cleanup):\n * pure helpers so `Dialog.tsx` stays within the size/complexity budget.\n */\n\n// Define pulse animation\nconst pulseAnimation = keyframes`\n 0% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 1;\n }\n 70% {\n box-shadow: 0 0 0 20px currentColor;\n opacity: 0;\n }\n 100% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 0;\n }\n`;\n\n/** Style toggles that shape the dialog paper (extracted so each fn stays small). */\ninterface VariantStyleOptions {\n variant: NonNullable<DialogProps['variant']>;\n size: NonNullable<DialogProps['size']>;\n borderRadius: NonNullable<DialogProps['borderRadius']>;\n glass: boolean;\n gradient: boolean;\n glow: boolean;\n pulse: boolean;\n}\n\nfunction borderRadiusOf(theme: Theme, borderRadius: VariantStyleOptions['borderRadius']) {\n switch (borderRadius) {\n case 'none': return 0;\n case 'sm': return theme.spacing(0.5);\n case 'md': return theme.spacing(1);\n case 'xl': return theme.spacing(3);\n case 'lg':\n default: return theme.spacing(2);\n }\n}\n\nfunction maxWidthOf(size: VariantStyleOptions['size']): number {\n switch (size) {\n case 'xs': return 400;\n case 'sm': return 600;\n case 'lg': return 1000;\n case 'xl': return 1200;\n case 'md':\n default: return 800;\n }\n}\n\nfunction baseStylesOf(theme: Theme, opts: VariantStyleOptions) {\n return {\n borderRadius: borderRadiusOf(theme, opts.borderRadius),\n maxWidth: maxWidthOf(opts.size),\n width: '90vw',\n margin: theme.spacing(2),\n transition: theme.transitions.create(\n ['box-shadow', 'background-color', 'backdrop-filter'],\n { duration: theme.transitions.duration.standard },\n ),\n };\n}\n\nfunction glowStylesOf(theme: Theme, glow: boolean) {\n return glow ? { boxShadow: `0 0 40px ${alpha(theme.palette.primary.main, 0.3)}` } : {};\n}\n\nfunction pulseStylesOf(theme: Theme, pulse: boolean) {\n if (!pulse) return {};\n return {\n position: 'relative' as const,\n '&::after': {\n content: '\"\"',\n position: 'absolute' as const,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n borderRadius: 'inherit',\n backgroundColor: theme.palette.primary.main,\n opacity: 0.3,\n animation: `${pulseAnimation} 2s infinite`,\n pointerEvents: 'none' as const,\n zIndex: -1,\n },\n };\n}\n\n/** The default variant's paper: optional gradient/glass over the base styles. */\nfunction defaultVariantStyles(theme: Theme, opts: VariantStyleOptions) {\n const gradientStyles = opts.gradient\n ? {\n background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.1)}, ${alpha(theme.palette.secondary.main, 0.1)})`,\n backdropFilter: 'blur(10px)',\n }\n : {};\n return {\n ...gradientStyles,\n backgroundColor: opts.glass\n ? alpha(theme.palette.background.paper, 0.1)\n : theme.palette.background.paper,\n backdropFilter: opts.glass ? 'blur(20px)' : 'none',\n border: opts.glass ? `1px solid ${alpha(theme.palette.primary.main, 0.2)}` : 'none',\n };\n}\n\nexport function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProps<Theme> {\n const decorations = {\n ...glowStylesOf(theme, opts.glow),\n ...pulseStylesOf(theme, opts.pulse),\n };\n switch (opts.variant) {\n case 'glass':\n return {\n ...baseStylesOf(theme, opts),\n ...decorations,\n backgroundColor: alpha(theme.palette.background.paper, 0.1),\n backdropFilter: 'blur(20px)',\n border: `1px solid ${alpha(theme.palette.primary.main, 0.2)}`,\n boxShadow: `0 8px 32px ${alpha(theme.palette.common.black, 0.1)}`,\n };\n case 'fullscreen':\n return {\n borderRadius: 0,\n margin: 0,\n width: '100vw',\n // `100dvh`, not `100vh` — see `dynamicViewportHeight`.\n ...dynamicViewportHeight('height'),\n maxWidth: 'none',\n maxHeight: 'none',\n ...decorations,\n };\n case 'drawer': {\n const radius = borderRadiusOf(theme, opts.borderRadius);\n return {\n borderRadius: `${radius}px 0 0 ${radius}px`,\n margin: 0,\n width: maxWidthOf(opts.size),\n ...dynamicViewportHeight('height'),\n maxHeight: 'none',\n position: 'absolute' as const,\n right: 0,\n ...decorations,\n };\n }\n default:\n return {\n ...baseStylesOf(theme, opts),\n ...decorations,\n ...defaultVariantStyles(theme, opts),\n };\n }\n}\n\nexport function backdropSxOf(theme: Theme, glass: boolean) {\n return {\n backgroundColor: glass\n ? alpha(theme.palette.common.black, 0.2)\n : alpha(theme.palette.common.black, 0.5),\n backdropFilter: glass ? 'blur(8px)' : 'none',\n };\n}\n\n"],"mappings":"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","names":[]}
@@ -44,7 +44,7 @@ import "../chunk-KFJKOVDD.js";
44
44
  import {
45
45
  Dialog,
46
46
  DialogContent
47
- } from "../chunk-U3J55YPN.js";
47
+ } from "../chunk-GSEAUMCS.js";
48
48
  import {
49
49
  DataGrid
50
50
  } from "../chunk-QLBYAYUG.js";
@@ -4,7 +4,7 @@ import {
4
4
  DialogActions,
5
5
  DialogContent,
6
6
  DialogHeader
7
- } from "../chunk-U3J55YPN.js";
7
+ } from "../chunk-GSEAUMCS.js";
8
8
  import "../chunk-TSPG6TWK.js";
9
9
  import "../chunk-PZ5AY32C.js";
10
10
  export {
@@ -3,7 +3,7 @@ import {
3
3
  } from "../chunk-LGB6Z34C.js";
4
4
  import {
5
5
  Dialog
6
- } from "../chunk-U3J55YPN.js";
6
+ } from "../chunk-GSEAUMCS.js";
7
7
  import {
8
8
  Button
9
9
  } from "../chunk-ANNZ3PLI.js";
@@ -135,20 +135,29 @@ function SocialLoginContainer({
135
135
  title = "Sign in to continue",
136
136
  subtitle,
137
137
  showDivider = false,
138
- dividerText = "or"
138
+ dividerText = "or",
139
+ maxWidth = 400
139
140
  }) {
140
- return /* @__PURE__ */ jsx(Card, { variant: "elevated", borderRadius: "lg", children: /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Stack, { spacing: 3, sx: { width: "100%", maxWidth: 400 }, children: [
141
- title && /* @__PURE__ */ jsxs(Box, { sx: { textAlign: "center" }, children: [
142
- /* @__PURE__ */ jsx(Heading, { level: "h2", children: title }),
143
- subtitle && /* @__PURE__ */ jsx(Text, { color: "secondary", size: "sm", children: subtitle })
144
- ] }),
145
- /* @__PURE__ */ jsx(Stack, { spacing: 2, children }),
146
- showDivider && /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 2 }, children: [
147
- /* @__PURE__ */ jsx(Separator, {}),
148
- /* @__PURE__ */ jsx(Text, { color: "secondary", size: "sm", children: dividerText }),
149
- /* @__PURE__ */ jsx(Separator, {})
150
- ] })
151
- ] }) }) });
141
+ return (
142
+ // `width: 100%` is what makes the cap below mean anything. Every caller
143
+ // centres this card in a flex column (`Container variant="centered"` does),
144
+ // and a flex item under `align-items: center` sizes to its CONTENT — so the
145
+ // card sat at whatever the longest label happened to need, ~267px, at every
146
+ // viewport from 390 to 1280. The 400 was never reached, which is why raising
147
+ // it would have changed nothing; the card had no width to cap.
148
+ /* @__PURE__ */ jsx(Card, { variant: "elevated", borderRadius: "lg", sx: { width: "100%", maxWidth }, children: /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Stack, { spacing: 3, sx: { width: "100%" }, children: [
149
+ title && /* @__PURE__ */ jsxs(Box, { sx: { textAlign: "center" }, children: [
150
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: title }),
151
+ subtitle && /* @__PURE__ */ jsx(Text, { color: "secondary", size: "sm", children: subtitle })
152
+ ] }),
153
+ /* @__PURE__ */ jsx(Stack, { spacing: 2, children }),
154
+ showDivider && /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 2 }, children: [
155
+ /* @__PURE__ */ jsx(Separator, {}),
156
+ /* @__PURE__ */ jsx(Text, { color: "secondary", size: "sm", children: dividerText }),
157
+ /* @__PURE__ */ jsx(Separator, {})
158
+ ] })
159
+ ] }) }) })
160
+ );
152
161
  }
153
162
  export {
154
163
  AppleIcon,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/social-login-button/social-login-button.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from 'react';\nimport { Box, Stack } from '@mui/material';\nimport { Button } from '../components/form/Button';\nimport { Card, CardContent } from '../components/layout/Card';\nimport { Heading } from '../components/typography/Heading';\nimport { Text } from '../components/typography/Text';\nimport { Separator } from '../components/layout/Separator';\n\nexport type SocialProvider = 'google' | 'facebook' | 'apple';\n\n/**\n * SVG Icons for social providers\n */\nconst GoogleIcon = (): React.ReactElement => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n fill=\"#4285F4\"\n />\n <path\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n fill=\"#34A853\"\n />\n <path\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"\n fill=\"#FBBC05\"\n />\n <path\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n fill=\"#EA4335\"\n />\n </svg>\n);\n\nconst FacebookIcon = (): React.ReactElement => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M24 12c0-6.627-5.373-12-12-12S0 5.373 0 12c0 5.99 4.388 10.954 10.125 11.854V15.47H7.078V12h3.047V9.356c0-3.007 1.792-4.668 4.533-4.668 1.312 0 2.686.234 2.686.234v2.953H15.83c-1.491 0-1.956.925-1.956 1.874V12h3.328l-.532 3.469h-2.796v8.385C19.612 22.954 24 17.99 24 12z\"\n fill=\"#1877F2\"\n />\n </svg>\n);\n\nconst AppleIcon = (): React.ReactElement => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z\" />\n </svg>\n);\n\ninterface ProviderConfig {\n label: string;\n Icon: () => React.ReactElement;\n variant: 'solid' | 'outline' | 'ghost';\n color: 'primary' | 'secondary' | 'neutral';\n sx?: object;\n}\n\nconst providerConfig: Record<SocialProvider, ProviderConfig> = {\n google: {\n label: \"Continue with Google\",\n Icon: GoogleIcon,\n variant: 'outline',\n color: 'neutral',\n sx: {\n backgroundColor: '#ffffff',\n color: '#1f1f1f',\n borderColor: '#dadce0',\n '&:hover': {\n backgroundColor: '#f5f5f5',\n borderColor: '#dadce0',\n },\n },\n },\n facebook: {\n label: \"Continue with Facebook\",\n Icon: FacebookIcon,\n variant: 'solid',\n color: 'primary',\n sx: {\n backgroundColor: '#1877F2',\n color: '#ffffff',\n '&:hover': {\n backgroundColor: '#166fe5',\n },\n },\n },\n apple: {\n label: \"Continue with Apple\",\n Icon: AppleIcon,\n variant: 'solid',\n color: 'neutral',\n sx: {\n backgroundColor: '#000000',\n color: '#ffffff',\n '&:hover': {\n backgroundColor: '#1a1a1a',\n },\n },\n },\n};\n\nexport interface SocialLoginButtonProps {\n provider: SocialProvider;\n onClick?: () => void;\n loading?: boolean;\n disabled?: boolean;\n fullWidth?: boolean;\n}\n\n/**\n * Social login button using UI package Button component\n */\nexport const SocialLoginButton = React.forwardRef<HTMLButtonElement, SocialLoginButtonProps>(\n ({ provider, onClick, loading = false, disabled = false, fullWidth = true }, ref) => {\n const config = providerConfig[provider];\n\n return (\n <Button\n ref={ref}\n variant={config.variant}\n color={config.color}\n size=\"lg\"\n loading={loading}\n disabled={disabled}\n onClick={onClick}\n icon={<config.Icon />}\n fullWidth={fullWidth}\n sx={{\n minHeight: 48,\n justifyContent: 'flex-start',\n gap: 2,\n ...config.sx,\n }}\n >\n {config.label}\n </Button>\n );\n }\n);\n\nSocialLoginButton.displayName = 'SocialLoginButton';\n\n/**\n * Container for social login buttons with optional divider\n */\nexport interface SocialLoginContainerProps {\n children: React.ReactNode;\n title?: string;\n subtitle?: string;\n showDivider?: boolean;\n dividerText?: string;\n}\n\nexport function SocialLoginContainer({\n children,\n title = \"Sign in to continue\",\n subtitle,\n showDivider = false,\n dividerText = \"or\",\n}: SocialLoginContainerProps): React.ReactElement {\n return (\n <Card variant=\"elevated\" borderRadius=\"lg\">\n <CardContent>\n <Stack spacing={3} sx={{ width: '100%', maxWidth: 400 }}>\n {title && (\n <Box sx={{ textAlign: 'center' }}>\n <Heading level=\"h2\">\n {title}\n </Heading>\n {subtitle && (\n <Text color=\"secondary\" size=\"sm\">\n {subtitle}\n </Text>\n )}\n </Box>\n )}\n\n <Stack spacing={2}>\n {children}\n </Stack>\n\n {showDivider && (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>\n <Separator />\n <Text color=\"secondary\" size=\"sm\">\n {dividerText}\n </Text>\n <Separator />\n </Box>\n )}\n </Stack>\n </CardContent>\n </Card>\n );\n}\n\nexport { GoogleIcon, FacebookIcon, AppleIcon };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/social-login-button/social-login-button.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from 'react';\nimport { Box, Stack } from '@mui/material';\nimport { Button } from '../components/form/Button';\nimport { Card, CardContent } from '../components/layout/Card';\nimport { Heading } from '../components/typography/Heading';\nimport { Text } from '../components/typography/Text';\nimport { Separator } from '../components/layout/Separator';\n\nexport type SocialProvider = 'google' | 'facebook' | 'apple';\n\n/**\n * SVG Icons for social providers\n */\nconst GoogleIcon = (): React.ReactElement => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n fill=\"#4285F4\"\n />\n <path\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n fill=\"#34A853\"\n />\n <path\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"\n fill=\"#FBBC05\"\n />\n <path\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n fill=\"#EA4335\"\n />\n </svg>\n);\n\nconst FacebookIcon = (): React.ReactElement => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M24 12c0-6.627-5.373-12-12-12S0 5.373 0 12c0 5.99 4.388 10.954 10.125 11.854V15.47H7.078V12h3.047V9.356c0-3.007 1.792-4.668 4.533-4.668 1.312 0 2.686.234 2.686.234v2.953H15.83c-1.491 0-1.956.925-1.956 1.874V12h3.328l-.532 3.469h-2.796v8.385C19.612 22.954 24 17.99 24 12z\"\n fill=\"#1877F2\"\n />\n </svg>\n);\n\nconst AppleIcon = (): React.ReactElement => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z\" />\n </svg>\n);\n\ninterface ProviderConfig {\n label: string;\n Icon: () => React.ReactElement;\n variant: 'solid' | 'outline' | 'ghost';\n color: 'primary' | 'secondary' | 'neutral';\n sx?: object;\n}\n\nconst providerConfig: Record<SocialProvider, ProviderConfig> = {\n google: {\n label: \"Continue with Google\",\n Icon: GoogleIcon,\n variant: 'outline',\n color: 'neutral',\n sx: {\n backgroundColor: '#ffffff',\n color: '#1f1f1f',\n borderColor: '#dadce0',\n '&:hover': {\n backgroundColor: '#f5f5f5',\n borderColor: '#dadce0',\n },\n },\n },\n facebook: {\n label: \"Continue with Facebook\",\n Icon: FacebookIcon,\n variant: 'solid',\n color: 'primary',\n sx: {\n backgroundColor: '#1877F2',\n color: '#ffffff',\n '&:hover': {\n backgroundColor: '#166fe5',\n },\n },\n },\n apple: {\n label: \"Continue with Apple\",\n Icon: AppleIcon,\n variant: 'solid',\n color: 'neutral',\n sx: {\n backgroundColor: '#000000',\n color: '#ffffff',\n '&:hover': {\n backgroundColor: '#1a1a1a',\n },\n },\n },\n};\n\nexport interface SocialLoginButtonProps {\n provider: SocialProvider;\n onClick?: () => void;\n loading?: boolean;\n disabled?: boolean;\n fullWidth?: boolean;\n}\n\n/**\n * Social login button using UI package Button component\n */\nexport const SocialLoginButton = React.forwardRef<HTMLButtonElement, SocialLoginButtonProps>(\n ({ provider, onClick, loading = false, disabled = false, fullWidth = true }, ref) => {\n const config = providerConfig[provider];\n\n return (\n <Button\n ref={ref}\n variant={config.variant}\n color={config.color}\n size=\"lg\"\n loading={loading}\n disabled={disabled}\n onClick={onClick}\n icon={<config.Icon />}\n fullWidth={fullWidth}\n sx={{\n minHeight: 48,\n justifyContent: 'flex-start',\n gap: 2,\n ...config.sx,\n }}\n >\n {config.label}\n </Button>\n );\n }\n);\n\nSocialLoginButton.displayName = 'SocialLoginButton';\n\n/**\n * Container for social login buttons with optional divider\n */\nexport interface SocialLoginContainerProps {\n children: React.ReactNode;\n title?: string;\n subtitle?: string;\n showDivider?: boolean;\n dividerText?: string;\n /**\n * How wide the card is allowed to get. Defaults to the 400 it has always\n * intended, so nothing that does not ask for a width moves.\n *\n * Worth passing for a card holding a FORM rather than a row of provider\n * buttons: 400 was chosen for the latter, and an e-mail + password pair reads\n * cramped in it.\n */\n maxWidth?: number | string;\n}\n\nexport function SocialLoginContainer({\n children,\n title = \"Sign in to continue\",\n subtitle,\n showDivider = false,\n dividerText = \"or\",\n maxWidth = 400,\n}: SocialLoginContainerProps): React.ReactElement {\n return (\n // `width: 100%` is what makes the cap below mean anything. Every caller\n // centres this card in a flex column (`Container variant=\"centered\"` does),\n // and a flex item under `align-items: center` sizes to its CONTENT — so the\n // card sat at whatever the longest label happened to need, ~267px, at every\n // viewport from 390 to 1280. The 400 was never reached, which is why raising\n // it would have changed nothing; the card had no width to cap.\n <Card variant=\"elevated\" borderRadius=\"lg\" sx={{ width: '100%', maxWidth }}>\n <CardContent>\n <Stack spacing={3} sx={{ width: '100%' }}>\n {title && (\n <Box sx={{ textAlign: 'center' }}>\n <Heading level=\"h2\">\n {title}\n </Heading>\n {subtitle && (\n <Text color=\"secondary\" size=\"sm\">\n {subtitle}\n </Text>\n )}\n </Box>\n )}\n\n <Stack spacing={2}>\n {children}\n </Stack>\n\n {showDivider && (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>\n <Separator />\n <Text color=\"secondary\" size=\"sm\">\n {dividerText}\n </Text>\n <Separator />\n </Box>\n )}\n </Stack>\n </CardContent>\n </Card>\n );\n}\n\nexport { GoogleIcon, FacebookIcon, AppleIcon };\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/Dialog/Dialog.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAgDxB,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA2ExC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAqDpD,CAAC;AA0BF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAuBpD,CAAC;AAEJ,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8BtD,CAAC"}
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/Dialog/Dialog.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACZ,MAAM,gBAAgB,CAAC;AA2FxB,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA2ExC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAqDpD,CAAC;AA0BF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAuBpD,CAAC;AAEJ,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8BtD,CAAC"}
@@ -26,7 +26,16 @@ export interface SocialLoginContainerProps {
26
26
  subtitle?: string;
27
27
  showDivider?: boolean;
28
28
  dividerText?: string;
29
+ /**
30
+ * How wide the card is allowed to get. Defaults to the 400 it has always
31
+ * intended, so nothing that does not ask for a width moves.
32
+ *
33
+ * Worth passing for a card holding a FORM rather than a row of provider
34
+ * buttons: 400 was chosen for the latter, and an e-mail + password pair reads
35
+ * cramped in it.
36
+ */
37
+ maxWidth?: number | string;
29
38
  }
30
- export declare function SocialLoginContainer({ children, title, subtitle, showDivider, dividerText, }: SocialLoginContainerProps): React.ReactElement;
39
+ export declare function SocialLoginContainer({ children, title, subtitle, showDivider, dividerText, maxWidth, }: SocialLoginContainerProps): React.ReactElement;
31
40
  export { GoogleIcon, FacebookIcon, AppleIcon };
32
41
  //# sourceMappingURL=social-login-button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"social-login-button.d.ts","sourceRoot":"","sources":["../../../src/social-login-button/social-login-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAE7D;;GAEG;AACH,QAAA,MAAM,UAAU,QAAO,KAAK,CAAC,YAmB5B,CAAC;AAEF,QAAA,MAAM,YAAY,QAAO,KAAK,CAAC,YAO9B,CAAC;AAEF,QAAA,MAAM,SAAS,QAAO,KAAK,CAAC,YAI3B,CAAC;AAsDF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,kGA0B7B,CAAC;AAIF;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,KAA6B,EAC7B,QAAQ,EACR,WAAmB,EACnB,WAAkB,GACnB,EAAE,yBAAyB,GAAG,KAAK,CAAC,YAAY,CAmChD;AAED,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"social-login-button.d.ts","sourceRoot":"","sources":["../../../src/social-login-button/social-login-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAE7D;;GAEG;AACH,QAAA,MAAM,UAAU,QAAO,KAAK,CAAC,YAmB5B,CAAC;AAEF,QAAA,MAAM,YAAY,QAAO,KAAK,CAAC,YAO9B,CAAC;AAEF,QAAA,MAAM,SAAS,QAAO,KAAK,CAAC,YAI3B,CAAC;AAsDF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,kGA0B7B,CAAC;AAIF;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAED,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,KAA6B,EAC7B,QAAQ,EACR,WAAmB,EACnB,WAAkB,EAClB,QAAc,GACf,EAAE,yBAAyB,GAAG,KAAK,CAAC,YAAY,CAyChD;AAED,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/ui",
3
- "version": "5.5.0",
3
+ "version": "6.0.1",
4
4
  "license": "MIT",
5
5
  "packageManager": "pnpm@9.0.0",
6
6
  "type": "module",
@@ -603,7 +603,7 @@
603
603
  "recharts": "^3.5.1"
604
604
  },
605
605
  "devDependencies": {
606
- "@12-apps/eslint-config": "^1.20.0",
606
+ "@12-apps/eslint-config": "^1.21.0",
607
607
  "@12-apps/typescript-config": "^1.20.0",
608
608
  "@playwright/test": "^1.55.0",
609
609
  "@storybook/addon-docs": "^9.1.10",
@@ -9,7 +9,7 @@ The Dialog component provides a powerful, flexible modal dialog system with mult
9
9
  - **Multiple Variants**: Default, glass, fullscreen, and drawer modes
10
10
  - **Flexible Sizing**: Five size options (xs, sm, md, lg, xl)
11
11
  - **Composable Architecture**: Separate DialogHeader, DialogContent, and DialogActions components
12
- - **Padded By Default**: Raw children (no DialogContent/DialogActions) get comfortable body padding automatically; composed dialogs keep managing their own spacing
12
+ - **Padded By Default**: Raw children (no DialogContent/DialogActions) get comfortable body padding automatically; composed dialogs keep managing their own spacing — including when the slot arrives through a fragment or from inside your own component (see [Body padding](#body-padding))
13
13
  - **Advanced Styling**: Glass morphism, gradient backgrounds, glow, and pulse effects
14
14
  - **Persistent Mode**: Prevent dismissal via backdrop click or escape key
15
15
  - **Customizable Border Radius**: Five border radius options (none, sm, md, lg, xl)
@@ -518,6 +518,45 @@ describe('Dialog Component', () => {
518
518
  });
519
519
  ```
520
520
 
521
+ ## Body padding
522
+
523
+ A dialog handed raw children pads them for you (24px sides, comfortable top and
524
+ bottom). A dialog handed `DialogContent` / `DialogActions` does not — those
525
+ slots pay their own spacing, and the paper is a flex column that wants them as
526
+ its DIRECT children, so that a `DialogContent` is the thing that scrolls and a
527
+ `DialogActions` stays pinned under it.
528
+
529
+ **It does not matter how the slot reaches the dialog.** All four of these are
530
+ "manages its own spacing":
531
+
532
+ ```tsx
533
+ <Dialog open> {/* the slot itself */}
534
+ <DialogContent>…</DialogContent>
535
+ </Dialog>
536
+
537
+ <Dialog open> {/* grouped in a fragment */}
538
+ <>
539
+ <DialogContent>…</DialogContent>
540
+ <DialogActions>…</DialogActions>
541
+ </>
542
+ </Dialog>
543
+
544
+ <Dialog open><Body /></Dialog> {/* Body renders a DialogContent */}
545
+ <Dialog open><Footer /></Dialog> {/* Footer renders a DialogActions */}
546
+ ```
547
+
548
+ The last two are the ones worth knowing about. Splitting a long dialog's body or
549
+ footer into its own component is an ordinary refactor — the size gates push you
550
+ toward it — and React cannot tell what a component renders until it has rendered
551
+ it. The dialog therefore settles the question in CSS (`:has()`), one step later,
552
+ where the answer exists: a wrapper that turns out to hold a slot generates no box
553
+ (`display: contents`), so its padding never applies and its children land in the
554
+ paper's column as if it were not there.
555
+
556
+ A `DialogContent` genuinely nested inside your own markup (`<div><DialogContent/></div>`)
557
+ is that div's content, not the dialog's slot, and stays padded. If you want the
558
+ slot behaviour, make it a direct child.
559
+
521
560
  ## Related Components
522
561
 
523
562
  - **AlertDialog** - Simplified dialog for alerts and confirmations
@@ -21,6 +21,54 @@ import type {
21
21
  DialogProps,
22
22
  } from './Dialog.types';
23
23
 
24
+ /**
25
+ * Does this hand us a spacing slot? Fragments are transparent: `<>` is a way of
26
+ * passing several children, not a child that owns them, and a consumer who
27
+ * groups a `DialogContent` and a `DialogActions` in one has still passed both.
28
+ *
29
+ * Only the slots themselves count, and only at the top. A `DialogContent`
30
+ * genuinely nested inside a `<div>` is that div's content, and the dialog
31
+ * padding the div is right.
32
+ */
33
+ function hasSpacingSlot(children: React.ReactNode): boolean {
34
+ return React.Children.toArray(children).some((child) => {
35
+ if (!React.isValidElement(child)) return false;
36
+ if (child.type === DialogContent || child.type === DialogActions) return true;
37
+ if (child.type !== React.Fragment) return false;
38
+ return hasSpacingSlot((child.props as { children?: React.ReactNode }).children);
39
+ });
40
+ }
41
+
42
+ /**
43
+ * The padding a dialog gives children that are not managing their own — and the
44
+ * rule that takes it back when it turns out they are.
45
+ *
46
+ * `:has()` is doing what {@link hasSpacingSlot} cannot. A slot passed through a
47
+ * COMPONENT (`<Body />` rendering a `DialogContent`) is invisible to any check
48
+ * on element type: React does not know what a component renders until it has
49
+ * rendered it, and by then the wrapper is already in the tree. The selector
50
+ * asks the question one step later, of the DOM, where the answer exists.
51
+ *
52
+ * `display: contents` rather than `padding: 0`, because the padding is only
53
+ * half of what a wrapper does. The other half is standing between the paper and
54
+ * its children: MUI's `scroll="paper"` makes the paper a flex column with
55
+ * `overflow-y: auto`, so a `DialogContent` that is no longer its direct child
56
+ * cannot be the thing that scrolls — the whole dialog scrolls instead and
57
+ * carries the `DialogActions` off the bottom with it. An element with
58
+ * `display: contents` generates no box at all: its children become the paper's
59
+ * flex items, and its padding is never applied. Both halves, one declaration.
60
+ *
61
+ * A browser without `:has()` falls back to the padded box — the layout this
62
+ * had before, not a broken one.
63
+ */
64
+ const BODY_SX = {
65
+ px: 3,
66
+ pb: 2.5,
67
+ '&:has(> .MuiDialogContent-root), &:has(> .MuiDialogActions-root)': {
68
+ display: 'contents',
69
+ },
70
+ } as const;
71
+
24
72
  /**
25
73
  * The dialog body. Consumers that pass raw children (no <DialogContent>) used
26
74
  * to render them flush against the paper edges — give them comfortable default
@@ -28,13 +76,8 @@ import type {
28
76
  * spacing.
29
77
  */
30
78
  function bodyOf(children: React.ReactNode, hasTitle: boolean): React.ReactNode {
31
- const managesOwnSpacing = React.Children.toArray(children).some(
32
- (child) =>
33
- React.isValidElement(child) &&
34
- (child.type === DialogContent || child.type === DialogActions),
35
- );
36
- if (managesOwnSpacing) return children;
37
- return <Box sx={{ px: 3, pb: 2.5, pt: hasTitle ? 0.5 : 2.5 }}>{children}</Box>;
79
+ if (hasSpacingSlot(children)) return children;
80
+ return <Box sx={{ ...BODY_SX, pt: hasTitle ? 0.5 : 2.5 }}>{children}</Box>;
38
81
  }
39
82
 
40
83
  const DIALOG_DEFAULTS = {
@@ -151,6 +151,15 @@ export interface SocialLoginContainerProps {
151
151
  subtitle?: string;
152
152
  showDivider?: boolean;
153
153
  dividerText?: string;
154
+ /**
155
+ * How wide the card is allowed to get. Defaults to the 400 it has always
156
+ * intended, so nothing that does not ask for a width moves.
157
+ *
158
+ * Worth passing for a card holding a FORM rather than a row of provider
159
+ * buttons: 400 was chosen for the latter, and an e-mail + password pair reads
160
+ * cramped in it.
161
+ */
162
+ maxWidth?: number | string;
154
163
  }
155
164
 
156
165
  export function SocialLoginContainer({
@@ -159,11 +168,18 @@ export function SocialLoginContainer({
159
168
  subtitle,
160
169
  showDivider = false,
161
170
  dividerText = "or",
171
+ maxWidth = 400,
162
172
  }: SocialLoginContainerProps): React.ReactElement {
163
173
  return (
164
- <Card variant="elevated" borderRadius="lg">
174
+ // `width: 100%` is what makes the cap below mean anything. Every caller
175
+ // centres this card in a flex column (`Container variant="centered"` does),
176
+ // and a flex item under `align-items: center` sizes to its CONTENT — so the
177
+ // card sat at whatever the longest label happened to need, ~267px, at every
178
+ // viewport from 390 to 1280. The 400 was never reached, which is why raising
179
+ // it would have changed nothing; the card had no width to cap.
180
+ <Card variant="elevated" borderRadius="lg" sx={{ width: '100%', maxWidth }}>
165
181
  <CardContent>
166
- <Stack spacing={3} sx={{ width: '100%', maxWidth: 400 }}>
182
+ <Stack spacing={3} sx={{ width: '100%' }}>
167
183
  {title && (
168
184
  <Box sx={{ textAlign: 'center' }}>
169
185
  <Heading level="h2">
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/feedback/Dialog/Dialog.tsx","../src/components/feedback/Dialog/Dialog.styles.ts"],"sourcesContent":["import CloseIcon from '@mui/icons-material/Close';\nimport {\n Backdrop,\n Box,\n Dialog as MuiDialog,\n DialogActions as MuiDialogActions,\n DialogContent as MuiDialogContent,\n DialogTitle as MuiDialogTitle,\n Drawer,\n IconButton,\n Typography,\n useTheme,\n} from '@mui/material';\nimport React from 'react';\n\nimport { backdropSxOf, variantStylesOf } from './Dialog.styles';\nimport type {\n DialogActionsProps,\n DialogContentProps,\n DialogHeaderProps,\n DialogProps,\n} from './Dialog.types';\n\n/**\n * The dialog body. Consumers that pass raw children (no <DialogContent>) used\n * to render them flush against the paper edges — give them comfortable default\n * padding; <DialogContent>/<DialogActions> users keep managing their own\n * spacing.\n */\nfunction bodyOf(children: React.ReactNode, hasTitle: boolean): React.ReactNode {\n const managesOwnSpacing = React.Children.toArray(children).some(\n (child) =>\n React.isValidElement(child) &&\n (child.type === DialogContent || child.type === DialogActions),\n );\n if (managesOwnSpacing) return children;\n return <Box sx={{ px: 3, pb: 2.5, pt: hasTitle ? 0.5 : 2.5 }}>{children}</Box>;\n}\n\nconst DIALOG_DEFAULTS = {\n variant: 'default',\n size: 'md',\n showCloseButton: true,\n backdrop: true,\n persistent: false,\n glass: false,\n gradient: false,\n glow: false,\n pulse: false,\n borderRadius: 'lg',\n} as const satisfies Partial<DialogProps>;\n\n/** DialogProps with every defaulted field guaranteed present (wide types). */\ntype DialogPropsWithDefaults = DialogProps &\n Required<Pick<DialogProps, keyof typeof DIALOG_DEFAULTS>>;\n\n/**\n * Apply {@link DIALOG_DEFAULTS} exactly like parameter defaults would: only a\n * missing/`undefined` prop falls back (a loop, so the component's cyclomatic\n * complexity doesn't pay one branch per defaulted prop).\n */\nfunction withDialogDefaults(props: DialogProps): DialogPropsWithDefaults {\n const merged: Record<string, unknown> = { ...props };\n for (const [key, value] of Object.entries(DIALOG_DEFAULTS)) {\n if (merged[key] === undefined) merged[key] = value;\n }\n return merged as unknown as DialogPropsWithDefaults;\n}\n\nexport const Dialog: React.FC<DialogProps> = (rawProps) => {\n const {\n children,\n variant,\n size,\n title,\n description,\n showCloseButton,\n backdrop,\n persistent,\n glass,\n gradient,\n glow,\n pulse,\n borderRadius,\n onClose,\n open,\n dataTestId,\n ...props\n } = withDialogDefaults(rawProps);\n const theme = useTheme();\n const testId = dataTestId || 'dialog';\n const paperSx = variantStylesOf(theme, {\n variant, size, borderRadius, glass, gradient, glow, pulse,\n });\n\n const handleClose = (event: object, reason: 'backdropClick' | 'escapeKeyDown') => {\n if (persistent && (reason === 'backdropClick' || reason === 'escapeKeyDown')) {\n return;\n }\n onClose?.();\n };\n\n const header = title ? (\n <DialogHeader\n title={title}\n subtitle={description}\n showCloseButton={showCloseButton}\n onClose={onClose}\n dataTestId={dataTestId}\n />\n ) : null;\n const body = bodyOf(children, Boolean(title));\n\n if (variant === 'drawer') {\n return (\n <Drawer\n anchor=\"right\"\n open={open}\n onClose={onClose}\n data-testid={testId}\n {...props}\n >\n <Box sx={{ ...paperSx, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>\n {header}\n {body}\n </Box>\n </Drawer>\n );\n }\n\n return (\n <MuiDialog\n open={open}\n onClose={handleClose}\n fullScreen={variant === 'fullscreen'}\n BackdropComponent={backdrop ? Backdrop : undefined}\n BackdropProps={{ sx: backdropSxOf(theme, glass) }}\n PaperProps={{ sx: paperSx, 'data-testid': testId }}\n {...props}\n >\n {header}\n {body}\n </MuiDialog>\n );\n};\n\nexport const DialogHeader: React.FC<DialogHeaderProps> = ({\n children,\n title,\n subtitle,\n showCloseButton = true,\n onClose,\n dataTestId,\n}) => {\n if (children) {\n return (\n <Box sx={{ p: 2, borderBottom: '1px solid', borderColor: 'divider' }}>\n {children}\n </Box>\n );\n }\n\n return (\n <MuiDialogTitle\n data-testid={dataTestId ? `${dataTestId}-title` : 'dialog-title'}\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n pb: subtitle ? 1 : 2,\n }}\n >\n <Box>\n <Typography variant=\"h6\" component=\"div\">\n {title}\n </Typography>\n {subtitle && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {subtitle}\n </Typography>\n )}\n </Box>\n {showCloseButton && onClose && (\n <IconButton\n aria-label=\"close\"\n onClick={onClose}\n data-testid={dataTestId ? `${dataTestId}-close` : 'dialog-close'}\n sx={{\n color: 'text.secondary',\n '&:hover': {\n backgroundColor: 'action.hover',\n },\n }}\n >\n <CloseIcon />\n </IconButton>\n )}\n </MuiDialogTitle>\n );\n};\n\n/**\n * Top padding for a body that sits directly under the title.\n *\n * MUI zeroes it there (`.MuiDialogTitle-root + &` on a non-`dividers` content),\n * assuming the title's own bottom padding is the whole gap. That assumption\n * breaks for a body opening with an outlined field: a filled field floats its\n * label ABOVE the input's border box, and `DialogContent` is `overflow-y: auto`\n * — a clipping box — so the label gets sliced in half (FUT-544: \"Tipo\" in the\n * \"Novo insumo\" dialog).\n *\n * Reserve the overhang rather than restore the full 24px: the title already\n * contributes its bottom padding, so a shrunk label's `translate(…, -9px)` is\n * all that is missing. 12px clears it and leaves the gap visually tight.\n */\nconst TITLED_BODY_PADDING_TOP = 1.5;\n\n/**\n * `.MuiDialogTitle-root + &` is `(0,2,0)`-specific and a plain `sx` entry is\n * `(0,1,0)`, so the padding above only survives the cascade by naming the class\n * again — `(0,3,0)`. Scoped to the title-following case so an untitled dialog\n * keeps MUI's roomier default.\n */\nconst TITLED_BODY_SELECTOR = '.MuiDialogTitle-root + &.MuiDialogContent-root';\n\nexport const DialogContent: React.FC<DialogContentProps> = ({\n children,\n dividers = false,\n dense = false,\n dataTestId,\n ...props\n}) => (\n <MuiDialogContent\n data-testid={dataTestId ? `${dataTestId}-content` : 'dialog-content'}\n dividers={dividers}\n sx={{\n padding: dense ? 1.5 : 3,\n [TITLED_BODY_SELECTOR]: { paddingTop: TITLED_BODY_PADDING_TOP },\n '&.MuiDialogContent-dividers': {\n borderTop: dividers ? '1px solid' : 'none',\n borderBottom: dividers ? '1px solid' : 'none',\n borderColor: 'divider',\n },\n }}\n {...props}\n >\n {children}\n </MuiDialogContent>\n );\n\nexport const DialogActions: React.FC<DialogActionsProps> = ({\n children,\n alignment = 'right',\n spacing = 1,\n dataTestId,\n ...props\n}) => {\n const getJustifyContent = () => {\n switch (alignment) {\n case 'left': return 'flex-start';\n case 'center': return 'center';\n case 'right': return 'flex-end';\n case 'space-between': return 'space-between';\n default: return 'flex-end';\n }\n };\n\n return (\n <MuiDialogActions\n data-testid={dataTestId ? `${dataTestId}-actions` : 'dialog-actions'}\n sx={{\n justifyContent: getJustifyContent(),\n gap: spacing,\n p: 2,\n }}\n {...props}\n >\n {children}\n </MuiDialogActions>\n );\n};","import type { SxProps, Theme } from '@mui/material';\nimport { alpha, keyframes } from '@mui/material';\n\nimport { dynamicViewportHeight } from '../../../utils/viewport';\nimport type { DialogProps } from './Dialog.types';\n\n/**\n * Paper/backdrop styling for the Dialog component (FUT-181 gate cleanup):\n * pure helpers so `Dialog.tsx` stays within the size/complexity budget.\n */\n\n// Define pulse animation\nconst pulseAnimation = keyframes`\n 0% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 1;\n }\n 70% {\n box-shadow: 0 0 0 20px currentColor;\n opacity: 0;\n }\n 100% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 0;\n }\n`;\n\n/** Style toggles that shape the dialog paper (extracted so each fn stays small). */\ninterface VariantStyleOptions {\n variant: NonNullable<DialogProps['variant']>;\n size: NonNullable<DialogProps['size']>;\n borderRadius: NonNullable<DialogProps['borderRadius']>;\n glass: boolean;\n gradient: boolean;\n glow: boolean;\n pulse: boolean;\n}\n\nfunction borderRadiusOf(theme: Theme, borderRadius: VariantStyleOptions['borderRadius']) {\n switch (borderRadius) {\n case 'none': return 0;\n case 'sm': return theme.spacing(0.5);\n case 'md': return theme.spacing(1);\n case 'xl': return theme.spacing(3);\n case 'lg':\n default: return theme.spacing(2);\n }\n}\n\nfunction maxWidthOf(size: VariantStyleOptions['size']): number {\n switch (size) {\n case 'xs': return 400;\n case 'sm': return 600;\n case 'lg': return 1000;\n case 'xl': return 1200;\n case 'md':\n default: return 800;\n }\n}\n\nfunction baseStylesOf(theme: Theme, opts: VariantStyleOptions) {\n return {\n borderRadius: borderRadiusOf(theme, opts.borderRadius),\n maxWidth: maxWidthOf(opts.size),\n width: '90vw',\n margin: theme.spacing(2),\n transition: theme.transitions.create(\n ['box-shadow', 'background-color', 'backdrop-filter'],\n { duration: theme.transitions.duration.standard },\n ),\n };\n}\n\nfunction glowStylesOf(theme: Theme, glow: boolean) {\n return glow ? { boxShadow: `0 0 40px ${alpha(theme.palette.primary.main, 0.3)}` } : {};\n}\n\nfunction pulseStylesOf(theme: Theme, pulse: boolean) {\n if (!pulse) return {};\n return {\n position: 'relative' as const,\n '&::after': {\n content: '\"\"',\n position: 'absolute' as const,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n borderRadius: 'inherit',\n backgroundColor: theme.palette.primary.main,\n opacity: 0.3,\n animation: `${pulseAnimation} 2s infinite`,\n pointerEvents: 'none' as const,\n zIndex: -1,\n },\n };\n}\n\n/** The default variant's paper: optional gradient/glass over the base styles. */\nfunction defaultVariantStyles(theme: Theme, opts: VariantStyleOptions) {\n const gradientStyles = opts.gradient\n ? {\n background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.1)}, ${alpha(theme.palette.secondary.main, 0.1)})`,\n backdropFilter: 'blur(10px)',\n }\n : {};\n return {\n ...gradientStyles,\n backgroundColor: opts.glass\n ? alpha(theme.palette.background.paper, 0.1)\n : theme.palette.background.paper,\n backdropFilter: opts.glass ? 'blur(20px)' : 'none',\n border: opts.glass ? `1px solid ${alpha(theme.palette.primary.main, 0.2)}` : 'none',\n };\n}\n\nexport function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProps<Theme> {\n const decorations = {\n ...glowStylesOf(theme, opts.glow),\n ...pulseStylesOf(theme, opts.pulse),\n };\n switch (opts.variant) {\n case 'glass':\n return {\n ...baseStylesOf(theme, opts),\n ...decorations,\n backgroundColor: alpha(theme.palette.background.paper, 0.1),\n backdropFilter: 'blur(20px)',\n border: `1px solid ${alpha(theme.palette.primary.main, 0.2)}`,\n boxShadow: `0 8px 32px ${alpha(theme.palette.common.black, 0.1)}`,\n };\n case 'fullscreen':\n return {\n borderRadius: 0,\n margin: 0,\n width: '100vw',\n // `100dvh`, not `100vh` — see `dynamicViewportHeight`.\n ...dynamicViewportHeight('height'),\n maxWidth: 'none',\n maxHeight: 'none',\n ...decorations,\n };\n case 'drawer': {\n const radius = borderRadiusOf(theme, opts.borderRadius);\n return {\n borderRadius: `${radius}px 0 0 ${radius}px`,\n margin: 0,\n width: maxWidthOf(opts.size),\n ...dynamicViewportHeight('height'),\n maxHeight: 'none',\n position: 'absolute' as const,\n right: 0,\n ...decorations,\n };\n }\n default:\n return {\n ...baseStylesOf(theme, opts),\n ...decorations,\n ...defaultVariantStyles(theme, opts),\n };\n }\n}\n\nexport function backdropSxOf(theme: Theme, glass: boolean) {\n return {\n backgroundColor: glass\n ? alpha(theme.palette.common.black, 0.2)\n : alpha(theme.palette.common.black, 0.5),\n backdropFilter: glass ? 'blur(8px)' : 'none',\n };\n}\n\n"],"mappings":"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","names":[]}