@simplybusiness/mobius 4.8.4 → 4.8.5
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/CHANGELOG.md +7 -0
- package/dist/cjs/components/Checkbox/Checkbox.js +4 -3
- package/dist/cjs/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/cjs/components/Checkbox/CheckboxGroup.js +4 -2
- package/dist/cjs/components/Checkbox/CheckboxGroup.js.map +1 -1
- package/dist/cjs/components/Flex/propUtils.js +0 -1
- package/dist/cjs/components/Flex/propUtils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/components/Checkbox/Checkbox.js +4 -3
- package/dist/esm/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/esm/components/Checkbox/CheckboxGroup.js +4 -2
- package/dist/esm/components/Checkbox/CheckboxGroup.js.map +1 -1
- package/dist/esm/components/Checkbox/types.js.map +1 -1
- package/dist/esm/components/Flex/propUtils.js +0 -1
- package/dist/esm/components/Flex/propUtils.js.map +1 -1
- package/dist/types/components/Checkbox/CheckboxGroup.stories.d.ts +1 -0
- package/dist/types/components/Checkbox/types.d.ts +12 -1
- package/package.json +1 -1
- package/src/components/Checkbox/Checkbox.test.tsx +13 -0
- package/src/components/Checkbox/Checkbox.tsx +4 -1
- package/src/components/Checkbox/CheckboxGroup.mdx +4 -0
- package/src/components/Checkbox/CheckboxGroup.stories.tsx +20 -0
- package/src/components/Checkbox/CheckboxGroup.test.tsx +121 -70
- package/src/components/Checkbox/CheckboxGroup.tsx +6 -1
- package/src/components/Checkbox/types.ts +17 -2
- package/src/components/Flex/Flex.test.tsx +1 -0
- package/src/components/Flex/propUtils.test.ts +0 -2
- package/src/components/Flex/propUtils.ts +0 -1
- package/src/components/Grid/Grid.stories.tsx +0 -17
- package/dist/cjs/utils/getPaddingValue.js +0 -21
- package/dist/cjs/utils/getPaddingValue.js.map +0 -1
- package/dist/esm/utils/getPaddingValue.js +0 -11
- package/dist/esm/utils/getPaddingValue.js.map +0 -1
- package/dist/types/utils/getPaddingValue.d.ts +0 -2
- package/dist/types/utils/getPaddingValue.test.d.ts +0 -1
|
@@ -5,7 +5,7 @@ import classNames from "classnames/dedupe";
|
|
|
5
5
|
import { ErrorMessage } from "../ErrorMessage";
|
|
6
6
|
import { spaceDelimitedList } from "../../utils/spaceDelimitedList";
|
|
7
7
|
export const Checkbox = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
8
|
-
const { id, label, isDisabled, isRequired, validationState, onChange, className, errorMessage, defaultSelected = false, isReadOnly, value } = props;
|
|
8
|
+
const { id, label, isDisabled, isRequired, validationState, onChange, className, errorMessage, defaultSelected = false, isReadOnly, value, ["aria-describedby"]: ariaDescribedBy, ...rest } = props;
|
|
9
9
|
const [selected, setSelected] = useState(defaultSelected);
|
|
10
10
|
const fallbackRef = useRef(null);
|
|
11
11
|
const refObj = ref || fallbackRef;
|
|
@@ -25,7 +25,7 @@ export const Checkbox = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
25
25
|
const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;
|
|
26
26
|
const describedBy = spaceDelimitedList([
|
|
27
27
|
shouldErrorMessageShow,
|
|
28
|
-
|
|
28
|
+
ariaDescribedBy
|
|
29
29
|
]);
|
|
30
30
|
const labelId = useId();
|
|
31
31
|
const toggleState = ()=>{
|
|
@@ -68,7 +68,8 @@ export const Checkbox = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
68
68
|
defaultChecked: defaultSelected,
|
|
69
69
|
required: isRequired,
|
|
70
70
|
id: id || inputId,
|
|
71
|
-
value: value
|
|
71
|
+
value: value,
|
|
72
|
+
...rest
|
|
72
73
|
}),
|
|
73
74
|
/*#__PURE__*/ _jsx("span", {
|
|
74
75
|
className: "mobius/CheckboxLabel",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n ChangeEvent,\n forwardRef,\n useRef,\n useState,\n KeyboardEvent,\n MouseEvent,\n useId,\n} from \"react\";\nimport classNames from \"classnames/dedupe\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport { CheckboxElementType, CheckboxProps, CheckboxRef } from \"./types\";\nimport { spaceDelimitedList } from \"../../utils/spaceDelimitedList\";\n\nexport const Checkbox: ForwardedRefComponent<\n CheckboxProps,\n CheckboxElementType\n> = forwardRef((props: CheckboxProps, ref: CheckboxRef) => {\n const {\n id,\n label,\n isDisabled,\n isRequired,\n validationState,\n onChange,\n className,\n errorMessage,\n defaultSelected = false,\n isReadOnly,\n value,\n } = props;\n const [selected, setSelected] = useState<boolean>(defaultSelected);\n const fallbackRef = useRef<HTMLInputElement>(null);\n const refObj = ref || fallbackRef;\n const inputId = useId();\n const checkboxClasses = classNames(\n {\n \"--is-disabled\": isDisabled,\n \"--is-selected\": selected,\n \"--is-valid\": validationState === \"valid\",\n \"--is-invalid\": validationState === \"invalid\",\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n },\n className,\n );\n // Append an additional wrapper class name to differenitate from input\n const wrapperClasses = classNames(\n \"mobius\",\n \"mobius/Checkbox\",\n checkboxClasses,\n );\n const inputClasses = classNames(\"mobius/CheckboxInput\", checkboxClasses);\n const errorMessageId = useId();\n const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;\n const describedBy = spaceDelimitedList([\n shouldErrorMessageShow,\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n ChangeEvent,\n forwardRef,\n useRef,\n useState,\n KeyboardEvent,\n MouseEvent,\n useId,\n} from \"react\";\nimport classNames from \"classnames/dedupe\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport { CheckboxElementType, CheckboxProps, CheckboxRef } from \"./types\";\nimport { spaceDelimitedList } from \"../../utils/spaceDelimitedList\";\n\nexport const Checkbox: ForwardedRefComponent<\n CheckboxProps,\n CheckboxElementType\n> = forwardRef((props: CheckboxProps, ref: CheckboxRef) => {\n const {\n id,\n label,\n isDisabled,\n isRequired,\n validationState,\n onChange,\n className,\n errorMessage,\n defaultSelected = false,\n isReadOnly,\n value,\n [\"aria-describedby\"]: ariaDescribedBy,\n ...rest\n } = props;\n const [selected, setSelected] = useState<boolean>(defaultSelected);\n const fallbackRef = useRef<HTMLInputElement>(null);\n const refObj = ref || fallbackRef;\n const inputId = useId();\n const checkboxClasses = classNames(\n {\n \"--is-disabled\": isDisabled,\n \"--is-selected\": selected,\n \"--is-valid\": validationState === \"valid\",\n \"--is-invalid\": validationState === \"invalid\",\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n },\n className,\n );\n // Append an additional wrapper class name to differenitate from input\n const wrapperClasses = classNames(\n \"mobius\",\n \"mobius/Checkbox\",\n checkboxClasses,\n );\n const inputClasses = classNames(\"mobius/CheckboxInput\", checkboxClasses);\n const errorMessageId = useId();\n const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;\n const describedBy = spaceDelimitedList([\n shouldErrorMessageShow,\n ariaDescribedBy,\n ]);\n const labelId = useId();\n\n const toggleState = () => {\n setSelected(!selected);\n };\n\n const handleClick = (event: MouseEvent<CheckboxElementType>) => {\n const isMouseEvent = event.clientX;\n\n if (isMouseEvent) {\n toggleState();\n }\n };\n\n const handleChange = (event: ChangeEvent<CheckboxElementType>) => {\n if (onChange) {\n onChange(event);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.code === \"Space\") {\n toggleState();\n }\n };\n\n return (\n <>\n <label id={labelId} className={wrapperClasses}>\n <input\n aria-describedby={describedBy}\n aria-errormessage={shouldErrorMessageShow}\n aria-invalid={validationState === \"invalid\"}\n readOnly={isReadOnly}\n disabled={isDisabled}\n ref={refObj}\n className={inputClasses}\n onClick={handleClick}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n type=\"checkbox\"\n defaultChecked={defaultSelected}\n required={isRequired}\n id={id || inputId}\n value={value}\n {...rest}\n />\n <span className=\"mobius/CheckboxLabel\">{label}</span>\n </label>\n <ErrorMessage id={errorMessageId} errorMessage={errorMessage} />\n </>\n );\n});\n"],"names":["forwardRef","useRef","useState","useId","classNames","ErrorMessage","spaceDelimitedList","Checkbox","props","ref","id","label","isDisabled","isRequired","validationState","onChange","className","errorMessage","defaultSelected","isReadOnly","value","ariaDescribedBy","rest","selected","setSelected","fallbackRef","refObj","inputId","checkboxClasses","wrapperClasses","inputClasses","errorMessageId","shouldErrorMessageShow","undefined","describedBy","labelId","toggleState","handleClick","event","isMouseEvent","clientX","handleChange","handleKeyDown","code","input","aria-describedby","aria-errormessage","aria-invalid","readOnly","disabled","onClick","onKeyDown","type","defaultChecked","required","span"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;AAEA,SAEEA,UAAU,EACVC,MAAM,EACNC,QAAQ,EAGRC,KAAK,QACA,QAAQ;AACf,OAAOC,gBAAgB,oBAAoB;AAC3C,SAASC,YAAY,QAAQ,kBAAkB;AAG/C,SAASC,kBAAkB,QAAQ,iCAAiC;AAEpE,OAAO,MAAMC,yBAGTP,WAAW,CAACQ,OAAsBC;IACpC,MAAM,EACJC,EAAE,EACFC,KAAK,EACLC,UAAU,EACVC,UAAU,EACVC,eAAe,EACfC,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,kBAAkB,KAAK,EACvBC,UAAU,EACVC,KAAK,EACL,CAAC,mBAAmB,EAAEC,eAAe,EACrC,GAAGC,MACJ,GAAGd;IACJ,MAAM,CAACe,UAAUC,YAAY,GAAGtB,SAAkBgB;IAClD,MAAMO,cAAcxB,OAAyB;IAC7C,MAAMyB,SAASjB,OAAOgB;IACtB,MAAME,UAAUxB;IAChB,MAAMyB,kBAAkBxB,WACtB;QACE,iBAAiBQ;QACjB,iBAAiBW;QACjB,cAAcT,oBAAoB;QAClC,gBAAgBA,oBAAoB;QACpC,iBAAiB,OAAOD,eAAe,aAAaA;QACpD,iBAAiB,OAAOA,eAAe,aAAa,CAACA;IACvD,GACAG;IAEF,sEAAsE;IACtE,MAAMa,iBAAiBzB,WACrB,UACA,mBACAwB;IAEF,MAAME,eAAe1B,WAAW,wBAAwBwB;IACxD,MAAMG,iBAAiB5B;IACvB,MAAM6B,yBAAyBf,eAAec,iBAAiBE;IAC/D,MAAMC,cAAc5B,mBAAmB;QACrC0B;QACAX;KACD;IACD,MAAMc,UAAUhC;IAEhB,MAAMiC,cAAc;QAClBZ,YAAY,CAACD;IACf;IAEA,MAAMc,cAAc,CAACC;QACnB,MAAMC,eAAeD,MAAME,OAAO;QAElC,IAAID,cAAc;YAChBH;QACF;IACF;IAEA,MAAMK,eAAe,CAACH;QACpB,IAAIvB,UAAU;YACZA,SAASuB;QACX;IACF;IAEA,MAAMI,gBAAgB,CAACJ;QACrB,IAAIA,MAAMK,IAAI,KAAK,SAAS;YAC1BP;QACF;IACF;IAEA,qBACE;;0BACE,MAACzB;gBAAMD,IAAIyB;gBAASnB,WAAWa;;kCAC7B,KAACe;wBACCC,oBAAkBX;wBAClBY,qBAAmBd;wBACnBe,gBAAcjC,oBAAoB;wBAClCkC,UAAU7B;wBACV8B,UAAUrC;wBACVH,KAAKiB;wBACLV,WAAWc;wBACXoB,SAASb;wBACTtB,UAAU0B;wBACVU,WAAWT;wBACXU,MAAK;wBACLC,gBAAgBnC;wBAChBoC,UAAUzC;wBACVH,IAAIA,MAAMiB;wBACVP,OAAOA;wBACN,GAAGE,IAAI;;kCAEV,KAACiC;wBAAKvC,WAAU;kCAAwBL;;;;0BAE1C,KAACN;gBAAaK,IAAIqB;gBAAgBd,cAAcA;;;;AAGtD,GAAG"}
|
|
@@ -6,7 +6,7 @@ import { Label } from "../Label";
|
|
|
6
6
|
import { ErrorMessage } from "../ErrorMessage";
|
|
7
7
|
import { spaceDelimitedList } from "../../utils/spaceDelimitedList";
|
|
8
8
|
export const CheckboxGroup = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
9
|
-
const { label, isDisabled = false, isRequired, validationState, orientation = "vertical", onChange, className, errorMessage, children, defaultValue = [], isReadOnly, ...rest } = props;
|
|
9
|
+
const { label, isDisabled = false, isRequired, validationState, orientation = "vertical", onChange, className, errorMessage, children, defaultValue = [], isReadOnly, itemsPerRow, ...rest } = props;
|
|
10
10
|
const [selected, setSelected] = useState(defaultValue);
|
|
11
11
|
const checkboxGroupClasses = classNames("mobius", "mobius/CheckboxGroup", className, {
|
|
12
12
|
"--is-horizontal": orientation === "horizontal",
|
|
@@ -52,6 +52,9 @@ export const CheckboxGroup = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
52
52
|
ref: ref,
|
|
53
53
|
className: checkboxGroupClasses,
|
|
54
54
|
role: "group",
|
|
55
|
+
style: {
|
|
56
|
+
"--checkbox-items-per-row": itemsPerRow || Children.count(children)
|
|
57
|
+
},
|
|
55
58
|
children: [
|
|
56
59
|
label && /*#__PURE__*/ _jsx(Label, {
|
|
57
60
|
elementType: "span",
|
|
@@ -64,7 +67,6 @@ export const CheckboxGroup = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
64
67
|
children: Children.map(children, (child)=>{
|
|
65
68
|
if (/*#__PURE__*/ isValidElement(child)) {
|
|
66
69
|
return /*#__PURE__*/ cloneElement(child, {
|
|
67
|
-
orientation,
|
|
68
70
|
isDisabled,
|
|
69
71
|
isRequired,
|
|
70
72
|
isReadOnly,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/Checkbox/CheckboxGroup.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Children,\n forwardRef,\n ReactElement,\n cloneElement,\n isValidElement,\n useId,\n ChangeEvent,\n useState,\n useEffect,\n} from \"react\";\nimport classNames from \"classnames/dedupe\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport {\n CheckboxElementType,\n CheckboxGroupElementType,\n CheckboxGroupProps,\n CheckboxGroupRef,\n} from \"./types\";\nimport { Label } from \"../Label\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { spaceDelimitedList } from \"../../utils/spaceDelimitedList\";\n\nexport const CheckboxGroup: ForwardedRefComponent<\n CheckboxGroupProps,\n CheckboxGroupElementType\n> = forwardRef((props: CheckboxGroupProps, ref: CheckboxGroupRef) => {\n const {\n label,\n isDisabled = false,\n isRequired,\n validationState,\n orientation = \"vertical\",\n onChange,\n className,\n errorMessage,\n children,\n defaultValue = [],\n isReadOnly,\n ...rest\n } = props;\n const [selected, setSelected] = useState<string[]>(defaultValue);\n const checkboxGroupClasses = classNames(\n \"mobius\",\n \"mobius/CheckboxGroup\",\n className,\n {\n \"--is-horizontal\": orientation === \"horizontal\",\n \"--is-vertical\": orientation === \"vertical\",\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n },\n );\n const labelClasses = classNames({\n \"--is-valid\": validationState === \"valid\",\n \"--is-invalid\": validationState === \"invalid\",\n \"--is-disabled\": isDisabled,\n });\n const errorMessageId = useId();\n const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;\n const describedBy = spaceDelimitedList([\n shouldErrorMessageShow,\n props[\"aria-describedby\"],\n ]);\n const labelId = useId();\n\n const handleChange = (event: ChangeEvent<CheckboxElementType>) => {\n const {\n target: { value, checked },\n } = event;\n\n if (!checked) {\n setSelected(selected.filter(item => item !== value));\n }\n\n if (checked) {\n setSelected([...selected, value]);\n }\n };\n\n useEffect(() => {\n if (onChange) {\n onChange(selected);\n }\n }, [selected, onChange]);\n\n return (\n <div\n {...rest}\n aria-labelledby={props[\"aria-labelledby\"] || labelId}\n ref={ref}\n className={checkboxGroupClasses}\n role=\"group\"\n >\n {label && (\n <Label elementType=\"span\" id={labelId} className={labelClasses}>\n {label}\n </Label>\n )}\n <div className=\"mobius/CheckboxWrapper\">\n {Children.map(children, child => {\n if (isValidElement(child)) {\n return cloneElement(child as ReactElement, {\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/Checkbox/CheckboxGroup.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Children,\n forwardRef,\n ReactElement,\n cloneElement,\n isValidElement,\n useId,\n ChangeEvent,\n useState,\n useEffect,\n} from \"react\";\nimport classNames from \"classnames/dedupe\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport {\n CheckboxElementType,\n CheckboxGroupElementType,\n CheckboxGroupProps,\n CheckboxGroupRef,\n} from \"./types\";\nimport { Label } from \"../Label\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { spaceDelimitedList } from \"../../utils/spaceDelimitedList\";\n\nexport const CheckboxGroup: ForwardedRefComponent<\n CheckboxGroupProps,\n CheckboxGroupElementType\n> = forwardRef((props: CheckboxGroupProps, ref: CheckboxGroupRef) => {\n const {\n label,\n isDisabled = false,\n isRequired,\n validationState,\n orientation = \"vertical\",\n onChange,\n className,\n errorMessage,\n children,\n defaultValue = [],\n isReadOnly,\n itemsPerRow,\n ...rest\n } = props;\n const [selected, setSelected] = useState<string[]>(defaultValue);\n const checkboxGroupClasses = classNames(\n \"mobius\",\n \"mobius/CheckboxGroup\",\n className,\n {\n \"--is-horizontal\": orientation === \"horizontal\",\n \"--is-vertical\": orientation === \"vertical\",\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n },\n );\n const labelClasses = classNames({\n \"--is-valid\": validationState === \"valid\",\n \"--is-invalid\": validationState === \"invalid\",\n \"--is-disabled\": isDisabled,\n });\n const errorMessageId = useId();\n const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;\n const describedBy = spaceDelimitedList([\n shouldErrorMessageShow,\n props[\"aria-describedby\"],\n ]);\n const labelId = useId();\n\n const handleChange = (event: ChangeEvent<CheckboxElementType>) => {\n const {\n target: { value, checked },\n } = event;\n\n if (!checked) {\n setSelected(selected.filter(item => item !== value));\n }\n\n if (checked) {\n setSelected([...selected, value]);\n }\n };\n\n useEffect(() => {\n if (onChange) {\n onChange(selected);\n }\n }, [selected, onChange]);\n\n return (\n <div\n {...rest}\n aria-labelledby={props[\"aria-labelledby\"] || labelId}\n ref={ref}\n className={checkboxGroupClasses}\n role=\"group\"\n style={\n {\n \"--checkbox-items-per-row\": itemsPerRow || Children.count(children),\n } as React.CSSProperties\n }\n >\n {label && (\n <Label elementType=\"span\" id={labelId} className={labelClasses}>\n {label}\n </Label>\n )}\n <div className=\"mobius/CheckboxWrapper\">\n {Children.map(children, child => {\n if (isValidElement(child)) {\n return cloneElement(child as ReactElement, {\n isDisabled,\n isRequired,\n isReadOnly,\n validationState,\n defaultSelected: selected.includes(child.props.value),\n onChange: handleChange,\n \"aria-describedby\": describedBy,\n });\n }\n\n return child;\n })}\n </div>\n {errorMessage && (\n <ErrorMessage id={errorMessageId} errorMessage={errorMessage} />\n )}\n </div>\n );\n});\n"],"names":["Children","forwardRef","cloneElement","isValidElement","useId","useState","useEffect","classNames","Label","ErrorMessage","spaceDelimitedList","CheckboxGroup","props","ref","label","isDisabled","isRequired","validationState","orientation","onChange","className","errorMessage","children","defaultValue","isReadOnly","itemsPerRow","rest","selected","setSelected","checkboxGroupClasses","labelClasses","errorMessageId","shouldErrorMessageShow","undefined","describedBy","labelId","handleChange","event","target","value","checked","filter","item","div","aria-labelledby","role","style","count","elementType","id","map","child","defaultSelected","includes"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;AAEA,SACEA,QAAQ,EACRC,UAAU,EAEVC,YAAY,EACZC,cAAc,EACdC,KAAK,EAELC,QAAQ,EACRC,SAAS,QACJ,QAAQ;AACf,OAAOC,gBAAgB,oBAAoB;AAQ3C,SAASC,KAAK,QAAQ,WAAW;AACjC,SAASC,YAAY,QAAQ,kBAAkB;AAC/C,SAASC,kBAAkB,QAAQ,iCAAiC;AAEpE,OAAO,MAAMC,8BAGTV,WAAW,CAACW,OAA2BC;IACzC,MAAM,EACJC,KAAK,EACLC,aAAa,KAAK,EAClBC,UAAU,EACVC,eAAe,EACfC,cAAc,UAAU,EACxBC,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,QAAQ,EACRC,eAAe,EAAE,EACjBC,UAAU,EACVC,WAAW,EACX,GAAGC,MACJ,GAAGd;IACJ,MAAM,CAACe,UAAUC,YAAY,GAAGvB,SAAmBkB;IACnD,MAAMM,uBAAuBtB,WAC3B,UACA,wBACAa,WACA;QACE,mBAAmBF,gBAAgB;QACnC,iBAAiBA,gBAAgB;QACjC,iBAAiB,OAAOF,eAAe,aAAaA;QACpD,iBAAiB,OAAOA,eAAe,aAAa,CAACA;IACvD;IAEF,MAAMc,eAAevB,WAAW;QAC9B,cAAcU,oBAAoB;QAClC,gBAAgBA,oBAAoB;QACpC,iBAAiBF;IACnB;IACA,MAAMgB,iBAAiB3B;IACvB,MAAM4B,yBAAyBX,eAAeU,iBAAiBE;IAC/D,MAAMC,cAAcxB,mBAAmB;QACrCsB;QACApB,KAAK,CAAC,mBAAmB;KAC1B;IACD,MAAMuB,UAAU/B;IAEhB,MAAMgC,eAAe,CAACC;QACpB,MAAM,EACJC,QAAQ,EAAEC,KAAK,EAAEC,OAAO,EAAE,EAC3B,GAAGH;QAEJ,IAAI,CAACG,SAAS;YACZZ,YAAYD,SAASc,MAAM,CAACC,CAAAA,OAAQA,SAASH;QAC/C;QAEA,IAAIC,SAAS;YACXZ,YAAY;mBAAID;gBAAUY;aAAM;QAClC;IACF;IAEAjC,UAAU;QACR,IAAIa,UAAU;YACZA,SAASQ;QACX;IACF,GAAG;QAACA;QAAUR;KAAS;IAEvB,qBACE,MAACwB;QACE,GAAGjB,IAAI;QACRkB,mBAAiBhC,KAAK,CAAC,kBAAkB,IAAIuB;QAC7CtB,KAAKA;QACLO,WAAWS;QACXgB,MAAK;QACLC,OACE;YACE,4BAA4BrB,eAAezB,SAAS+C,KAAK,CAACzB;QAC5D;;YAGDR,uBACC,KAACN;gBAAMwC,aAAY;gBAAOC,IAAId;gBAASf,WAAWU;0BAC/ChB;;0BAGL,KAAC6B;gBAAIvB,WAAU;0BACZpB,SAASkD,GAAG,CAAC5B,UAAU6B,CAAAA;oBACtB,kBAAIhD,eAAegD,QAAQ;wBACzB,qBAAOjD,aAAaiD,OAAuB;4BACzCpC;4BACAC;4BACAQ;4BACAP;4BACAmC,iBAAiBzB,SAAS0B,QAAQ,CAACF,MAAMvC,KAAK,CAAC2B,KAAK;4BACpDpB,UAAUiB;4BACV,oBAAoBF;wBACtB;oBACF;oBAEA,OAAOiB;gBACT;;YAED9B,8BACC,KAACZ;gBAAawC,IAAIlB;gBAAgBV,cAAcA;;;;AAIxD,GAAG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/Checkbox/types.ts"],"sourcesContent":["import { ChangeEvent, ReactNode, Ref, RefAttributes } from \"react\";\nimport { DOMProps } from \"../../types/dom\";\n\nexport type CheckboxElementType = HTMLInputElement;\nexport type CheckboxRef = Ref<CheckboxElementType>;\n\nexport interface CheckboxProps\n extends DOMProps,\n RefAttributes<CheckboxElementType> {\n className?: string;\n // The content to display as the label.\n label?: ReactNode;\n errorMessage?: string;\n /** The current value (controlled). */\n value?: string;\n // Whether the input is disabled.\n isDisabled?: boolean;\n onChange?: (event: ChangeEvent<CheckboxElementType>) => void;\n // The default value (uncontrolled).\n defaultSelected?: boolean;\n // Whether the input should display its \"valid\" or \"invalid\" visual styling.\n validationState?: \"valid\" | \"invalid\";\n // Whether the input can be selected but not changed by the user.\n isReadOnly?: boolean;\n // Whether user input is required on the input before form submission.\n isRequired?: boolean;\n // Identifies the element that provides an error message for the object.\n \"aria-errormessage\"?: string;\n /**\n * Identifies the element (or elements) that describes the object.\n */\n \"aria-describedby\"?: string;\n /**\n * **Internal:** Do not use\n */\n groupDisabled?: boolean;\n /**\n * **Internal:** Do not use\n */\n selected?: string;\n /**\n * **Internal:** Do not use\n */\n setSelected?: React.Dispatch<React.SetStateAction<string>>;\n}\n\nexport type CheckboxGroupElementType = HTMLDivElement;\
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/Checkbox/types.ts"],"sourcesContent":["import { ChangeEvent, ReactNode, Ref, RefAttributes } from \"react\";\nimport { DOMProps } from \"../../types/dom\";\n\nexport type CheckboxElementType = HTMLInputElement;\nexport type CheckboxRef = Ref<CheckboxElementType>;\n\nexport interface CheckboxProps\n extends DOMProps,\n RefAttributes<CheckboxElementType> {\n className?: string;\n // The content to display as the label.\n label?: ReactNode;\n errorMessage?: string;\n /** The current value (controlled). */\n value?: string;\n // Whether the input is disabled.\n isDisabled?: boolean;\n onChange?: (event: ChangeEvent<CheckboxElementType>) => void;\n // The default value (uncontrolled).\n defaultSelected?: boolean;\n // Whether the input should display its \"valid\" or \"invalid\" visual styling.\n validationState?: \"valid\" | \"invalid\";\n // Whether the input can be selected but not changed by the user.\n isReadOnly?: boolean;\n // Whether user input is required on the input before form submission.\n isRequired?: boolean;\n // Identifies the element that provides an error message for the object.\n \"aria-errormessage\"?: string;\n /**\n * Identifies the element (or elements) that describes the object.\n */\n \"aria-describedby\"?: string;\n /**\n * **Internal:** Do not use\n */\n groupDisabled?: boolean;\n /**\n * **Internal:** Do not use\n */\n selected?: string;\n /**\n * **Internal:** Do not use\n */\n setSelected?: React.Dispatch<React.SetStateAction<string>>;\n}\n\nexport type CheckboxGroupElementType = HTMLDivElement;\ninterface CheckboxGroupPropsInternal\n extends DOMProps,\n RefAttributes<CheckboxGroupElementType> {\n children: ReactNode;\n className?: string;\n orientation?: \"horizontal\" | \"vertical\";\n // Defines number of items to be displayed on a single row when used with orientation=\"horizontal\". Defaults to number of items in the group.\n itemsPerRow?: number;\n errorMessage?: string;\n onChange?: (values: string[]) => void;\n // Defines a string value that labels the current element.\n // \"aria-label\"?: string;\n // Identifies the element (or elements) that labels the current element.\n \"aria-labelledby\"?: string;\n // Identifies the element that provides an error message for the object.\n // \"aria-errormessage\"?: string;\n // Identifies the element (or elements) that describes the object.\n \"aria-describedby\"?: string;\n // Whether the input should display its \"valid\" or \"invalid\" visual styling.\n validationState?: \"valid\" | \"invalid\";\n // Whether user input is required on the input before form submission.\n isRequired?: boolean;\n // Whether the input is disabled.\n isDisabled?: boolean;\n // Whether the input can be selected but not changed by the user.\n isReadOnly?: boolean;\n // The default value (uncontrolled).\n defaultValue?: string[];\n // The content to display as the label.\n label?: ReactNode;\n /**\n * The value of the radio button, used when submitting an HTML form.\n * See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio#Value).\n */\n value?: string;\n}\n\ninterface HorizontalCheckboxGroupProps extends CheckboxGroupPropsInternal {\n orientation?: \"horizontal\";\n itemsPerRow: number;\n}\n\ninterface VerticalCheckboxGroupProps extends CheckboxGroupPropsInternal {\n orientation?: \"vertical\";\n itemsPerRow?: never;\n}\n\nexport type CheckboxGroupProps =\n | HorizontalCheckboxGroupProps\n | VerticalCheckboxGroupProps;\n\nexport type CheckboxGroupRef = Ref<CheckboxGroupElementType>;\n"],"names":[],"rangeMappings":"","mappings":"AAkGA,WAA6D"}
|
|
@@ -3,7 +3,6 @@ import { filterUndefinedProps } from "../../utils/filterUndefinedProps";
|
|
|
3
3
|
export const buildFlexStyles = (props)=>{
|
|
4
4
|
const { flexDirection, flexWrap, flexGrow, flex, justifyContent, alignItems, alignContent, gap, rowGap, columnGap } = props;
|
|
5
5
|
const styleProps = {
|
|
6
|
-
display: "flex",
|
|
7
6
|
flexDirection,
|
|
8
7
|
flexWrap,
|
|
9
8
|
flexGrow,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/Flex/propUtils.ts"],"sourcesContent":["import { getSpacingValue } from \"../../utils\";\nimport { filterUndefinedProps } from \"../../utils/filterUndefinedProps\";\nimport { FlexNonStyleProps, FlexProps, FlexStyleProps } from \"./types\";\n\nexport const buildFlexStyles = (props: FlexStyleProps) => {\n const {\n flexDirection,\n flexWrap,\n flexGrow,\n flex,\n justifyContent,\n alignItems,\n alignContent,\n gap,\n rowGap,\n columnGap,\n } = props;\n\n const styleProps = {\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/Flex/propUtils.ts"],"sourcesContent":["import { getSpacingValue } from \"../../utils\";\nimport { filterUndefinedProps } from \"../../utils/filterUndefinedProps\";\nimport { FlexNonStyleProps, FlexProps, FlexStyleProps } from \"./types\";\n\nexport const buildFlexStyles = (props: FlexStyleProps) => {\n const {\n flexDirection,\n flexWrap,\n flexGrow,\n flex,\n justifyContent,\n alignItems,\n alignContent,\n gap,\n rowGap,\n columnGap,\n } = props;\n\n const styleProps = {\n flexDirection,\n flexWrap,\n flexGrow,\n flex,\n justifyContent,\n alignItems,\n alignContent,\n gap: getSpacingValue(gap),\n columnGap: getSpacingValue(columnGap),\n rowGap: getSpacingValue(rowGap),\n };\n\n return filterUndefinedProps(styleProps);\n};\n\nexport const splitProps = (\n props: FlexProps,\n): [FlexStyleProps, FlexNonStyleProps] => {\n const {\n flexDirection,\n flexWrap,\n flexGrow,\n flex,\n justifyContent,\n alignItems,\n alignContent,\n gap,\n rowGap,\n columnGap,\n ...otherProps\n } = props;\n\n return [\n {\n flexDirection,\n flexWrap,\n flexGrow,\n flex,\n justifyContent,\n alignItems,\n alignContent,\n gap,\n rowGap,\n columnGap,\n },\n otherProps,\n ];\n};\n"],"names":["getSpacingValue","filterUndefinedProps","buildFlexStyles","props","flexDirection","flexWrap","flexGrow","flex","justifyContent","alignItems","alignContent","gap","rowGap","columnGap","styleProps","splitProps","otherProps"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,eAAe,QAAQ,cAAc;AAC9C,SAASC,oBAAoB,QAAQ,mCAAmC;AAGxE,OAAO,MAAMC,kBAAkB,CAACC;IAC9B,MAAM,EACJC,aAAa,EACbC,QAAQ,EACRC,QAAQ,EACRC,IAAI,EACJC,cAAc,EACdC,UAAU,EACVC,YAAY,EACZC,GAAG,EACHC,MAAM,EACNC,SAAS,EACV,GAAGV;IAEJ,MAAMW,aAAa;QACjBV;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC,KAAKX,gBAAgBW;QACrBE,WAAWb,gBAAgBa;QAC3BD,QAAQZ,gBAAgBY;IAC1B;IAEA,OAAOX,qBAAqBa;AAC9B,EAAE;AAEF,OAAO,MAAMC,aAAa,CACxBZ;IAEA,MAAM,EACJC,aAAa,EACbC,QAAQ,EACRC,QAAQ,EACRC,IAAI,EACJC,cAAc,EACdC,UAAU,EACVC,YAAY,EACZC,GAAG,EACHC,MAAM,EACNC,SAAS,EACT,GAAGG,YACJ,GAAGb;IAEJ,OAAO;QACL;YACEC;YACAC;YACAC;YACAC;YACAC;YACAC;YACAC;YACAC;YACAC;YACAC;QACF;QACAG;KACD;AACH,EAAE"}
|
|
@@ -3,6 +3,7 @@ import { CheckboxGroup } from ".";
|
|
|
3
3
|
type StoryType = StoryObj<typeof CheckboxGroup>;
|
|
4
4
|
declare const meta: Meta<typeof CheckboxGroup>;
|
|
5
5
|
export declare const Normal: StoryType;
|
|
6
|
+
export declare const Horizontal: StoryType;
|
|
6
7
|
export declare const Disabled: StoryType;
|
|
7
8
|
export declare const Valid: StoryType;
|
|
8
9
|
export declare const Invalid: StoryType;
|
|
@@ -33,10 +33,11 @@ export interface CheckboxProps extends DOMProps, RefAttributes<CheckboxElementTy
|
|
|
33
33
|
setSelected?: React.Dispatch<React.SetStateAction<string>>;
|
|
34
34
|
}
|
|
35
35
|
export type CheckboxGroupElementType = HTMLDivElement;
|
|
36
|
-
|
|
36
|
+
interface CheckboxGroupPropsInternal extends DOMProps, RefAttributes<CheckboxGroupElementType> {
|
|
37
37
|
children: ReactNode;
|
|
38
38
|
className?: string;
|
|
39
39
|
orientation?: "horizontal" | "vertical";
|
|
40
|
+
itemsPerRow?: number;
|
|
40
41
|
errorMessage?: string;
|
|
41
42
|
onChange?: (values: string[]) => void;
|
|
42
43
|
"aria-labelledby"?: string;
|
|
@@ -53,4 +54,14 @@ export interface CheckboxGroupProps extends DOMProps, RefAttributes<CheckboxGrou
|
|
|
53
54
|
*/
|
|
54
55
|
value?: string;
|
|
55
56
|
}
|
|
57
|
+
interface HorizontalCheckboxGroupProps extends CheckboxGroupPropsInternal {
|
|
58
|
+
orientation?: "horizontal";
|
|
59
|
+
itemsPerRow: number;
|
|
60
|
+
}
|
|
61
|
+
interface VerticalCheckboxGroupProps extends CheckboxGroupPropsInternal {
|
|
62
|
+
orientation?: "vertical";
|
|
63
|
+
itemsPerRow?: never;
|
|
64
|
+
}
|
|
65
|
+
export type CheckboxGroupProps = HorizontalCheckboxGroupProps | VerticalCheckboxGroupProps;
|
|
56
66
|
export type CheckboxGroupRef = Ref<CheckboxGroupElementType>;
|
|
67
|
+
export {};
|
package/package.json
CHANGED
|
@@ -64,6 +64,19 @@ describe("Checkbox", () => {
|
|
|
64
64
|
expect(option).toHaveAccessibleDescription(errorText);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
+
it("should pass additional props as attributes to the input element", () => {
|
|
68
|
+
const optionText = "Agree";
|
|
69
|
+
const dataTestId = "test";
|
|
70
|
+
|
|
71
|
+
const { getByLabelText } = render(
|
|
72
|
+
<Checkbox label={optionText} data-testid={dataTestId} value="value" />,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const option = getByLabelText(optionText);
|
|
76
|
+
|
|
77
|
+
expect(option).toHaveAttribute("data-testid", dataTestId);
|
|
78
|
+
});
|
|
79
|
+
|
|
67
80
|
describe("isRequired", () => {
|
|
68
81
|
it("should set required attribute", () => {
|
|
69
82
|
const optionText = "Agree";
|
|
@@ -31,6 +31,8 @@ export const Checkbox: ForwardedRefComponent<
|
|
|
31
31
|
defaultSelected = false,
|
|
32
32
|
isReadOnly,
|
|
33
33
|
value,
|
|
34
|
+
["aria-describedby"]: ariaDescribedBy,
|
|
35
|
+
...rest
|
|
34
36
|
} = props;
|
|
35
37
|
const [selected, setSelected] = useState<boolean>(defaultSelected);
|
|
36
38
|
const fallbackRef = useRef<HTMLInputElement>(null);
|
|
@@ -58,7 +60,7 @@ export const Checkbox: ForwardedRefComponent<
|
|
|
58
60
|
const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;
|
|
59
61
|
const describedBy = spaceDelimitedList([
|
|
60
62
|
shouldErrorMessageShow,
|
|
61
|
-
|
|
63
|
+
ariaDescribedBy,
|
|
62
64
|
]);
|
|
63
65
|
const labelId = useId();
|
|
64
66
|
|
|
@@ -105,6 +107,7 @@ export const Checkbox: ForwardedRefComponent<
|
|
|
105
107
|
required={isRequired}
|
|
106
108
|
id={id || inputId}
|
|
107
109
|
value={value}
|
|
110
|
+
{...rest}
|
|
108
111
|
/>
|
|
109
112
|
<span className="mobius/CheckboxLabel">{label}</span>
|
|
110
113
|
</label>
|
|
@@ -47,6 +47,26 @@ export const Normal: StoryType = {
|
|
|
47
47
|
},
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
+
export const Horizontal: StoryType = {
|
|
51
|
+
render: (args: CheckboxGroupProps) => (
|
|
52
|
+
<CheckboxGroup {...args}>
|
|
53
|
+
<Checkbox label="Option 1" value="option1" />
|
|
54
|
+
<Checkbox label="Option 2" value="option2" />
|
|
55
|
+
<Checkbox label="Option 3" value="option3" />
|
|
56
|
+
<Checkbox label="Option 4" value="option4" />
|
|
57
|
+
</CheckboxGroup>
|
|
58
|
+
),
|
|
59
|
+
args: {
|
|
60
|
+
label: "Value",
|
|
61
|
+
errorMessage: "",
|
|
62
|
+
isDisabled: false,
|
|
63
|
+
orientation: "horizontal",
|
|
64
|
+
defaultValue: ["option2", "option4"],
|
|
65
|
+
isRequired: false,
|
|
66
|
+
itemsPerRow: 2,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
50
70
|
export const Disabled: StoryType = {
|
|
51
71
|
render: (args: CheckboxGroupProps) => (
|
|
52
72
|
<CheckboxGroup {...args}>
|
|
@@ -67,76 +67,6 @@ describe("CheckboxGroup", () => {
|
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
describe("isRequired", () => {
|
|
71
|
-
it("should have className of --is-required when true", () => {
|
|
72
|
-
const outerContainerLabel = "Checkbox Group";
|
|
73
|
-
const REQUIRED_CLASS_NAME = "--is-required";
|
|
74
|
-
|
|
75
|
-
render(
|
|
76
|
-
<CheckboxGroup
|
|
77
|
-
label={outerContainerLabel}
|
|
78
|
-
errorMessage="Error message"
|
|
79
|
-
isRequired
|
|
80
|
-
>
|
|
81
|
-
<Checkbox label="Checkbox 1" value="value1" />
|
|
82
|
-
<Checkbox label="Checkbox 2" value="value2" />
|
|
83
|
-
</CheckboxGroup>,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const outerContainer = screen.getByLabelText(outerContainerLabel);
|
|
87
|
-
const checkboxes = screen.getAllByRole("checkbox");
|
|
88
|
-
|
|
89
|
-
expect(outerContainer).toHaveClass(REQUIRED_CLASS_NAME);
|
|
90
|
-
|
|
91
|
-
checkboxes.forEach(checkbox => {
|
|
92
|
-
expect(checkbox).toHaveClass(REQUIRED_CLASS_NAME);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("should have className of --is-optional when false", () => {
|
|
97
|
-
const outerContainerLabel = "Checkbox Group";
|
|
98
|
-
const OPTIONAL_CLASS_NAME = "--is-optional";
|
|
99
|
-
|
|
100
|
-
render(
|
|
101
|
-
<CheckboxGroup
|
|
102
|
-
label={outerContainerLabel}
|
|
103
|
-
errorMessage="Error message"
|
|
104
|
-
isRequired={false}
|
|
105
|
-
>
|
|
106
|
-
<Checkbox label="Checkbox 1" value="value1" />
|
|
107
|
-
<Checkbox label="Checkbox 2" value="value2" />
|
|
108
|
-
</CheckboxGroup>,
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
const outerContainer = screen.getByLabelText(outerContainerLabel);
|
|
112
|
-
const checkboxes = screen.getAllByRole("checkbox");
|
|
113
|
-
|
|
114
|
-
expect(outerContainer).toHaveClass(OPTIONAL_CLASS_NAME);
|
|
115
|
-
|
|
116
|
-
checkboxes.forEach(checkbox => {
|
|
117
|
-
expect(checkbox).toHaveClass(OPTIONAL_CLASS_NAME);
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it("should have neither --is-required nor --is-optional when unset", () => {
|
|
122
|
-
const outerContainerLabel = "Checkbox Group";
|
|
123
|
-
const REQUIRED_CLASS_NAME = "--is-required";
|
|
124
|
-
const OPTIONAL_CLASS_NAME = "--is-optional";
|
|
125
|
-
|
|
126
|
-
render(
|
|
127
|
-
<CheckboxGroup label={outerContainerLabel} errorMessage="Error message">
|
|
128
|
-
<Checkbox label="Checkbox 1" value="value1" />
|
|
129
|
-
<Checkbox label="Checkbox 2" value="value2" />
|
|
130
|
-
</CheckboxGroup>,
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
const outerContainer = screen.getByLabelText(outerContainerLabel);
|
|
134
|
-
|
|
135
|
-
expect(outerContainer).not.toHaveClass(REQUIRED_CLASS_NAME);
|
|
136
|
-
expect(outerContainer).not.toHaveClass(OPTIONAL_CLASS_NAME);
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
70
|
describe("onChange", () => {
|
|
141
71
|
describe("given an item is toggled", () => {
|
|
142
72
|
it("should call onChange with a list of toggled items", async () => {
|
|
@@ -316,6 +246,74 @@ describe("CheckboxGroup", () => {
|
|
|
316
246
|
expect(option).not.toHaveClass("--is-required");
|
|
317
247
|
expect(option).not.toHaveClass("--is-optional");
|
|
318
248
|
});
|
|
249
|
+
|
|
250
|
+
it("should have className of --is-required when true", () => {
|
|
251
|
+
const outerContainerLabel = "Checkbox Group";
|
|
252
|
+
const REQUIRED_CLASS_NAME = "--is-required";
|
|
253
|
+
|
|
254
|
+
render(
|
|
255
|
+
<CheckboxGroup
|
|
256
|
+
label={outerContainerLabel}
|
|
257
|
+
errorMessage="Error message"
|
|
258
|
+
isRequired
|
|
259
|
+
>
|
|
260
|
+
<Checkbox label="Checkbox 1" value="value1" />
|
|
261
|
+
<Checkbox label="Checkbox 2" value="value2" />
|
|
262
|
+
</CheckboxGroup>,
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
const outerContainer = screen.getByLabelText(outerContainerLabel);
|
|
266
|
+
const checkboxes = screen.getAllByRole("checkbox");
|
|
267
|
+
|
|
268
|
+
expect(outerContainer).toHaveClass(REQUIRED_CLASS_NAME);
|
|
269
|
+
|
|
270
|
+
checkboxes.forEach(checkbox => {
|
|
271
|
+
expect(checkbox).toHaveClass(REQUIRED_CLASS_NAME);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("should have className of --is-optional when false", () => {
|
|
276
|
+
const outerContainerLabel = "Checkbox Group";
|
|
277
|
+
const OPTIONAL_CLASS_NAME = "--is-optional";
|
|
278
|
+
|
|
279
|
+
render(
|
|
280
|
+
<CheckboxGroup
|
|
281
|
+
label={outerContainerLabel}
|
|
282
|
+
errorMessage="Error message"
|
|
283
|
+
isRequired={false}
|
|
284
|
+
>
|
|
285
|
+
<Checkbox label="Checkbox 1" value="value1" />
|
|
286
|
+
<Checkbox label="Checkbox 2" value="value2" />
|
|
287
|
+
</CheckboxGroup>,
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
const outerContainer = screen.getByLabelText(outerContainerLabel);
|
|
291
|
+
const checkboxes = screen.getAllByRole("checkbox");
|
|
292
|
+
|
|
293
|
+
expect(outerContainer).toHaveClass(OPTIONAL_CLASS_NAME);
|
|
294
|
+
|
|
295
|
+
checkboxes.forEach(checkbox => {
|
|
296
|
+
expect(checkbox).toHaveClass(OPTIONAL_CLASS_NAME);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it("should have neither --is-required nor --is-optional when unset", () => {
|
|
301
|
+
const outerContainerLabel = "Checkbox Group";
|
|
302
|
+
const REQUIRED_CLASS_NAME = "--is-required";
|
|
303
|
+
const OPTIONAL_CLASS_NAME = "--is-optional";
|
|
304
|
+
|
|
305
|
+
render(
|
|
306
|
+
<CheckboxGroup label={outerContainerLabel} errorMessage="Error message">
|
|
307
|
+
<Checkbox label="Checkbox 1" value="value1" />
|
|
308
|
+
<Checkbox label="Checkbox 2" value="value2" />
|
|
309
|
+
</CheckboxGroup>,
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
const outerContainer = screen.getByLabelText(outerContainerLabel);
|
|
313
|
+
|
|
314
|
+
expect(outerContainer).not.toHaveClass(REQUIRED_CLASS_NAME);
|
|
315
|
+
expect(outerContainer).not.toHaveClass(OPTIONAL_CLASS_NAME);
|
|
316
|
+
});
|
|
319
317
|
});
|
|
320
318
|
|
|
321
319
|
describe("uses correct class names", () => {
|
|
@@ -359,6 +357,24 @@ describe("CheckboxGroup", () => {
|
|
|
359
357
|
expect(option).toHaveClass("--is-disabled");
|
|
360
358
|
});
|
|
361
359
|
|
|
360
|
+
describe("includes orientation class name", () => {
|
|
361
|
+
it.each(["horizontal", "vertical"])(
|
|
362
|
+
"when orientation is %s",
|
|
363
|
+
orientation => {
|
|
364
|
+
const optionText = "Agree";
|
|
365
|
+
|
|
366
|
+
const { container } = render(
|
|
367
|
+
// @ts-expect-error can't assert as CheckboxGroupProps["orientation"]
|
|
368
|
+
<CheckboxGroup orientation={orientation}>
|
|
369
|
+
<Checkbox label={optionText} value="value" />
|
|
370
|
+
</CheckboxGroup>,
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
expect(container.firstChild).toHaveClass(`--is-${orientation}`);
|
|
374
|
+
},
|
|
375
|
+
);
|
|
376
|
+
});
|
|
377
|
+
|
|
362
378
|
it("includes valid class name", () => {
|
|
363
379
|
const optionText = "Agree";
|
|
364
380
|
|
|
@@ -445,6 +461,41 @@ describe("CheckboxGroup", () => {
|
|
|
445
461
|
});
|
|
446
462
|
});
|
|
447
463
|
|
|
464
|
+
describe("items per row", () => {
|
|
465
|
+
describe("when props is set", () => {
|
|
466
|
+
it("provides CSS variable with the number of items per row", () => {
|
|
467
|
+
const { container } = render(
|
|
468
|
+
<CheckboxGroup itemsPerRow={2}>
|
|
469
|
+
<Checkbox label="Option 1" value="value1" />
|
|
470
|
+
<Checkbox label="Option 2" value="value2" />
|
|
471
|
+
<Checkbox label="Option 3" value="value3" />
|
|
472
|
+
<Checkbox label="Option 4" value="value4" />
|
|
473
|
+
</CheckboxGroup>,
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
expect(container.firstChild).toHaveStyle("--checkbox-items-per-row: 2");
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
describe("when props is not set", () => {
|
|
481
|
+
it("provides CSS variable with the number of items per row", () => {
|
|
482
|
+
const numberOfItems = 3;
|
|
483
|
+
|
|
484
|
+
const { container } = render(
|
|
485
|
+
<CheckboxGroup>
|
|
486
|
+
<Checkbox label="Option 1" value="value1" />
|
|
487
|
+
<Checkbox label="Option 2" value="value2" />
|
|
488
|
+
<Checkbox label="Option 3" value="value3" />
|
|
489
|
+
</CheckboxGroup>,
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
expect(container.firstChild).toHaveStyle(
|
|
493
|
+
`--checkbox-items-per-row: ${numberOfItems}`,
|
|
494
|
+
);
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
448
499
|
describe("given the component is read only", () => {
|
|
449
500
|
it("renders readonly attribute", () => {
|
|
450
501
|
const optionText = "Agree";
|
|
@@ -39,6 +39,7 @@ export const CheckboxGroup: ForwardedRefComponent<
|
|
|
39
39
|
children,
|
|
40
40
|
defaultValue = [],
|
|
41
41
|
isReadOnly,
|
|
42
|
+
itemsPerRow,
|
|
42
43
|
...rest
|
|
43
44
|
} = props;
|
|
44
45
|
const [selected, setSelected] = useState<string[]>(defaultValue);
|
|
@@ -93,6 +94,11 @@ export const CheckboxGroup: ForwardedRefComponent<
|
|
|
93
94
|
ref={ref}
|
|
94
95
|
className={checkboxGroupClasses}
|
|
95
96
|
role="group"
|
|
97
|
+
style={
|
|
98
|
+
{
|
|
99
|
+
"--checkbox-items-per-row": itemsPerRow || Children.count(children),
|
|
100
|
+
} as React.CSSProperties
|
|
101
|
+
}
|
|
96
102
|
>
|
|
97
103
|
{label && (
|
|
98
104
|
<Label elementType="span" id={labelId} className={labelClasses}>
|
|
@@ -103,7 +109,6 @@ export const CheckboxGroup: ForwardedRefComponent<
|
|
|
103
109
|
{Children.map(children, child => {
|
|
104
110
|
if (isValidElement(child)) {
|
|
105
111
|
return cloneElement(child as ReactElement, {
|
|
106
|
-
orientation,
|
|
107
112
|
isDisabled,
|
|
108
113
|
isRequired,
|
|
109
114
|
isReadOnly,
|
|
@@ -45,13 +45,14 @@ export interface CheckboxProps
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export type CheckboxGroupElementType = HTMLDivElement;
|
|
48
|
-
|
|
49
|
-
export interface CheckboxGroupProps
|
|
48
|
+
interface CheckboxGroupPropsInternal
|
|
50
49
|
extends DOMProps,
|
|
51
50
|
RefAttributes<CheckboxGroupElementType> {
|
|
52
51
|
children: ReactNode;
|
|
53
52
|
className?: string;
|
|
54
53
|
orientation?: "horizontal" | "vertical";
|
|
54
|
+
// Defines number of items to be displayed on a single row when used with orientation="horizontal". Defaults to number of items in the group.
|
|
55
|
+
itemsPerRow?: number;
|
|
55
56
|
errorMessage?: string;
|
|
56
57
|
onChange?: (values: string[]) => void;
|
|
57
58
|
// Defines a string value that labels the current element.
|
|
@@ -81,4 +82,18 @@ export interface CheckboxGroupProps
|
|
|
81
82
|
value?: string;
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
interface HorizontalCheckboxGroupProps extends CheckboxGroupPropsInternal {
|
|
86
|
+
orientation?: "horizontal";
|
|
87
|
+
itemsPerRow: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface VerticalCheckboxGroupProps extends CheckboxGroupPropsInternal {
|
|
91
|
+
orientation?: "vertical";
|
|
92
|
+
itemsPerRow?: never;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type CheckboxGroupProps =
|
|
96
|
+
| HorizontalCheckboxGroupProps
|
|
97
|
+
| VerticalCheckboxGroupProps;
|
|
98
|
+
|
|
84
99
|
export type CheckboxGroupRef = Ref<CheckboxGroupElementType>;
|
|
@@ -23,7 +23,6 @@ describe("buildFlexStyles", () => {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
const expectedProps = {
|
|
26
|
-
display: "flex",
|
|
27
26
|
...props,
|
|
28
27
|
...transformedProps,
|
|
29
28
|
};
|
|
@@ -55,7 +54,6 @@ describe("buildFlexStyles", () => {
|
|
|
55
54
|
justifyContent: "start",
|
|
56
55
|
alignContent: "center",
|
|
57
56
|
rowGap: "20px",
|
|
58
|
-
display: "flex",
|
|
59
57
|
};
|
|
60
58
|
|
|
61
59
|
const actual = buildFlexStyles(props);
|