@mrshmllw/smores-react 16.8.0 → 16.10.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/ButtonContainer/ButtonContainer.d.ts +39 -0
- package/dist/ButtonContainer/ButtonContainer.js +143 -0
- package/dist/ButtonContainer/ButtonContainer.js.map +1 -0
- package/dist/ButtonContainer/index.d.ts +2 -0
- package/dist/ButtonContainer/index.js +2 -0
- package/dist/ButtonContainer/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FC, ReactElement } from 'react';
|
|
2
|
+
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
|
|
3
|
+
type ButtonElement = ReactElement<{
|
|
4
|
+
'aria-describedby'?: string;
|
|
5
|
+
}>;
|
|
6
|
+
export type ButtonContainerOrientation = 'vertical' | 'horizontal';
|
|
7
|
+
export type ButtonContainerAlignment = 'center' | 'start' | 'end';
|
|
8
|
+
export type ButtonContainerSupportingMessage = {
|
|
9
|
+
/** Short plain text, e.g. reassurance copy. Required, so an icon never shows on its own */
|
|
10
|
+
text: string;
|
|
11
|
+
/** Optional decorative icon shown before the text */
|
|
12
|
+
icon?: IconDefinition;
|
|
13
|
+
};
|
|
14
|
+
export type ButtonContainerProps = {
|
|
15
|
+
className?: string;
|
|
16
|
+
/** Main action. Shown first when vertical, last (right) when horizontal */
|
|
17
|
+
primaryButton: ButtonElement;
|
|
18
|
+
/** Optional supporting action */
|
|
19
|
+
secondaryButton?: ButtonElement;
|
|
20
|
+
/** Optional low-emphasis action. Shown last when vertical, first (left) when horizontal */
|
|
21
|
+
tertiaryButton?: ButtonElement;
|
|
22
|
+
/** Stack the buttons vertically or lay them out side by side */
|
|
23
|
+
orientation?: ButtonContainerOrientation;
|
|
24
|
+
/**
|
|
25
|
+
* Where the buttons and supporting text sit from 768px up. Use `start` or
|
|
26
|
+
* `end` to line them up with the edge of the page content. On mobile they
|
|
27
|
+
* fill the width.
|
|
28
|
+
*/
|
|
29
|
+
align?: ButtonContainerAlignment;
|
|
30
|
+
/** Optional message shown below the buttons, e.g. reassurance copy */
|
|
31
|
+
supportingMessage?: ButtonContainerSupportingMessage;
|
|
32
|
+
/**
|
|
33
|
+
* Pin the container to the bottom of the viewport on mobile.
|
|
34
|
+
* On larger screens it always sits in the page flow.
|
|
35
|
+
*/
|
|
36
|
+
pinned?: boolean;
|
|
37
|
+
};
|
|
38
|
+
export declare const ButtonContainer: FC<ButtonContainerProps>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, cloneElement, useEffect, useId, useRef, useState, } from 'react';
|
|
3
|
+
import styled, { css, useTheme } from 'styled-components';
|
|
4
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
5
|
+
export const ButtonContainer = ({ className, primaryButton, secondaryButton, tertiaryButton, orientation = 'vertical', align = 'center', supportingMessage, pinned = true, }) => {
|
|
6
|
+
const theme = useTheme();
|
|
7
|
+
const supportingTextId = useId();
|
|
8
|
+
const containerRef = useRef(null);
|
|
9
|
+
const [containerHeight, setContainerHeight] = useState(0);
|
|
10
|
+
// Reserve the pinned container's height in the page flow so it never covers content
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const element = containerRef.current;
|
|
13
|
+
if (!pinned || !element || typeof ResizeObserver === 'undefined')
|
|
14
|
+
return;
|
|
15
|
+
const observer = new ResizeObserver(() => {
|
|
16
|
+
setContainerHeight(element.getBoundingClientRect().height);
|
|
17
|
+
});
|
|
18
|
+
observer.observe(element);
|
|
19
|
+
return () => observer.disconnect();
|
|
20
|
+
}, [pinned]);
|
|
21
|
+
const hasSupportingMessage = Boolean(supportingMessage?.text?.trim());
|
|
22
|
+
const describedPrimaryButton = hasSupportingMessage
|
|
23
|
+
? cloneElement(primaryButton, {
|
|
24
|
+
'aria-describedby': [
|
|
25
|
+
primaryButton.props['aria-describedby'],
|
|
26
|
+
supportingTextId,
|
|
27
|
+
]
|
|
28
|
+
.filter(Boolean)
|
|
29
|
+
.join(' '),
|
|
30
|
+
})
|
|
31
|
+
: primaryButton;
|
|
32
|
+
// DOM order follows the visual order so keyboard focus moves the way the buttons read
|
|
33
|
+
const buttons = orientation === 'horizontal'
|
|
34
|
+
? [tertiaryButton, secondaryButton, describedPrimaryButton]
|
|
35
|
+
: [describedPrimaryButton, secondaryButton, tertiaryButton];
|
|
36
|
+
return (_jsxs(_Fragment, { children: [pinned && _jsx(Spacer, { "aria-hidden": "true", $height: containerHeight }), _jsxs(Container, { ref: containerRef, className: className, $pinned: pinned, children: [_jsx(ButtonGroup, { $orientation: orientation, $align: align, children: buttons.map((button, index) => button && _jsx(Fragment, { children: button }, index)) }), supportingMessage && hasSupportingMessage && (_jsxs(SupportingText, { id: supportingTextId, $align: align, children: [supportingMessage.icon && (_jsx(SupportingIconContainer, { children: _jsx(FontAwesomeIcon, { icon: supportingMessage.icon, color: theme.color.icon.subtle }) })), supportingMessage.text] }))] })] }));
|
|
37
|
+
};
|
|
38
|
+
const desktopMediaQuery = '@media (min-width: 768px)';
|
|
39
|
+
const horizontalMargins = {
|
|
40
|
+
center: '0 auto',
|
|
41
|
+
start: '0 auto 0 0',
|
|
42
|
+
end: '0 0 0 auto',
|
|
43
|
+
};
|
|
44
|
+
const desktopVerticalButtonMaxWidth = '400px';
|
|
45
|
+
const desktopHorizontalButtonMinWidth = '160px';
|
|
46
|
+
const Spacer = styled.div(({ $height }) => css `
|
|
47
|
+
height: ${$height}px;
|
|
48
|
+
|
|
49
|
+
${desktopMediaQuery} {
|
|
50
|
+
display: none;
|
|
51
|
+
}
|
|
52
|
+
`);
|
|
53
|
+
const Container = styled.div(({ theme, $pinned }) => css `
|
|
54
|
+
display: flex;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
gap: ${theme.space[150]};
|
|
57
|
+
width: 100%;
|
|
58
|
+
// The library ships no CSS reset, so keep the pinned padding inside the viewport width
|
|
59
|
+
box-sizing: border-box;
|
|
60
|
+
|
|
61
|
+
${$pinned &&
|
|
62
|
+
css `
|
|
63
|
+
position: fixed;
|
|
64
|
+
bottom: 0;
|
|
65
|
+
left: 0;
|
|
66
|
+
right: 0;
|
|
67
|
+
z-index: ${theme.elevation.floating};
|
|
68
|
+
padding: ${theme.space[200]};
|
|
69
|
+
padding-bottom: calc(
|
|
70
|
+
${theme.space[200]} + env(safe-area-inset-bottom, 0px)
|
|
71
|
+
);
|
|
72
|
+
background-color: ${theme.color.surface.base[200]};
|
|
73
|
+
border-radius: ${theme.radius[200]} ${theme.radius[200]} 0 0;
|
|
74
|
+
|
|
75
|
+
${desktopMediaQuery} {
|
|
76
|
+
position: static;
|
|
77
|
+
z-index: auto;
|
|
78
|
+
padding: 0;
|
|
79
|
+
background-color: transparent;
|
|
80
|
+
border-radius: 0;
|
|
81
|
+
}
|
|
82
|
+
`}
|
|
83
|
+
`);
|
|
84
|
+
// On desktop, horizontal buttons all match the width of the longest label
|
|
85
|
+
const ButtonGroup = styled.div(({ theme, $orientation, $align }) => css `
|
|
86
|
+
display: grid;
|
|
87
|
+
gap: ${theme.space[150]};
|
|
88
|
+
|
|
89
|
+
${$orientation === 'vertical' &&
|
|
90
|
+
css `
|
|
91
|
+
${desktopMediaQuery} {
|
|
92
|
+
grid-template-columns: minmax(0, ${desktopVerticalButtonMaxWidth});
|
|
93
|
+
justify-content: ${$align};
|
|
94
|
+
}
|
|
95
|
+
`}
|
|
96
|
+
|
|
97
|
+
${$orientation === 'horizontal' &&
|
|
98
|
+
css `
|
|
99
|
+
grid-auto-flow: column;
|
|
100
|
+
grid-auto-columns: minmax(0, 1fr);
|
|
101
|
+
|
|
102
|
+
// On desktop the buttons share the width of the longest label
|
|
103
|
+
${desktopMediaQuery} {
|
|
104
|
+
grid-auto-columns: minmax(${desktopHorizontalButtonMinWidth}, 1fr);
|
|
105
|
+
width: fit-content;
|
|
106
|
+
max-width: 100%;
|
|
107
|
+
margin: ${horizontalMargins[$align]};
|
|
108
|
+
}
|
|
109
|
+
`}
|
|
110
|
+
`);
|
|
111
|
+
// Figma icons use Font Awesome's square "full" bounding box (640 units),
|
|
112
|
+
// in which the glyph's 512 unit em height takes up 80% of the box
|
|
113
|
+
const SupportingIconContainer = styled.span(({ theme }) => css `
|
|
114
|
+
display: inline-flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
justify-content: center;
|
|
117
|
+
width: 20px;
|
|
118
|
+
height: 20px;
|
|
119
|
+
margin-right: ${theme.space['050']};
|
|
120
|
+
vertical-align: top;
|
|
121
|
+
|
|
122
|
+
svg {
|
|
123
|
+
width: 100%;
|
|
124
|
+
height: 80%;
|
|
125
|
+
overflow: visible;
|
|
126
|
+
}
|
|
127
|
+
`);
|
|
128
|
+
const SupportingText = styled.p(({ theme, $align }) => css `
|
|
129
|
+
margin: 0;
|
|
130
|
+
font-size: ${theme.font.body[200].fontSize};
|
|
131
|
+
font-weight: ${theme.font.body[200].fontWeight};
|
|
132
|
+
line-height: ${theme.font.body[200].lineHeight};
|
|
133
|
+
color: ${theme.color.text.subtle};
|
|
134
|
+
text-align: center;
|
|
135
|
+
|
|
136
|
+
${$align !== 'center' &&
|
|
137
|
+
css `
|
|
138
|
+
${desktopMediaQuery} {
|
|
139
|
+
text-align: ${$align};
|
|
140
|
+
}
|
|
141
|
+
`}
|
|
142
|
+
`);
|
|
143
|
+
//# sourceMappingURL=ButtonContainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonContainer.js","sourceRoot":"","sources":["../../src/ButtonContainer/ButtonContainer.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n FC,\n Fragment,\n ReactElement,\n cloneElement,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react'\nimport styled, { css, useTheme } from 'styled-components'\nimport { IconDefinition } from '@fortawesome/fontawesome-svg-core'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\n\ntype ButtonElement = ReactElement<{ 'aria-describedby'?: string }>\n\nexport type ButtonContainerOrientation = 'vertical' | 'horizontal'\n\nexport type ButtonContainerAlignment = 'center' | 'start' | 'end'\n\nexport type ButtonContainerSupportingMessage = {\n /** Short plain text, e.g. reassurance copy. Required, so an icon never shows on its own */\n text: string\n /** Optional decorative icon shown before the text */\n icon?: IconDefinition\n}\n\nexport type ButtonContainerProps = {\n className?: string\n /** Main action. Shown first when vertical, last (right) when horizontal */\n primaryButton: ButtonElement\n /** Optional supporting action */\n secondaryButton?: ButtonElement\n /** Optional low-emphasis action. Shown last when vertical, first (left) when horizontal */\n tertiaryButton?: ButtonElement\n /** Stack the buttons vertically or lay them out side by side */\n orientation?: ButtonContainerOrientation\n /**\n * Where the buttons and supporting text sit from 768px up. Use `start` or\n * `end` to line them up with the edge of the page content. On mobile they\n * fill the width.\n */\n align?: ButtonContainerAlignment\n /** Optional message shown below the buttons, e.g. reassurance copy */\n supportingMessage?: ButtonContainerSupportingMessage\n /**\n * Pin the container to the bottom of the viewport on mobile.\n * On larger screens it always sits in the page flow.\n */\n pinned?: boolean\n}\n\nexport const ButtonContainer: FC<ButtonContainerProps> = ({\n className,\n primaryButton,\n secondaryButton,\n tertiaryButton,\n orientation = 'vertical',\n align = 'center',\n supportingMessage,\n pinned = true,\n}) => {\n const theme = useTheme()\n const supportingTextId = useId()\n const containerRef = useRef<HTMLDivElement>(null)\n const [containerHeight, setContainerHeight] = useState(0)\n\n // Reserve the pinned container's height in the page flow so it never covers content\n useEffect(() => {\n const element = containerRef.current\n if (!pinned || !element || typeof ResizeObserver === 'undefined') return\n\n const observer = new ResizeObserver(() => {\n setContainerHeight(element.getBoundingClientRect().height)\n })\n observer.observe(element)\n\n return () => observer.disconnect()\n }, [pinned])\n\n const hasSupportingMessage = Boolean(supportingMessage?.text?.trim())\n\n const describedPrimaryButton = hasSupportingMessage\n ? cloneElement(primaryButton, {\n 'aria-describedby': [\n primaryButton.props['aria-describedby'],\n supportingTextId,\n ]\n .filter(Boolean)\n .join(' '),\n })\n : primaryButton\n\n // DOM order follows the visual order so keyboard focus moves the way the buttons read\n const buttons =\n orientation === 'horizontal'\n ? [tertiaryButton, secondaryButton, describedPrimaryButton]\n : [describedPrimaryButton, secondaryButton, tertiaryButton]\n\n return (\n <>\n {pinned && <Spacer aria-hidden=\"true\" $height={containerHeight} />}\n <Container ref={containerRef} className={className} $pinned={pinned}>\n <ButtonGroup $orientation={orientation} $align={align}>\n {buttons.map(\n (button, index) =>\n button && <Fragment key={index}>{button}</Fragment>,\n )}\n </ButtonGroup>\n {supportingMessage && hasSupportingMessage && (\n <SupportingText id={supportingTextId} $align={align}>\n {supportingMessage.icon && (\n <SupportingIconContainer>\n <FontAwesomeIcon\n icon={supportingMessage.icon}\n color={theme.color.icon.subtle}\n />\n </SupportingIconContainer>\n )}\n {supportingMessage.text}\n </SupportingText>\n )}\n </Container>\n </>\n )\n}\n\nconst desktopMediaQuery = '@media (min-width: 768px)'\n\nconst horizontalMargins: Record<ButtonContainerAlignment, string> = {\n center: '0 auto',\n start: '0 auto 0 0',\n end: '0 0 0 auto',\n}\nconst desktopVerticalButtonMaxWidth = '400px'\nconst desktopHorizontalButtonMinWidth = '160px'\n\nconst Spacer = styled.div<{ $height: number }>(\n ({ $height }) => css`\n height: ${$height}px;\n\n ${desktopMediaQuery} {\n display: none;\n }\n `,\n)\n\nconst Container = styled.div<{ $pinned: boolean }>(\n ({ theme, $pinned }) => css`\n display: flex;\n flex-direction: column;\n gap: ${theme.space[150]};\n width: 100%;\n // The library ships no CSS reset, so keep the pinned padding inside the viewport width\n box-sizing: border-box;\n\n ${\n $pinned &&\n css`\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n z-index: ${theme.elevation.floating};\n padding: ${theme.space[200]};\n padding-bottom: calc(\n ${theme.space[200]} + env(safe-area-inset-bottom, 0px)\n );\n background-color: ${theme.color.surface.base[200]};\n border-radius: ${theme.radius[200]} ${theme.radius[200]} 0 0;\n\n ${desktopMediaQuery} {\n position: static;\n z-index: auto;\n padding: 0;\n background-color: transparent;\n border-radius: 0;\n }\n `\n }\n `,\n)\n\n// On desktop, horizontal buttons all match the width of the longest label\nconst ButtonGroup = styled.div<{\n $orientation: ButtonContainerOrientation\n $align: ButtonContainerAlignment\n}>(\n ({ theme, $orientation, $align }) => css`\n display: grid;\n gap: ${theme.space[150]};\n\n ${\n $orientation === 'vertical' &&\n css`\n ${desktopMediaQuery} {\n grid-template-columns: minmax(0, ${desktopVerticalButtonMaxWidth});\n justify-content: ${$align};\n }\n `\n }\n\n ${\n $orientation === 'horizontal' &&\n css`\n grid-auto-flow: column;\n grid-auto-columns: minmax(0, 1fr);\n\n // On desktop the buttons share the width of the longest label\n ${desktopMediaQuery} {\n grid-auto-columns: minmax(${desktopHorizontalButtonMinWidth}, 1fr);\n width: fit-content;\n max-width: 100%;\n margin: ${horizontalMargins[$align]};\n }\n `\n }\n `,\n)\n\n// Figma icons use Font Awesome's square \"full\" bounding box (640 units),\n// in which the glyph's 512 unit em height takes up 80% of the box\nconst SupportingIconContainer = styled.span(\n ({ theme }) => css`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n margin-right: ${theme.space['050']};\n vertical-align: top;\n\n svg {\n width: 100%;\n height: 80%;\n overflow: visible;\n }\n `,\n)\n\nconst SupportingText = styled.p<{ $align: ButtonContainerAlignment }>(\n ({ theme, $align }) => css`\n margin: 0;\n font-size: ${theme.font.body[200].fontSize};\n font-weight: ${theme.font.body[200].fontWeight};\n line-height: ${theme.font.body[200].lineHeight};\n color: ${theme.color.text.subtle};\n text-align: center;\n\n ${\n $align !== 'center' &&\n css`\n ${desktopMediaQuery} {\n text-align: ${$align};\n }\n `\n }\n `,\n)\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ButtonContainer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA","sourcesContent":["export { ButtonContainer } from './ButtonContainer'\nexport type {\n ButtonContainerAlignment,\n ButtonContainerOrientation,\n ButtonContainerProps,\n ButtonContainerSupportingMessage,\n} from './ButtonContainer'\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,OAAO,CAAA;AACrB,cAAc,UAAU,CAAA;AACxB,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,QAAQ,CAAA;AACtB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,QAAQ,CAAA;AACtB,cAAc,UAAU,CAAA;AACxB,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,OAAO,CAAA;AACrB,cAAc,eAAe,CAAA;AAC7B,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,SAAS,CAAA;AACvB,cAAc,OAAO,CAAA;AACrB,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,wBAAwB,CAAA;AACtC,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,0CAA0C,CAAA;AACxD,cAAc,gDAAgD,CAAA;AAC9D,cAAc,4BAA4B,CAAA;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,UAAU,CAAA;AACxB,cAAc,8BAA8B,CAAA","sourcesContent":["export * from './Accordion'\nexport * from './ActionDropdown'\nexport * from './Badge'\nexport * from './Alert'\nexport * from './BadgeList'\nexport * from './Banner'\nexport * from './Box'\nexport * from './Button'\nexport * from './Card'\nexport * from './CheckBox'\nexport * from './CheckBoxGroup'\nexport * from './Chip'\nexport * from './CurrencyInput'\nexport * from './Datepicker'\nexport * from './Divider'\nexport * from './Dropdown'\nexport * from './fields/Field'\nexport * from './fields/Fieldset'\nexport * from './fontStyle'\nexport * from './hooks'\nexport * from './Icon'\nexport * from './IconStrict'\nexport * from './IconWrapper'\nexport * from './LabelledText'\nexport * from './Link'\nexport * from './Loader'\nexport * from './Logo'\nexport * from './Modal'\nexport * from './NumberInput'\nexport * from './Pagination'\nexport * from './ProgressIndicator'\nexport * from './PromoCard'\nexport * from './RadioGroup'\nexport * from './RichText'\nexport * from './RichTextEditor'\nexport * from './Row'\nexport * from './SearchInput'\nexport * from './SegmentedControl'\nexport * from './SliderInput'\nexport * from './Snackbar'\nexport * from './SupportMessage'\nexport * from './Table'\nexport * from './Tag'\nexport * from './Text'\nexport * from './Textarea'\nexport * from './TextDateOfBirthInput'\nexport * from './TextInput'\nexport * from './theme'\nexport * from './Toggle'\nexport * from './Tooltip'\nexport * from './utils/dateOfBirth/dateOfBirthValidator'\nexport * from './utils/dateOfBirth/dateOfBirthValidator.utils'\nexport * from './utils/dateOfBirth/schema'\nexport * from './utils/utilTypes'\nexport * from './utils/space'\nexport * from './ThemeProvider'\nexport * from './styled'\nexport * from './sharedStyles/shared.styles'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,OAAO,CAAA;AACrB,cAAc,UAAU,CAAA;AACxB,cAAc,mBAAmB,CAAA;AACjC,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,QAAQ,CAAA;AACtB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,QAAQ,CAAA;AACtB,cAAc,UAAU,CAAA;AACxB,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,OAAO,CAAA;AACrB,cAAc,eAAe,CAAA;AAC7B,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,SAAS,CAAA;AACvB,cAAc,OAAO,CAAA;AACrB,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,wBAAwB,CAAA;AACtC,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,0CAA0C,CAAA;AACxD,cAAc,gDAAgD,CAAA;AAC9D,cAAc,4BAA4B,CAAA;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,UAAU,CAAA;AACxB,cAAc,8BAA8B,CAAA","sourcesContent":["export * from './Accordion'\nexport * from './ActionDropdown'\nexport * from './Badge'\nexport * from './Alert'\nexport * from './BadgeList'\nexport * from './Banner'\nexport * from './Box'\nexport * from './Button'\nexport * from './ButtonContainer'\nexport * from './Card'\nexport * from './CheckBox'\nexport * from './CheckBoxGroup'\nexport * from './Chip'\nexport * from './CurrencyInput'\nexport * from './Datepicker'\nexport * from './Divider'\nexport * from './Dropdown'\nexport * from './fields/Field'\nexport * from './fields/Fieldset'\nexport * from './fontStyle'\nexport * from './hooks'\nexport * from './Icon'\nexport * from './IconStrict'\nexport * from './IconWrapper'\nexport * from './LabelledText'\nexport * from './Link'\nexport * from './Loader'\nexport * from './Logo'\nexport * from './Modal'\nexport * from './NumberInput'\nexport * from './Pagination'\nexport * from './ProgressIndicator'\nexport * from './PromoCard'\nexport * from './RadioGroup'\nexport * from './RichText'\nexport * from './RichTextEditor'\nexport * from './Row'\nexport * from './SearchInput'\nexport * from './SegmentedControl'\nexport * from './SliderInput'\nexport * from './Snackbar'\nexport * from './SupportMessage'\nexport * from './Table'\nexport * from './Tag'\nexport * from './Text'\nexport * from './Textarea'\nexport * from './TextDateOfBirthInput'\nexport * from './TextInput'\nexport * from './theme'\nexport * from './Toggle'\nexport * from './Tooltip'\nexport * from './utils/dateOfBirth/dateOfBirthValidator'\nexport * from './utils/dateOfBirth/dateOfBirthValidator.utils'\nexport * from './utils/dateOfBirth/schema'\nexport * from './utils/utilTypes'\nexport * from './utils/space'\nexport * from './ThemeProvider'\nexport * from './styled'\nexport * from './sharedStyles/shared.styles'\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrshmllw/smores-react",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.10.0",
|
|
4
4
|
"description": "Collection of React components used by Marshmallow Technology",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@commitlint/cli": "^21.2.3",
|
|
70
70
|
"@mrshmllw/campfire": "^7.1.0",
|
|
71
|
-
"@snyk/protect": "^1.
|
|
71
|
+
"@snyk/protect": "^1.1308.0",
|
|
72
72
|
"@storybook/addon-a11y": "^10.6.1",
|
|
73
73
|
"@storybook/addon-coverage": "^3.0.2",
|
|
74
74
|
"@storybook/addon-docs": "^10.6.1",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"@types/react": "^19.3.0",
|
|
83
83
|
"@types/react-dom": "^19.3.0",
|
|
84
84
|
"axe-playwright": "^2.2.2",
|
|
85
|
-
"concurrently": "^10.0.
|
|
85
|
+
"concurrently": "^10.0.6",
|
|
86
86
|
"eslint-plugin-prettier": "^5.5.6",
|
|
87
87
|
"husky": "^9.1.7",
|
|
88
88
|
"jest-styled-components": "^7.4.0",
|