@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.
- package/dist/{chunk-U3J55YPN.js → chunk-GSEAUMCS.js} +18 -6
- package/dist/chunk-GSEAUMCS.js.map +1 -0
- package/dist/data-display/DataViews.js +1 -1
- package/dist/feedback/Dialog.js +1 -1
- package/dist/navigation/AppHeader.js +1 -1
- package/dist/social-login-button.js +22 -13
- package/dist/social-login-button.js.map +1 -1
- package/dist/types/components/feedback/Dialog/Dialog.d.ts.map +1 -1
- package/dist/types/social-login-button/social-login-button.d.ts +10 -1
- package/dist/types/social-login-button/social-login-button.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/feedback/Dialog/Dialog.md +40 -1
- package/src/components/feedback/Dialog/Dialog.tsx +50 -7
- package/src/social-login-button/social-login-button.tsx +18 -2
- package/dist/chunk-U3J55YPN.js.map +0 -1
|
@@ -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
|
-
|
|
172
|
-
|
|
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-
|
|
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":[]}
|
package/dist/feedback/Dialog.js
CHANGED
|
@@ -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
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
/* @__PURE__ */
|
|
149
|
-
|
|
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%'
|
|
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;
|
|
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;
|
|
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": "
|
|
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.
|
|
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
|
-
|
|
32
|
-
|
|
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
|
-
|
|
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%'
|
|
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":[]}
|