@takaro/lib-components 0.0.1 → 0.0.4
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/package.json +4 -5
- package/src/components/actions/Button/index.tsx +68 -70
- package/src/components/actions/Button/style.ts +1 -1
- package/src/components/actions/ContextMenu/Group.tsx +1 -1
- package/src/components/actions/ContextMenu/MenuItem.tsx +4 -1
- package/src/components/actions/ContextMenu/index.tsx +11 -12
- package/src/components/actions/Dropdown/DropdownMenu.tsx +5 -2
- package/src/components/actions/Dropdown/DropdownTrigger.tsx +55 -57
- package/src/components/actions/Dropdown/useDropdown.tsx +1 -1
- package/src/components/actions/IconButton/index.tsx +11 -10
- package/src/components/actions/IconButton/style.ts +5 -2
- package/src/components/actions/ToggleButton/ToggleButton.tsx +26 -28
- package/src/components/actions/ToggleButton/ToggleButtonGroup.tsx +3 -8
- package/src/components/actions/ToggleButton/style.ts +5 -7
- package/src/components/charts/AreaChart/index.tsx +7 -8
- package/src/components/charts/BarChart/index.tsx +4 -4
- package/src/components/charts/GeoMercator/index.tsx +1 -1
- package/src/components/charts/Heatmap/index.tsx +3 -4
- package/src/components/charts/LineChart/index.tsx +3 -3
- package/src/components/charts/PieChart/index.tsx +1 -1
- package/src/components/charts/RadarChart/index.tsx +1 -1
- package/src/components/charts/RadialBarChart/index.tsx +1 -1
- package/src/components/charts/index.tsx +3 -0
- package/src/components/data/Avatar/index.tsx +7 -3
- package/src/components/data/Avatar/style.ts +2 -2
- package/src/components/data/Chip/index.tsx +39 -41
- package/src/components/data/Chip/style.ts +3 -2
- package/src/components/data/Console/Console.tsx +14 -12
- package/src/components/data/CopyId/index.tsx +3 -2
- package/src/components/data/Drawer/Drawer.stories.tsx +3 -5
- package/src/components/data/Drawer/DrawerContent.tsx +1 -1
- package/src/components/data/Drawer/DrawerHeading.tsx +30 -29
- package/src/components/data/Drawer/useDrawer.tsx +1 -1
- package/src/components/data/InfiniteScroll/index.tsx +37 -36
- package/src/components/data/Table/Table.stories.tsx +6 -2
- package/src/components/data/Table/index.tsx +63 -44
- package/src/components/data/Table/style.ts +3 -2
- package/src/components/data/Table/subcomponents/ColumnHeader/ColumnSettings.tsx +22 -19
- package/src/components/data/Table/subcomponents/ColumnHeader/index.tsx +3 -3
- package/src/components/data/Table/subcomponents/ColumnHeader/style.ts +2 -1
- package/src/components/data/Table/subcomponents/Filter/field.tsx +2 -3
- package/src/components/data/Table/subcomponents/Filter/index.tsx +6 -10
- package/src/components/data/Table/subcomponents/Pagination/{index.tsx → PagePicker.tsx} +7 -7
- package/src/components/data/Table/subcomponents/Pagination/PageSizeSelect.tsx +37 -0
- package/src/components/data/Table/subcomponents/Pagination/style.ts +1 -1
- package/src/components/dialogs/Dialog/Dialog.stories.tsx +1 -2
- package/src/components/dialogs/Dialog/DialogBody.tsx +18 -17
- package/src/components/dialogs/Dialog/DialogContent.tsx +30 -28
- package/src/components/dialogs/Dialog/DialogHeading.tsx +1 -1
- package/src/components/dialogs/Dialog/useDialog.tsx +1 -1
- package/src/components/feedback/Alert/index.tsx +74 -73
- package/src/components/feedback/NotificationBanner/NotificationBanner.test.tsx +1 -1
- package/src/components/feedback/NotificationBanner/index.tsx +1 -1
- package/src/components/feedback/Popover/PopoverContent.tsx +4 -1
- package/src/components/feedback/Popover/PopoverTrigger.tsx +33 -31
- package/src/components/feedback/Popover/usePopover.tsx +1 -1
- package/src/components/feedback/ProgressBar/index.tsx +1 -1
- package/src/components/feedback/QuestionTooltip/index.tsx +1 -2
- package/src/components/feedback/Tooltip/TooltipContent.tsx +4 -1
- package/src/components/feedback/Tooltip/TooltipTrigger.tsx +3 -3
- package/src/components/feedback/Tooltip/useTooltip.tsx +1 -1
- package/src/components/feedback/snacks/CookieConsent/index.tsx +5 -2
- package/src/components/feedback/snacks/Default/index.tsx +51 -50
- package/src/components/feedback/snacks/Drawer/index.tsx +22 -21
- package/src/components/feedback/snacks/NetworkDetector/index.tsx +35 -31
- package/src/components/inputs/CheckBox/Controlled.tsx +2 -3
- package/src/components/inputs/CheckBox/Generic.tsx +18 -72
- package/src/components/inputs/CheckBox/style.ts +40 -97
- package/src/components/inputs/CodeField/CodeField.stories.tsx +4 -5
- package/src/components/inputs/CodeField/index.tsx +1 -0
- package/src/components/inputs/Date/DatePicker/DatePicker.stories.tsx +2 -3
- package/src/components/inputs/Date/DatePicker/Generic.tsx +20 -10
- package/src/components/inputs/Date/DateRangePicker/Context.tsx +12 -1
- package/src/components/inputs/Date/DateRangePicker/Controlled.tsx +74 -0
- package/src/components/inputs/Date/DateRangePicker/DateRangePicker.stories.tsx +11 -6
- package/src/components/inputs/Date/DateRangePicker/DateSelector/Absolute.tsx +3 -3
- package/src/components/inputs/Date/DateRangePicker/DateSelector/Relative.tsx +1 -1
- package/src/components/inputs/Date/DateRangePicker/DateSelector/index.tsx +1 -1
- package/src/components/inputs/Date/DateRangePicker/{index.tsx → Generic.tsx} +43 -11
- package/src/components/inputs/Date/DateRangePicker/QuickSelect/index.tsx +1 -1
- package/src/components/inputs/Date/DateRangePicker/style.ts +19 -5
- package/src/components/inputs/Date/subcomponents/Calendar/index.tsx +1 -1
- package/src/components/inputs/Date/subcomponents/RelativePicker/index.tsx +1 -1
- package/src/components/inputs/DurationField/Generic.tsx +149 -152
- package/src/components/inputs/FileField/FileField.stories.tsx +6 -6
- package/src/components/inputs/FileField/Generic.tsx +101 -99
- package/src/components/inputs/InputProps.ts +0 -2
- package/src/components/inputs/RadioGroup/Controlled.tsx +1 -2
- package/src/components/inputs/RadioGroup/RadioGroup.stories.tsx +6 -4
- package/src/components/inputs/RadioGroup/RadioItem.tsx +54 -53
- package/src/components/inputs/Slider/Generic.tsx +1 -1
- package/src/components/inputs/Slider/Slider.stories.tsx +1 -1
- package/src/components/inputs/Slider/handle.tsx +1 -0
- package/src/components/inputs/Switch/Controlled.tsx +1 -2
- package/src/components/inputs/Switch/Generic.tsx +18 -45
- package/src/components/inputs/Switch/Switch.stories.tsx +2 -4
- package/src/components/inputs/Switch/style.ts +44 -38
- package/src/components/inputs/TagField/Generic.tsx +109 -109
- package/src/components/inputs/TextAreaField/Generic.tsx +41 -39
- package/src/components/inputs/TextAreaField/TextAreaField.stories.tsx +2 -3
- package/src/components/inputs/TextField/Generic.tsx +81 -79
- package/src/components/inputs/TextField/TextField.stories.tsx +3 -4
- package/src/components/inputs/index.ts +3 -2
- package/src/components/inputs/layout/Description.tsx +1 -2
- package/src/components/inputs/layout/InputWrapper.ts +2 -2
- package/src/components/inputs/selects/SelectField/Controlled.tsx +1 -2
- package/src/components/inputs/selects/SelectField/Generic/FilterInput.tsx +4 -1
- package/src/components/inputs/selects/SelectField/SelectField.stories.tsx +9 -10
- package/src/components/inputs/selects/SelectQueryField/Generic/index.tsx +200 -197
- package/src/components/inputs/selects/SelectQueryField/SelectQueryField.stories.tsx +1 -1
- package/src/components/inputs/selects/SubComponents/Option.tsx +3 -3
- package/src/components/inputs/selects/SubComponents/OptionGroup.tsx +1 -1
- package/src/components/inputs/selects/SubComponents/style.ts +18 -4
- package/src/components/inputs/selects/index.tsx +5 -2
- package/src/components/inputs/selects/sharedStyle.ts +1 -0
- package/src/components/navigation/HorizontalNav/index.tsx +5 -32
- package/src/components/navigation/HorizontalNav/style.ts +11 -26
- package/src/components/navigation/IconNav/index.tsx +1 -1
- package/src/components/navigation/Steppers/SlimStepper/index.tsx +1 -1
- package/src/components/navigation/Steppers/SlimStepper/style.ts +1 -2
- package/src/components/navigation/Steppers/Stepper/index.tsx +1 -1
- package/src/components/navigation/Steppers/context.tsx +2 -2
- package/src/components/navigation/Tabs/Content.tsx +4 -1
- package/src/components/navigation/Tabs/Trigger.tsx +24 -23
- package/src/components/navigation/index.ts +1 -1
- package/src/components/other/ActionMenu/ActionMenu.stories.tsx +1 -2
- package/src/components/other/ActionMenu/index.tsx +30 -29
- package/src/components/other/Collapsible/CollapsibleTrigger.tsx +8 -4
- package/src/components/other/Company/index.tsx +25 -26
- package/src/components/other/Empty/Empty.stories.tsx +1 -1
- package/src/components/other/Empty/index.tsx +1 -3
- package/src/components/other/PermissionsGuard/index.tsx +2 -2
- package/src/components/visual/Card/index.tsx +4 -1
- package/src/errors/base.ts +4 -1
- package/src/errors/errors.ts +19 -2
- package/src/helpers/getSnackbarProvider.tsx +3 -3
- package/src/helpers/regexprs.ts +1 -0
- package/src/hooks/useFocus.tsx +3 -1
- package/src/hooks/useOnScreen.ts +1 -1
- package/src/hooks/useTableActions.ts +10 -5
- package/src/styled/GlobalStyle.ts +2 -1
- package/src/styled/zIndex.ts +1 -1
- package/src/test/testUtils.tsx +3 -0
- package/src/components/data/Table/subcomponents/index.ts +0 -4
|
@@ -42,7 +42,7 @@ interface SharedSelectQueryFieldProps {
|
|
|
42
42
|
placeholder?: string;
|
|
43
43
|
/// Debounce time in milliseconds (when clientside data it should be 0)
|
|
44
44
|
debounce?: number;
|
|
45
|
-
/// Triggered whenever the input value changes
|
|
45
|
+
/// Triggered whenever the input value changes.
|
|
46
46
|
/// This is used to trigger the API call to get the new options
|
|
47
47
|
handleInputValueChange: (value: string) => void;
|
|
48
48
|
/// render inPortal
|
|
@@ -84,217 +84,220 @@ export interface InputValue {
|
|
|
84
84
|
shouldUpdate: boolean;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
export const GenericSelectQueryField = forwardRef<HTMLInputElement, GenericSelectQueryFieldProps>(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
87
|
+
export const GenericSelectQueryField = forwardRef<HTMLInputElement, GenericSelectQueryFieldProps>(
|
|
88
|
+
function GenericSelectQueryField(props, ref) {
|
|
89
|
+
const {
|
|
90
|
+
onBlur = () => {},
|
|
91
|
+
onFocus = () => {},
|
|
92
|
+
onChange,
|
|
93
|
+
name,
|
|
94
|
+
disabled,
|
|
95
|
+
value,
|
|
96
|
+
id,
|
|
97
|
+
placeholder = 'Search field',
|
|
98
|
+
hasDescription,
|
|
99
|
+
inPortal = false,
|
|
100
|
+
hasError,
|
|
101
|
+
children,
|
|
102
|
+
readOnly,
|
|
103
|
+
render,
|
|
104
|
+
multiple = false,
|
|
105
|
+
canClear = false,
|
|
106
|
+
debounce = 250,
|
|
107
|
+
isLoadingData: isLoading = false,
|
|
108
|
+
handleInputValueChange,
|
|
109
|
+
} = defaultsApplier(props);
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
const [open, setOpen] = useState<boolean>(false);
|
|
112
|
+
const [inputValue, setInputValue] = useState<InputValue>({ value: '', shouldUpdate: false, label: '' });
|
|
113
|
+
const [activeIndex, setActiveIndex] = useState<number | null>(null);
|
|
114
|
+
const [selectedItems, setSelectedItems] = useState<SelectItem[]>([]);
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
const debouncedValue = useDebounce(inputValue.value, debounce);
|
|
117
|
+
const listItemsRef = useRef<Array<HTMLLIElement | null>>([]);
|
|
117
118
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if ((inputValue.shouldUpdate && debouncedValue) || (inputValue && debouncedValue === ''))
|
|
121
|
+
handleInputValueChange(debouncedValue);
|
|
122
|
+
}, [debouncedValue]);
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
124
|
+
const { refs, strategy, x, y, context } = useFloating<HTMLInputElement>({
|
|
125
|
+
whileElementsMounted: autoUpdate,
|
|
126
|
+
open,
|
|
127
|
+
onOpenChange: readOnly || disabled ? () => {} : setOpen,
|
|
128
|
+
middleware: [
|
|
129
|
+
offset(5),
|
|
130
|
+
size({
|
|
131
|
+
apply({ rects, elements }) {
|
|
132
|
+
Object.assign(elements.floating.style, {
|
|
133
|
+
width: `${rects.reference.width}px`,
|
|
134
|
+
maxHeight: '255px',
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
padding: 10,
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
});
|
|
139
141
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
|
|
143
|
+
useClick(context),
|
|
144
|
+
useRole(context, { role: 'listbox' }),
|
|
145
|
+
useDismiss(context),
|
|
146
|
+
]);
|
|
145
147
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
function onInputChange(event: React.ChangeEvent<HTMLInputElement>) {
|
|
149
|
+
const value = event.target.value;
|
|
150
|
+
setInputValue({ value, shouldUpdate: true, label: value });
|
|
151
|
+
if (value) {
|
|
152
|
+
setActiveIndex(0);
|
|
153
|
+
}
|
|
151
154
|
}
|
|
152
|
-
}
|
|
153
155
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
const handleClear = (e: MouseEvent) => {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
e.stopPropagation();
|
|
159
|
+
setSelectedItems([]);
|
|
158
160
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
// the undefined is an expection
|
|
162
|
+
if (onChange) onChange(multiple ? ([] as string[]) : (undefined as any));
|
|
163
|
+
};
|
|
162
164
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
/* This handles the case where the value is changed externally (e.g. from a parent component) */
|
|
166
|
+
/* onChange propagates the value to the parent component, but since the value prop is not a required prop, the parent might not reflect the change
|
|
167
|
+
* which ends up not running this useEffect. Meaning we still need to update the selectedIndex when clicked on an option.
|
|
168
|
+
*/
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
// Function to create an item with a value and label
|
|
171
|
+
const createItem = (v: string) => ({ value: v, label: getLabelFromChildren(children, v) as unknown as string });
|
|
170
172
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
if (Array.isArray(value)) {
|
|
174
|
+
const items = value.map(createItem);
|
|
175
|
+
setSelectedItems(items);
|
|
176
|
+
} else if (typeof value === 'string' && value !== '') {
|
|
177
|
+
setSelectedItems([createItem(value)]);
|
|
178
|
+
}
|
|
179
|
+
}, [value, children]);
|
|
180
|
+
|
|
181
|
+
const renderSelect = () => {
|
|
182
|
+
const hasOptions = options && Children.count(options[0].props.children) > 1;
|
|
183
|
+
|
|
184
|
+
// initialFocus=-1 is used to prevent the first item from being focused when the list opens
|
|
185
|
+
return (
|
|
186
|
+
<FloatingFocusManager context={context} visuallyHiddenDismiss initialFocus={-1}>
|
|
187
|
+
<SelectContainer
|
|
188
|
+
{...getFloatingProps({
|
|
189
|
+
ref: refs.setFloating,
|
|
190
|
+
style: {
|
|
191
|
+
position: strategy,
|
|
192
|
+
top: y ?? 0,
|
|
193
|
+
left: x ?? 0,
|
|
194
|
+
overflow: 'auto',
|
|
195
|
+
borderBottom: '10px solid transparent',
|
|
196
|
+
},
|
|
197
|
+
})}
|
|
198
|
+
>
|
|
199
|
+
<GenericTextField
|
|
200
|
+
id={`${name}-input`}
|
|
201
|
+
name={`${name}-input`}
|
|
202
|
+
hasDescription={false}
|
|
203
|
+
icon={<SearchIcon />}
|
|
204
|
+
hasError={hasError}
|
|
205
|
+
value={inputValue.value}
|
|
206
|
+
onChange={onInputChange}
|
|
207
|
+
placeholder={placeholder}
|
|
208
|
+
ref={ref}
|
|
209
|
+
/>
|
|
210
|
+
{/* it will always contain 1 because of the group label */}
|
|
211
|
+
{isLoading && (
|
|
212
|
+
<FeedBackContainer>
|
|
213
|
+
<Spinner size="small" />
|
|
214
|
+
<span style={{ marginLeft: '10px' }}>loading results</span>
|
|
215
|
+
</FeedBackContainer>
|
|
216
|
+
)}
|
|
217
|
+
{hasOptions && options}
|
|
218
|
+
{/* Basically first interaction */}
|
|
219
|
+
{!hasOptions && inputValue.value === '' && <FeedBackContainer>Start typing to search</FeedBackContainer>}
|
|
220
|
+
{/* When there is no result */}
|
|
221
|
+
{!hasOptions && !isLoading && inputValue.value !== '' && (
|
|
222
|
+
<FeedBackContainer>No results found</FeedBackContainer>
|
|
223
|
+
)}
|
|
224
|
+
</SelectContainer>
|
|
225
|
+
</FloatingFocusManager>
|
|
226
|
+
);
|
|
227
|
+
};
|
|
178
228
|
|
|
179
|
-
|
|
180
|
-
|
|
229
|
+
const options = useMemo(() => {
|
|
230
|
+
return [
|
|
231
|
+
...(Children.map(
|
|
232
|
+
children,
|
|
233
|
+
(child) =>
|
|
234
|
+
isValidElement(child) && (
|
|
235
|
+
<ul key={child.props.label} role="group" aria-labelledby={`select-${child.props.label}`}>
|
|
236
|
+
{child.props.label && (
|
|
237
|
+
<GroupLabel role="presentation" id={`select-${child.props.label}`} aria-hidden="true">
|
|
238
|
+
{child.props.label}
|
|
239
|
+
</GroupLabel>
|
|
240
|
+
)}
|
|
241
|
+
{Children.map(child.props.children, (option) => {
|
|
242
|
+
return cloneElement(option, {
|
|
243
|
+
onChange: onChange,
|
|
244
|
+
});
|
|
245
|
+
})}
|
|
246
|
+
</ul>
|
|
247
|
+
),
|
|
248
|
+
) ?? []),
|
|
249
|
+
];
|
|
250
|
+
}, [children]);
|
|
181
251
|
|
|
182
|
-
// initialFocus=-1 is used to prevent the first item from being focused when the list opens
|
|
183
252
|
return (
|
|
184
|
-
<
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
253
|
+
<SelectContext.Provider
|
|
254
|
+
value={{
|
|
255
|
+
listRef: listItemsRef,
|
|
256
|
+
setOpen,
|
|
257
|
+
getItemProps,
|
|
258
|
+
setActiveIndex,
|
|
259
|
+
activeIndex,
|
|
260
|
+
dataRef: context.dataRef,
|
|
261
|
+
multiple,
|
|
262
|
+
selectedItems,
|
|
263
|
+
setSelectedItems,
|
|
264
|
+
name,
|
|
265
|
+
}}
|
|
266
|
+
>
|
|
267
|
+
<SelectButton
|
|
268
|
+
id={id}
|
|
269
|
+
ref={refs.setReference}
|
|
270
|
+
disabled={disabled}
|
|
271
|
+
readOnly={readOnly}
|
|
272
|
+
onBlur={onBlur}
|
|
273
|
+
onFocus={onFocus}
|
|
274
|
+
isOpen={open}
|
|
275
|
+
tabIndex={disabled ? -1 : 0}
|
|
276
|
+
hasError={hasError}
|
|
277
|
+
aria-describedby={setAriaDescribedBy(name, hasDescription)}
|
|
278
|
+
{...getReferenceProps()}
|
|
196
279
|
>
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
icon={<SearchIcon />}
|
|
202
|
-
hasError={hasError}
|
|
203
|
-
value={inputValue.value}
|
|
204
|
-
onChange={onInputChange}
|
|
205
|
-
placeholder={placeholder}
|
|
206
|
-
ref={ref}
|
|
207
|
-
/>
|
|
208
|
-
{/* it will always contain 1 because of the group label */}
|
|
209
|
-
{isLoading && (
|
|
210
|
-
<FeedBackContainer>
|
|
211
|
-
<Spinner size="small" />
|
|
212
|
-
<span style={{ marginLeft: '10px' }}>loading results</span>
|
|
213
|
-
</FeedBackContainer>
|
|
280
|
+
{render ? (
|
|
281
|
+
render(selectedItems)
|
|
282
|
+
) : (
|
|
283
|
+
<div>{selectedItems.length === 0 ? 'Select' : selectedItems.map((item) => item.label).join(', ')}</div>
|
|
214
284
|
)}
|
|
215
|
-
|
|
216
|
-
{
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
<FeedBackContainer>No results found</FeedBackContainer>
|
|
285
|
+
|
|
286
|
+
{!readOnly && canClear && selectedItems.length > 0 && !open ? (
|
|
287
|
+
<IconButton size="tiny" icon={<ClearIcon />} ariaLabel="clear" onClick={(e) => handleClear(e)} />
|
|
288
|
+
) : (
|
|
289
|
+
<StyledArrowIcon size={16} />
|
|
221
290
|
)}
|
|
222
|
-
</
|
|
223
|
-
|
|
291
|
+
</SelectButton>
|
|
292
|
+
{open &&
|
|
293
|
+
(!inPortal ? (
|
|
294
|
+
<StyledFloatingOverlay lockScroll style={{ zIndex: 1000 }}>
|
|
295
|
+
{renderSelect()}
|
|
296
|
+
</StyledFloatingOverlay>
|
|
297
|
+
) : (
|
|
298
|
+
<FloatingPortal>{renderSelect()}</FloatingPortal>
|
|
299
|
+
))}
|
|
300
|
+
</SelectContext.Provider>
|
|
224
301
|
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const options = useMemo(() => {
|
|
228
|
-
return [
|
|
229
|
-
...(Children.map(
|
|
230
|
-
children,
|
|
231
|
-
(child) =>
|
|
232
|
-
isValidElement(child) && (
|
|
233
|
-
<ul key={child.props.label} role="group" aria-labelledby={`select-${child.props.label}`}>
|
|
234
|
-
{child.props.label && (
|
|
235
|
-
<GroupLabel role="presentation" id={`select-${child.props.label}`} aria-hidden="true">
|
|
236
|
-
{child.props.label}
|
|
237
|
-
</GroupLabel>
|
|
238
|
-
)}
|
|
239
|
-
{Children.map(child.props.children, (option) => {
|
|
240
|
-
return cloneElement(option, {
|
|
241
|
-
onChange: onChange,
|
|
242
|
-
});
|
|
243
|
-
})}
|
|
244
|
-
</ul>
|
|
245
|
-
)
|
|
246
|
-
) ?? []),
|
|
247
|
-
];
|
|
248
|
-
}, [children]);
|
|
249
|
-
|
|
250
|
-
return (
|
|
251
|
-
<SelectContext.Provider
|
|
252
|
-
value={{
|
|
253
|
-
listRef: listItemsRef,
|
|
254
|
-
setOpen,
|
|
255
|
-
getItemProps,
|
|
256
|
-
setActiveIndex,
|
|
257
|
-
activeIndex,
|
|
258
|
-
dataRef: context.dataRef,
|
|
259
|
-
multiple,
|
|
260
|
-
selectedItems,
|
|
261
|
-
setSelectedItems,
|
|
262
|
-
name,
|
|
263
|
-
}}
|
|
264
|
-
>
|
|
265
|
-
<SelectButton
|
|
266
|
-
id={id}
|
|
267
|
-
ref={refs.setReference}
|
|
268
|
-
disabled={disabled}
|
|
269
|
-
readOnly={readOnly}
|
|
270
|
-
onBlur={onBlur}
|
|
271
|
-
onFocus={onFocus}
|
|
272
|
-
isOpen={open}
|
|
273
|
-
tabIndex={disabled ? -1 : 0}
|
|
274
|
-
hasError={hasError}
|
|
275
|
-
aria-describedby={setAriaDescribedBy(name, hasDescription)}
|
|
276
|
-
{...getReferenceProps()}
|
|
277
|
-
>
|
|
278
|
-
{render ? (
|
|
279
|
-
render(selectedItems)
|
|
280
|
-
) : (
|
|
281
|
-
<div>{selectedItems.length === 0 ? 'Select' : selectedItems.map((item) => item.label).join(', ')}</div>
|
|
282
|
-
)}
|
|
283
|
-
|
|
284
|
-
{!readOnly && canClear && selectedItems.length > 0 && !open ? (
|
|
285
|
-
<IconButton size="tiny" icon={<ClearIcon />} ariaLabel="clear" onClick={(e) => handleClear(e)} />
|
|
286
|
-
) : (
|
|
287
|
-
<StyledArrowIcon size={16} />
|
|
288
|
-
)}
|
|
289
|
-
</SelectButton>
|
|
290
|
-
{open &&
|
|
291
|
-
(!inPortal ? (
|
|
292
|
-
<StyledFloatingOverlay lockScroll style={{ zIndex: 1000 }}>
|
|
293
|
-
{renderSelect()}
|
|
294
|
-
</StyledFloatingOverlay>
|
|
295
|
-
) : (
|
|
296
|
-
<FloatingPortal>{renderSelect()}</FloatingPortal>
|
|
297
|
-
))}
|
|
298
|
-
</SelectContext.Provider>
|
|
299
|
-
);
|
|
300
|
-
});
|
|
302
|
+
},
|
|
303
|
+
);
|
|
@@ -42,7 +42,7 @@ export const ServerSideSubmit: StoryFn<SelectQueryFieldProps> = (args) => {
|
|
|
42
42
|
|
|
43
43
|
setTimeout(() => {
|
|
44
44
|
const filteredOptions = films.filter((film) =>
|
|
45
|
-
film.name.toLowerCase().trim().includes(debouncedValue.toLowerCase())
|
|
45
|
+
film.name.toLowerCase().trim().includes(debouncedValue.toLowerCase()),
|
|
46
46
|
);
|
|
47
47
|
setOptions(filteredOptions);
|
|
48
48
|
setLoading(false);
|
|
@@ -26,10 +26,9 @@ function toggleSelectedItem(selectedValues: SelectItem[], itemToToggle: SelectIt
|
|
|
26
26
|
if (existingIndex > -1) {
|
|
27
27
|
// If it exists, remove it from the array
|
|
28
28
|
return selectedValues.filter((_, index) => index !== existingIndex);
|
|
29
|
-
} else {
|
|
30
|
-
// If it doesn't exist, add it to the array
|
|
31
|
-
return [...selectedValues, itemToToggle];
|
|
32
29
|
}
|
|
30
|
+
// If it doesn't exist, add it to the array
|
|
31
|
+
return [...selectedValues, itemToToggle];
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
function hasSelectedItem(selectedItems: SelectItem[], itemToCheck: SelectItem) {
|
|
@@ -84,6 +83,7 @@ export const Option: FC<OptionProps> = ({ children, index = 0, value, onChange,
|
|
|
84
83
|
tabIndex={activeIndex === index ? 0 : 1}
|
|
85
84
|
isMultiSelect={multiple}
|
|
86
85
|
isActive={activeIndex === index}
|
|
86
|
+
disabled={disabled}
|
|
87
87
|
aria-disabled={disabled}
|
|
88
88
|
isGrouped={false}
|
|
89
89
|
aria-selected={activeIndex === index}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { styled } from '../../../../styled';
|
|
2
2
|
|
|
3
|
-
export const OptionContainer = styled.li<{
|
|
3
|
+
export const OptionContainer = styled.li<{
|
|
4
|
+
isActive: boolean;
|
|
5
|
+
isMultiSelect: boolean;
|
|
6
|
+
isGrouped: boolean;
|
|
7
|
+
disabled: boolean;
|
|
8
|
+
}>`
|
|
4
9
|
padding: ${({ theme }) => `${theme.spacing['0_75']} ${theme.spacing['1']}`};
|
|
5
10
|
min-height: ${({ theme }) => theme.spacing[4]};
|
|
6
11
|
cursor: default;
|
|
@@ -15,12 +20,13 @@ export const OptionContainer = styled.li<{ isActive: boolean; isMultiSelect: boo
|
|
|
15
20
|
scroll-margin: ${({ theme }) => theme.spacing['0_75']};
|
|
16
21
|
padding-left: ${({ isGrouped, theme }) => (isGrouped ? `calc(1.7 * ${theme.spacing['2']})` : theme.spacing['1'])}};
|
|
17
22
|
|
|
23
|
+
|
|
18
24
|
&:focus {
|
|
19
25
|
border-color: ${({ theme }) => theme.colors.primary};
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
&:hover {
|
|
23
|
-
border-color: ${({ theme }) => theme.colors.backgroundAccent};
|
|
29
|
+
border-color: ${({ theme, disabled }) => (disabled ? theme.colors.backgroundAlt : theme.colors.backgroundAccent)};
|
|
24
30
|
span {
|
|
25
31
|
color: white;
|
|
26
32
|
}
|
|
@@ -32,8 +38,16 @@ export const OptionContainer = styled.li<{ isActive: boolean; isMultiSelect: boo
|
|
|
32
38
|
gap: ${({ theme }) => theme.spacing[1]};
|
|
33
39
|
|
|
34
40
|
span {
|
|
35
|
-
cursor: pointer;
|
|
36
|
-
color: ${({ theme, isActive }) =>
|
|
41
|
+
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
|
|
42
|
+
color: ${({ theme, isActive, disabled }) => {
|
|
43
|
+
if (disabled) {
|
|
44
|
+
return theme.colors.backgroundAccent;
|
|
45
|
+
}
|
|
46
|
+
if (isActive) {
|
|
47
|
+
return theme.colors.white;
|
|
48
|
+
}
|
|
49
|
+
return theme.colors.text;
|
|
50
|
+
}};
|
|
37
51
|
}
|
|
38
52
|
}
|
|
39
53
|
`;
|
|
@@ -41,7 +41,10 @@ export const getLabelFromChildren = (children: ReactNode, value: string) => {
|
|
|
41
41
|
return matchedOption.props.label;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
|
|
45
|
+
// eslint-disable-next-line no-console
|
|
46
|
+
console.error(
|
|
47
|
+
`No label found for value ${value}. This occurs when a value is passed through the defaultValue prop of useForm, but the value is not present in the options.`,
|
|
46
48
|
);
|
|
49
|
+
return undefined;
|
|
47
50
|
};
|
|
@@ -1,40 +1,13 @@
|
|
|
1
|
-
import { FC } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { Block, NavBar, Underline } from './style';
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
|
+
import { NavBar } from './style';
|
|
4
3
|
|
|
5
4
|
export type HorizontalNavVariant = 'underline' | 'block';
|
|
6
5
|
|
|
7
|
-
export type HorizontalNavLink = Partial<LinkProps> & {
|
|
8
|
-
text: string;
|
|
9
|
-
to: string;
|
|
10
|
-
params?: Record<string, string>;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
6
|
export interface HorizontalNavProps {
|
|
14
|
-
|
|
7
|
+
children: ReactNode;
|
|
15
8
|
variant: HorizontalNavVariant;
|
|
16
9
|
}
|
|
17
10
|
|
|
18
|
-
export const HorizontalNav: FC<HorizontalNavProps> = ({
|
|
19
|
-
return
|
|
20
|
-
<NavBar variant={variant}>
|
|
21
|
-
{links.map(({ text, ...rest }) => {
|
|
22
|
-
return (
|
|
23
|
-
<>
|
|
24
|
-
{/*eslint-disable-next-line @typescript-eslint/ban-ts-comment*/}
|
|
25
|
-
{/*@ts-ignore reusable link*/}
|
|
26
|
-
<Link key={`${rest.to}-${text}`} {...rest}>
|
|
27
|
-
{({ isActive }) => (
|
|
28
|
-
<>
|
|
29
|
-
{isActive && variant === 'block' && <Block layoutId="block" />}
|
|
30
|
-
{isActive && variant === 'underline' && <Underline layoutId="underline" />}
|
|
31
|
-
<span>{text}</span>
|
|
32
|
-
</>
|
|
33
|
-
)}
|
|
34
|
-
</Link>
|
|
35
|
-
</>
|
|
36
|
-
);
|
|
37
|
-
})}
|
|
38
|
-
</NavBar>
|
|
39
|
-
);
|
|
11
|
+
export const HorizontalNav: FC<HorizontalNavProps> = ({ children, variant }) => {
|
|
12
|
+
return <NavBar variant={variant}>{children}</NavBar>;
|
|
40
13
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { styled } from '../../../styled';
|
|
2
|
-
import { motion } from 'framer-motion';
|
|
3
2
|
import { HorizontalNavVariant } from '.';
|
|
4
3
|
|
|
5
4
|
export const NavBar = styled.nav<{ variant: HorizontalNavVariant }>`
|
|
@@ -53,31 +52,17 @@ export const NavBar = styled.nav<{ variant: HorizontalNavVariant }>`
|
|
|
53
52
|
|
|
54
53
|
&.active {
|
|
55
54
|
color: ${({ theme }) => theme.colors.text};
|
|
55
|
+
|
|
56
|
+
&:after {
|
|
57
|
+
content: '';
|
|
58
|
+
position: absolute;
|
|
59
|
+
bottom: -8px;
|
|
60
|
+
left: 0;
|
|
61
|
+
right: 0;
|
|
62
|
+
height: 1px;
|
|
63
|
+
width: 100%;
|
|
64
|
+
background-color: ${({ theme }) => theme.colors.primary};
|
|
65
|
+
}
|
|
56
66
|
}
|
|
57
67
|
}
|
|
58
68
|
`;
|
|
59
|
-
|
|
60
|
-
export const Underline = styled(motion.div)`
|
|
61
|
-
position: absolute;
|
|
62
|
-
bottom: -${({ theme }) => theme.spacing['0_75']};
|
|
63
|
-
left: 0px;
|
|
64
|
-
display: block;
|
|
65
|
-
height: 2px;
|
|
66
|
-
background-color: ${({ theme }) => theme.colors.primary};
|
|
67
|
-
content: '';
|
|
68
|
-
width: 100%;
|
|
69
|
-
`;
|
|
70
|
-
|
|
71
|
-
export const Block = styled(motion.div)`
|
|
72
|
-
position: absolute;
|
|
73
|
-
top: 0;
|
|
74
|
-
left: 0px;
|
|
75
|
-
z-index: 1;
|
|
76
|
-
display: block;
|
|
77
|
-
height: 100%;
|
|
78
|
-
border: 1px solid ${({ theme }) => theme.colors.primary};
|
|
79
|
-
background-color: ${({ theme }) => theme.colors.primaryShade};
|
|
80
|
-
border-radius: ${({ theme }) => theme.borderRadius.medium};
|
|
81
|
-
content: '';
|
|
82
|
-
width: 100%;
|
|
83
|
-
`;
|
|
@@ -26,7 +26,7 @@ const StepperSteps: FC<PropsWithChildren<void>> = ({ children }) => {
|
|
|
26
26
|
{children &&
|
|
27
27
|
Children.map(
|
|
28
28
|
children,
|
|
29
|
-
(child) => steps.length !== 0 && isValidElement(child) && child.props.id === steps[currentStep].id && child
|
|
29
|
+
(child) => steps.length !== 0 && isValidElement(child) && child.props.id === steps[currentStep].id && child,
|
|
30
30
|
)}
|
|
31
31
|
</div>
|
|
32
32
|
);
|
|
@@ -28,9 +28,8 @@ export const StepperHeaderItem = styled.div<{
|
|
|
28
28
|
${({ theme, stepState }) => {
|
|
29
29
|
if (stepState === StepStates.COMPLETE) {
|
|
30
30
|
return `border-right: .6rem solid ${lighten(0.15, theme.colors.primary)}`;
|
|
31
|
-
} else {
|
|
32
|
-
return 'border-right: .6rem solid transparent';
|
|
33
31
|
}
|
|
32
|
+
return 'border-right: .6rem solid transparent';
|
|
34
33
|
}};
|
|
35
34
|
|
|
36
35
|
cursor: ${({ stepState, canStepBack }) => (stepState === StepStates.COMPLETE && canStepBack ? 'pointer' : 'inherit')};
|
|
@@ -27,7 +27,7 @@ const StepperSteps: FC<PropsWithChildren<void>> = ({ children }) => {
|
|
|
27
27
|
{children &&
|
|
28
28
|
Children.map(
|
|
29
29
|
children,
|
|
30
|
-
(child) => steps.length !== 0 && isValidElement(child) && child.props.id === steps[currentStep].id && child
|
|
30
|
+
(child) => steps.length !== 0 && isValidElement(child) && child.props.id === steps[currentStep].id && child,
|
|
31
31
|
)}
|
|
32
32
|
</div>
|
|
33
33
|
);
|