@simplybusiness/mobius 5.3.1 → 5.5.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/CHANGELOG.md +23 -0
- package/dist/cjs/components/Checkbox/Checkbox.js +16 -22
- package/dist/cjs/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/cjs/components/Checkbox/CheckboxGroup.js +29 -11
- package/dist/cjs/components/Checkbox/CheckboxGroup.js.map +1 -1
- package/dist/cjs/components/Combobox/Combobox.js +129 -0
- package/dist/cjs/components/Combobox/Combobox.js.map +1 -0
- package/dist/cjs/components/Combobox/fixtures.js +244 -0
- package/dist/cjs/components/Combobox/fixtures.js.map +1 -0
- package/dist/cjs/components/Combobox/index.js +21 -0
- package/dist/cjs/components/Combobox/index.js.map +1 -0
- package/dist/cjs/components/Combobox/types.js +6 -0
- package/dist/cjs/components/Combobox/types.js.map +1 -0
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/hooks/index.js +1 -0
- package/dist/cjs/hooks/index.js.map +1 -1
- package/dist/cjs/hooks/useRenderCount/index.js +20 -0
- package/dist/cjs/hooks/useRenderCount/index.js.map +1 -0
- package/dist/cjs/hooks/useRenderCount/useRenderCount.js +20 -0
- package/dist/cjs/hooks/useRenderCount/useRenderCount.js.map +1 -0
- package/dist/cjs/hooks/useTextField/useTextField.js +1 -0
- package/dist/cjs/hooks/useTextField/useTextField.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/components/Checkbox/Checkbox.js +17 -23
- package/dist/esm/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/esm/components/Checkbox/CheckboxGroup.js +29 -11
- package/dist/esm/components/Checkbox/CheckboxGroup.js.map +1 -1
- package/dist/esm/components/Checkbox/types.js.map +1 -1
- package/dist/esm/components/Combobox/Combobox.js +114 -0
- package/dist/esm/components/Combobox/Combobox.js.map +1 -0
- package/dist/esm/components/Combobox/fixtures.js +226 -0
- package/dist/esm/components/Combobox/fixtures.js.map +1 -0
- package/dist/esm/components/Combobox/index.js +4 -0
- package/dist/esm/components/Combobox/index.js.map +1 -0
- package/dist/esm/components/Combobox/types.js +3 -0
- package/dist/esm/components/Combobox/types.js.map +1 -0
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/hooks/index.js +1 -0
- package/dist/esm/hooks/index.js.map +1 -1
- package/dist/esm/hooks/useRenderCount/index.js +3 -0
- package/dist/esm/hooks/useRenderCount/index.js.map +1 -0
- package/dist/esm/hooks/useRenderCount/useRenderCount.js +10 -0
- package/dist/esm/hooks/useRenderCount/useRenderCount.js.map +1 -0
- package/dist/esm/hooks/useTextField/types.js.map +1 -1
- package/dist/esm/hooks/useTextField/useTextField.js +1 -0
- package/dist/esm/hooks/useTextField/useTextField.js.map +1 -1
- package/dist/types/components/Checkbox/CheckboxGroup.stories.d.ts +1 -0
- package/dist/types/components/Checkbox/types.d.ts +10 -6
- package/dist/types/components/Combobox/Combobox.d.ts +3 -0
- package/dist/types/components/Combobox/Combobox.stories.d.ts +7 -0
- package/dist/types/components/Combobox/Combobox.test.d.ts +1 -0
- package/dist/types/components/Combobox/fixtures.d.ts +5 -0
- package/dist/types/components/Combobox/index.d.ts +2 -0
- package/dist/types/components/Combobox/types.d.ts +16 -0
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/hooks/index.d.ts +1 -0
- package/dist/types/hooks/useRenderCount/index.d.ts +1 -0
- package/dist/types/hooks/useRenderCount/useRenderCount.d.ts +1 -0
- package/dist/types/hooks/useRenderCount/useRenderCount.test.d.ts +1 -0
- package/dist/types/hooks/useTextField/types.d.ts +3 -2
- package/package.json +17 -17
- package/src/components/Checkbox/Checkbox.tsx +18 -28
- package/src/components/Checkbox/CheckboxGroup.stories.tsx +15 -0
- package/src/components/Checkbox/CheckboxGroup.test.tsx +107 -1
- package/src/components/Checkbox/CheckboxGroup.tsx +45 -15
- package/src/components/Checkbox/types.ts +13 -6
- package/src/components/Combobox/Combobox.css +30 -0
- package/src/components/Combobox/Combobox.stories.tsx +26 -0
- package/src/components/Combobox/Combobox.test.tsx +578 -0
- package/src/components/Combobox/Combobox.tsx +154 -0
- package/src/components/Combobox/fixtures.tsx +93 -0
- package/src/components/Combobox/index.tsx +2 -0
- package/src/components/Combobox/types.tsx +20 -0
- package/src/components/index.tsx +1 -0
- package/src/hooks/index.tsx +1 -0
- package/src/hooks/useRenderCount/index.ts +1 -0
- package/src/hooks/useRenderCount/useRenderCount.test.ts +26 -0
- package/src/hooks/useRenderCount/useRenderCount.ts +9 -0
- package/src/hooks/useTextField/types.tsx +7 -1
- package/src/hooks/useTextField/useTextField.test.tsx +1 -0
- package/src/hooks/useTextField/useTextField.tsx +1 -0
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import classNames from "classnames/dedupe";
|
|
3
4
|
import {
|
|
5
|
+
type ChangeEvent,
|
|
6
|
+
type ReactElement,
|
|
4
7
|
Children,
|
|
5
|
-
forwardRef,
|
|
6
|
-
ReactElement,
|
|
7
8
|
cloneElement,
|
|
9
|
+
forwardRef,
|
|
8
10
|
isValidElement,
|
|
11
|
+
useEffect,
|
|
9
12
|
useId,
|
|
10
|
-
ChangeEvent,
|
|
11
13
|
useState,
|
|
12
|
-
useEffect,
|
|
13
14
|
} from "react";
|
|
14
|
-
import
|
|
15
|
+
import { useRenderCount, useValidationClasses } from "../../hooks";
|
|
15
16
|
import { ForwardedRefComponent } from "../../types/components";
|
|
17
|
+
import { spaceDelimitedList } from "../../utils/spaceDelimitedList";
|
|
18
|
+
import { ErrorMessage } from "../ErrorMessage";
|
|
19
|
+
import { Label } from "../Label";
|
|
20
|
+
import { Checkbox } from "./Checkbox";
|
|
16
21
|
import {
|
|
17
22
|
CheckboxElementType,
|
|
18
23
|
CheckboxGroupElementType,
|
|
19
24
|
CheckboxGroupProps,
|
|
20
25
|
CheckboxGroupRef,
|
|
21
26
|
} from "./types";
|
|
22
|
-
import { Label } from "../Label";
|
|
23
|
-
import { ErrorMessage } from "../ErrorMessage";
|
|
24
|
-
import { spaceDelimitedList } from "../../utils/spaceDelimitedList";
|
|
25
|
-
import { useValidationClasses } from "../../hooks";
|
|
26
27
|
|
|
27
28
|
export const CheckboxGroup: ForwardedRefComponent<
|
|
28
29
|
CheckboxGroupProps,
|
|
@@ -42,6 +43,7 @@ export const CheckboxGroup: ForwardedRefComponent<
|
|
|
42
43
|
defaultValue = [],
|
|
43
44
|
isReadOnly,
|
|
44
45
|
itemsPerRow,
|
|
46
|
+
lastItemDisables = false,
|
|
45
47
|
...rest
|
|
46
48
|
} = props;
|
|
47
49
|
const [selected, setSelected] = useState<string[]>(defaultValue);
|
|
@@ -74,7 +76,10 @@ export const CheckboxGroup: ForwardedRefComponent<
|
|
|
74
76
|
]);
|
|
75
77
|
const labelId = useId();
|
|
76
78
|
|
|
77
|
-
const handleChange = (
|
|
79
|
+
const handleChange = (
|
|
80
|
+
event: ChangeEvent<CheckboxElementType>,
|
|
81
|
+
isLastItem = false,
|
|
82
|
+
) => {
|
|
78
83
|
const {
|
|
79
84
|
target: { value, checked },
|
|
80
85
|
} = event;
|
|
@@ -83,16 +88,34 @@ export const CheckboxGroup: ForwardedRefComponent<
|
|
|
83
88
|
setSelected(selected.filter(item => item !== value));
|
|
84
89
|
}
|
|
85
90
|
|
|
91
|
+
if (checked && lastItemDisables && isLastItem) {
|
|
92
|
+
setSelected([value]);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
86
96
|
if (checked) {
|
|
87
97
|
setSelected([...selected, value]);
|
|
88
98
|
}
|
|
89
99
|
};
|
|
90
100
|
|
|
101
|
+
// HACK: This is a workaround to ensure that the onChange event is not
|
|
102
|
+
// fired on the initial render.
|
|
103
|
+
const renderCount = useRenderCount();
|
|
91
104
|
useEffect(() => {
|
|
92
|
-
if (onChange) {
|
|
105
|
+
if (onChange && renderCount > 1) {
|
|
93
106
|
onChange(selected);
|
|
94
107
|
}
|
|
95
|
-
}, [selected, onChange]);
|
|
108
|
+
}, [selected, onChange, renderCount]);
|
|
109
|
+
|
|
110
|
+
const childrenArray = Children.toArray(children);
|
|
111
|
+
const lastCheckbox = childrenArray
|
|
112
|
+
.filter(
|
|
113
|
+
child =>
|
|
114
|
+
isValidElement(child) && (child as ReactElement).type === Checkbox,
|
|
115
|
+
)
|
|
116
|
+
.pop() as ReactElement<CheckboxElementType> | undefined;
|
|
117
|
+
const lastCheckboxIsChecked =
|
|
118
|
+
lastCheckbox && selected.includes(lastCheckbox.props.value);
|
|
96
119
|
|
|
97
120
|
return (
|
|
98
121
|
<div
|
|
@@ -113,14 +136,21 @@ export const CheckboxGroup: ForwardedRefComponent<
|
|
|
113
136
|
</Label>
|
|
114
137
|
)}
|
|
115
138
|
<div className="mobius-checkbox-group__wrapper">
|
|
116
|
-
{
|
|
139
|
+
{childrenArray.map(child => {
|
|
117
140
|
if (isValidElement(child)) {
|
|
141
|
+
// lastItemDisables support
|
|
142
|
+
const isLastItem = child === lastCheckbox;
|
|
143
|
+
const isChildDisabled =
|
|
144
|
+
isDisabled ||
|
|
145
|
+
(lastItemDisables && lastCheckboxIsChecked && !isLastItem);
|
|
146
|
+
|
|
118
147
|
return cloneElement(child as ReactElement, {
|
|
119
|
-
isDisabled,
|
|
148
|
+
isDisabled: isChildDisabled,
|
|
120
149
|
isRequired,
|
|
121
150
|
isReadOnly,
|
|
122
151
|
isInvalid,
|
|
123
|
-
|
|
152
|
+
isLastItem,
|
|
153
|
+
selected: selected.includes(child.props.value),
|
|
124
154
|
onChange: handleChange,
|
|
125
155
|
"aria-describedby": describedBy,
|
|
126
156
|
});
|
|
@@ -19,7 +19,10 @@ export interface CheckboxProps
|
|
|
19
19
|
value?: string;
|
|
20
20
|
// Whether the input is disabled.
|
|
21
21
|
isDisabled?: boolean;
|
|
22
|
-
onChange?: (
|
|
22
|
+
onChange?: (
|
|
23
|
+
event: ChangeEvent<CheckboxElementType>,
|
|
24
|
+
isLastItem?: boolean,
|
|
25
|
+
) => void;
|
|
23
26
|
// The default value (uncontrolled).
|
|
24
27
|
defaultSelected?: boolean;
|
|
25
28
|
// Whether the input can be selected but not changed by the user.
|
|
@@ -33,17 +36,17 @@ export interface CheckboxProps
|
|
|
33
36
|
*/
|
|
34
37
|
"aria-describedby"?: string;
|
|
35
38
|
/**
|
|
36
|
-
*
|
|
39
|
+
* Whether the checkbox is the last item of a group.
|
|
37
40
|
*/
|
|
38
|
-
|
|
41
|
+
isLastItem?: boolean;
|
|
39
42
|
/**
|
|
40
43
|
* **Internal:** Do not use
|
|
41
44
|
*/
|
|
42
|
-
|
|
45
|
+
groupDisabled?: boolean;
|
|
43
46
|
/**
|
|
44
|
-
*
|
|
47
|
+
* Whether the checkbox is selected.
|
|
45
48
|
*/
|
|
46
|
-
|
|
49
|
+
selected?: boolean;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
export type CheckboxGroupElementType = HTMLDivElement;
|
|
@@ -81,6 +84,10 @@ interface CheckboxGroupPropsInternal
|
|
|
81
84
|
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio#Value).
|
|
82
85
|
*/
|
|
83
86
|
value?: string;
|
|
87
|
+
/**
|
|
88
|
+
* This determines if the last item in the group should disable the other items when selected.
|
|
89
|
+
*/
|
|
90
|
+
lastItemDisables?: boolean;
|
|
84
91
|
}
|
|
85
92
|
|
|
86
93
|
interface HorizontalCheckboxGroupProps extends CheckboxGroupPropsInternal {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.mobius-combobox {
|
|
2
|
+
position: relative;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.mobius-combobox__list {
|
|
6
|
+
position: absolute;
|
|
7
|
+
margin: 0;
|
|
8
|
+
padding: 0;
|
|
9
|
+
top: 100%;
|
|
10
|
+
left: 0;
|
|
11
|
+
right: 0;
|
|
12
|
+
z-index: 1000;
|
|
13
|
+
background-color: #fff;
|
|
14
|
+
border: 1px solid #ccc;
|
|
15
|
+
border-top: 0;
|
|
16
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
17
|
+
max-height: 200px;
|
|
18
|
+
overflow-y: auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.mobius-combobox__option {
|
|
22
|
+
padding: 0.5rem 1rem;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.mobius-combobox__option:hover,
|
|
27
|
+
.mobius-combobox__option--is-highlighted {
|
|
28
|
+
background-color: var(--color-primary);
|
|
29
|
+
color: var(--color-neutral-100);
|
|
30
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Combobox, type ComboboxProps } from ".";
|
|
3
|
+
import { FRUITS, FRUITS_OBJECTS } from "./fixtures";
|
|
4
|
+
|
|
5
|
+
type StoryType = StoryObj<typeof Combobox>;
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Combobox> = {
|
|
8
|
+
title: "Forms/Combobox",
|
|
9
|
+
component: Combobox,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const Default: StoryType = {
|
|
13
|
+
render: (args: ComboboxProps) => <Combobox {...args} />,
|
|
14
|
+
args: {
|
|
15
|
+
options: FRUITS,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const ObjectOptions: StoryType = {
|
|
20
|
+
render: (args: ComboboxProps) => <Combobox {...args} />,
|
|
21
|
+
args: {
|
|
22
|
+
options: FRUITS_OBJECTS,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default meta;
|