@sproutsocial/seeds-react-menu 1.10.8 → 1.11.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/.turbo/turbo-build.log +21 -15
- package/CHANGELOG.md +22 -0
- package/dist/esm/index.js +45 -24
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v2/index.js +1 -1
- package/dist/esm/v2/index.js.map +1 -1
- package/dist/esm/v3/index.js +800 -0
- package/dist/esm/v3/index.js.map +1 -0
- package/dist/index.d.mts +22 -22
- package/dist/index.d.ts +22 -22
- package/dist/index.js +35 -14
- package/dist/index.js.map +1 -1
- package/dist/v2/index.js +1 -1
- package/dist/v2/index.js.map +1 -1
- package/dist/v3/index.d.mts +295 -0
- package/dist/v3/index.d.ts +295 -0
- package/dist/v3/index.js +868 -0
- package/dist/v3/index.js.map +1 -0
- package/package.json +7 -1
- package/src/MenuGroup/MenuGroup.tsx +16 -3
- package/src/MenuGroup/__tests__/MenuGroup.test.tsx +19 -0
- package/src/MenuItem/MenuItem.tsx +21 -10
- package/src/MenuItem/__tests__/MenuItem.test.tsx +19 -0
- package/src/v2/Common-V2/ComboboxContent.tsx +1 -1
- package/src/v3/Common/ComboboxItem.tsx +82 -0
- package/src/v3/Common/ComboboxStyles.tsx +475 -0
- package/src/v3/Common/SelectGroup.tsx +28 -0
- package/src/v3/Common/SelectIcons.tsx +26 -0
- package/src/v3/Common/SelectItem.tsx +108 -0
- package/src/v3/Common/SelectStyles.tsx +126 -0
- package/src/v3/Common/VirtualizedComboboxList.tsx +200 -0
- package/src/v3/Common/groupItems.ts +12 -0
- package/src/v3/Common/types.ts +3 -0
- package/src/v3/ModalStories.stories.tsx +181 -0
- package/src/v3/MultiCombobox.stories.tsx +322 -0
- package/src/v3/MultiCombobox.tsx +562 -0
- package/src/v3/MultiSearchableSelect.stories.tsx +389 -0
- package/src/v3/MultiSearchableSelect.tsx +545 -0
- package/src/v3/MultiSelect.stories.tsx +300 -0
- package/src/v3/MultiSelect.tsx +498 -0
- package/src/v3/SeedsPortal.tsx +35 -0
- package/src/v3/SingleCombobox.stories.tsx +169 -0
- package/src/v3/SingleCombobox.tsx +304 -0
- package/src/v3/SingleSearchableSelect.stories.tsx +239 -0
- package/src/v3/SingleSearchableSelect.tsx +319 -0
- package/src/v3/SingleSelect.stories.tsx +227 -0
- package/src/v3/SingleSelect.tsx +245 -0
- package/src/v3/index.ts +7 -0
- package/src/v3/storyData.tsx +117 -0
- package/tsup.config.ts +1 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Select } from "@base-ui/react/select";
|
|
2
|
+
import styled from "styled-components";
|
|
3
|
+
import { focusRing } from "@sproutsocial/seeds-react-mixins";
|
|
4
|
+
|
|
5
|
+
export const Field = styled.div`
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
gap: ${({ theme }) => theme.space[200]};
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
export const SelectLabel = styled(Select.Label)`
|
|
12
|
+
font-size: ${({ theme }) => theme.typography[200].fontSize};
|
|
13
|
+
font-weight: ${({ theme }) => theme.fontWeights.semibold};
|
|
14
|
+
color: ${({ theme }) => theme.colors.text.body};
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export const SelectTrigger = styled(Select.Trigger)`
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: space-between;
|
|
21
|
+
gap: ${({ theme }) => theme.space[300]};
|
|
22
|
+
padding: ${({ theme }) => `${theme.space[300]}`};
|
|
23
|
+
min-width: 160px;
|
|
24
|
+
border-radius: ${({ theme }) => theme.radii[500]};
|
|
25
|
+
border: 1px solid ${({ theme }) => theme.colors.form.border.base};
|
|
26
|
+
background: ${({ theme }) => theme.colors.form.background.base};
|
|
27
|
+
font-size: ${({ theme }) => theme.typography[200].fontSize};
|
|
28
|
+
color: ${({ theme }) => theme.colors.text.body};
|
|
29
|
+
cursor: default;
|
|
30
|
+
outline: none;
|
|
31
|
+
transition: border-color ${({ theme }) => theme.duration.fast}
|
|
32
|
+
${({ theme }) => theme.easing.ease_in},
|
|
33
|
+
box-shadow ${({ theme }) => theme.duration.fast}
|
|
34
|
+
${({ theme }) => theme.easing.ease_in};
|
|
35
|
+
|
|
36
|
+
&:focus-visible {
|
|
37
|
+
${focusRing}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&[data-popup-open] {
|
|
41
|
+
${focusRing}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&[data-popup-open] [data-chevron] {
|
|
45
|
+
transform: rotate(-180deg);
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
export const SelectValue = styled(Select.Value)`
|
|
50
|
+
min-width: 0;
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
export const SelectIcon = styled(Select.Icon)`
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
color: ${({ theme }) => theme.colors.icon.base};
|
|
58
|
+
flex-shrink: 0;
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export const SelectGroup = styled(Select.Group)`
|
|
62
|
+
display: block;
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
export const SelectGroupLabel = styled(Select.GroupLabel)`
|
|
66
|
+
padding: ${({ theme }) =>
|
|
67
|
+
`${theme.space[300]} ${theme.space[300]} ${theme.space[200]}`};
|
|
68
|
+
font-size: ${({ theme }) => theme.typography[100].fontSize};
|
|
69
|
+
font-weight: ${({ theme }) => theme.fontWeights.semibold};
|
|
70
|
+
text-transform: uppercase;
|
|
71
|
+
letter-spacing: 0.05em;
|
|
72
|
+
color: ${({ theme }) => theme.colors.text.subtext};
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
export const SelectSeparator = styled(Select.Separator)`
|
|
76
|
+
height: 1px;
|
|
77
|
+
margin: ${({ theme }) => `${theme.space[200]} ${theme.space[300]}`};
|
|
78
|
+
background: ${({ theme }) => theme.colors.container.border.base};
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
export const SelectPositioner = styled(Select.Positioner)`
|
|
82
|
+
width: var(--anchor-width);
|
|
83
|
+
z-index: 7;
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
export const SelectPopup = styled(Select.Popup)`
|
|
87
|
+
font-family: ${({ theme }) => theme.fontFamily};
|
|
88
|
+
background: ${({ theme }) => theme.colors.container.background.base};
|
|
89
|
+
border: 1px solid ${({ theme }) => theme.colors.container.border.base};
|
|
90
|
+
border-radius: ${({ theme }) => theme.radii[500]};
|
|
91
|
+
box-shadow: ${({ theme }) => theme.shadows.low};
|
|
92
|
+
outline: none;
|
|
93
|
+
max-height: min(var(--base-ui-available-height, 400px), 400px);
|
|
94
|
+
overflow-y: auto;
|
|
95
|
+
padding: ${({ theme }) => theme.space[200]};
|
|
96
|
+
|
|
97
|
+
&[data-open] {
|
|
98
|
+
animation: select-popup-in 120ms ease-out;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&[data-closed] {
|
|
102
|
+
animation: select-popup-out 100ms ease-in;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@keyframes select-popup-in {
|
|
106
|
+
from {
|
|
107
|
+
opacity: 0;
|
|
108
|
+
transform: scale(0.95);
|
|
109
|
+
}
|
|
110
|
+
to {
|
|
111
|
+
opacity: 1;
|
|
112
|
+
transform: scale(1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@keyframes select-popup-out {
|
|
117
|
+
from {
|
|
118
|
+
opacity: 1;
|
|
119
|
+
transform: scale(1);
|
|
120
|
+
}
|
|
121
|
+
to {
|
|
122
|
+
opacity: 0;
|
|
123
|
+
transform: scale(0.95);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
`;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Combobox } from "@base-ui/react/combobox";
|
|
3
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
4
|
+
import ComboboxItem from "./ComboboxItem";
|
|
5
|
+
import {
|
|
6
|
+
ComboboxGroupHeaderItem,
|
|
7
|
+
ComboboxGroupHeaderCheckbox,
|
|
8
|
+
ComboboxSelectAllItem,
|
|
9
|
+
} from "./ComboboxStyles";
|
|
10
|
+
import type { DataWithId } from "./types";
|
|
11
|
+
|
|
12
|
+
export const ITEM_HEIGHT = 32;
|
|
13
|
+
|
|
14
|
+
interface GroupHeaderSentinel {
|
|
15
|
+
__groupHeader: true;
|
|
16
|
+
groupName: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface SelectAllSentinel {
|
|
20
|
+
__selectAll: true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isGroupHeaderSentinel(v: unknown): v is GroupHeaderSentinel {
|
|
24
|
+
return typeof v === "object" && v !== null && "__groupHeader" in v;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isSelectAllSentinel(v: unknown): v is SelectAllSentinel {
|
|
28
|
+
return typeof v === "object" && v !== null && "__selectAll" in v;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type FlatSentinelRow<T> = T | GroupHeaderSentinel | SelectAllSentinel;
|
|
32
|
+
|
|
33
|
+
interface VirtualizedComboboxListProps<T extends DataWithId> {
|
|
34
|
+
open: boolean;
|
|
35
|
+
virtualizerRef: React.RefObject<ReturnType<
|
|
36
|
+
typeof useVirtualizer<HTMLDivElement, Element>
|
|
37
|
+
> | null>;
|
|
38
|
+
value: T | T[] | null;
|
|
39
|
+
groups: Array<{ value: string; items: T[] }> | null;
|
|
40
|
+
data: T[];
|
|
41
|
+
itemToString: (item: T) => string;
|
|
42
|
+
inputType: "icon" | "radio" | "checkbox" | "none";
|
|
43
|
+
renderItem?: (item: T) => React.ReactNode;
|
|
44
|
+
renderGroupHeading?: (label: string) => React.ReactNode;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default function VirtualizedComboboxList<T extends DataWithId>({
|
|
48
|
+
open,
|
|
49
|
+
virtualizerRef,
|
|
50
|
+
value,
|
|
51
|
+
groups,
|
|
52
|
+
data,
|
|
53
|
+
itemToString,
|
|
54
|
+
inputType,
|
|
55
|
+
renderItem,
|
|
56
|
+
renderGroupHeading,
|
|
57
|
+
}: VirtualizedComboboxListProps<T>) {
|
|
58
|
+
type Row = FlatSentinelRow<T>;
|
|
59
|
+
|
|
60
|
+
const filteredItems = Combobox.useFilteredItems<Row>();
|
|
61
|
+
const scrollElementRef = React.useRef<HTMLDivElement | null>(null);
|
|
62
|
+
|
|
63
|
+
const virtualizer = useVirtualizer({
|
|
64
|
+
enabled: open,
|
|
65
|
+
count: filteredItems.length,
|
|
66
|
+
getScrollElement: () => scrollElementRef.current,
|
|
67
|
+
estimateSize: () => ITEM_HEIGHT,
|
|
68
|
+
overscan: 20,
|
|
69
|
+
paddingStart: 4,
|
|
70
|
+
paddingEnd: 4,
|
|
71
|
+
scrollPaddingStart: 4,
|
|
72
|
+
scrollPaddingEnd: 4,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
React.useImperativeHandle(virtualizerRef, () => virtualizer);
|
|
76
|
+
|
|
77
|
+
const handleScrollRef = React.useCallback(
|
|
78
|
+
(el: HTMLDivElement | null) => {
|
|
79
|
+
scrollElementRef.current = el;
|
|
80
|
+
if (el) virtualizer.measure();
|
|
81
|
+
},
|
|
82
|
+
[virtualizer]
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (!filteredItems.length) return null;
|
|
86
|
+
|
|
87
|
+
const selectedArray = Array.isArray(value)
|
|
88
|
+
? value
|
|
89
|
+
: value != null
|
|
90
|
+
? [value]
|
|
91
|
+
: [];
|
|
92
|
+
|
|
93
|
+
const totalSize = virtualizer.getTotalSize();
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div
|
|
97
|
+
role="presentation"
|
|
98
|
+
ref={handleScrollRef}
|
|
99
|
+
style={{
|
|
100
|
+
flex: 1,
|
|
101
|
+
minHeight: 0,
|
|
102
|
+
overflowY: "auto",
|
|
103
|
+
overscrollBehavior: "contain",
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<div
|
|
107
|
+
role="presentation"
|
|
108
|
+
style={{ position: "relative", width: "100%", height: totalSize }}
|
|
109
|
+
>
|
|
110
|
+
{virtualizer.getVirtualItems().map((virtualItem) => {
|
|
111
|
+
const row = filteredItems[virtualItem.index];
|
|
112
|
+
if (!row) return null;
|
|
113
|
+
|
|
114
|
+
const baseStyle: React.CSSProperties = {
|
|
115
|
+
position: "absolute",
|
|
116
|
+
top: 0,
|
|
117
|
+
left: 0,
|
|
118
|
+
width: "100%",
|
|
119
|
+
transform: `translateY(${virtualItem.start}px)`,
|
|
120
|
+
boxSizing: "border-box",
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (isSelectAllSentinel(row)) {
|
|
124
|
+
const selectedCount = selectedArray.length;
|
|
125
|
+
const totalCount = data.length;
|
|
126
|
+
const state =
|
|
127
|
+
selectedCount === 0
|
|
128
|
+
? "none"
|
|
129
|
+
: selectedCount === totalCount
|
|
130
|
+
? "all"
|
|
131
|
+
: "partial";
|
|
132
|
+
return (
|
|
133
|
+
<ComboboxSelectAllItem
|
|
134
|
+
key={virtualItem.key}
|
|
135
|
+
index={virtualItem.index}
|
|
136
|
+
data-index={virtualItem.index}
|
|
137
|
+
value={row}
|
|
138
|
+
style={baseStyle}
|
|
139
|
+
ref={virtualizer.measureElement}
|
|
140
|
+
>
|
|
141
|
+
<ComboboxGroupHeaderCheckbox $state={state} id="__selectAll" />
|
|
142
|
+
Select all
|
|
143
|
+
</ComboboxSelectAllItem>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (isGroupHeaderSentinel(row)) {
|
|
148
|
+
const group = groups?.find((g) => g.value === row.groupName);
|
|
149
|
+
const groupItems = group?.items ?? [];
|
|
150
|
+
const selectedCount = groupItems.filter((item) =>
|
|
151
|
+
selectedArray.some((s) => s.id === item.id)
|
|
152
|
+
).length;
|
|
153
|
+
const state =
|
|
154
|
+
selectedCount === 0
|
|
155
|
+
? "none"
|
|
156
|
+
: selectedCount === groupItems.length
|
|
157
|
+
? "all"
|
|
158
|
+
: "partial";
|
|
159
|
+
return (
|
|
160
|
+
<ComboboxGroupHeaderItem
|
|
161
|
+
key={virtualItem.key}
|
|
162
|
+
index={virtualItem.index}
|
|
163
|
+
data-index={virtualItem.index}
|
|
164
|
+
value={row}
|
|
165
|
+
style={baseStyle}
|
|
166
|
+
ref={virtualizer.measureElement}
|
|
167
|
+
>
|
|
168
|
+
<ComboboxGroupHeaderCheckbox
|
|
169
|
+
$state={state}
|
|
170
|
+
id={`__header-${row.groupName}`}
|
|
171
|
+
/>
|
|
172
|
+
{renderGroupHeading
|
|
173
|
+
? renderGroupHeading(row.groupName)
|
|
174
|
+
: row.groupName}
|
|
175
|
+
</ComboboxGroupHeaderItem>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const item = row as T;
|
|
180
|
+
return (
|
|
181
|
+
<ComboboxItem
|
|
182
|
+
key={virtualItem.key}
|
|
183
|
+
index={virtualItem.index}
|
|
184
|
+
data-index={virtualItem.index}
|
|
185
|
+
value={item}
|
|
186
|
+
itemId={String(item.id)}
|
|
187
|
+
label={itemToString(item)}
|
|
188
|
+
inputType={inputType}
|
|
189
|
+
renderItem={
|
|
190
|
+
renderItem ? () => renderItem(item) : () => itemToString(item)
|
|
191
|
+
}
|
|
192
|
+
style={baseStyle}
|
|
193
|
+
ref={virtualizer.measureElement}
|
|
194
|
+
/>
|
|
195
|
+
);
|
|
196
|
+
})}
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function groupItems<T>(
|
|
2
|
+
data: T[],
|
|
3
|
+
groupBy: (item: T) => string
|
|
4
|
+
): Array<{ value: string; items: T[] }> {
|
|
5
|
+
const map = new Map<string, T[]>();
|
|
6
|
+
for (const item of data) {
|
|
7
|
+
const key = groupBy(item);
|
|
8
|
+
if (!map.has(key)) map.set(key, []);
|
|
9
|
+
map.get(key)!.push(item);
|
|
10
|
+
}
|
|
11
|
+
return Array.from(map.entries()).map(([value, items]) => ({ value, items }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { FormField } from "@sproutsocial/seeds-react-form-field";
|
|
4
|
+
import { Button } from "@sproutsocial/seeds-react-button";
|
|
5
|
+
import { Input } from "@sproutsocial/seeds-react-input";
|
|
6
|
+
import { TokenInput } from "@sproutsocial/seeds-react-token-input";
|
|
7
|
+
import {
|
|
8
|
+
Modal as ModalV1,
|
|
9
|
+
ModalV2,
|
|
10
|
+
ModalBody,
|
|
11
|
+
ModalFooter,
|
|
12
|
+
} from "@sproutsocial/seeds-react-modal";
|
|
13
|
+
import SingleSelect from "./SingleSelect";
|
|
14
|
+
import MultiSelect from "./MultiSelect";
|
|
15
|
+
import SingleCombobox from "./SingleCombobox";
|
|
16
|
+
import MultiCombobox from "./MultiCombobox";
|
|
17
|
+
import SingleSearchableSelect from "./SingleSearchableSelect";
|
|
18
|
+
import MultiSearchableSelect from "./MultiSearchableSelect";
|
|
19
|
+
import { books, itemToString } from "./storyData";
|
|
20
|
+
|
|
21
|
+
// ─── Shared content ───────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
function AllComponents() {
|
|
24
|
+
return (
|
|
25
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
|
|
26
|
+
<FormField label="Input`">
|
|
27
|
+
{({ id }) => (
|
|
28
|
+
<Input
|
|
29
|
+
id={id}
|
|
30
|
+
name="input"
|
|
31
|
+
value="Some Value"
|
|
32
|
+
placeholder="Select a book"
|
|
33
|
+
/>
|
|
34
|
+
)}
|
|
35
|
+
</FormField>
|
|
36
|
+
<FormField label="Token Input">
|
|
37
|
+
{({ id }) => (
|
|
38
|
+
<TokenInput
|
|
39
|
+
id={id}
|
|
40
|
+
name="token-input"
|
|
41
|
+
tokens={[{ id: "token", value: "Token" }]}
|
|
42
|
+
value="Some Value"
|
|
43
|
+
placeholder="Select a book"
|
|
44
|
+
/>
|
|
45
|
+
)}
|
|
46
|
+
</FormField>
|
|
47
|
+
<FormField label="Token Input2">
|
|
48
|
+
{({ id }) => (
|
|
49
|
+
<TokenInput
|
|
50
|
+
id={id}
|
|
51
|
+
name="token-input"
|
|
52
|
+
tokens={[]}
|
|
53
|
+
value="Some Value"
|
|
54
|
+
placeholder="Select a book"
|
|
55
|
+
/>
|
|
56
|
+
)}
|
|
57
|
+
</FormField>
|
|
58
|
+
<FormField label="Single Select">
|
|
59
|
+
{({ id }) => (
|
|
60
|
+
<SingleSelect
|
|
61
|
+
id={id}
|
|
62
|
+
data={books}
|
|
63
|
+
itemToString={itemToString}
|
|
64
|
+
placeholder="Select a book"
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
</FormField>
|
|
68
|
+
<FormField label="Multi Select">
|
|
69
|
+
{({ id }) => (
|
|
70
|
+
<MultiSelect
|
|
71
|
+
id={id}
|
|
72
|
+
data={books}
|
|
73
|
+
itemToString={itemToString}
|
|
74
|
+
placeholder="Select books"
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</FormField>
|
|
78
|
+
<FormField label="Single Combobox">
|
|
79
|
+
{({ id }) => (
|
|
80
|
+
<SingleCombobox
|
|
81
|
+
id={id}
|
|
82
|
+
data={books}
|
|
83
|
+
itemToString={itemToString}
|
|
84
|
+
placeholder="Search books..."
|
|
85
|
+
/>
|
|
86
|
+
)}
|
|
87
|
+
</FormField>
|
|
88
|
+
<FormField label="Multi Combobox">
|
|
89
|
+
{({ id }) => (
|
|
90
|
+
<MultiCombobox
|
|
91
|
+
id={id}
|
|
92
|
+
data={books}
|
|
93
|
+
itemToString={itemToString}
|
|
94
|
+
placeholder="Search books..."
|
|
95
|
+
/>
|
|
96
|
+
)}
|
|
97
|
+
</FormField>
|
|
98
|
+
<FormField label="Single Searchable Select">
|
|
99
|
+
{({ id }) => (
|
|
100
|
+
<SingleSearchableSelect
|
|
101
|
+
id={id}
|
|
102
|
+
data={books}
|
|
103
|
+
itemToString={itemToString}
|
|
104
|
+
placeholder="Select a book"
|
|
105
|
+
searchPlaceholder="Search books..."
|
|
106
|
+
/>
|
|
107
|
+
)}
|
|
108
|
+
</FormField>
|
|
109
|
+
<FormField label="Multi Searchable Select">
|
|
110
|
+
{({ id }) => (
|
|
111
|
+
<MultiSearchableSelect
|
|
112
|
+
id={id}
|
|
113
|
+
data={books}
|
|
114
|
+
itemToString={itemToString}
|
|
115
|
+
placeholder="Select books"
|
|
116
|
+
searchPlaceholder="Search books..."
|
|
117
|
+
/>
|
|
118
|
+
)}
|
|
119
|
+
</FormField>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ─── Meta ─────────────────────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
const meta: Meta = {
|
|
127
|
+
title: "Really Under Development/V3/In Modal",
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export default meta;
|
|
131
|
+
type Story = StoryObj;
|
|
132
|
+
|
|
133
|
+
// ─── Stories ──────────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
export const V1Modal: Story = {
|
|
136
|
+
name: "V1 Modal",
|
|
137
|
+
render: () => {
|
|
138
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
139
|
+
return (
|
|
140
|
+
<>
|
|
141
|
+
<Button appearance="primary" onClick={() => setIsOpen(true)}>
|
|
142
|
+
Open V1 Modal
|
|
143
|
+
</Button>
|
|
144
|
+
<ModalV1
|
|
145
|
+
appElementSelector="#root"
|
|
146
|
+
isOpen={isOpen}
|
|
147
|
+
onClose={() => setIsOpen(false)}
|
|
148
|
+
closeButtonLabel="Close"
|
|
149
|
+
label="V1 Modal"
|
|
150
|
+
>
|
|
151
|
+
<ModalV1.Header title="" subtitle="" bordered>
|
|
152
|
+
V1 modal
|
|
153
|
+
</ModalV1.Header>
|
|
154
|
+
<ModalV1.Content>
|
|
155
|
+
<AllComponents />
|
|
156
|
+
</ModalV1.Content>
|
|
157
|
+
<ModalV1.Footer>Footer</ModalV1.Footer>
|
|
158
|
+
</ModalV1>
|
|
159
|
+
</>
|
|
160
|
+
);
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const V2Modal: Story = {
|
|
165
|
+
name: "V2 Modal",
|
|
166
|
+
render: () => (
|
|
167
|
+
<>
|
|
168
|
+
<ModalV2
|
|
169
|
+
title="Pick some books"
|
|
170
|
+
modalTrigger={<Button appearance="primary">Open V2 Modal</Button>}
|
|
171
|
+
closeButtonAriaLabel="Close"
|
|
172
|
+
>
|
|
173
|
+
<ModalBody>
|
|
174
|
+
<AllComponents />
|
|
175
|
+
</ModalBody>
|
|
176
|
+
<ModalFooter cancelButton={<Button>Cancel</Button>} />
|
|
177
|
+
</ModalV2>
|
|
178
|
+
<AllComponents />
|
|
179
|
+
</>
|
|
180
|
+
),
|
|
181
|
+
};
|