@mrshmllw/smores-react 16.4.0 → 16.6.0
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/Alert/Alert.js +1 -1
- package/dist/Alert/Alert.js.map +1 -1
- package/dist/Button/Button.d.ts +17 -2
- package/dist/Button/Button.js +27 -7
- package/dist/Button/Button.js.map +1 -1
- package/dist/Button/index.d.ts +1 -0
- package/dist/Button/index.js.map +1 -1
- package/dist/Dropdown/Dropdown.d.ts +5 -1
- package/dist/Dropdown/Dropdown.js +57 -48
- package/dist/Dropdown/Dropdown.js.map +1 -1
- package/dist/Modal/Modal.d.ts +15 -0
- package/dist/Modal/Modal.js +49 -11
- package/dist/Modal/Modal.js.map +1 -1
- package/dist/PromoCard/PromoCard.js +5 -4
- package/dist/PromoCard/PromoCard.js.map +1 -1
- package/dist/Table/types.d.ts +1 -1
- package/dist/Table/types.js.map +1 -1
- package/dist/fields/Field/Field.d.ts +2 -0
- package/dist/fields/Field/Field.js.map +1 -1
- package/dist/fields/components/InternalField.d.ts +5 -1
- package/dist/fields/components/InternalField.js +8 -3
- package/dist/fields/components/InternalField.js.map +1 -1
- package/dist/fields/components/fieldStyles.d.ts +17 -0
- package/dist/fields/components/fieldStyles.js +39 -0
- package/dist/fields/components/fieldStyles.js.map +1 -0
- package/package.json +2 -2
package/dist/Alert/Alert.js
CHANGED
|
@@ -41,7 +41,7 @@ export const Alert = ({ type = 'info', title, message, isDismissible = false, ct
|
|
|
41
41
|
const backgroundColor = resolveToThemeColor(typeConfig[type].backgroundColor, theme);
|
|
42
42
|
const accentColor = resolveToThemeColor(typeConfig[type].accentColor, theme);
|
|
43
43
|
const [alertClosed, setAlertClosed] = useState(false);
|
|
44
|
-
return (_jsxs(StyledAlert, { $backgroundColor: backgroundColor, $accentColor: accentColor, $alertClosed: alertClosed, $maxWidth: maxWidth, ...marginProps, children: [_jsx(IconContainer, { $size: 16, style: { margin: '2px' }, children: _jsx(FontAwesomeIcon, { icon: typeConfig[type].icon, color: theme.color.icon.base }) }), _jsxs(Box, { flex: true, direction: "row", justifyContent: "space-between", alignItems: "flex-start", width: "100%", gap: "space.100", children: [_jsxs(Box, { maxWidth: "512px", children: [title && (_jsx(Text, { mb: "space.050", typo: "headline-regular", children: title })), typeof message === 'string' ? (_jsx(Text, { typo: "body-small", mb: ctaType && '8px', children: message })) : (message), ctaType === 'button' && typeof ctaAction === 'function' && (_jsx(Button, {
|
|
44
|
+
return (_jsxs(StyledAlert, { $backgroundColor: backgroundColor, $accentColor: accentColor, $alertClosed: alertClosed, $maxWidth: maxWidth, ...marginProps, children: [_jsx(IconContainer, { $size: 16, style: { margin: '2px' }, children: _jsx(FontAwesomeIcon, { icon: typeConfig[type].icon, color: theme.color.icon.base }) }), _jsxs(Box, { flex: true, direction: "row", justifyContent: "space-between", alignItems: "flex-start", width: "100%", gap: "space.100", children: [_jsxs(Box, { maxWidth: "512px", children: [title && (_jsx(Text, { mb: "space.050", typo: "headline-regular", children: title })), typeof message === 'string' ? (_jsx(Text, { typo: "body-small", mb: ctaType && '8px', children: message })) : (message), ctaType === 'button' && typeof ctaAction === 'function' && (_jsx(Button, { size: "small", variant: "neutral", onClick: () => ctaAction(), children: ctaLabel })), ctaType === 'link' && typeof ctaAction === 'string' && (_jsx(Link, { href: ctaAction, children: ctaLabel }))] }), isDismissible && (_jsx(IconContainer, { as: "button", type: "button", title: "icon-button", $size: 16, style: { cursor: 'pointer' }, onClick: () => setAlertClosed(true), children: _jsx(FontAwesomeIcon, { icon: faXmark, color: theme.color.icon.base }) }))] })] }));
|
|
45
45
|
};
|
|
46
46
|
const StyledAlert = styled(Box)(({ $backgroundColor, $accentColor, $alertClosed, $maxWidth }) => css `
|
|
47
47
|
display: flex;
|
package/dist/Alert/Alert.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Alert.js","sourceRoot":"","sources":["../../src/Alert/Alert.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Alert.js","sourceRoot":"","sources":["../../src/Alert/Alert.tsx"],"names":[],"mappings":"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","sourcesContent":["import { FC, ReactElement, useState } from 'react'\nimport styled, { css, useTheme } from 'styled-components'\n\nimport { MarginProps } from '../utils/space'\nimport { NewColor, resolveToThemeColor } from '../ThemeProvider/utils/colourMap'\n\nimport { Box } from '../Box'\nimport { Text } from '../Text'\nimport { Button } from '../Button'\nimport { Link } from '../Link'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport {\n faCircleInfo,\n faTriangleExclamation,\n faCircleExclamation,\n faCircleCheck,\n faXmark,\n} from '@awesome.me/kit-46ca99185c/icons/classic/regular'\n\nimport { IconDefinition } from '@fortawesome/fontawesome-svg-core'\nimport { IconContainer } from '../sharedStyles/shared.styles'\n\ntype AlertType = 'info' | 'fallback' | 'notice' | 'negative' | 'positive'\n\ntype CtaProps =\n | {\n ctaType: 'button'\n ctaAction: () => void\n ctaLabel: string\n }\n | {\n ctaType: 'link'\n ctaAction: string\n ctaLabel: string\n }\n | {\n ctaType?: undefined\n ctaAction?: undefined\n ctaLabel?: undefined\n }\n\nexport type AlertProps = {\n type?: AlertType\n title?: string\n message: string | ReactElement<unknown>\n isDismissible?: boolean\n maxWidth?: string\n} & CtaProps &\n MarginProps\n\ntype AlertTypeConfig = {\n backgroundColor: NewColor\n accentColor: NewColor\n icon: IconDefinition\n}\n\nconst typeConfig: Record<AlertType, AlertTypeConfig> = {\n info: {\n backgroundColor: 'color.feedback.informative.100',\n accentColor: 'color.feedback.informative.200',\n icon: faCircleInfo,\n },\n fallback: {\n backgroundColor: 'color.surface.base.100',\n accentColor: 'color.surface.base.400',\n icon: faCircleInfo,\n },\n notice: {\n backgroundColor: 'color.feedback.notice.100',\n accentColor: 'color.feedback.notice.200',\n icon: faTriangleExclamation,\n },\n negative: {\n backgroundColor: 'color.feedback.negative.100',\n accentColor: 'color.feedback.negative.200',\n icon: faCircleExclamation,\n },\n positive: {\n backgroundColor: 'color.feedback.positive.100',\n accentColor: 'color.feedback.positive.200',\n icon: faCircleCheck,\n },\n}\n\nexport const Alert: FC<AlertProps> = ({\n type = 'info',\n title,\n message,\n isDismissible = false,\n ctaType,\n ctaAction,\n ctaLabel,\n maxWidth = '512px',\n ...marginProps\n}) => {\n const theme = useTheme()\n\n const backgroundColor = resolveToThemeColor(\n typeConfig[type].backgroundColor,\n theme,\n )\n const accentColor = resolveToThemeColor(typeConfig[type].accentColor, theme)\n const [alertClosed, setAlertClosed] = useState(false)\n\n return (\n <StyledAlert\n $backgroundColor={backgroundColor}\n $accentColor={accentColor}\n $alertClosed={alertClosed}\n $maxWidth={maxWidth}\n {...marginProps}\n >\n <IconContainer $size={16} style={{ margin: '2px' }}>\n <FontAwesomeIcon\n icon={typeConfig[type].icon}\n color={theme.color.icon.base}\n />\n </IconContainer>\n <Box\n flex\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"flex-start\"\n width=\"100%\"\n gap=\"space.100\"\n >\n <Box maxWidth=\"512px\">\n {title && (\n <Text mb=\"space.050\" typo=\"headline-regular\">\n {title}\n </Text>\n )}\n {typeof message === 'string' ? (\n <Text typo=\"body-small\" mb={ctaType && '8px'}>\n {message}\n </Text>\n ) : (\n message\n )}\n {ctaType === 'button' && typeof ctaAction === 'function' && (\n <Button size=\"small\" variant=\"neutral\" onClick={() => ctaAction()}>\n {ctaLabel}\n </Button>\n )}\n {ctaType === 'link' && typeof ctaAction === 'string' && (\n <Link href={ctaAction}>{ctaLabel}</Link>\n )}\n </Box>\n {isDismissible && (\n <IconContainer\n as=\"button\"\n type=\"button\"\n title=\"icon-button\"\n $size={16}\n style={{ cursor: 'pointer' }}\n onClick={() => setAlertClosed(true)}\n >\n <FontAwesomeIcon icon={faXmark} color={theme.color.icon.base} />\n </IconContainer>\n )}\n </Box>\n </StyledAlert>\n )\n}\n\ninterface IStyledAlert {\n $backgroundColor: string\n $accentColor: string\n $alertClosed: boolean\n $maxWidth?: string\n}\n\nconst StyledAlert = styled(Box)<IStyledAlert>(\n ({ $backgroundColor, $accentColor, $alertClosed, $maxWidth }) => css`\n display: flex;\n width: 100%;\n max-width: ${$maxWidth};\n min-width: min-content;\n padding: 12px 12px 12px 20px;\n align-items: flex-start;\n gap: ${({ theme }) => theme.space[100]};\n border-radius: 8px 16px 16px 8px;\n background: ${$backgroundColor};\n position: relative;\n display: ${$alertClosed ? 'none' : 'flex'};\n\n &:before {\n width: 8px;\n height: 100%;\n position: absolute;\n background: ${$accentColor};\n content: '';\n top: 0;\n left: 0;\n border-radius: 16px 0 0 16px;\n }\n `,\n)\n"]}
|
package/dist/Button/Button.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ButtonHTMLAttributes, FC, FormEvent, ReactNode } from 'react';
|
|
2
2
|
import { Icons } from '../Icon';
|
|
3
3
|
import { MarginProps } from '../utils/space';
|
|
4
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'neutral' | 'tertiary';
|
|
5
|
+
export type ButtonSize = 'regular' | 'small';
|
|
4
6
|
type Props = {
|
|
5
7
|
children: ReactNode;
|
|
6
8
|
id?: string;
|
|
@@ -8,13 +10,26 @@ type Props = {
|
|
|
8
10
|
disabled?: boolean;
|
|
9
11
|
handleClick?: (e: FormEvent<HTMLButtonElement>) => void;
|
|
10
12
|
loading?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Visual style of the button:
|
|
15
|
+
* - `primary`: the main action on a screen
|
|
16
|
+
* - `secondary`: supporting or alternative actions
|
|
17
|
+
* - `neutral`: as secondary, for when it lacks contrast with the background
|
|
18
|
+
* - `tertiary`: low-emphasis, text-only actions, e.g. "Skip" or "Cancel"
|
|
19
|
+
*/
|
|
20
|
+
variant?: ButtonVariant;
|
|
21
|
+
size?: ButtonSize;
|
|
22
|
+
/** @deprecated Use `variant="primary"` */
|
|
11
23
|
primary?: boolean;
|
|
24
|
+
/** @deprecated Use `variant="secondary"` */
|
|
12
25
|
secondary?: boolean;
|
|
13
|
-
/**
|
|
26
|
+
/** @deprecated Use `variant="tertiary"` */
|
|
14
27
|
tertiary?: boolean;
|
|
28
|
+
/** @deprecated Use `variant="neutral"` */
|
|
15
29
|
fallbackStyle?: boolean;
|
|
16
|
-
/** Legacy underlined text style. Prefer `tertiary` for new low-emphasis actions */
|
|
30
|
+
/** Legacy underlined text style. Prefer `variant="tertiary"` for new low-emphasis actions */
|
|
17
31
|
textBtn?: boolean;
|
|
32
|
+
/** @deprecated Use `size="small"` */
|
|
18
33
|
smallButton?: boolean;
|
|
19
34
|
icon?: Icons;
|
|
20
35
|
iconComponent?: ReactNode;
|
package/dist/Button/Button.js
CHANGED
|
@@ -5,20 +5,40 @@ import { Box } from '../Box';
|
|
|
5
5
|
import { Icon as IconComponent } from '../Icon';
|
|
6
6
|
import { Loader } from '../Loader';
|
|
7
7
|
import { focusOutlineStyle } from '../utils/focusOutline';
|
|
8
|
+
import { useDeprecatedWarning } from '../utils/deprecated';
|
|
8
9
|
export const Button = forwardRef((props, ref) => {
|
|
9
|
-
const { children, id, className = '', disabled = false, handleClick, loading = false, primary = false, secondary = false, tertiary = false, fallbackStyle = false, textBtn = false, smallButton = false, icon, iconComponent, trailingIcon = false, forcedWidth = '', form, type, ...otherProps } = props;
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const { children, id, className = '', disabled = false, handleClick, loading = false, variant, size, primary = false, secondary = false, tertiary = false, fallbackStyle = false, textBtn = false, smallButton = false, icon, iconComponent, trailingIcon = false, forcedWidth = '', form, type, ...otherProps } = props;
|
|
11
|
+
useDeprecatedWarning({
|
|
12
|
+
enabled: primary || secondary || tertiary || fallbackStyle || smallButton,
|
|
13
|
+
title: 'Button',
|
|
14
|
+
message: 'The primary, secondary, tertiary, fallbackStyle and smallButton props are deprecated. Use variant="primary" | "secondary" | "neutral" | "tertiary" and size="regular" | "small" instead.',
|
|
15
|
+
});
|
|
16
|
+
// Legacy props resolve in the order their styles used to override each other.
|
|
17
|
+
// Primary is the default, except for the legacy text button which has no variant
|
|
18
|
+
const resolvedVariant = variant ??
|
|
19
|
+
(fallbackStyle
|
|
20
|
+
? 'neutral'
|
|
21
|
+
: tertiary
|
|
22
|
+
? 'tertiary'
|
|
23
|
+
: secondary
|
|
24
|
+
? 'secondary'
|
|
25
|
+
: primary || !textBtn
|
|
26
|
+
? 'primary'
|
|
27
|
+
: undefined);
|
|
28
|
+
const isSmall = size ? size === 'small' : smallButton;
|
|
29
|
+
const isTertiary = resolvedVariant === 'tertiary';
|
|
12
30
|
// Icon-only buttons drop the gap so the icon stays centred
|
|
13
31
|
// React renders nothing for null, undefined, booleans and empty strings
|
|
14
32
|
const hasLabel = children != null && typeof children !== 'boolean' && children !== '';
|
|
15
33
|
const iconToRender = iconComponent ? (_jsx(CustomIconContainer, { children: iconComponent })) : icon ? (_jsx(IconComponent, { render: icon, size: iconSize,
|
|
16
34
|
// Matches the label, which tertiary dims by colour rather than opacity when disabled
|
|
17
|
-
color:
|
|
18
|
-
|
|
35
|
+
color: isTertiary && disabled
|
|
36
|
+
? 'color.icon.nonEssential'
|
|
37
|
+
: 'color.icon.contrast' })) : null;
|
|
38
|
+
return (_jsxs(Container, { forwardedAs: "button", id: id, className: className, disabled: disabled || loading, onClick: handleClick, $loading: loading, $primary: resolvedVariant === 'primary', $secondary: resolvedVariant === 'secondary', $tertiary: isTertiary, $neutral: resolvedVariant === 'neutral', $textBtn: textBtn, $smallButton: isSmall, $trailingIcon: trailingIcon, $forcedWidth: forcedWidth, ...(form ? { form } : {}), type: type, ...otherProps, ref: ref, children: [loading && (_jsx(LoaderContainer, { children: _jsx(Loader, { color: "color.icon.base", height: "16" }) })), _jsxs(ContentContainer, { $loading: loading, $hasLabel: hasLabel, children: [!trailingIcon && iconToRender ? iconToRender : null, _jsx(ChildrenContainer, { className: "childrenContainer", children: children }), trailingIcon && iconToRender ? iconToRender : null] })] }));
|
|
19
39
|
});
|
|
20
40
|
Button.displayName = 'Button';
|
|
21
|
-
const Container = styled(Box)(({ disabled, $loading, $primary, $secondary, $tertiary, $forcedWidth, $
|
|
41
|
+
const Container = styled(Box)(({ disabled, $loading, $primary, $secondary, $tertiary, $forcedWidth, $neutral, $textBtn, $smallButton, }) => css `
|
|
22
42
|
position: relative;
|
|
23
43
|
background-color: ${({ theme }) => theme.color.interactive.primary.base};
|
|
24
44
|
box-shadow: none;
|
|
@@ -75,7 +95,7 @@ const Container = styled(Box)(({ disabled, $loading, $primary, $secondary, $tert
|
|
|
75
95
|
color: ${({ theme }) => theme.color.text.nonEssential};
|
|
76
96
|
`}
|
|
77
97
|
`}
|
|
78
|
-
${$
|
|
98
|
+
${$neutral &&
|
|
79
99
|
css `
|
|
80
100
|
background-color: ${({ theme }) => theme.color.interactive.neutral.subtle.base};
|
|
81
101
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/Button/Button.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n ButtonHTMLAttributes,\n FC,\n FormEvent,\n ReactNode,\n forwardRef,\n} from 'react'\nimport styled, { css } from 'styled-components'\n\nimport { TransientProps } from '../utils/utilTypes'\nimport { Box } from '../Box'\nimport { Icon as IconComponent, Icons } from '../Icon'\n\nimport { Loader } from '../Loader'\nimport { focusOutlineStyle } from '../utils/focusOutline'\nimport { MarginProps } from '../utils/space'\n\ntype Props = {\n children: ReactNode\n id?: string\n className?: string\n disabled?: boolean\n handleClick?: (e: FormEvent<HTMLButtonElement>) => void\n loading?: boolean\n primary?: boolean\n secondary?: boolean\n /** Low-emphasis, text-only action, e.g. \"Skip\" or \"Cancel\" */\n tertiary?: boolean\n fallbackStyle?: boolean\n /** Legacy underlined text style. Prefer `tertiary` for new low-emphasis actions */\n textBtn?: boolean\n smallButton?: boolean\n icon?: Icons\n iconComponent?: ReactNode\n trailingIcon?: boolean\n forcedWidth?: string\n form?: string\n}\n\nexport type ButtonProps = Props &\n MarginProps &\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'>\n\nexport const Button: FC<ButtonProps> = forwardRef<\n HTMLButtonElement,\n ButtonProps\n>((props, ref) => {\n const {\n children,\n id,\n className = '',\n disabled = false,\n handleClick,\n loading = false,\n primary = false,\n secondary = false,\n tertiary = false,\n fallbackStyle = false,\n textBtn = false,\n smallButton = false,\n icon,\n iconComponent,\n trailingIcon = false,\n forcedWidth = '',\n form,\n type,\n ...otherProps\n } = props\n\n // Primary is the default type, so an untyped button gets Primary's hover and pressed states too\n const isPrimary =\n primary || !(secondary || tertiary || fallbackStyle || textBtn)\n\n // Icon-only buttons drop the gap so the icon stays centred\n // React renders nothing for null, undefined, booleans and empty strings\n const hasLabel =\n children != null && typeof children !== 'boolean' && children !== ''\n\n const iconToRender = iconComponent ? (\n <CustomIconContainer>{iconComponent}</CustomIconContainer>\n ) : icon ? (\n <IconComponent\n render={icon}\n size={iconSize}\n // Matches the label, which tertiary dims by colour rather than opacity when disabled\n color={\n tertiary && disabled ? 'color.icon.nonEssential' : 'color.icon.contrast'\n }\n />\n ) : null\n\n return (\n <Container\n forwardedAs=\"button\"\n id={id}\n className={className}\n disabled={disabled || loading}\n onClick={handleClick}\n $loading={loading}\n $primary={isPrimary}\n $secondary={secondary}\n $tertiary={tertiary}\n $fallbackStyle={fallbackStyle}\n $textBtn={textBtn}\n $smallButton={smallButton}\n $trailingIcon={trailingIcon}\n $forcedWidth={forcedWidth}\n {...(form ? { form } : {})}\n type={type}\n {...otherProps}\n ref={ref}\n >\n {loading && (\n <LoaderContainer>\n <Loader color=\"color.icon.base\" height=\"16\" />\n </LoaderContainer>\n )}\n <ContentContainer $loading={loading} $hasLabel={hasLabel}>\n {!trailingIcon && iconToRender ? iconToRender : null}\n <ChildrenContainer className=\"childrenContainer\">\n {children}\n </ChildrenContainer>\n {trailingIcon && iconToRender ? iconToRender : null}\n </ContentContainer>\n </Container>\n )\n})\n\nButton.displayName = 'Button'\n\ntype IButton = TransientProps<\n Required<\n Pick<\n ButtonProps,\n | 'primary'\n | 'secondary'\n | 'tertiary'\n | 'forcedWidth'\n | 'fallbackStyle'\n | 'textBtn'\n | 'trailingIcon'\n | 'smallButton'\n >\n >\n> & {\n $loading: NonNullable<ButtonProps['loading']>\n disabled: boolean\n}\n\nconst Container = styled(Box)<IButton>(\n ({\n disabled,\n $loading,\n $primary,\n $secondary,\n $tertiary,\n $forcedWidth,\n $fallbackStyle,\n $textBtn,\n $smallButton,\n }) => css`\n position: relative;\n background-color: ${({ theme }) => theme.color.interactive.primary.base};\n box-shadow: none;\n color: ${({ theme }) => theme.color.text.contrast};\n padding: 0 20px;\n outline: none;\n border-radius: 10000px;\n font-weight: ${({ theme }) => theme.fontWeight[500]};\n cursor: ${disabled || $loading ? 'not-allowed' : 'pointer'};\n line-height: 100%;\n font-size: 16px;\n opacity: ${disabled ? '0.5' : '1'};\n width: ${$forcedWidth ? $forcedWidth : 'auto'};\n\n ${focusOutlineStyle}\n\n ${\n $primary &&\n css`\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) && theme.color.interactive.primary.hover};\n }\n &:active {\n background-color: ${({ theme }) =>\n theme.color.interactive.primary.selected};\n }\n `\n }\n\n ${\n $secondary &&\n css`\n background-color: ${({ theme }) =>\n theme.color.interactive.secondary.base};\n\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) && theme.color.interactive.secondary.hover};\n }\n &:active {\n background-color: ${({ theme }) =>\n theme.color.interactive.secondary.selected};\n }\n `\n }\n ${\n $tertiary &&\n css`\n background-color: transparent;\n opacity: 1;\n\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) &&\n theme.color.interactive.neutral.subtle.hover};\n }\n &:active {\n background-color: ${({ theme }) =>\n !(disabled || $loading) &&\n theme.color.interactive.neutral.subtle.selected};\n }\n\n ${\n disabled &&\n css`\n color: ${({ theme }) => theme.color.text.nonEssential};\n `\n }\n `\n }\n ${\n $fallbackStyle &&\n css`\n background-color: ${({ theme }) => theme.color.interactive.neutral.subtle.base};\n\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) &&\n theme.color.interactive.neutral.subtle.hover};\n }\n &:active {\n background-color: ${({ theme }) =>\n theme.color.interactive.neutral.subtle.selected};\n }\n `\n }\n ${\n $smallButton &&\n css`\n padding: 0 12px;\n min-width: 54px;\n\n .childrenContainer {\n padding: 8px 0;\n }\n `\n }\n ${\n $textBtn &&\n css`\n background-color: transparent;\n padding: 0;\n border-radius: 0;\n text-decoration: underline;\n\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) && theme.color.interactive.primary.hover};\n }\n &:active {\n background-color: transparent;\n color: ${({ theme }) => theme.color.text.subtle};\n }\n\n ${\n $smallButton &&\n css`\n font-size: 14px;\n\n .childrenContainer {\n padding: 9px 0;\n }\n `\n }\n `\n }\n `,\n)\n\nconst LoaderContainer = styled.div`\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n`\n\nconst ContentContainer = styled.div<{ $loading: boolean; $hasLabel: boolean }>`\n display: flex;\n align-items: center;\n justify-content: center;\n gap: ${({ $hasLabel }) => ($hasLabel ? '4px' : '0')};\n opacity: ${({ $loading }) => ($loading ? '0' : '1')};\n`\n\nconst iconSize = 20\n\n// Figma icons use Font Awesome's square bounding box, in which the glyph's em height\n// takes up 80% of the box, so custom (Font Awesome) icons are drawn at that size\nconst CustomIconContainer = styled.span`\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: ${iconSize}px;\n height: ${iconSize}px;\n\n svg {\n width: 100%;\n height: 80%;\n overflow: visible;\n }\n`\n\nconst ChildrenContainer = styled.div`\n padding: 16px 0;\n`\n"]}
|
|
1
|
+
{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/Button/Button.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n ButtonHTMLAttributes,\n FC,\n FormEvent,\n ReactNode,\n forwardRef,\n} from 'react'\nimport styled, { css } from 'styled-components'\n\nimport { TransientProps } from '../utils/utilTypes'\nimport { Box } from '../Box'\nimport { Icon as IconComponent, Icons } from '../Icon'\n\nimport { Loader } from '../Loader'\nimport { focusOutlineStyle } from '../utils/focusOutline'\nimport { MarginProps } from '../utils/space'\nimport { useDeprecatedWarning } from '../utils/deprecated'\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'neutral' | 'tertiary'\nexport type ButtonSize = 'regular' | 'small'\n\ntype Props = {\n children: ReactNode\n id?: string\n className?: string\n disabled?: boolean\n handleClick?: (e: FormEvent<HTMLButtonElement>) => void\n loading?: boolean\n /**\n * Visual style of the button:\n * - `primary`: the main action on a screen\n * - `secondary`: supporting or alternative actions\n * - `neutral`: as secondary, for when it lacks contrast with the background\n * - `tertiary`: low-emphasis, text-only actions, e.g. \"Skip\" or \"Cancel\"\n */\n variant?: ButtonVariant\n size?: ButtonSize\n /** @deprecated Use `variant=\"primary\"` */\n primary?: boolean\n /** @deprecated Use `variant=\"secondary\"` */\n secondary?: boolean\n /** @deprecated Use `variant=\"tertiary\"` */\n tertiary?: boolean\n /** @deprecated Use `variant=\"neutral\"` */\n fallbackStyle?: boolean\n /** Legacy underlined text style. Prefer `variant=\"tertiary\"` for new low-emphasis actions */\n textBtn?: boolean\n /** @deprecated Use `size=\"small\"` */\n smallButton?: boolean\n icon?: Icons\n iconComponent?: ReactNode\n trailingIcon?: boolean\n forcedWidth?: string\n form?: string\n}\n\nexport type ButtonProps = Props &\n MarginProps &\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'>\n\nexport const Button: FC<ButtonProps> = forwardRef<\n HTMLButtonElement,\n ButtonProps\n>((props, ref) => {\n const {\n children,\n id,\n className = '',\n disabled = false,\n handleClick,\n loading = false,\n variant,\n size,\n primary = false,\n secondary = false,\n tertiary = false,\n fallbackStyle = false,\n textBtn = false,\n smallButton = false,\n icon,\n iconComponent,\n trailingIcon = false,\n forcedWidth = '',\n form,\n type,\n ...otherProps\n } = props\n\n useDeprecatedWarning({\n enabled: primary || secondary || tertiary || fallbackStyle || smallButton,\n title: 'Button',\n message:\n 'The primary, secondary, tertiary, fallbackStyle and smallButton props are deprecated. Use variant=\"primary\" | \"secondary\" | \"neutral\" | \"tertiary\" and size=\"regular\" | \"small\" instead.',\n })\n\n // Legacy props resolve in the order their styles used to override each other.\n // Primary is the default, except for the legacy text button which has no variant\n const resolvedVariant: ButtonVariant | undefined =\n variant ??\n (fallbackStyle\n ? 'neutral'\n : tertiary\n ? 'tertiary'\n : secondary\n ? 'secondary'\n : primary || !textBtn\n ? 'primary'\n : undefined)\n const isSmall = size ? size === 'small' : smallButton\n const isTertiary = resolvedVariant === 'tertiary'\n\n // Icon-only buttons drop the gap so the icon stays centred\n // React renders nothing for null, undefined, booleans and empty strings\n const hasLabel =\n children != null && typeof children !== 'boolean' && children !== ''\n\n const iconToRender = iconComponent ? (\n <CustomIconContainer>{iconComponent}</CustomIconContainer>\n ) : icon ? (\n <IconComponent\n render={icon}\n size={iconSize}\n // Matches the label, which tertiary dims by colour rather than opacity when disabled\n color={\n isTertiary && disabled\n ? 'color.icon.nonEssential'\n : 'color.icon.contrast'\n }\n />\n ) : null\n\n return (\n <Container\n forwardedAs=\"button\"\n id={id}\n className={className}\n disabled={disabled || loading}\n onClick={handleClick}\n $loading={loading}\n $primary={resolvedVariant === 'primary'}\n $secondary={resolvedVariant === 'secondary'}\n $tertiary={isTertiary}\n $neutral={resolvedVariant === 'neutral'}\n $textBtn={textBtn}\n $smallButton={isSmall}\n $trailingIcon={trailingIcon}\n $forcedWidth={forcedWidth}\n {...(form ? { form } : {})}\n type={type}\n {...otherProps}\n ref={ref}\n >\n {loading && (\n <LoaderContainer>\n <Loader color=\"color.icon.base\" height=\"16\" />\n </LoaderContainer>\n )}\n <ContentContainer $loading={loading} $hasLabel={hasLabel}>\n {!trailingIcon && iconToRender ? iconToRender : null}\n <ChildrenContainer className=\"childrenContainer\">\n {children}\n </ChildrenContainer>\n {trailingIcon && iconToRender ? iconToRender : null}\n </ContentContainer>\n </Container>\n )\n})\n\nButton.displayName = 'Button'\n\ntype IButton = TransientProps<\n Required<\n Pick<\n ButtonProps,\n | 'primary'\n | 'secondary'\n | 'tertiary'\n | 'forcedWidth'\n | 'textBtn'\n | 'trailingIcon'\n | 'smallButton'\n >\n >\n> & {\n $neutral: boolean\n $loading: NonNullable<ButtonProps['loading']>\n disabled: boolean\n}\n\nconst Container = styled(Box)<IButton>(\n ({\n disabled,\n $loading,\n $primary,\n $secondary,\n $tertiary,\n $forcedWidth,\n $neutral,\n $textBtn,\n $smallButton,\n }) => css`\n position: relative;\n background-color: ${({ theme }) => theme.color.interactive.primary.base};\n box-shadow: none;\n color: ${({ theme }) => theme.color.text.contrast};\n padding: 0 20px;\n outline: none;\n border-radius: 10000px;\n font-weight: ${({ theme }) => theme.fontWeight[500]};\n cursor: ${disabled || $loading ? 'not-allowed' : 'pointer'};\n line-height: 100%;\n font-size: 16px;\n opacity: ${disabled ? '0.5' : '1'};\n width: ${$forcedWidth ? $forcedWidth : 'auto'};\n\n ${focusOutlineStyle}\n\n ${\n $primary &&\n css`\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) && theme.color.interactive.primary.hover};\n }\n &:active {\n background-color: ${({ theme }) =>\n theme.color.interactive.primary.selected};\n }\n `\n }\n\n ${\n $secondary &&\n css`\n background-color: ${({ theme }) =>\n theme.color.interactive.secondary.base};\n\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) && theme.color.interactive.secondary.hover};\n }\n &:active {\n background-color: ${({ theme }) =>\n theme.color.interactive.secondary.selected};\n }\n `\n }\n ${\n $tertiary &&\n css`\n background-color: transparent;\n opacity: 1;\n\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) &&\n theme.color.interactive.neutral.subtle.hover};\n }\n &:active {\n background-color: ${({ theme }) =>\n !(disabled || $loading) &&\n theme.color.interactive.neutral.subtle.selected};\n }\n\n ${\n disabled &&\n css`\n color: ${({ theme }) => theme.color.text.nonEssential};\n `\n }\n `\n }\n ${\n $neutral &&\n css`\n background-color: ${({ theme }) => theme.color.interactive.neutral.subtle.base};\n\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) &&\n theme.color.interactive.neutral.subtle.hover};\n }\n &:active {\n background-color: ${({ theme }) =>\n theme.color.interactive.neutral.subtle.selected};\n }\n `\n }\n ${\n $smallButton &&\n css`\n padding: 0 12px;\n min-width: 54px;\n\n .childrenContainer {\n padding: 8px 0;\n }\n `\n }\n ${\n $textBtn &&\n css`\n background-color: transparent;\n padding: 0;\n border-radius: 0;\n text-decoration: underline;\n\n &:hover {\n background-color: ${({ theme }) =>\n !(disabled || $loading) && theme.color.interactive.primary.hover};\n }\n &:active {\n background-color: transparent;\n color: ${({ theme }) => theme.color.text.subtle};\n }\n\n ${\n $smallButton &&\n css`\n font-size: 14px;\n\n .childrenContainer {\n padding: 9px 0;\n }\n `\n }\n `\n }\n `,\n)\n\nconst LoaderContainer = styled.div`\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n`\n\nconst ContentContainer = styled.div<{ $loading: boolean; $hasLabel: boolean }>`\n display: flex;\n align-items: center;\n justify-content: center;\n gap: ${({ $hasLabel }) => ($hasLabel ? '4px' : '0')};\n opacity: ${({ $loading }) => ($loading ? '0' : '1')};\n`\n\nconst iconSize = 20\n\n// Figma icons use Font Awesome's square bounding box, in which the glyph's em height\n// takes up 80% of the box, so custom (Font Awesome) icons are drawn at that size\nconst CustomIconContainer = styled.span`\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: ${iconSize}px;\n height: ${iconSize}px;\n\n svg {\n width: 100%;\n height: 80%;\n overflow: visible;\n }\n`\n\nconst ChildrenContainer = styled.div`\n padding: 16px 0;\n`\n"]}
|
package/dist/Button/index.d.ts
CHANGED
package/dist/Button/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA","sourcesContent":["export { Button } from './Button'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA","sourcesContent":["export { Button } from './Button'\nexport type { ButtonProps, ButtonSize, ButtonVariant } from './Button'\n"]}
|
|
@@ -18,7 +18,11 @@ export interface Props extends CommonFieldProps {
|
|
|
18
18
|
frontIcon?: Icons;
|
|
19
19
|
iconComponent?: ReactNode;
|
|
20
20
|
fallbackStyle?: boolean;
|
|
21
|
-
|
|
21
|
+
/** Accessible name, for when there is no visible `label` */
|
|
22
|
+
'aria-label'?: string;
|
|
23
|
+
/** Lets the browser autofill the field, e.g. `honorific-prefix` */
|
|
24
|
+
autoComplete?: string;
|
|
25
|
+
onSelect?: (element: string) => void;
|
|
22
26
|
onBlur?: (e: FocusEvent<HTMLSelectElement>) => void;
|
|
23
27
|
}
|
|
24
28
|
type TruncateProps = {
|
|
@@ -4,18 +4,21 @@ import styled, { css, useTheme } from 'styled-components';
|
|
|
4
4
|
import { Box } from '../Box';
|
|
5
5
|
import { Field } from '../fields/Field';
|
|
6
6
|
import { InputLeadingIconContainer, StyledFrontIcon, } from '../fields/components/CommonInput';
|
|
7
|
+
import { fieldDisabledStyle, fieldFocusAttrs, fieldFocusRing, } from '../fields/components/fieldStyles';
|
|
7
8
|
import { useUniqueId } from '../utils/id';
|
|
8
9
|
import { useControllableState } from '../utils/useControlledState';
|
|
9
10
|
import { IconContainer } from '../sharedStyles/shared.styles';
|
|
10
|
-
import { faChevronDown } from '@awesome.me/kit-46ca99185c/icons/classic/
|
|
11
|
+
import { faChevronDown } from '@awesome.me/kit-46ca99185c/icons/classic/solid';
|
|
11
12
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
12
|
-
export const Dropdown = forwardRef(function Dropdown({ id: idProp, placeholder, showDefaultOption = false, customDefaultOption, name, value: valueProp, defaultValue, disabled = false, list, onSelect, error = false, onInputChange, onBlur, frontIcon, iconComponent, fallbackStyle, ...fieldProps }, ref) {
|
|
13
|
+
export const Dropdown = forwardRef(function Dropdown({ id: idProp, placeholder, showDefaultOption = false, customDefaultOption, name, value: valueProp, defaultValue, disabled = false, list, onSelect, error = false, onInputChange, onBlur, frontIcon, iconComponent, fallbackStyle, required, 'aria-label': ariaLabel, autoComplete, ...fieldProps }, ref) {
|
|
13
14
|
const theme = useTheme();
|
|
14
15
|
const [value, setValue] = useControllableState({
|
|
15
16
|
initialState: defaultValue,
|
|
16
17
|
stateProp: valueProp,
|
|
17
18
|
});
|
|
18
19
|
const id = useUniqueId(idProp);
|
|
20
|
+
const assistiveTextId = `${id}-assistive-text`;
|
|
21
|
+
const errorMsgId = `${id}-error`;
|
|
19
22
|
const hasOptGroups = list.findIndex((item) => !!item.optionGroupLabel) !== -1;
|
|
20
23
|
const dropdownItemsGroups = useMemo(() => {
|
|
21
24
|
const itemsPerGroupLabel = new Map();
|
|
@@ -33,64 +36,70 @@ export const Dropdown = forwardRef(function Dropdown({ id: idProp, placeholder,
|
|
|
33
36
|
}
|
|
34
37
|
return customDefaultOption ?? 'Select an option';
|
|
35
38
|
};
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
// Only reference messages that the field actually renders.
|
|
40
|
+
const describedBy = [
|
|
41
|
+
fieldProps.assistiveText &&
|
|
42
|
+
(!fieldProps.renderAsTitle || fieldProps.label) &&
|
|
43
|
+
assistiveTextId,
|
|
44
|
+
error && fieldProps.errorMsg && errorMsgId,
|
|
45
|
+
]
|
|
46
|
+
.filter(Boolean)
|
|
47
|
+
.join(' ') || undefined;
|
|
48
|
+
const iconToRender = iconComponent ? (_jsx(InputLeadingIconContainer, { $size: 16, $iconColor: theme.color.text.base, children: iconComponent })) : frontIcon ? (_jsx(StyledFrontIcon, { render: frontIcon, color: "color.icon.subtle" })) : null;
|
|
49
|
+
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, required: required, assistiveTextId: assistiveTextId, errorMsgId: errorMsgId, children: _jsxs(Box, { flex: true, alignItems: "center", style: { position: 'relative' }, children: [iconToRender, _jsxs(StyledSelect, { id: id, disabled: disabled || list.length < 1, onChange: (event) => {
|
|
38
50
|
const value = event.currentTarget.value;
|
|
39
51
|
onSelect?.(value);
|
|
40
52
|
onInputChange?.(event);
|
|
41
53
|
setValue(value);
|
|
42
|
-
}, $error: error, ref: ref, onBlur: onBlur, name: name,
|
|
54
|
+
}, $error: error, ref: ref, onBlur: onBlur, name: name, autoComplete: autoComplete, "aria-label": ariaLabel, "aria-invalid": error || undefined, "aria-required": required || undefined, "aria-describedby": describedBy, $frontIcon: !!iconToRender, $fallbackStyle: fallbackStyle, value: value ?? '', children: [_jsx("option", { value: "", hidden: !showDefaultOption, disabled: true, children: defaultOptionLabel() }), dropdownItemsGroups.map((groupItems, i) => hasOptGroups ? (_jsx("optgroup", { label: groupItems[0].optionGroupLabel ?? 'Other', children: groupItems.map((el, j) => (_jsx("option", { value: el.value, children: el.label }, `${i}-${j}`))) }, i)) : (groupItems.map((el, j) => (_jsx("option", { value: el.value, children: el.label }, j)))))] }), _jsx(Caret, { children: _jsx(IconContainer, { $size: 16, children: _jsx(FontAwesomeIcon, { icon: faChevronDown, color: theme.color.icon.subtle }) }) })] }) }));
|
|
43
55
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
// Figma's 32px chevron slot sits 12px from the edge, 16px from the text
|
|
57
|
+
const CHEVRON_INSET = 20;
|
|
58
|
+
const StyledSelect = styled.select.attrs(fieldFocusAttrs)(({ theme, $error, $frontIcon, $fallbackStyle, value }) => {
|
|
59
|
+
const borderColor = (color) => $error ? theme.color.feedback.negative[200] : color;
|
|
60
|
+
return css `
|
|
61
|
+
appearance: none;
|
|
62
|
+
width: 100%;
|
|
63
|
+
height: 48px;
|
|
64
|
+
margin: 0;
|
|
65
|
+
padding: 12px 60px 12px ${$frontIcon ? '42px' : '12px'};
|
|
66
|
+
border: 2px solid ${borderColor(theme.color.border.subtle)};
|
|
67
|
+
border-radius: 12px;
|
|
68
|
+
background-color: ${$fallbackStyle
|
|
69
|
+
? theme.color.surface.base[300]
|
|
70
|
+
: theme.color.background['000']};
|
|
71
|
+
color: ${value === '' ? theme.color.text.subtle : theme.color.text.base};
|
|
72
|
+
font-family: inherit;
|
|
73
|
+
font-size: 16px;
|
|
74
|
+
line-height: 20px;
|
|
75
|
+
text-overflow: ellipsis;
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
outline: none;
|
|
66
78
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
`}
|
|
79
|
+
option,
|
|
80
|
+
optgroup {
|
|
81
|
+
color: ${theme.color.text.base};
|
|
82
|
+
}
|
|
72
83
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
84
|
+
// Hover mustn't override the focus border while the pointer is over a
|
|
85
|
+
// focused field.
|
|
86
|
+
&:hover:not(:disabled):not(:focus) {
|
|
87
|
+
border-color: ${borderColor(theme.color.border.base)};
|
|
88
|
+
}
|
|
77
89
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
:not(:disabled) {
|
|
81
|
-
&:hover,
|
|
82
|
-
&:focus,
|
|
83
|
-
&:focus-visible,
|
|
84
|
-
&:checked {
|
|
85
|
-
border-color: ${({ theme }) => theme.color.icon.nonEssential};
|
|
90
|
+
&:focus {
|
|
91
|
+
border-color: ${borderColor(theme.color.border.contrast)};
|
|
86
92
|
}
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
|
|
94
|
+
${fieldFocusRing}
|
|
95
|
+
${fieldDisabledStyle}
|
|
96
|
+
`;
|
|
97
|
+
});
|
|
89
98
|
const Caret = styled.div `
|
|
90
99
|
position: absolute;
|
|
91
100
|
z-index: 1;
|
|
92
|
-
right:
|
|
101
|
+
right: ${CHEVRON_INSET}px;
|
|
102
|
+
display: flex;
|
|
93
103
|
pointer-events: none;
|
|
94
|
-
color: ${({ theme }) => theme.color.icon.nonEssential};
|
|
95
104
|
`;
|
|
96
105
|
//# sourceMappingURL=Dropdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.js","sourceRoot":"","sources":["../../src/Dropdown/Dropdown.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n FocusEvent,\n FormEvent,\n ForwardedRef,\n forwardRef,\n ReactNode,\n useMemo,\n} from 'react'\nimport styled, { css, useTheme } from 'styled-components'\n\nimport { Box } from '../Box'\nimport { Icons } from '../Icon'\n\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\nimport {\n InputLeadingIconContainer,\n StyledFrontIcon,\n} from '../fields/components/CommonInput'\nimport { useUniqueId } from '../utils/id'\nimport { useControllableState } from '../utils/useControlledState'\nimport { IconContainer } from '../sharedStyles/shared.styles'\nimport { faChevronDown } from '@awesome.me/kit-46ca99185c/icons/classic/regular'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\n\nexport type DropdownItem = {\n optionGroupLabel?: string\n label: string\n value: string\n}\n\nexport interface Props extends CommonFieldProps {\n placeholder?: string\n showDefaultOption?: boolean\n customDefaultOption?: string\n name?: string\n value?: string | null\n defaultValue?: string\n disabled?: boolean\n list: DropdownItem[]\n frontIcon?: Icons\n iconComponent?: ReactNode\n fallbackStyle?: boolean\n onSelect: (element: string) => void\n onBlur?: (e: FocusEvent<HTMLSelectElement>) => void\n}\n\ntype TruncateProps =\n | {\n onSelect: (e: string) => void\n onInputChange?: (e: FormEvent<HTMLSelectElement>) => void\n }\n | {\n onSelect?: (e: string) => void\n onInputChange: (e: FormEvent<HTMLSelectElement>) => void\n }\n\nexport type DropdownProps = Props & TruncateProps\n\nexport const Dropdown = forwardRef(function Dropdown(\n {\n id: idProp,\n placeholder,\n showDefaultOption = false,\n customDefaultOption,\n name,\n value: valueProp,\n defaultValue,\n disabled = false,\n list,\n onSelect,\n error = false,\n onInputChange,\n onBlur,\n frontIcon,\n iconComponent,\n fallbackStyle,\n ...fieldProps\n }: DropdownProps,\n ref: ForwardedRef<HTMLSelectElement>,\n) {\n const theme = useTheme()\n const [value, setValue] = useControllableState({\n initialState: defaultValue,\n stateProp: valueProp,\n })\n const id = useUniqueId(idProp)\n const hasOptGroups = list.findIndex((item) => !!item.optionGroupLabel) !== -1\n\n const dropdownItemsGroups = useMemo(() => {\n const itemsPerGroupLabel = new Map<string, DropdownItem[]>()\n\n list.forEach((item) => {\n const key = item.optionGroupLabel ?? ''\n const group = itemsPerGroupLabel.get(key) ?? []\n\n group.push(item)\n itemsPerGroupLabel.set(key, group)\n })\n\n return Array.from(itemsPerGroupLabel.values())\n }, [list])\n\n const defaultOptionLabel = () => {\n if (!showDefaultOption) {\n return placeholder\n }\n return customDefaultOption ?? 'Select an option'\n }\n\n const iconToRender = iconComponent ? (\n <InputLeadingIconContainer $size={16} $iconColor={theme.color.text.base}>\n {iconComponent}\n </InputLeadingIconContainer>\n ) : frontIcon ? (\n <StyledFrontIcon $disabled={disabled} render={frontIcon} color=\"sesame\" />\n ) : null\n\n return (\n <Field {...fieldProps} htmlFor={id} error={error}>\n <Box flex alignItems=\"center\" style={{ position: 'relative' }}>\n {iconToRender}\n <StyledSelect\n id={id}\n disabled={disabled || list.length < 1}\n onChange={(event) => {\n const value = event.currentTarget.value\n\n onSelect?.(value)\n onInputChange?.(event)\n setValue(value)\n }}\n $error={error}\n ref={ref}\n onBlur={onBlur}\n name={name}\n $frontIcon={frontIcon}\n $fallbackStyle={fallbackStyle}\n value={value ?? ''}\n >\n {hasOptGroups ? (\n <optgroup label={defaultOptionLabel()}>\n <option value=\"\" hidden={!showDefaultOption} disabled>\n {defaultOptionLabel()}\n </option>\n </optgroup>\n ) : (\n <option value=\"\" hidden={!showDefaultOption} disabled>\n {defaultOptionLabel()}\n </option>\n )}\n\n {dropdownItemsGroups.map((groupItems, i) =>\n hasOptGroups ? (\n <optgroup\n key={i}\n label={groupItems[0].optionGroupLabel ?? 'Other'}\n >\n {groupItems.map((el, j) => (\n <option key={`${i}-${j}`} value={el.value}>\n {el.label}\n </option>\n ))}\n </optgroup>\n ) : (\n groupItems.map((el, j) => (\n <option key={j} value={el.value}>\n {el.label}\n </option>\n ))\n ),\n )}\n </StyledSelect>\n <Caret>\n <IconContainer $size={20}>\n <FontAwesomeIcon\n icon={faChevronDown}\n color={theme.color.illustration.neutral[400]}\n />\n </IconContainer>\n </Caret>\n </Box>\n </Field>\n )\n})\n\nconst resetSelect = css`\n border: none;\n border-radius: 0;\n font-size: 16px;\n appearance: none; /* remove default arrow */\n outline: none;\n`\n\ninterface SSelect {\n $error: boolean\n $frontIcon?: string\n $fallbackStyle?: boolean\n value?: string | null\n}\n\nconst StyledSelect = styled.select<SSelect>`\n ${resetSelect}\n width: 100%;\n height: 32px;\n color: ${({ value, theme }) =>\n value === '' ? theme.color.text.subtle : theme.color.text.base};\n cursor: pointer;\n background-color: ${({ $fallbackStyle, theme }) =>\n $fallbackStyle\n ? theme.color.surface.base[300]\n : theme.color.background['000']};\n\n border-radius: 12px;\n padding: 18px 14px;\n border: 2px solid\n ${({ $error, theme }) =>\n $error ? theme.color.feedback.negative[200] : theme.color.border.subtle};\n height: auto;\n\n ${({ $frontIcon }) =>\n $frontIcon &&\n $frontIcon != '' &&\n `\n padding-left: 42px;\n `}\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n ${({ $error }) =>\n !$error &&\n css`\n :not(:disabled) {\n &:hover,\n &:focus,\n &:focus-visible,\n &:checked {\n border-color: ${({ theme }) => theme.color.icon.nonEssential};\n }\n `}\n`\n\nconst Caret = styled.div`\n position: absolute;\n z-index: 1;\n right: 15px;\n pointer-events: none;\n color: ${({ theme }) => theme.color.icon.nonEssential};\n`\n"]}
|
|
1
|
+
{"version":3,"file":"Dropdown.js","sourceRoot":"","sources":["../../src/Dropdown/Dropdown.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n FocusEvent,\n FormEvent,\n ForwardedRef,\n forwardRef,\n ReactNode,\n useMemo,\n} from 'react'\nimport styled, { css, useTheme } from 'styled-components'\n\nimport { Box } from '../Box'\nimport { Icons } from '../Icon'\n\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\nimport {\n InputLeadingIconContainer,\n StyledFrontIcon,\n} from '../fields/components/CommonInput'\nimport {\n fieldDisabledStyle,\n fieldFocusAttrs,\n fieldFocusRing,\n} from '../fields/components/fieldStyles'\nimport { useUniqueId } from '../utils/id'\nimport { useControllableState } from '../utils/useControlledState'\nimport { IconContainer } from '../sharedStyles/shared.styles'\nimport { faChevronDown } from '@awesome.me/kit-46ca99185c/icons/classic/solid'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\n\nexport type DropdownItem = {\n optionGroupLabel?: string\n label: string\n value: string\n}\n\nexport interface Props extends CommonFieldProps {\n placeholder?: string\n showDefaultOption?: boolean\n customDefaultOption?: string\n name?: string\n value?: string | null\n defaultValue?: string\n disabled?: boolean\n list: DropdownItem[]\n frontIcon?: Icons\n iconComponent?: ReactNode\n fallbackStyle?: boolean\n /** Accessible name, for when there is no visible `label` */\n 'aria-label'?: string\n /** Lets the browser autofill the field, e.g. `honorific-prefix` */\n autoComplete?: string\n onSelect?: (element: string) => void\n onBlur?: (e: FocusEvent<HTMLSelectElement>) => void\n}\n\ntype TruncateProps =\n | {\n onSelect: (e: string) => void\n onInputChange?: (e: FormEvent<HTMLSelectElement>) => void\n }\n | {\n onSelect?: (e: string) => void\n onInputChange: (e: FormEvent<HTMLSelectElement>) => void\n }\n\nexport type DropdownProps = Props & TruncateProps\n\nexport const Dropdown = forwardRef(function Dropdown(\n {\n id: idProp,\n placeholder,\n showDefaultOption = false,\n customDefaultOption,\n name,\n value: valueProp,\n defaultValue,\n disabled = false,\n list,\n onSelect,\n error = false,\n onInputChange,\n onBlur,\n frontIcon,\n iconComponent,\n fallbackStyle,\n required,\n 'aria-label': ariaLabel,\n autoComplete,\n ...fieldProps\n }: DropdownProps,\n ref: ForwardedRef<HTMLSelectElement>,\n) {\n const theme = useTheme()\n const [value, setValue] = useControllableState({\n initialState: defaultValue,\n stateProp: valueProp,\n })\n const id = useUniqueId(idProp)\n const assistiveTextId = `${id}-assistive-text`\n const errorMsgId = `${id}-error`\n const hasOptGroups = list.findIndex((item) => !!item.optionGroupLabel) !== -1\n\n const dropdownItemsGroups = useMemo(() => {\n const itemsPerGroupLabel = new Map<string, DropdownItem[]>()\n\n list.forEach((item) => {\n const key = item.optionGroupLabel ?? ''\n const group = itemsPerGroupLabel.get(key) ?? []\n\n group.push(item)\n itemsPerGroupLabel.set(key, group)\n })\n\n return Array.from(itemsPerGroupLabel.values())\n }, [list])\n\n const defaultOptionLabel = () => {\n if (!showDefaultOption) {\n return placeholder\n }\n return customDefaultOption ?? 'Select an option'\n }\n\n // Only reference messages that the field actually renders.\n const describedBy =\n [\n fieldProps.assistiveText &&\n (!fieldProps.renderAsTitle || fieldProps.label) &&\n assistiveTextId,\n error && fieldProps.errorMsg && errorMsgId,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n\n const iconToRender = iconComponent ? (\n <InputLeadingIconContainer $size={16} $iconColor={theme.color.text.base}>\n {iconComponent}\n </InputLeadingIconContainer>\n ) : frontIcon ? (\n <StyledFrontIcon render={frontIcon} color=\"color.icon.subtle\" />\n ) : null\n\n return (\n <Field\n {...fieldProps}\n htmlFor={id}\n error={error}\n required={required}\n assistiveTextId={assistiveTextId}\n errorMsgId={errorMsgId}\n >\n <Box flex alignItems=\"center\" style={{ position: 'relative' }}>\n {iconToRender}\n <StyledSelect\n id={id}\n disabled={disabled || list.length < 1}\n onChange={(event) => {\n const value = event.currentTarget.value\n\n onSelect?.(value)\n onInputChange?.(event)\n setValue(value)\n }}\n $error={error}\n ref={ref}\n onBlur={onBlur}\n name={name}\n autoComplete={autoComplete}\n aria-label={ariaLabel}\n aria-invalid={error || undefined}\n aria-required={required || undefined}\n aria-describedby={describedBy}\n $frontIcon={!!iconToRender}\n $fallbackStyle={fallbackStyle}\n value={value ?? ''}\n >\n <option value=\"\" hidden={!showDefaultOption} disabled>\n {defaultOptionLabel()}\n </option>\n\n {dropdownItemsGroups.map((groupItems, i) =>\n hasOptGroups ? (\n <optgroup\n key={i}\n label={groupItems[0].optionGroupLabel ?? 'Other'}\n >\n {groupItems.map((el, j) => (\n <option key={`${i}-${j}`} value={el.value}>\n {el.label}\n </option>\n ))}\n </optgroup>\n ) : (\n groupItems.map((el, j) => (\n <option key={j} value={el.value}>\n {el.label}\n </option>\n ))\n ),\n )}\n </StyledSelect>\n <Caret>\n <IconContainer $size={16}>\n <FontAwesomeIcon\n icon={faChevronDown}\n color={theme.color.icon.subtle}\n />\n </IconContainer>\n </Caret>\n </Box>\n </Field>\n )\n})\n\ninterface SSelect {\n $error: boolean\n $frontIcon: boolean\n $fallbackStyle?: boolean\n value?: string | null\n}\n\n// Figma's 32px chevron slot sits 12px from the edge, 16px from the text\nconst CHEVRON_INSET = 20\n\nconst StyledSelect = styled.select.attrs(fieldFocusAttrs)<SSelect>(\n ({ theme, $error, $frontIcon, $fallbackStyle, value }) => {\n const borderColor = (color: string) =>\n $error ? theme.color.feedback.negative[200] : color\n\n return css`\n appearance: none;\n width: 100%;\n height: 48px;\n margin: 0;\n padding: 12px 60px 12px ${$frontIcon ? '42px' : '12px'};\n border: 2px solid ${borderColor(theme.color.border.subtle)};\n border-radius: 12px;\n background-color: ${\n $fallbackStyle\n ? theme.color.surface.base[300]\n : theme.color.background['000']\n };\n color: ${value === '' ? theme.color.text.subtle : theme.color.text.base};\n font-family: inherit;\n font-size: 16px;\n line-height: 20px;\n text-overflow: ellipsis;\n cursor: pointer;\n outline: none;\n\n option,\n optgroup {\n color: ${theme.color.text.base};\n }\n\n // Hover mustn't override the focus border while the pointer is over a\n // focused field.\n &:hover:not(:disabled):not(:focus) {\n border-color: ${borderColor(theme.color.border.base)};\n }\n\n &:focus {\n border-color: ${borderColor(theme.color.border.contrast)};\n }\n\n ${fieldFocusRing}\n ${fieldDisabledStyle}\n `\n },\n)\n\nconst Caret = styled.div`\n position: absolute;\n z-index: 1;\n right: ${CHEVRON_INSET}px;\n display: flex;\n pointer-events: none;\n`\n"]}
|
package/dist/Modal/Modal.d.ts
CHANGED
|
@@ -27,6 +27,21 @@ export type ModalProps = {
|
|
|
27
27
|
containerClass?: string;
|
|
28
28
|
portalContainer?: Element | DocumentFragment;
|
|
29
29
|
closeOnOverlayClick?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Keeps the title and close button visible while the content scrolls.
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
stickyHeader?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Rendered below the content, e.g. one or two buttons, which share the
|
|
37
|
+
* width equally. Put the primary action last.
|
|
38
|
+
*/
|
|
39
|
+
footer?: ReactNode;
|
|
40
|
+
/**
|
|
41
|
+
* Keeps `footer` visible while the content scrolls.
|
|
42
|
+
* @default false
|
|
43
|
+
*/
|
|
44
|
+
stickyFooter?: boolean;
|
|
30
45
|
};
|
|
31
46
|
export type TitleProps = TextProps;
|
|
32
47
|
export declare const Modal: FC<ModalProps>;
|
package/dist/Modal/Modal.js
CHANGED
|
@@ -14,7 +14,7 @@ const getDefaultTitleProps = (title) => ({
|
|
|
14
14
|
typo: 'heading-small',
|
|
15
15
|
align: 'left',
|
|
16
16
|
});
|
|
17
|
-
export const Modal = ({ title = '', children, rightPanel, showModal = false, handleClick, drawer = true, cross = true, width, containerClass, portalContainer = document.body, closeOnOverlayClick = true, }) => {
|
|
17
|
+
export const Modal = ({ title = '', children, rightPanel, showModal = false, handleClick, drawer = true, cross = true, width, containerClass, portalContainer = document.body, closeOnOverlayClick = true, stickyHeader = false, footer, stickyFooter = false, }) => {
|
|
18
18
|
const modalRef = useRef(null);
|
|
19
19
|
const theme = useTheme();
|
|
20
20
|
// oxlint-disable-next-line react/react-compiler
|
|
@@ -23,13 +23,13 @@ export const Modal = ({ title = '', children, rightPanel, showModal = false, han
|
|
|
23
23
|
const titleProps = isTitleString ? getDefaultTitleProps(title) : title;
|
|
24
24
|
if (!showModal)
|
|
25
25
|
return null;
|
|
26
|
-
return createPortal(_jsxs(Wrapper, { ref: modalRef, children: [_jsx(Overlay, { onClick: () => closeOnOverlayClick && handleClick(), $closeOnOverlayClick: closeOnOverlayClick }),
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
return createPortal(_jsxs(Wrapper, { ref: modalRef, children: [_jsx(Overlay, { onClick: () => closeOnOverlayClick && handleClick(), $closeOnOverlayClick: closeOnOverlayClick }), _jsx(Container, { $drawer: drawer, $width: width || '460px', className: containerClass, children: _jsxs(ScrollArea, { children: [_jsxs(Header, { flex: true, alignItems: "flex-start", justifyContent: "space-between", $sticky: stickyHeader, children: [_jsx(TitleElements, { flex: true, direction: "column", children: _jsx(Text, { ...titleProps }) }), _jsxs(Box, { flex: true, alignItems: "center", gap: 'space.100', children: [rightPanel, cross && (_jsx(IconContainer, { as: "button", onClick: handleClick, role: "button", title: "Close modal", $size: 32, style: {
|
|
27
|
+
background: theme.color.illustration.neutral[300],
|
|
28
|
+
borderRadius: '100%',
|
|
29
|
+
padding: '6px',
|
|
30
|
+
border: 'none',
|
|
31
|
+
cursor: 'pointer',
|
|
32
|
+
}, children: _jsx(FontAwesomeIcon, { icon: faXmark, color: theme.color.icon.base }) }))] })] }), _jsx(ContentArea, { flex: true, direction: "column", $hasFooter: !!footer, children: children }), footer ? _jsx(Footer, { $sticky: stickyFooter, children: footer }) : null] }) })] }), portalContainer);
|
|
33
33
|
};
|
|
34
34
|
const Wrapper = styled(Box) `
|
|
35
35
|
display: flex;
|
|
@@ -53,15 +53,16 @@ const Overlay = styled.div `
|
|
|
53
53
|
right: 0;
|
|
54
54
|
`;
|
|
55
55
|
const Container = styled.div(({ $drawer, $width }) => css `
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
56
58
|
background: ${({ theme }) => theme.color.background[100]};
|
|
57
59
|
box-sizing: border-box;
|
|
58
60
|
border-radius: 16px;
|
|
59
|
-
padding: ${({ theme }) => theme.space[300]};
|
|
60
61
|
width: 100%;
|
|
61
62
|
max-width: ${$width};
|
|
62
63
|
position: fixed;
|
|
63
64
|
max-height: calc(100vh - 64px);
|
|
64
|
-
overflow:
|
|
65
|
+
overflow: hidden;
|
|
65
66
|
transition: all 0.3s ease-in-out;
|
|
66
67
|
|
|
67
68
|
${$drawer === true &&
|
|
@@ -69,7 +70,6 @@ const Container = styled.div(({ $drawer, $width }) => css `
|
|
|
69
70
|
@media (max-width: 768px) {
|
|
70
71
|
max-width: none;
|
|
71
72
|
border-radius: 16px 16px 0px 0px;
|
|
72
|
-
padding: 10% 24px;
|
|
73
73
|
max-height: 90vh;
|
|
74
74
|
|
|
75
75
|
position: fixed;
|
|
@@ -79,6 +79,44 @@ const Container = styled.div(({ $drawer, $width }) => css `
|
|
|
79
79
|
}
|
|
80
80
|
`}
|
|
81
81
|
`);
|
|
82
|
+
// The scrollbar lives here so Container's border-radius can clip it.
|
|
83
|
+
const ScrollArea = styled.div `
|
|
84
|
+
flex: 1;
|
|
85
|
+
min-height: 0;
|
|
86
|
+
overflow-y: auto;
|
|
87
|
+
overscroll-behavior-y: none;
|
|
88
|
+
`;
|
|
89
|
+
const Header = styled(Box)(({ $sticky, theme }) => css `
|
|
90
|
+
padding: ${theme.space[300]} ${theme.space[200]} ${theme.space[200]};
|
|
91
|
+
|
|
92
|
+
${$sticky &&
|
|
93
|
+
css `
|
|
94
|
+
position: sticky;
|
|
95
|
+
top: 0;
|
|
96
|
+
z-index: 1;
|
|
97
|
+
background: ${theme.color.background[100]};
|
|
98
|
+
`}
|
|
99
|
+
`);
|
|
100
|
+
const ContentArea = styled(Box)(({ $hasFooter, theme }) => css `
|
|
101
|
+
padding: 0 ${theme.space[200]} ${$hasFooter ? '0' : theme.space[300]};
|
|
102
|
+
`);
|
|
103
|
+
const Footer = styled.div(({ $sticky, theme }) => css `
|
|
104
|
+
display: flex;
|
|
105
|
+
gap: ${theme.space[100]};
|
|
106
|
+
padding: ${theme.space[300]} ${theme.space[200]};
|
|
107
|
+
|
|
108
|
+
& > * {
|
|
109
|
+
flex: 1;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
${$sticky &&
|
|
113
|
+
css `
|
|
114
|
+
position: sticky;
|
|
115
|
+
bottom: 0;
|
|
116
|
+
z-index: 1;
|
|
117
|
+
background: ${theme.color.background[100]};
|
|
118
|
+
`}
|
|
119
|
+
`);
|
|
82
120
|
const TitleElements = styled(Box) `
|
|
83
121
|
align-self: center;
|
|
84
122
|
`;
|
package/dist/Modal/Modal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../src/Modal/Modal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { FC, ReactNode, useRef } from 'react'\nimport { createPortal } from 'react-dom'\nimport styled, { css, useTheme } from 'styled-components'\n\nimport { Box } from '../Box'\nimport { Text, type TextProps } from '../Text'\nimport { useBodyScrollLock } from '../hooks/useBodyScrollLock'\nimport { IconContainer } from '../sharedStyles/shared.styles'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faXmark } from '@awesome.me/kit-46ca99185c/icons/classic/regular'\n\ninterface IModalContainer {\n // drawer state\n $drawer: boolean\n // modal width\n $width: string\n}\n\nexport type ModalProps = {\n /**\n * Title of the modal\n * @default \"\" (empty string)\n *\n * @example\n * ```tsx\n * <Modal title=\"MultiCar Account\" />\n * ```\n *\n * @example\n * ```tsx\n * <Modal title={{ typo: 'hero', children: 'MultiCar Account' }} />\n * ```\n */\n title?: string | TitleProps\n icon?: string\n children?: ReactNode\n rightPanel?: ReactNode\n showModal?: boolean\n handleClick: () => void\n drawer?: boolean\n cross?: boolean\n width?: string\n containerClass?: string\n portalContainer?: Element | DocumentFragment\n closeOnOverlayClick?: boolean\n}\n\nexport type TitleProps = TextProps\n\nconst getDefaultTitleProps = (title: string): TitleProps => ({\n children: title,\n tag: 'h2',\n typo: 'heading-small',\n align: 'left',\n})\n\nexport const Modal: FC<ModalProps> = ({\n title = '',\n children,\n rightPanel,\n showModal = false,\n handleClick,\n drawer = true,\n cross = true,\n width,\n containerClass,\n portalContainer = document.body,\n closeOnOverlayClick = true,\n}) => {\n const modalRef = useRef<HTMLDivElement>(null)\n const theme = useTheme()\n\n // oxlint-disable-next-line react/react-compiler\n useBodyScrollLock({ node: modalRef.current, showModal })\n\n const isTitleString = typeof title === 'string'\n const titleProps = isTitleString ? getDefaultTitleProps(title) : title\n\n if (!showModal) return null\n\n return createPortal(\n <Wrapper ref={modalRef}>\n <Overlay\n onClick={() => closeOnOverlayClick && handleClick()}\n $closeOnOverlayClick={closeOnOverlayClick}\n />\n <Container\n $drawer={drawer}\n $width={width || '460px'}\n className={containerClass}\n >\n <Box\n flex\n alignItems=\"flex-start\"\n justifyContent=\"space-between\"\n mb=\"space.100\"\n >\n <TitleElements flex direction=\"column\">\n <Text {...titleProps} />\n </TitleElements>\n <Box flex alignItems=\"center\" gap={'space.100'}>\n {rightPanel}\n {cross && (\n <IconContainer\n as=\"button\"\n onClick={handleClick}\n role=\"button\"\n title=\"Close modal\"\n $size={32}\n style={{\n background: theme.color.illustration.neutral[300],\n borderRadius: '100%',\n padding: '6px',\n border: 'none',\n cursor: 'pointer',\n }}\n >\n <FontAwesomeIcon icon={faXmark} color={theme.color.icon.base} />\n </IconContainer>\n )}\n </Box>\n </Box>\n <Box flex direction=\"column\">\n {children}\n </Box>\n </Container>\n </Wrapper>,\n portalContainer,\n )\n}\n\nconst Wrapper = styled(Box)`\n display: flex;\n position: absolute;\n z-index: 999;\n top: 0;\n left: 0;\n height: 100vh;\n width: 100%;\n justify-content: center;\n align-items: center;\n`\n\nconst Overlay = styled.div<{ $closeOnOverlayClick: boolean }>`\n position: fixed;\n background: ${({ theme }) => theme.color.surface.base[900]};\n cursor: ${(props) => (props.$closeOnOverlayClick ? 'pointer' : 'default')};\n opacity: 0.4;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n`\n\nconst Container = styled.div<IModalContainer>(\n ({ $drawer, $width }) => css`\n background: ${({ theme }) => theme.color.background[100]};\n box-sizing: border-box;\n border-radius: 16px;\n padding: ${({ theme }) => theme.space[300]};\n width: 100%;\n max-width: ${$width};\n position: fixed;\n max-height: calc(100vh - 64px);\n overflow: auto;\n transition: all 0.3s ease-in-out;\n\n ${\n $drawer === true &&\n css`\n @media (max-width: 768px) {\n max-width: none;\n border-radius: 16px 16px 0px 0px;\n padding: 10% 24px;\n max-height: 90vh;\n\n position: fixed;\n right: 0;\n left: 0;\n bottom: 0;\n }\n `\n }\n `,\n)\n\nconst TitleElements = styled(Box)`\n align-self: center;\n`\n"]}
|
|
1
|
+
{"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../src/Modal/Modal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { FC, ReactNode, useRef } from 'react'\nimport { createPortal } from 'react-dom'\nimport styled, { css, useTheme } from 'styled-components'\n\nimport { Box } from '../Box'\nimport { Text, type TextProps } from '../Text'\nimport { useBodyScrollLock } from '../hooks/useBodyScrollLock'\nimport { IconContainer } from '../sharedStyles/shared.styles'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faXmark } from '@awesome.me/kit-46ca99185c/icons/classic/regular'\n\ninterface IModalContainer {\n // drawer state\n $drawer: boolean\n // modal width\n $width: string\n}\n\nexport type ModalProps = {\n /**\n * Title of the modal\n * @default \"\" (empty string)\n *\n * @example\n * ```tsx\n * <Modal title=\"MultiCar Account\" />\n * ```\n *\n * @example\n * ```tsx\n * <Modal title={{ typo: 'hero', children: 'MultiCar Account' }} />\n * ```\n */\n title?: string | TitleProps\n icon?: string\n children?: ReactNode\n rightPanel?: ReactNode\n showModal?: boolean\n handleClick: () => void\n drawer?: boolean\n cross?: boolean\n width?: string\n containerClass?: string\n portalContainer?: Element | DocumentFragment\n closeOnOverlayClick?: boolean\n /**\n * Keeps the title and close button visible while the content scrolls.\n * @default false\n */\n stickyHeader?: boolean\n /**\n * Rendered below the content, e.g. one or two buttons, which share the\n * width equally. Put the primary action last.\n */\n footer?: ReactNode\n /**\n * Keeps `footer` visible while the content scrolls.\n * @default false\n */\n stickyFooter?: boolean\n}\n\nexport type TitleProps = TextProps\n\nconst getDefaultTitleProps = (title: string): TitleProps => ({\n children: title,\n tag: 'h2',\n typo: 'heading-small',\n align: 'left',\n})\n\nexport const Modal: FC<ModalProps> = ({\n title = '',\n children,\n rightPanel,\n showModal = false,\n handleClick,\n drawer = true,\n cross = true,\n width,\n containerClass,\n portalContainer = document.body,\n closeOnOverlayClick = true,\n stickyHeader = false,\n footer,\n stickyFooter = false,\n}) => {\n const modalRef = useRef<HTMLDivElement>(null)\n const theme = useTheme()\n\n // oxlint-disable-next-line react/react-compiler\n useBodyScrollLock({ node: modalRef.current, showModal })\n\n const isTitleString = typeof title === 'string'\n const titleProps = isTitleString ? getDefaultTitleProps(title) : title\n\n if (!showModal) return null\n\n return createPortal(\n <Wrapper ref={modalRef}>\n <Overlay\n onClick={() => closeOnOverlayClick && handleClick()}\n $closeOnOverlayClick={closeOnOverlayClick}\n />\n <Container\n $drawer={drawer}\n $width={width || '460px'}\n className={containerClass}\n >\n <ScrollArea>\n <Header\n flex\n alignItems=\"flex-start\"\n justifyContent=\"space-between\"\n $sticky={stickyHeader}\n >\n <TitleElements flex direction=\"column\">\n <Text {...titleProps} />\n </TitleElements>\n <Box flex alignItems=\"center\" gap={'space.100'}>\n {rightPanel}\n {cross && (\n <IconContainer\n as=\"button\"\n onClick={handleClick}\n role=\"button\"\n title=\"Close modal\"\n $size={32}\n style={{\n background: theme.color.illustration.neutral[300],\n borderRadius: '100%',\n padding: '6px',\n border: 'none',\n cursor: 'pointer',\n }}\n >\n <FontAwesomeIcon\n icon={faXmark}\n color={theme.color.icon.base}\n />\n </IconContainer>\n )}\n </Box>\n </Header>\n <ContentArea flex direction=\"column\" $hasFooter={!!footer}>\n {children}\n </ContentArea>\n {footer ? <Footer $sticky={stickyFooter}>{footer}</Footer> : null}\n </ScrollArea>\n </Container>\n </Wrapper>,\n portalContainer,\n )\n}\n\nconst Wrapper = styled(Box)`\n display: flex;\n position: absolute;\n z-index: 999;\n top: 0;\n left: 0;\n height: 100vh;\n width: 100%;\n justify-content: center;\n align-items: center;\n`\n\nconst Overlay = styled.div<{ $closeOnOverlayClick: boolean }>`\n position: fixed;\n background: ${({ theme }) => theme.color.surface.base[900]};\n cursor: ${(props) => (props.$closeOnOverlayClick ? 'pointer' : 'default')};\n opacity: 0.4;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n`\n\nconst Container = styled.div<IModalContainer>(\n ({ $drawer, $width }) => css`\n display: flex;\n flex-direction: column;\n background: ${({ theme }) => theme.color.background[100]};\n box-sizing: border-box;\n border-radius: 16px;\n width: 100%;\n max-width: ${$width};\n position: fixed;\n max-height: calc(100vh - 64px);\n overflow: hidden;\n transition: all 0.3s ease-in-out;\n\n ${\n $drawer === true &&\n css`\n @media (max-width: 768px) {\n max-width: none;\n border-radius: 16px 16px 0px 0px;\n max-height: 90vh;\n\n position: fixed;\n right: 0;\n left: 0;\n bottom: 0;\n }\n `\n }\n `,\n)\n\n// The scrollbar lives here so Container's border-radius can clip it.\nconst ScrollArea = styled.div`\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior-y: none;\n`\n\nconst Header = styled(Box)<{ $sticky: boolean }>(\n ({ $sticky, theme }) => css`\n padding: ${theme.space[300]} ${theme.space[200]} ${theme.space[200]};\n\n ${\n $sticky &&\n css`\n position: sticky;\n top: 0;\n z-index: 1;\n background: ${theme.color.background[100]};\n `\n }\n `,\n)\n\nconst ContentArea = styled(Box)<{ $hasFooter: boolean }>(\n ({ $hasFooter, theme }) => css`\n padding: 0 ${theme.space[200]} ${$hasFooter ? '0' : theme.space[300]};\n `,\n)\n\nconst Footer = styled.div<{ $sticky: boolean }>(\n ({ $sticky, theme }) => css`\n display: flex;\n gap: ${theme.space[100]};\n padding: ${theme.space[300]} ${theme.space[200]};\n\n & > * {\n flex: 1;\n }\n\n ${\n $sticky &&\n css`\n position: sticky;\n bottom: 0;\n z-index: 1;\n background: ${theme.color.background[100]};\n `\n }\n `,\n)\n\nconst TitleElements = styled(Box)`\n align-self: center;\n`\n"]}
|
|
@@ -6,12 +6,13 @@ import { Button } from '../Button';
|
|
|
6
6
|
import { Text } from '../Text';
|
|
7
7
|
const toButtonProps = ({ variant, disabled, loading }, defaultVariant) => {
|
|
8
8
|
const resolved = variant ?? defaultVariant;
|
|
9
|
+
// PromoCard's tertiary is the legacy underlined text button
|
|
10
|
+
if (resolved === 'tertiary')
|
|
11
|
+
return { disabled, loading, textBtn: true };
|
|
9
12
|
return {
|
|
10
13
|
disabled,
|
|
11
14
|
loading,
|
|
12
|
-
|
|
13
|
-
fallbackStyle: resolved === 'fallbackStyle',
|
|
14
|
-
textBtn: resolved === 'tertiary',
|
|
15
|
+
variant: resolved === 'fallbackStyle' ? 'neutral' : 'secondary',
|
|
15
16
|
};
|
|
16
17
|
};
|
|
17
18
|
/**
|
|
@@ -28,7 +29,7 @@ const toButtonProps = ({ variant, disabled, loading }, defaultVariant) => {
|
|
|
28
29
|
*
|
|
29
30
|
* @see https://www.figma.com/design/FqSaizGOyOzXFZNmZ4X0LGMn/%F0%9F%A7%B1-S-mores-components?node-id=33734-3198
|
|
30
31
|
*/
|
|
31
|
-
export const PromoCard = ({ title, body, imagePosition = 'left', backgroundColor = 'custard', illustration, primaryButton, secondaryButton, className, ...marginProps }) => (_jsxs(Container, { $imagePosition: imagePosition, $backgroundColor: backgroundColor, className: className, ...marginProps, children: [illustration && _jsx(IllustrationWrapper, { children: illustration }), _jsxs(Content, { children: [_jsxs(Box, { flex: true, direction: "column", gap: "space.050", children: [_jsx(Text, { typo: "heading-small", children: title }), body && _jsx(Text, { typo: "body-regular", children: body })] }), (primaryButton ?? secondaryButton) && (_jsxs(Box, { flex: true, direction: "row", gap: "space.100", children: [primaryButton && (_jsx(Button, {
|
|
32
|
+
export const PromoCard = ({ title, body, imagePosition = 'left', backgroundColor = 'custard', illustration, primaryButton, secondaryButton, className, ...marginProps }) => (_jsxs(Container, { $imagePosition: imagePosition, $backgroundColor: backgroundColor, className: className, ...marginProps, children: [illustration && _jsx(IllustrationWrapper, { children: illustration }), _jsxs(Content, { children: [_jsxs(Box, { flex: true, direction: "column", gap: "space.050", children: [_jsx(Text, { typo: "heading-small", children: title }), body && _jsx(Text, { typo: "body-regular", children: body })] }), (primaryButton ?? secondaryButton) && (_jsxs(Box, { flex: true, direction: "row", gap: "space.100", children: [primaryButton && (_jsx(Button, { size: "small", handleClick: primaryButton.onClick, ...toButtonProps(primaryButton, 'secondary'), children: primaryButton.label })), secondaryButton && (_jsx(Button, { size: "small", handleClick: secondaryButton.onClick, ...toButtonProps(secondaryButton, 'fallbackStyle'), children: secondaryButton.label }))] }))] })] }));
|
|
32
33
|
PromoCard.displayName = 'PromoCard';
|
|
33
34
|
const Container = styled(Box) `
|
|
34
35
|
display: flex;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromoCard.js","sourceRoot":"","sources":["../../src/PromoCard/PromoCard.tsx"],"names":[],"mappings":";AACA,OAAO,MAAM,MAAM,mBAAmB,CAAA;AAItC,OAAO,EAEL,mBAAmB,GACpB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAA;AAC5B,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"PromoCard.js","sourceRoot":"","sources":["../../src/PromoCard/PromoCard.tsx"],"names":[],"mappings":"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","sourcesContent":["import { FC, ReactNode } from 'react'\nimport styled from 'styled-components'\n\nimport { MarginProps } from '../utils/space'\nimport { TransientProps } from '../utils/utilTypes'\nimport {\n ColorTypes,\n resolveToThemeColor,\n} from '../ThemeProvider/utils/colourMap'\nimport { Box } from '../Box'\nimport { Button, ButtonProps } from '../Button'\nimport { Text } from '../Text'\n\ntype PromoCardButtonVariant = 'secondary' | 'fallbackStyle' | 'tertiary'\n\nexport type PromoCardAction = {\n label: string\n onClick: () => void\n variant?: PromoCardButtonVariant\n disabled?: boolean\n loading?: boolean\n}\n\nexport type PromoCardProps = {\n title: string\n body?: string\n imagePosition?: 'left' | 'right'\n /** Card background, as a theme colour. Defaults to `custard`. */\n backgroundColor?: ColorTypes\n illustration?: ReactNode\n primaryButton?: PromoCardAction\n secondaryButton?: PromoCardAction\n className?: string\n} & MarginProps\n\nconst toButtonProps = (\n { variant, disabled, loading }: PromoCardAction,\n defaultVariant: PromoCardButtonVariant,\n): Pick<ButtonProps, 'disabled' | 'loading' | 'variant' | 'textBtn'> => {\n const resolved = variant ?? defaultVariant\n // PromoCard's tertiary is the legacy underlined text button\n if (resolved === 'tertiary') return { disabled, loading, textBtn: true }\n return {\n disabled,\n loading,\n variant: resolved === 'fallbackStyle' ? 'neutral' : 'secondary',\n }\n}\n\n/**\n * A small promotional card following the Figma \"PromoCardSmall\" design\n * (S-mores components, node 33734-3198).\n *\n * The card is a horizontal layout containing an optional illustration slot\n * (positioned left or right via `imagePosition`), a heading + body text\n * group, and an optional pair of CTA buttons whose variant, disabled, and\n * loading states are fully controlled by the consumer.\n *\n * **Scope:** this component implements the *small* iteration of PromoCard\n * only. A larger variant (if required) would need to be added separately.\n *\n * @see https://www.figma.com/design/FqSaizGOyOzXFZNmZ4X0LGMn/%F0%9F%A7%B1-S-mores-components?node-id=33734-3198\n */\nexport const PromoCard: FC<PromoCardProps> = ({\n title,\n body,\n imagePosition = 'left',\n backgroundColor = 'custard',\n illustration,\n primaryButton,\n secondaryButton,\n className,\n ...marginProps\n}) => (\n <Container\n $imagePosition={imagePosition}\n $backgroundColor={backgroundColor}\n className={className}\n {...marginProps}\n >\n {illustration && <IllustrationWrapper>{illustration}</IllustrationWrapper>}\n <Content>\n <Box flex direction=\"column\" gap=\"space.050\">\n <Text typo=\"heading-small\">{title}</Text>\n {body && <Text typo=\"body-regular\">{body}</Text>}\n </Box>\n {(primaryButton ?? secondaryButton) && (\n <Box flex direction=\"row\" gap=\"space.100\">\n {primaryButton && (\n <Button\n size=\"small\"\n handleClick={primaryButton.onClick}\n {...toButtonProps(primaryButton, 'secondary')}\n >\n {primaryButton.label}\n </Button>\n )}\n {secondaryButton && (\n <Button\n size=\"small\"\n handleClick={secondaryButton.onClick}\n {...toButtonProps(secondaryButton, 'fallbackStyle')}\n >\n {secondaryButton.label}\n </Button>\n )}\n </Box>\n )}\n </Content>\n </Container>\n)\n\nPromoCard.displayName = 'PromoCard'\n\ntype IContainer = TransientProps<\n Required<Pick<PromoCardProps, 'imagePosition' | 'backgroundColor'>>\n>\n\nconst Container = styled(Box)<IContainer>`\n display: flex;\n flex-direction: ${({ $imagePosition }) =>\n $imagePosition === 'right' ? 'row-reverse' : 'row'};\n align-items: flex-end;\n gap: ${({ theme }) => theme.space[200]};\n padding: ${({ theme }) => theme.space[200]};\n background: ${({ theme, $backgroundColor }) =>\n resolveToThemeColor($backgroundColor, theme)};\n border-radius: 24px;\n box-sizing: border-box;\n`\n\nconst Content = styled(Box)`\n display: flex;\n flex-direction: column;\n gap: ${({ theme }) => theme.space[150]};\n flex: 1;\n overflow: hidden;\n`\n\nconst IllustrationWrapper = styled(Box)`\n flex-shrink: 0;\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n`\n"]}
|
package/dist/Table/types.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export type RowActionButtonDefault<T> = {
|
|
|
34
34
|
iconButton?: Pick<IconStrictProps, 'size' | 'render' | 'iconColor' | 'backgroundColor' | 'id' | 'title'> & {
|
|
35
35
|
tooltipText?: string;
|
|
36
36
|
};
|
|
37
|
-
genericButton?: Pick<ButtonProps, 'children' | 'loading' | 'disabled' | 'primary' | 'secondary' | 'fallbackStyle' | 'textBtn' | 'smallButton' | 'id'>;
|
|
37
|
+
genericButton?: Pick<ButtonProps, 'children' | 'loading' | 'disabled' | 'variant' | 'size' | 'primary' | 'secondary' | 'fallbackStyle' | 'textBtn' | 'smallButton' | 'id'>;
|
|
38
38
|
} & BaseRowAction<T>;
|
|
39
39
|
export type RowActionElementOverride<T> = {
|
|
40
40
|
element: ReactElement<any>;
|
package/dist/Table/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/Table/types.ts"],"names":[],"mappings":"","sourcesContent":["import { ReactElement, ReactNode } from 'react'\nimport { ButtonProps } from '../Button/Button'\nimport { IconStrictProps } from '../IconStrict'\nimport type { BoxSpacing, SingleSpacing } from './helper.types'\nimport { ColorTypes } from '../ThemeProvider/utils/colourMap'\n\nexport type TableStylesProps = {\n hasKeyline?: boolean\n fixedHeader?: boolean\n headerHeight?: string\n stripedColor?: string\n stickyCell?: boolean\n headerColor?: string\n rowColor?: string\n rowBorderColor?: string\n rowActionsBgColor?: string\n width?: string\n minWidth?: string\n maxWidth?: string\n noWrapContent?: boolean\n truncateContent?: boolean\n rowPadding?: string\n columnPadding?: string\n hideOverflow?: boolean\n clickableRow?: boolean\n noRowBorderColor?: boolean\n}\n\nexport type Primitive = string | number | boolean | bigint\n\nexport type BaseRowAction<T> = {\n onClick: (rowData: T) => void\n showCondition?: (rowData: T) => boolean\n}\n\nexport type RowAction<T> =\n RowActionButtonDefault<T> | RowActionElementOverride<T>\n\nexport type RowActionButtonDefault<T> = {\n iconButton?: Pick<\n IconStrictProps,\n 'size' | 'render' | 'iconColor' | 'backgroundColor' | 'id' | 'title'\n > & { tooltipText?: string }\n genericButton?: Pick<\n ButtonProps,\n | 'children'\n | 'loading'\n | 'disabled'\n | 'primary'\n | 'secondary'\n | 'fallbackStyle'\n | 'textBtn'\n | 'smallButton'\n | 'id'\n >\n} & BaseRowAction<T>\n\nexport type RowActionElementOverride<T> = {\n element: ReactElement<any>\n} & BaseRowAction<T>\n\nexport type RowActions<T> = {\n actions: RowAction<T>[]\n minWidth?: string\n bgColor?: ColorTypes\n}\n\ntype RowCellRenderer<T> = (\n row: T,\n rowIndex: number,\n column: TableColumn<T>,\n id: string | number,\n) => ReactNode\n\nexport interface TableColumn<T> {\n name?: string | number | ReactNode\n minWidth?: string\n maxWidth?: string\n noWrapContent?: boolean\n truncateContent?: boolean\n hideOverflow?: boolean\n cell?: RowCellRenderer<T>\n}\n\ntype SubElementProps = {\n bgColor?: ColorTypes\n padding?: BoxSpacing\n margin?: BoxSpacing\n}\n\n/** @template T - The type of data the table displays. */\ninterface CommonTableProps<T, ColorT = ColorTypes> {\n /** Array of columns to display in the table. */\n columns: TableColumn<T>[]\n /** Sets the height of the header. */\n headerHeight?: string\n /** If true, the table header will be fixed/sticky. */\n fixedHeader?: boolean\n /** If true, the table header will have a key line. */\n hasKeyline?: boolean\n /** If present, the table rows will have alternating colors. */\n stripedColor?: ColorT\n /** A function to determine if a row is expandable. */\n expandable?: (rowData: T) => boolean\n /** The color for the table header. */\n headerColor?: ColorT\n /** The default color for each table row. */\n rowColor?: ColorT\n /** The default color for each table row border. */\n rowBorderColor?: ColorT\n /** If true, the table will have rounded corners */\n roundedTable?: true\n /** A React element to show when a row is expanded. */\n subTable?: SubElementProps & {\n table: (rowData: T) => ReactElement<any>\n }\n\n /** Settings for sub rows. */\n subRows?: SubElementProps & {\n /** Function that returns a React element for the sub row. */\n rows: (rowData: T) => ReactElement<any> | ReactElement<any>[]\n }\n /** Function to apply to a row, to make the entire row clickable, useful for navigation. */\n clickableRow?: (rowData: T) => void\n /** Array of actions that can be performed on each row. */\n rowActions?: RowActions<T>\n /** The Y padding for each row. */\n rowPadding?: SingleSpacing\n /** The X padding for each row. */\n columnPadding?: SingleSpacing\n /** Hides the table header. Table defaults to always showing the header. */\n hideTableHeader?: boolean\n}\n\n/**\n * Type for each table row's data object.\n **/\nexport type TableRowData = {\n /**\n * Optionally include a unique `rowKey` for stable React keys.\n * If omitted, row index is used, which may cause issues if rows move.\n */\n rowKey?: React.Key\n}\n\nexport interface TableProps<T, K = undefined> extends CommonTableProps<T> {\n /** Array of data to be displayed in the table. */\n data: T[]\n\n /** Callback to derive a stable React key for each row. Falls back to row index if not provided. */\n getRowKey?: (row: T, index: number) => React.Key\n\n /** If true, the sub table columns will be aligned with the main table columns, by using the widths of the main table columns. */\n alignSubTableColumns?: boolean\n\n /** The widths of the table columns to be set to, usually passed down to a subtable to align to the main table columns.\n * The array length should match the number of columns in the table.\n * @example ['100px', '200px', '150px']\n */\n columnWidths?: string[]\n\n footer?: TableFooter<K>\n\n /** The text to show when there is no available data to map through. */\n noDataContent?: ReactNode\n}\n\n/**\n * The type of the footer prop in the Table component.\n * It can either be an array of columns and data, or a React element.\n *\n * For columns, the columns and data will be passed to each column.cell component to generate the footer.\n * For a React element, it will render that as the table footer.\n */\nexport type TableFooter<K> =\n TableFooterColumnsProps<K> | TableFooterElementProps<K>\n\nexport interface TableRowProps<T> extends CommonTableProps<T> {\n rowData: T\n rowIndex: number\n showActions?: boolean\n hideBorder?: boolean\n\n renderSubTable?: (rowData: T) => ReactElement<any>\n}\n\nexport interface RowActionsProps<T> extends Pick<\n CommonTableProps<T, string>,\n 'expandable' | 'rowActions'\n> {\n rowData: T\n width?: string\n canExpandRow: boolean\n toggleExpansion: () => void\n isExpanded?: boolean\n}\n\ntype TableFooterElementProps<K> = {\n element: ReactElement<K>\n}\n\ntype TableFooterColumnsProps<K> = {\n /**\n * Row color of the footer.\n *\n * @default 'custard'\n */\n rowColor?: ColorTypes\n rowPadding?: SingleSpacing\n columnPadding?: SingleSpacing\n columns: TableColumn<K>[]\n data: K\n}\n\nexport type TableHeaderProps<T> = CommonTableProps<T, string>\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/Table/types.ts"],"names":[],"mappings":"","sourcesContent":["import { ReactElement, ReactNode } from 'react'\nimport { ButtonProps } from '../Button/Button'\nimport { IconStrictProps } from '../IconStrict'\nimport type { BoxSpacing, SingleSpacing } from './helper.types'\nimport { ColorTypes } from '../ThemeProvider/utils/colourMap'\n\nexport type TableStylesProps = {\n hasKeyline?: boolean\n fixedHeader?: boolean\n headerHeight?: string\n stripedColor?: string\n stickyCell?: boolean\n headerColor?: string\n rowColor?: string\n rowBorderColor?: string\n rowActionsBgColor?: string\n width?: string\n minWidth?: string\n maxWidth?: string\n noWrapContent?: boolean\n truncateContent?: boolean\n rowPadding?: string\n columnPadding?: string\n hideOverflow?: boolean\n clickableRow?: boolean\n noRowBorderColor?: boolean\n}\n\nexport type Primitive = string | number | boolean | bigint\n\nexport type BaseRowAction<T> = {\n onClick: (rowData: T) => void\n showCondition?: (rowData: T) => boolean\n}\n\nexport type RowAction<T> =\n RowActionButtonDefault<T> | RowActionElementOverride<T>\n\nexport type RowActionButtonDefault<T> = {\n iconButton?: Pick<\n IconStrictProps,\n 'size' | 'render' | 'iconColor' | 'backgroundColor' | 'id' | 'title'\n > & { tooltipText?: string }\n genericButton?: Pick<\n ButtonProps,\n | 'children'\n | 'loading'\n | 'disabled'\n | 'variant'\n | 'size'\n | 'primary'\n | 'secondary'\n | 'fallbackStyle'\n | 'textBtn'\n | 'smallButton'\n | 'id'\n >\n} & BaseRowAction<T>\n\nexport type RowActionElementOverride<T> = {\n element: ReactElement<any>\n} & BaseRowAction<T>\n\nexport type RowActions<T> = {\n actions: RowAction<T>[]\n minWidth?: string\n bgColor?: ColorTypes\n}\n\ntype RowCellRenderer<T> = (\n row: T,\n rowIndex: number,\n column: TableColumn<T>,\n id: string | number,\n) => ReactNode\n\nexport interface TableColumn<T> {\n name?: string | number | ReactNode\n minWidth?: string\n maxWidth?: string\n noWrapContent?: boolean\n truncateContent?: boolean\n hideOverflow?: boolean\n cell?: RowCellRenderer<T>\n}\n\ntype SubElementProps = {\n bgColor?: ColorTypes\n padding?: BoxSpacing\n margin?: BoxSpacing\n}\n\n/** @template T - The type of data the table displays. */\ninterface CommonTableProps<T, ColorT = ColorTypes> {\n /** Array of columns to display in the table. */\n columns: TableColumn<T>[]\n /** Sets the height of the header. */\n headerHeight?: string\n /** If true, the table header will be fixed/sticky. */\n fixedHeader?: boolean\n /** If true, the table header will have a key line. */\n hasKeyline?: boolean\n /** If present, the table rows will have alternating colors. */\n stripedColor?: ColorT\n /** A function to determine if a row is expandable. */\n expandable?: (rowData: T) => boolean\n /** The color for the table header. */\n headerColor?: ColorT\n /** The default color for each table row. */\n rowColor?: ColorT\n /** The default color for each table row border. */\n rowBorderColor?: ColorT\n /** If true, the table will have rounded corners */\n roundedTable?: true\n /** A React element to show when a row is expanded. */\n subTable?: SubElementProps & {\n table: (rowData: T) => ReactElement<any>\n }\n\n /** Settings for sub rows. */\n subRows?: SubElementProps & {\n /** Function that returns a React element for the sub row. */\n rows: (rowData: T) => ReactElement<any> | ReactElement<any>[]\n }\n /** Function to apply to a row, to make the entire row clickable, useful for navigation. */\n clickableRow?: (rowData: T) => void\n /** Array of actions that can be performed on each row. */\n rowActions?: RowActions<T>\n /** The Y padding for each row. */\n rowPadding?: SingleSpacing\n /** The X padding for each row. */\n columnPadding?: SingleSpacing\n /** Hides the table header. Table defaults to always showing the header. */\n hideTableHeader?: boolean\n}\n\n/**\n * Type for each table row's data object.\n **/\nexport type TableRowData = {\n /**\n * Optionally include a unique `rowKey` for stable React keys.\n * If omitted, row index is used, which may cause issues if rows move.\n */\n rowKey?: React.Key\n}\n\nexport interface TableProps<T, K = undefined> extends CommonTableProps<T> {\n /** Array of data to be displayed in the table. */\n data: T[]\n\n /** Callback to derive a stable React key for each row. Falls back to row index if not provided. */\n getRowKey?: (row: T, index: number) => React.Key\n\n /** If true, the sub table columns will be aligned with the main table columns, by using the widths of the main table columns. */\n alignSubTableColumns?: boolean\n\n /** The widths of the table columns to be set to, usually passed down to a subtable to align to the main table columns.\n * The array length should match the number of columns in the table.\n * @example ['100px', '200px', '150px']\n */\n columnWidths?: string[]\n\n footer?: TableFooter<K>\n\n /** The text to show when there is no available data to map through. */\n noDataContent?: ReactNode\n}\n\n/**\n * The type of the footer prop in the Table component.\n * It can either be an array of columns and data, or a React element.\n *\n * For columns, the columns and data will be passed to each column.cell component to generate the footer.\n * For a React element, it will render that as the table footer.\n */\nexport type TableFooter<K> =\n TableFooterColumnsProps<K> | TableFooterElementProps<K>\n\nexport interface TableRowProps<T> extends CommonTableProps<T> {\n rowData: T\n rowIndex: number\n showActions?: boolean\n hideBorder?: boolean\n\n renderSubTable?: (rowData: T) => ReactElement<any>\n}\n\nexport interface RowActionsProps<T> extends Pick<\n CommonTableProps<T, string>,\n 'expandable' | 'rowActions'\n> {\n rowData: T\n width?: string\n canExpandRow: boolean\n toggleExpansion: () => void\n isExpanded?: boolean\n}\n\ntype TableFooterElementProps<K> = {\n element: ReactElement<K>\n}\n\ntype TableFooterColumnsProps<K> = {\n /**\n * Row color of the footer.\n *\n * @default 'custard'\n */\n rowColor?: ColorTypes\n rowPadding?: SingleSpacing\n columnPadding?: SingleSpacing\n columns: TableColumn<K>[]\n data: K\n}\n\nexport type TableHeaderProps<T> = CommonTableProps<T, string>\n"]}
|
|
@@ -3,5 +3,7 @@ import { CommonFieldProps } from '../commonFieldTypes';
|
|
|
3
3
|
export interface FieldProps extends CommonFieldProps {
|
|
4
4
|
htmlFor?: string;
|
|
5
5
|
children: ReactNode;
|
|
6
|
+
assistiveTextId?: string;
|
|
7
|
+
errorMsgId?: string;
|
|
6
8
|
}
|
|
7
9
|
export declare const Field: ({ children, ...fieldProps }: FieldProps) => import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Field.js","sourceRoot":"","sources":["../../../src/fields/Field/Field.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"Field.js","sourceRoot":"","sources":["../../../src/fields/Field/Field.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAS3D,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAc,EAAE,EAAE;IAC/D,OAAO,CACL,KAAC,aAAa,IAAC,SAAS,EAAC,OAAO,KAAK,UAAU,YAC5C,QAAQ,GACK,CACjB,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { ReactNode } from 'react'\n\nimport { CommonFieldProps } from '../commonFieldTypes'\nimport { InternalField } from '../components/InternalField'\n\nexport interface FieldProps extends CommonFieldProps {\n htmlFor?: string\n children: ReactNode\n assistiveTextId?: string\n errorMsgId?: string\n}\n\nexport const Field = ({ children, ...fieldProps }: FieldProps) => {\n return (\n <InternalField fieldType=\"field\" {...fieldProps}>\n {children}\n </InternalField>\n )\n}\n"]}
|
|
@@ -5,6 +5,10 @@ interface InternalFieldProps extends CommonFieldProps {
|
|
|
5
5
|
className?: string;
|
|
6
6
|
htmlFor?: string;
|
|
7
7
|
fieldType: 'field' | 'fieldset';
|
|
8
|
+
/** id for the assistive text, so a control can reference it with `aria-describedby` */
|
|
9
|
+
assistiveTextId?: string;
|
|
10
|
+
/** id for the error message, so a control can reference it with `aria-describedby` */
|
|
11
|
+
errorMsgId?: string;
|
|
8
12
|
}
|
|
9
|
-
export declare const InternalField: ({ children, fieldType, renderAsTitle, htmlFor, className, label, assistiveText, error, errorMsg, required, completed, ...marginProps }: InternalFieldProps) => import("react").JSX.Element;
|
|
13
|
+
export declare const InternalField: ({ children, fieldType, renderAsTitle, htmlFor, className, label, assistiveText, error, errorMsg, required, completed, assistiveTextId, errorMsgId, ...marginProps }: InternalFieldProps) => import("react").JSX.Element;
|
|
10
14
|
export {};
|
|
@@ -3,12 +3,17 @@ import styled, { css } from 'styled-components';
|
|
|
3
3
|
import { Box } from '../../Box';
|
|
4
4
|
import { Icon } from '../../Icon';
|
|
5
5
|
import { Text } from '../../Text';
|
|
6
|
-
|
|
6
|
+
import { markPointerFocus } from './fieldStyles';
|
|
7
|
+
export const InternalField = ({ children, fieldType, renderAsTitle, htmlFor, className, label, assistiveText, error, errorMsg, required, completed, assistiveTextId, errorMsgId, ...marginProps }) => {
|
|
7
8
|
const labelTag = fieldType === 'field' ? 'label' : 'legend';
|
|
9
|
+
// Clicking a label focuses its field, which shouldn't show the focus ring.
|
|
10
|
+
const handleLabelPointerDown = htmlFor
|
|
11
|
+
? () => markPointerFocus(document.getElementById(htmlFor))
|
|
12
|
+
: undefined;
|
|
8
13
|
const textColor = error ? 'color.feedback.negative.200' : 'color.text.subtle';
|
|
9
|
-
return (_jsxs(Container, { forwardedAs: fieldType === 'field' ? 'div' : 'fieldset', className: className, ...marginProps, children: [label && (_jsx(_Fragment, { children: renderAsTitle ? (_jsxs(Box, { mb: "space.200", children: [_jsx(Text, { tag: labelTag, typo: "heading-small", htmlFor: htmlFor, children: label }), assistiveText && (_jsx(Text, { tag: "p", color: "
|
|
14
|
+
return (_jsxs(Container, { forwardedAs: fieldType === 'field' ? 'div' : 'fieldset', className: className, ...marginProps, children: [label && (_jsx(_Fragment, { children: renderAsTitle ? (_jsxs(Box, { mb: "space.200", children: [_jsx(Text, { tag: labelTag, typo: "heading-small", htmlFor: htmlFor, onPointerDown: handleLabelPointerDown, children: label }), assistiveText && (_jsx(Text, { tag: "p", color: "color.text.subtle", mt: "space.050", id: assistiveTextId, children: assistiveText }))] })) : (_jsxs(Text, { tag: labelTag, typo: "label", color: textColor, htmlFor: htmlFor, onPointerDown: handleLabelPointerDown, mb: "space.050", children: [label, required && (_jsx(Text, { tag: "span", typo: "body-small", color: "color.feedback.negative.200", children: "*" }))] })) })), _jsx(Box, { children: children }), fieldType === 'field' && assistiveText && !renderAsTitle && (_jsx(Text, { tag: labelTag, typo: "caption", color: textColor, mt: "space.050", id: assistiveTextId, children: assistiveText })), error &&
|
|
10
15
|
errorMsg &&
|
|
11
|
-
(typeof errorMsg === 'string' ? (_jsxs(Box, { flex: true, alignItems: "center", mt: "space.100", gap: "space.050", children: [_jsx(Icon, { render: "warning", size: 16, color: "color.feedback.negative.200" }), _jsx(Text, { tag: "span", typo: "caption", color: "color.feedback.negative.200", children: errorMsg })] })) : (_jsx(Box, { mt: "space.100", children: errorMsg }))), completed !== undefined && (_jsx(AnimationWrapper, { $displayStatus: completed, $isError: !!(error && errorMsg), children: _jsxs(StatusWrapper, { mt: 'space.100', children: [_jsx(Icon, { render: "included", size: 16, color: "color.feedback.positive.200" }), _jsx(Text, { typo: "caption", color: "color.feedback.positive.200", children: "Complete" })] }) }))] }));
|
|
16
|
+
(typeof errorMsg === 'string' ? (_jsxs(Box, { flex: true, alignItems: "center", mt: "space.100", gap: "space.050", id: errorMsgId, children: [_jsx(Icon, { render: "warning", size: 16, color: "color.feedback.negative.200" }), _jsx(Text, { tag: "span", typo: "caption", color: "color.feedback.negative.200", children: errorMsg })] })) : (_jsx(Box, { mt: "space.100", id: errorMsgId, children: errorMsg }))), completed !== undefined && (_jsx(AnimationWrapper, { $displayStatus: completed, $isError: !!(error && errorMsg), children: _jsxs(StatusWrapper, { mt: 'space.100', children: [_jsx(Icon, { render: "included", size: 16, color: "color.feedback.positive.200" }), _jsx(Text, { typo: "caption", color: "color.feedback.positive.200", children: "Complete" })] }) }))] }));
|
|
12
17
|
};
|
|
13
18
|
const AnimationWrapper = styled(Box) `
|
|
14
19
|
width: 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InternalField.js","sourceRoot":"","sources":["../../../src/fields/components/InternalField.tsx"],"names":[],"mappings":";AACA,OAAO,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAC/B,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"InternalField.js","sourceRoot":"","sources":["../../../src/fields/components/InternalField.tsx"],"names":[],"mappings":"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","sourcesContent":["import { ReactNode } from 'react'\nimport styled, { css } from 'styled-components'\n\nimport { Box } from '../../Box'\nimport { Icon } from '../../Icon'\nimport { Text } from '../../Text'\nimport { CommonFieldProps } from '../commonFieldTypes'\nimport { markPointerFocus } from './fieldStyles'\n\ninterface InternalFieldProps extends CommonFieldProps {\n children: ReactNode\n className?: string\n htmlFor?: string\n fieldType: 'field' | 'fieldset'\n /** id for the assistive text, so a control can reference it with `aria-describedby` */\n assistiveTextId?: string\n /** id for the error message, so a control can reference it with `aria-describedby` */\n errorMsgId?: string\n}\n\nexport const InternalField = ({\n children,\n fieldType,\n renderAsTitle,\n htmlFor,\n className,\n label,\n assistiveText,\n error,\n errorMsg,\n required,\n completed,\n assistiveTextId,\n errorMsgId,\n ...marginProps\n}: InternalFieldProps) => {\n const labelTag = fieldType === 'field' ? 'label' : 'legend'\n // Clicking a label focuses its field, which shouldn't show the focus ring.\n const handleLabelPointerDown = htmlFor\n ? () => markPointerFocus(document.getElementById(htmlFor))\n : undefined\n\n const textColor = error ? 'color.feedback.negative.200' : 'color.text.subtle'\n return (\n <Container\n forwardedAs={fieldType === 'field' ? 'div' : 'fieldset'}\n className={className}\n {...marginProps}\n >\n {label && (\n <>\n {renderAsTitle ? (\n <Box mb=\"space.200\">\n <Text\n tag={labelTag}\n typo=\"heading-small\"\n htmlFor={htmlFor}\n onPointerDown={handleLabelPointerDown}\n >\n {label}\n </Text>\n\n {assistiveText && (\n <Text\n tag=\"p\"\n color=\"color.text.subtle\"\n mt=\"space.050\"\n id={assistiveTextId}\n >\n {assistiveText}\n </Text>\n )}\n </Box>\n ) : (\n <Text\n tag={labelTag}\n typo=\"label\"\n color={textColor}\n htmlFor={htmlFor}\n onPointerDown={handleLabelPointerDown}\n mb=\"space.050\"\n >\n {label}\n {required && (\n <Text\n tag=\"span\"\n typo=\"body-small\"\n color=\"color.feedback.negative.200\"\n >\n *\n </Text>\n )}\n </Text>\n )}\n </>\n )}\n\n <Box>{children}</Box>\n {fieldType === 'field' && assistiveText && !renderAsTitle && (\n <Text\n tag={labelTag}\n typo=\"caption\"\n color={textColor}\n mt=\"space.050\"\n id={assistiveTextId}\n >\n {assistiveText}\n </Text>\n )}\n\n {error &&\n errorMsg &&\n (typeof errorMsg === 'string' ? (\n <Box\n flex\n alignItems=\"center\"\n mt=\"space.100\"\n gap=\"space.050\"\n id={errorMsgId}\n >\n <Icon\n render=\"warning\"\n size={16}\n color=\"color.feedback.negative.200\"\n />\n <Text tag=\"span\" typo=\"caption\" color=\"color.feedback.negative.200\">\n {errorMsg}\n </Text>\n </Box>\n ) : (\n <Box mt=\"space.100\" id={errorMsgId}>\n {errorMsg}\n </Box>\n ))}\n\n {/* When completed is false, whitespace is rendered */}\n {completed !== undefined && (\n <AnimationWrapper\n $displayStatus={completed}\n $isError={!!(error && errorMsg)}\n >\n <StatusWrapper mt={'space.100'}>\n <Icon\n render=\"included\"\n size={16}\n color=\"color.feedback.positive.200\"\n />\n <Text typo=\"caption\" color=\"color.feedback.positive.200\">\n Complete\n </Text>\n </StatusWrapper>\n </AnimationWrapper>\n )}\n </Container>\n )\n}\n\nconst AnimationWrapper = styled(Box)<{\n $displayStatus: boolean\n $isError: boolean\n}>`\n width: 0;\n overflow: hidden;\n\n ${({ $displayStatus }) =>\n $displayStatus &&\n css`\n transition: width 0.6s ease-in;\n width: 100%;\n `}\n\n /* This enables animation to appear when previous state is error */\n ${({ $isError }) =>\n $isError &&\n css`\n height: 0;\n `}\n`\n\nconst StatusWrapper = styled(Box)`\n display: flex;\n align-items: center;\n gap: ${({ theme }) => theme.space['050']};\n`\n\nconst Container = styled(Box)`\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n\n // In case, the element is a 'fieldset', we remove the border\n border: 0;\n`\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { FocusEvent, FocusEventHandler, PointerEvent, PointerEventHandler } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Browsers treat text fields as `:focus-visible` even when they are clicked,
|
|
4
|
+
* so fields flag focus that comes from a pointer and only show the focus ring
|
|
5
|
+
* for keyboard focus.
|
|
6
|
+
*/
|
|
7
|
+
export declare const markPointerFocus: (element: HTMLElement | null) => void;
|
|
8
|
+
/** Pass to styled-components `.attrs`. Callers' own handlers still run. */
|
|
9
|
+
export declare const fieldFocusAttrs: <T extends HTMLElement>({ onPointerDown, onBlurCapture, }: {
|
|
10
|
+
onPointerDown?: PointerEventHandler<T>;
|
|
11
|
+
onBlurCapture?: FocusEventHandler<T>;
|
|
12
|
+
}) => {
|
|
13
|
+
onPointerDown: (event: PointerEvent<T>) => void;
|
|
14
|
+
onBlurCapture: (event: FocusEvent<T>) => void;
|
|
15
|
+
};
|
|
16
|
+
export declare const fieldFocusRing: import("styled-components").RuleSet<object>;
|
|
17
|
+
export declare const fieldDisabledStyle: import("styled-components").RuleSet<object>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { css } from 'styled-components';
|
|
2
|
+
/**
|
|
3
|
+
* Browsers treat text fields as `:focus-visible` even when they are clicked,
|
|
4
|
+
* so fields flag focus that comes from a pointer and only show the focus ring
|
|
5
|
+
* for keyboard focus.
|
|
6
|
+
*/
|
|
7
|
+
export const markPointerFocus = (element) => {
|
|
8
|
+
if (element)
|
|
9
|
+
element.dataset.pointerFocus = '';
|
|
10
|
+
};
|
|
11
|
+
/** Pass to styled-components `.attrs`. Callers' own handlers still run. */
|
|
12
|
+
export const fieldFocusAttrs = ({ onPointerDown, onBlurCapture, }) => ({
|
|
13
|
+
onPointerDown: (event) => {
|
|
14
|
+
markPointerFocus(event.currentTarget);
|
|
15
|
+
onPointerDown?.(event);
|
|
16
|
+
},
|
|
17
|
+
onBlurCapture: (event) => {
|
|
18
|
+
delete event.currentTarget.dataset.pointerFocus;
|
|
19
|
+
onBlurCapture?.(event);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
export const fieldFocusRing = css `
|
|
23
|
+
&:focus-visible:not([data-pointer-focus]) {
|
|
24
|
+
outline: 2px solid ${({ theme }) => theme.color.focus.onLight};
|
|
25
|
+
outline-offset: 2px;
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
export const fieldDisabledStyle = css `
|
|
29
|
+
&:disabled {
|
|
30
|
+
border-color: ${({ theme }) => theme.color.feedback.inactive[100]};
|
|
31
|
+
background-color: ${({ theme }) => theme.color.feedback.inactive[50]};
|
|
32
|
+
color: ${({ theme }) => theme.color.text.subtle};
|
|
33
|
+
cursor: not-allowed;
|
|
34
|
+
/* Safari fades disabled fields on top of these colours */
|
|
35
|
+
opacity: 1;
|
|
36
|
+
-webkit-text-fill-color: currentColor;
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
//# sourceMappingURL=fieldStyles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fieldStyles.js","sourceRoot":"","sources":["../../../src/fields/components/fieldStyles.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAA;AAEvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA2B,EAAE,EAAE;IAC9D,IAAI,OAAO;QAAE,OAAO,CAAC,OAAO,CAAC,YAAY,GAAG,EAAE,CAAA;AAChD,CAAC,CAAA;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,eAAe,GAAG,CAAwB,EACrD,aAAa,EACb,aAAa,GAId,EAAE,EAAE,CAAC,CAAC;IACL,aAAa,EAAE,CAAC,KAAsB,EAAE,EAAE;QACxC,gBAAgB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;QACrC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAA;IACxB,CAAC;IACD,aAAa,EAAE,CAAC,KAAoB,EAAE,EAAE;QACtC,OAAO,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,YAAY,CAAA;QAC/C,aAAa,EAAE,CAAC,KAAK,CAAC,CAAA;IACxB,CAAC;CACF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAA;;yBAER,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO;;;CAGhE,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAA;;oBAEjB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;wBAC7C,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;aAC3D,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;;;;;;CAMlD,CAAA","sourcesContent":["import {\n FocusEvent,\n FocusEventHandler,\n PointerEvent,\n PointerEventHandler,\n} from 'react'\nimport { css } from 'styled-components'\n\n/**\n * Browsers treat text fields as `:focus-visible` even when they are clicked,\n * so fields flag focus that comes from a pointer and only show the focus ring\n * for keyboard focus.\n */\nexport const markPointerFocus = (element: HTMLElement | null) => {\n if (element) element.dataset.pointerFocus = ''\n}\n\n/** Pass to styled-components `.attrs`. Callers' own handlers still run. */\nexport const fieldFocusAttrs = <T extends HTMLElement>({\n onPointerDown,\n onBlurCapture,\n}: {\n onPointerDown?: PointerEventHandler<T>\n onBlurCapture?: FocusEventHandler<T>\n}) => ({\n onPointerDown: (event: PointerEvent<T>) => {\n markPointerFocus(event.currentTarget)\n onPointerDown?.(event)\n },\n onBlurCapture: (event: FocusEvent<T>) => {\n delete event.currentTarget.dataset.pointerFocus\n onBlurCapture?.(event)\n },\n})\n\nexport const fieldFocusRing = css`\n &:focus-visible:not([data-pointer-focus]) {\n outline: 2px solid ${({ theme }) => theme.color.focus.onLight};\n outline-offset: 2px;\n }\n`\n\nexport const fieldDisabledStyle = css`\n &:disabled {\n border-color: ${({ theme }) => theme.color.feedback.inactive[100]};\n background-color: ${({ theme }) => theme.color.feedback.inactive[50]};\n color: ${({ theme }) => theme.color.text.subtle};\n cursor: not-allowed;\n /* Safari fades disabled fields on top of these colours */\n opacity: 1;\n -webkit-text-fill-color: currentColor;\n }\n`\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrshmllw/smores-react",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.6.0",
|
|
4
4
|
"description": "Collection of React components used by Marshmallow Technology",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@storybook/addon-docs": "^10.6.1",
|
|
75
75
|
"@storybook/addon-links": "^10.6.1",
|
|
76
76
|
"@storybook/react-vite": "^10.6.1",
|
|
77
|
-
"@storybook/test-runner": "^0.
|
|
77
|
+
"@storybook/test-runner": "^0.26.0",
|
|
78
78
|
"@testing-library/jest-dom": "^7.0.1",
|
|
79
79
|
"@testing-library/react": "^16.3.3",
|
|
80
80
|
"@types/body-scroll-lock": "^3.1.2",
|