@vygruppen/spor-react 11.3.9 → 12.0.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 +32 -11
- package/.turbo/turbo-typegen.log +23 -0
- package/CHANGELOG.md +245 -0
- package/dist/index.d.mts +2552 -8319
- package/dist/index.d.ts +2552 -8319
- package/dist/index.js +9609 -8607
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9487 -8454
- package/dist/index.mjs.map +1 -1
- package/package.json +21 -13
- package/src/accordion/Accordion.tsx +96 -45
- package/src/accordion/Expandable.tsx +54 -127
- package/src/accordion/helpers.ts +31 -0
- package/src/accordion/types.ts +60 -0
- package/src/alert/Alert.tsx +101 -0
- package/src/alert/AlertIcon.tsx +63 -45
- package/src/alert/ExpandableAlert.tsx +96 -64
- package/src/alert/ServiceAlert.tsx +127 -125
- package/src/alert/{index.tsx → index.ts} +1 -2
- package/src/breadcrumb/Breadcrumb.tsx +39 -24
- package/src/button/Button.tsx +86 -105
- package/src/button/ButtonGroup.tsx +45 -20
- package/src/button/Clipboard.tsx +82 -0
- package/src/button/CloseButton.tsx +4 -3
- package/src/button/FloatingActionButton.tsx +35 -41
- package/src/button/IconButton.tsx +34 -30
- package/src/button/index.tsx +1 -0
- package/src/color-mode/color-mode.tsx +75 -0
- package/src/color-mode/index.ts +1 -0
- package/src/datepicker/Calendar.tsx +17 -8
- package/src/datepicker/CalendarCell.tsx +20 -13
- package/src/datepicker/CalendarGrid.tsx +18 -10
- package/src/datepicker/CalendarHeader.tsx +2 -0
- package/src/datepicker/CalendarNavigationButton.tsx +1 -0
- package/src/datepicker/CalendarTriggerButton.tsx +43 -45
- package/src/datepicker/DateField.tsx +21 -12
- package/src/datepicker/DatePicker.tsx +61 -58
- package/src/datepicker/DateRangePicker.tsx +52 -58
- package/src/datepicker/DateTimeSegment.tsx +13 -5
- package/src/datepicker/RangeCalendar.tsx +13 -7
- package/src/datepicker/StyledField.tsx +25 -17
- package/src/datepicker/TimeField.tsx +10 -8
- package/src/datepicker/TimePicker.tsx +48 -45
- package/src/datepicker/types.ts +5 -0
- package/src/dialog/Dialog.tsx +56 -0
- package/src/dialog/Drawer.tsx +187 -0
- package/src/dialog/index.ts +2 -0
- package/src/dialog/types.ts +26 -0
- package/src/image/index.tsx +2 -2
- package/src/index.tsx +5 -3
- package/src/input/AttachedInputs.tsx +17 -42
- package/src/input/CardSelect.tsx +75 -162
- package/src/input/Checkbox.tsx +30 -6
- package/src/input/CheckboxGroup.tsx +25 -16
- package/src/input/ChoiceChip.tsx +58 -77
- package/src/input/Combobox.tsx +172 -172
- package/src/input/CountryCodeSelect.tsx +42 -28
- package/src/input/Dialog.tsx +1 -0
- package/src/input/Field.tsx +71 -0
- package/src/input/Fieldset.tsx +7 -0
- package/src/input/Input.tsx +68 -73
- package/src/input/InputGroup.tsx +66 -0
- package/src/input/ListBox.tsx +83 -70
- package/src/input/NativeSelect.tsx +68 -33
- package/src/input/NumericStepper.tsx +173 -171
- package/src/input/PasswordInput.tsx +99 -52
- package/src/input/PhoneNumberInput.tsx +69 -72
- package/src/input/Popover.tsx +1 -0
- package/src/input/Radio.tsx +37 -17
- package/src/input/SearchInput.tsx +24 -86
- package/src/input/Select.tsx +237 -0
- package/src/input/Switch.tsx +60 -18
- package/src/input/Textarea.tsx +53 -101
- package/src/input/{index.tsx → index.ts} +2 -8
- package/src/layout/PressableCard.tsx +12 -21
- package/src/layout/RadioCard.tsx +68 -100
- package/src/layout/Separator.tsx +32 -0
- package/src/layout/StaticCard.tsx +13 -33
- package/src/layout/index.tsx +3 -7
- package/src/linjetag/InfoTag.tsx +16 -9
- package/src/linjetag/LineIcon.tsx +74 -28
- package/src/linjetag/TravelTag.tsx +38 -27
- package/src/link/TextLink.tsx +25 -16
- package/src/list/index.tsx +24 -2
- package/src/loader/ClientOnly.tsx +8 -7
- package/src/loader/ColorInlineLoader.tsx +4 -3
- package/src/loader/ColorSpinner.tsx +5 -4
- package/src/loader/ContentLoader.tsx +6 -4
- package/src/loader/DarkFullScreenLoader.tsx +11 -3
- package/src/loader/DarkInlineLoader.tsx +5 -3
- package/src/loader/DarkSpinner.tsx +7 -3
- package/src/loader/LightFullScreenLoader.tsx +11 -3
- package/src/loader/LightInlineLoader.tsx +11 -3
- package/src/loader/LightSpinner.tsx +5 -3
- package/src/loader/Lottie.tsx +3 -3
- package/src/loader/ProgressBar.tsx +83 -84
- package/src/loader/ProgressLoader.tsx +120 -75
- package/src/loader/Skeleton.tsx +94 -19
- package/src/loader/index.tsx +0 -2
- package/src/loader/useHydrated.tsx +1 -0
- package/src/loader/useRotatingLabel.tsx +2 -1
- package/src/logo/CargonetLogo.tsx +89 -89
- package/src/logo/VyLogo.tsx +61 -42
- package/src/logo/VyLogoPride.tsx +137 -139
- package/src/media-controller/JumpButton.tsx +48 -38
- package/src/media-controller/PlayPauseButton.tsx +31 -29
- package/src/media-controller/SkipButton.tsx +38 -37
- package/src/nudge/Nudge.tsx +195 -123
- package/src/nudge/index.tsx +0 -1
- package/src/pagination/Pagination.tsx +221 -118
- package/src/pagination/types.ts +23 -0
- package/src/popover/index.tsx +67 -0
- package/src/progress-indicator/ProgressDot.tsx +11 -10
- package/src/progress-indicator/ProgressIndicator.tsx +28 -15
- package/src/provider/SporProvider.tsx +17 -14
- package/src/stepper/Stepper.tsx +88 -85
- package/src/stepper/StepperContext.tsx +2 -1
- package/src/stepper/StepperStep.tsx +28 -21
- package/src/tab/Tabs.tsx +62 -12
- package/src/tab/index.tsx +1 -9
- package/src/table/Table.tsx +35 -30
- package/src/table/index.tsx +11 -7
- package/src/theme/brand.ts +7 -0
- package/src/theme/index.ts +45 -37
- package/src/theme/recipes/attached-inputs.ts +43 -0
- package/src/theme/recipes/badge.ts +104 -0
- package/src/theme/recipes/button.ts +124 -0
- package/src/theme/recipes/choice-chip.ts +144 -0
- package/src/theme/recipes/close-button.ts +41 -0
- package/src/theme/recipes/code.ts +14 -0
- package/src/theme/recipes/group.ts +19 -0
- package/src/theme/recipes/index.ts +29 -0
- package/src/theme/recipes/input.ts +89 -0
- package/src/theme/recipes/link.ts +64 -0
- package/src/theme/recipes/nudge.ts +12 -0
- package/src/theme/recipes/pressable-card.ts +83 -0
- package/src/theme/recipes/progress-loader.ts +14 -0
- package/src/theme/recipes/separator.ts +85 -0
- package/src/theme/recipes/skeleton.ts +57 -0
- package/src/theme/recipes/static-card.ts +39 -0
- package/src/theme/recipes/textarea.ts +27 -0
- package/src/theme/semantic-tokens/colors.ts +22 -0
- package/src/theme/semantic-tokens/index.ts +24 -0
- package/src/theme/semantic-tokens/radii.ts +14 -0
- package/src/theme/semantic-tokens/shadows.ts +17 -0
- package/src/theme/slot-recipes/accordion.ts +131 -0
- package/src/theme/slot-recipes/alert-expandable.ts +133 -0
- package/src/theme/slot-recipes/alert-service.ts +66 -0
- package/src/theme/slot-recipes/alert.ts +72 -0
- package/src/theme/slot-recipes/anatomy.ts +269 -0
- package/src/theme/slot-recipes/breadcrumb.ts +61 -0
- package/src/theme/slot-recipes/checkbox.ts +89 -0
- package/src/theme/slot-recipes/datepicker.ts +214 -0
- package/src/theme/slot-recipes/dialog.ts +221 -0
- package/src/theme/slot-recipes/drawer.ts +205 -0
- package/src/theme/slot-recipes/field.ts +79 -0
- package/src/theme/slot-recipes/floating-action-button.ts +131 -0
- package/src/theme/slot-recipes/index.ts +65 -0
- package/src/theme/slot-recipes/info-tag.ts +62 -0
- package/src/theme/slot-recipes/line-icon.ts +140 -0
- package/src/theme/slot-recipes/list.ts +45 -0
- package/src/theme/slot-recipes/listbox.ts +72 -0
- package/src/theme/slot-recipes/media-controller-button.ts +131 -0
- package/src/theme/slot-recipes/native-select.ts +54 -0
- package/src/theme/slot-recipes/numeric-stepper.ts +65 -0
- package/src/theme/slot-recipes/pagination.ts +41 -0
- package/src/theme/slot-recipes/popover.ts +78 -0
- package/src/theme/slot-recipes/progress-bar.ts +39 -0
- package/src/theme/slot-recipes/progress-indicator.ts +22 -0
- package/src/theme/slot-recipes/radio-card.ts +112 -0
- package/src/theme/slot-recipes/radio.ts +80 -0
- package/src/theme/slot-recipes/select.ts +243 -0
- package/src/theme/slot-recipes/stepper.ts +92 -0
- package/src/theme/slot-recipes/switch.ts +147 -0
- package/src/theme/slot-recipes/table.ts +200 -0
- package/src/theme/slot-recipes/tabs.ts +169 -0
- package/src/theme/slot-recipes/toast.ts +56 -0
- package/src/theme/slot-recipes/travel-tag.ts +192 -0
- package/src/theme/tokens/animation-styles.ts +50 -0
- package/src/theme/tokens/animations.ts +22 -0
- package/src/theme/tokens/aspect-ratios.ts +22 -0
- package/src/theme/tokens/blurs.ts +28 -0
- package/src/theme/tokens/borders.ts +26 -0
- package/src/theme/{foundations → tokens}/breakpoints.ts +0 -1
- package/src/theme/tokens/colors.ts +10 -0
- package/src/theme/tokens/config.ts +10 -0
- package/src/theme/tokens/cursor.ts +28 -0
- package/src/theme/tokens/durations.ts +25 -0
- package/src/theme/tokens/easings.ts +16 -0
- package/src/theme/tokens/font-sizes.ts +30 -0
- package/src/theme/tokens/font-weights.ts +31 -0
- package/src/theme/tokens/fonts.ts +8 -0
- package/src/theme/tokens/global-css.ts +18 -0
- package/src/theme/tokens/index.ts +37 -0
- package/src/theme/tokens/keyframes.ts +255 -0
- package/src/theme/tokens/letter-spacings.ts +19 -0
- package/src/theme/tokens/line-heights.ts +19 -0
- package/src/theme/tokens/radii.ts +13 -0
- package/src/theme/tokens/sizes.ts +51 -0
- package/src/theme/tokens/spacing.ts +20 -0
- package/src/theme/tokens/text-styles.ts +89 -0
- package/src/theme/tokens/z-index.ts +17 -0
- package/src/theme/utils/accent-utils.ts +8 -21
- package/src/theme/utils/bg-utils.ts +4 -6
- package/src/theme/utils/brand-utils.ts +6 -19
- package/src/theme/utils/core-utils.ts +91 -0
- package/src/theme/utils/floating-utils.ts +20 -39
- package/src/theme/utils/ghost-utils.ts +7 -21
- package/src/theme/utils/input-utils.ts +32 -37
- package/src/theme/utils/outline-utils.ts +4 -11
- package/src/theme/utils/surface-utils.ts +5 -19
- package/src/theme/utils/types.ts +1 -0
- package/src/toast/index.tsx +1 -1
- package/src/toast/toast.tsx +105 -0
- package/src/transition/index.ts +2 -8
- package/src/typography/Badge.tsx +15 -61
- package/src/typography/Code.tsx +16 -28
- package/src/typography/Heading.tsx +34 -19
- package/src/typography/Text.tsx +9 -6
- package/src/typography/{index.tsx → index.ts} +1 -0
- package/src/util/externals.tsx +13 -27
- package/tsconfig.json +5 -1
- package/src/accordion/Accordion.test.tsx +0 -20
- package/src/alert/BaseAlert.test.tsx +0 -37
- package/src/alert/BaseAlert.tsx +0 -34
- package/src/alert/ClosableAlert.test.tsx +0 -37
- package/src/alert/ClosableAlert.tsx +0 -85
- package/src/alert/ExpandableAlert.test.tsx +0 -84
- package/src/alert/StaticAlert.tsx +0 -33
- package/src/button/Button.test.tsx +0 -23
- package/src/datepicker/TimePicker.test.tsx +0 -74
- package/src/input/FormControl.tsx +0 -2
- package/src/input/FormErrorMessage.tsx +0 -95
- package/src/input/FormLabel.tsx +0 -11
- package/src/input/InfoSelect.tsx +0 -274
- package/src/input/InputElement.tsx +0 -44
- package/src/input/RadioGroup.tsx +0 -47
- package/src/layout/Divider.tsx +0 -27
- package/src/layout/RadioCardGroup.tsx +0 -79
- package/src/layout/Stack.tsx +0 -42
- package/src/loader/SkeletonCircle.tsx +0 -13
- package/src/loader/SkeletonText.tsx +0 -14
- package/src/media-controller/index.test.tsx +0 -59
- package/src/modal/Drawer.tsx +0 -120
- package/src/modal/FullScreenDrawer.tsx +0 -239
- package/src/modal/Modal.tsx +0 -15
- package/src/modal/ModalHeader.tsx +0 -31
- package/src/modal/SimpleDrawer.tsx +0 -51
- package/src/modal/index.tsx +0 -5
- package/src/nudge/WizardNudge.tsx +0 -107
- package/src/theme/components/accordion.ts +0 -102
- package/src/theme/components/alert-expandable.ts +0 -125
- package/src/theme/components/alert-service.ts +0 -98
- package/src/theme/components/alert.ts +0 -71
- package/src/theme/components/badge.ts +0 -109
- package/src/theme/components/breadcrumb.ts +0 -60
- package/src/theme/components/button.ts +0 -125
- package/src/theme/components/card-select.ts +0 -117
- package/src/theme/components/checkbox.ts +0 -88
- package/src/theme/components/choice-chip.ts +0 -161
- package/src/theme/components/close-button.ts +0 -48
- package/src/theme/components/code.ts +0 -17
- package/src/theme/components/datepicker.ts +0 -198
- package/src/theme/components/divider.ts +0 -50
- package/src/theme/components/drawer.ts +0 -95
- package/src/theme/components/fab.ts +0 -109
- package/src/theme/components/form-label.ts +0 -17
- package/src/theme/components/form.ts +0 -27
- package/src/theme/components/index.ts +0 -45
- package/src/theme/components/info-select.ts +0 -85
- package/src/theme/components/info-tag.ts +0 -63
- package/src/theme/components/input.ts +0 -28
- package/src/theme/components/line-icon.ts +0 -129
- package/src/theme/components/link.ts +0 -78
- package/src/theme/components/list.ts +0 -23
- package/src/theme/components/listbox.ts +0 -77
- package/src/theme/components/media-controller-button.ts +0 -97
- package/src/theme/components/modal.ts +0 -96
- package/src/theme/components/numeric-stepper.ts +0 -65
- package/src/theme/components/pagination.ts +0 -74
- package/src/theme/components/popover.ts +0 -68
- package/src/theme/components/pressable-card.ts +0 -72
- package/src/theme/components/progress-bar.ts +0 -47
- package/src/theme/components/progress-indicator.ts +0 -44
- package/src/theme/components/radio-card.ts +0 -134
- package/src/theme/components/radio.ts +0 -68
- package/src/theme/components/select.ts +0 -74
- package/src/theme/components/skeleton.ts +0 -40
- package/src/theme/components/static-card.ts +0 -82
- package/src/theme/components/stepper.ts +0 -100
- package/src/theme/components/switch.ts +0 -112
- package/src/theme/components/table.ts +0 -161
- package/src/theme/components/tabs.ts +0 -135
- package/src/theme/components/textarea.ts +0 -33
- package/src/theme/components/toast.ts +0 -28
- package/src/theme/components/travel-tag.ts +0 -256
- package/src/theme/foundations/borders.ts +0 -11
- package/src/theme/foundations/colors.ts +0 -12
- package/src/theme/foundations/config.ts +0 -5
- package/src/theme/foundations/fontSizes.ts +0 -29
- package/src/theme/foundations/fontWeights.ts +0 -5
- package/src/theme/foundations/fonts.ts +0 -7
- package/src/theme/foundations/index.ts +0 -15
- package/src/theme/foundations/lineHeights.ts +0 -6
- package/src/theme/foundations/radii.ts +0 -12
- package/src/theme/foundations/shadows.ts +0 -8
- package/src/theme/foundations/sizes.ts +0 -36
- package/src/theme/foundations/spacing.ts +0 -31
- package/src/theme/foundations/styles.ts +0 -12
- package/src/theme/foundations/textStyles.ts +0 -74
- package/src/theme/foundations/zIndices.ts +0 -17
- package/src/theme/utils/base-utils.ts +0 -104
- package/src/theme/utils/focus-utils.ts +0 -10
- package/src/toast/ActionToast.test.tsx +0 -22
- package/src/toast/ActionToast.tsx +0 -28
- package/src/toast/BaseToast.test.tsx +0 -27
- package/src/toast/BaseToast.tsx +0 -75
- package/src/toast/ClosableToast.test.tsx +0 -17
- package/src/toast/ClosableToast.tsx +0 -40
- package/src/toast/useToast.tsx +0 -121
- package/src/tooltip/Tooltip.tsx +0 -70
- package/src/tooltip/index.tsx +0 -1
package/src/input/Input.tsx
CHANGED
@@ -1,23 +1,29 @@
|
|
1
|
+
"use client";
|
2
|
+
|
3
|
+
import { inputRecipe } from "@/theme/recipes/input";
|
1
4
|
import {
|
2
|
-
|
5
|
+
chakra,
|
3
6
|
InputProps as ChakraInputProps,
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
InputRightElement,
|
8
|
-
forwardRef,
|
9
|
-
useFormControlContext,
|
7
|
+
useRecipe,
|
8
|
+
type RecipeVariantProps,
|
9
|
+
Input as ChakraInput,
|
10
10
|
} from "@chakra-ui/react";
|
11
|
-
import React, {
|
11
|
+
import React, { forwardRef, PropsWithChildren } from "react";
|
12
|
+
import { Field, FieldProps } from "./Field";
|
13
|
+
import { InputGroup } from "./InputGroup";
|
12
14
|
|
13
|
-
export type InputProps =
|
14
|
-
|
15
|
-
label
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
export type InputProps = Exclude<
|
16
|
+
ChakraInputProps,
|
17
|
+
"size" | "label" | "colorPalette"
|
18
|
+
> &
|
19
|
+
FieldProps & {
|
20
|
+
/** The input's label */
|
21
|
+
label: string;
|
22
|
+
/** Element that shows up to the left */
|
23
|
+
startElement?: React.ReactNode;
|
24
|
+
/** Element that shows up to the right */
|
25
|
+
endElement?: React.ReactNode;
|
26
|
+
};
|
21
27
|
/**
|
22
28
|
* Inputs let you enter text or other data.
|
23
29
|
*
|
@@ -30,71 +36,60 @@ export type InputProps = Omit<ChakraInputProps, "size"> & {
|
|
30
36
|
* You can also add icons to the left and right of the input. Please use the 24 px icons for this.
|
31
37
|
*
|
32
38
|
* ```tsx
|
33
|
-
* <Input label="E-mail"
|
39
|
+
* <Input label="E-mail" startElement={<EmailOutline24Icon />} />
|
34
40
|
* ```
|
35
41
|
*
|
36
|
-
* Input has two variants
|
42
|
+
* Input has two variants core, and floating.
|
37
43
|
*
|
38
44
|
* ```tsx
|
39
|
-
* <Input label="E-mail"
|
45
|
+
* <Input label="E-mail" startElement={<EmailOutline24Icon />} variant="floating" />
|
40
46
|
* ```
|
47
|
+
*
|
48
|
+
* Field is added to Input, so you can add helperText, errorText, and optionalText.
|
49
|
+
*
|
50
|
+
* ```tsx
|
51
|
+
* <Input label="E-mail" startElement={<EmailOutline24Icon />} helperText="We will never share your email." />
|
52
|
+
* ```
|
53
|
+
*
|
54
|
+
* @see https://spor.vy.no/components/input
|
41
55
|
*/
|
42
|
-
export const Input = forwardRef<InputProps, "input">(
|
43
|
-
({ label, leftIcon, rightIcon, id, size, ...props }, ref) => {
|
44
|
-
const formControlProps = useFormControlContext();
|
45
|
-
const fallbackId = `input-${useId()}`;
|
46
|
-
const inputId = id ?? formControlProps?.id ?? fallbackId;
|
47
|
-
const labelId = `${useId()}-label`;
|
48
|
-
return (
|
49
|
-
<InputGroup position="relative">
|
50
|
-
{leftIcon && (
|
51
|
-
<InputLeftElement pointerEvents="none">{leftIcon}</InputLeftElement>
|
52
|
-
)}
|
53
|
-
<ChakraInput
|
54
|
-
data-attachable
|
55
|
-
paddingLeft={leftIcon ? 7 : undefined}
|
56
|
-
paddingRight={rightIcon ? 7 : undefined}
|
57
|
-
{...props}
|
58
|
-
id={inputId}
|
59
|
-
aria-labelledby={labelId}
|
60
|
-
ref={ref}
|
61
|
-
overflow="hidden"
|
62
|
-
placeholder=" " // This is needed to make the label work as expected
|
63
|
-
css={{
|
64
|
-
"&::-webkit-search-cancel-button": {
|
65
|
-
WebkitAppearance: "none",
|
66
|
-
},
|
67
|
-
}}
|
68
|
-
/>
|
69
56
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
}
|
57
|
+
const StyledInput = chakra(ChakraInput, inputRecipe);
|
58
|
+
|
59
|
+
export const Input = forwardRef<HTMLInputElement, InputProps>(
|
60
|
+
(
|
61
|
+
{
|
62
|
+
startElement,
|
63
|
+
endElement,
|
64
|
+
label,
|
65
|
+
invalid,
|
66
|
+
helperText,
|
67
|
+
errorText,
|
68
|
+
...props
|
69
|
+
},
|
70
|
+
ref,
|
71
|
+
) => {
|
72
|
+
return (
|
73
|
+
<Field invalid={invalid} helperText={helperText} errorText={errorText}>
|
74
|
+
<InputGroup
|
75
|
+
endElement={endElement && endElement}
|
76
|
+
startElement={startElement && startElement}
|
77
|
+
width="100%"
|
78
|
+
position="relative"
|
79
|
+
label={label}
|
89
80
|
>
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
81
|
+
<StyledInput
|
82
|
+
data-attachable
|
83
|
+
ref={ref}
|
84
|
+
className="peer"
|
85
|
+
overflow="hidden"
|
86
|
+
paddingLeft={startElement ? "2.6rem" : undefined}
|
87
|
+
paddingRight={endElement ? "2.6rem" : undefined}
|
88
|
+
placeholder=""
|
89
|
+
{...props}
|
90
|
+
/>
|
91
|
+
</InputGroup>
|
92
|
+
</Field>
|
98
93
|
);
|
99
94
|
},
|
100
95
|
);
|
@@ -0,0 +1,66 @@
|
|
1
|
+
"use client";
|
2
|
+
|
3
|
+
import type { InputElementProps, GroupProps } from "@chakra-ui/react";
|
4
|
+
import { Group, InputElement } from "@chakra-ui/react";
|
5
|
+
import * as React from "react";
|
6
|
+
import { FieldLabel } from "./Field";
|
7
|
+
|
8
|
+
export type InputGroupProps = GroupProps & {
|
9
|
+
startElementProps?: InputElementProps;
|
10
|
+
endElementProps?: InputElementProps;
|
11
|
+
startElement?: React.ReactNode;
|
12
|
+
endElement?: React.ReactNode;
|
13
|
+
children: React.ReactElement;
|
14
|
+
label?: string;
|
15
|
+
};
|
16
|
+
|
17
|
+
/**
|
18
|
+
*
|
19
|
+
* InputGroup is a wrapper for inputs that have a startElement and/or endElement.
|
20
|
+
*
|
21
|
+
* It is not exported to users, but used internally in the Input component.
|
22
|
+
*
|
23
|
+
*/
|
24
|
+
|
25
|
+
export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
|
26
|
+
(props, ref) => {
|
27
|
+
const {
|
28
|
+
startElement,
|
29
|
+
startElementProps,
|
30
|
+
endElement,
|
31
|
+
endElementProps,
|
32
|
+
label,
|
33
|
+
children,
|
34
|
+
attached,
|
35
|
+
...rest
|
36
|
+
} = props;
|
37
|
+
|
38
|
+
return (
|
39
|
+
<Group ref={ref} {...rest}>
|
40
|
+
{startElement && (
|
41
|
+
<InputElement
|
42
|
+
pointerEvents="none"
|
43
|
+
paddingX={2}
|
44
|
+
{...startElementProps}
|
45
|
+
>
|
46
|
+
{startElement}
|
47
|
+
</InputElement>
|
48
|
+
)}
|
49
|
+
{React.cloneElement(children, {
|
50
|
+
...children.props,
|
51
|
+
})}
|
52
|
+
{label && (
|
53
|
+
<FieldLabel left={startElement ? 4 : "0"} right={endElement ? 4 : 0}>
|
54
|
+
{label}
|
55
|
+
</FieldLabel>
|
56
|
+
)}
|
57
|
+
|
58
|
+
{endElement && (
|
59
|
+
<InputElement placement="end" paddingX={2} {...endElementProps}>
|
60
|
+
{endElement}
|
61
|
+
</InputElement>
|
62
|
+
)}
|
63
|
+
</Group>
|
64
|
+
);
|
65
|
+
},
|
66
|
+
);
|
package/src/input/ListBox.tsx
CHANGED
@@ -1,13 +1,20 @@
|
|
1
|
+
"use client";
|
1
2
|
import {
|
2
3
|
Box,
|
3
|
-
List,
|
4
4
|
ListItem,
|
5
|
-
|
6
|
-
|
5
|
+
ListRootProps,
|
6
|
+
RecipeVariantProps,
|
7
|
+
useSlotRecipe,
|
7
8
|
type BoxProps,
|
8
9
|
} from "@chakra-ui/react";
|
9
10
|
import type { Node } from "@react-types/shared";
|
10
|
-
import React, {
|
11
|
+
import React, {
|
12
|
+
forwardRef,
|
13
|
+
PropsWithChildren,
|
14
|
+
useContext,
|
15
|
+
useEffect,
|
16
|
+
useRef,
|
17
|
+
} from "react";
|
11
18
|
import {
|
12
19
|
AriaListBoxProps,
|
13
20
|
useListBox,
|
@@ -15,21 +22,30 @@ import {
|
|
15
22
|
useOption,
|
16
23
|
} from "react-aria";
|
17
24
|
import { type ListState, type SelectState } from "react-stately";
|
25
|
+
import { List } from "..";
|
26
|
+
import { useColorModeValue } from "../color-mode";
|
27
|
+
import { listBoxSlotRecipe } from "../theme/slot-recipes/listbox";
|
18
28
|
|
19
29
|
export { Item, Section } from "react-stately";
|
20
30
|
|
31
|
+
type ListBoxVariantProps = RecipeVariantProps<typeof listBoxSlotRecipe>;
|
32
|
+
|
21
33
|
type ListBoxProps<T> = AriaListBoxProps<T> &
|
22
|
-
Omit<BoxProps, "filter" | "autoFocus" | "children"> &
|
34
|
+
Omit<BoxProps, "filter" | "autoFocus" | "children"> &
|
35
|
+
PropsWithChildren<ListBoxVariantProps> &
|
36
|
+
Exclude<ListRootProps, "variant"> & {
|
23
37
|
/** External reference to the ListBox itself */
|
24
38
|
listBoxRef: React.RefObject<HTMLUListElement>;
|
25
39
|
/** Whether or not the listbox is waiting on new data, i.e. through a autosuggest search */
|
26
|
-
|
40
|
+
loading?: boolean;
|
27
41
|
/** The state of the listbox, provided externally somehow. */
|
28
42
|
state: ListState<T> | SelectState<T>;
|
29
43
|
/** UI to render if the collection is empty */
|
30
44
|
emptyContent?: React.ReactNode;
|
31
45
|
maxWidth?: BoxProps["maxWidth"];
|
32
|
-
variant?: "
|
46
|
+
variant?: "core" | "floating";
|
47
|
+
children: React.ReactNode;
|
48
|
+
autoFocus?: boolean;
|
33
49
|
};
|
34
50
|
|
35
51
|
/**
|
@@ -66,37 +82,34 @@ type ListBoxProps<T> = AriaListBoxProps<T> &
|
|
66
82
|
* );
|
67
83
|
* ```
|
68
84
|
*/
|
69
|
-
export function ListBox<T extends object>({
|
70
|
-
isLoading,
|
71
|
-
listBoxRef,
|
72
|
-
state,
|
73
|
-
maxWidth,
|
74
|
-
variant,
|
75
|
-
...props
|
76
|
-
}: ListBoxProps<T>) {
|
77
|
-
const { listBoxProps } = useListBox(props, state, listBoxRef);
|
78
|
-
const styles = useMultiStyleConfig("ListBox", { variant });
|
79
85
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
}
|
86
|
+
export const ListBox = forwardRef<HTMLDivElement, ListBoxProps<object>>(
|
87
|
+
(props) => {
|
88
|
+
const { loading, listBoxRef, state, maxWidth, variant, children } = props;
|
89
|
+
const { listBoxProps } = useListBox(props, state, listBoxRef);
|
90
|
+
const recipe = useSlotRecipe({ key: "listBox" });
|
91
|
+
const styles = recipe({ variant });
|
92
|
+
return (
|
93
|
+
<List
|
94
|
+
{...listBoxProps}
|
95
|
+
ref={listBoxRef}
|
96
|
+
css={styles.root}
|
97
|
+
aria-busy={loading}
|
98
|
+
maxWidth={maxWidth}
|
99
|
+
>
|
100
|
+
{state.collection.size === 0 && props.emptyContent}
|
101
|
+
{Array.from(state.collection).map((item) =>
|
102
|
+
item.type === "section" ? (
|
103
|
+
<ListBoxSection key={item.key} section={item} state={state} />
|
104
|
+
) : (
|
105
|
+
<Option key={item.key} item={item} state={state} />
|
106
|
+
),
|
107
|
+
)}
|
108
|
+
{children}
|
109
|
+
</List>
|
110
|
+
);
|
111
|
+
},
|
112
|
+
);
|
100
113
|
|
101
114
|
/**
|
102
115
|
* Renders a label for a listbox item.
|
@@ -105,12 +118,7 @@ export function ListBox<T extends object>({
|
|
105
118
|
*/
|
106
119
|
export function ItemLabel({ children }: { children: React.ReactNode }) {
|
107
120
|
let { labelProps } = useOptionContext();
|
108
|
-
|
109
|
-
return (
|
110
|
-
<Box {...labelProps} sx={styles.label}>
|
111
|
-
{children}
|
112
|
-
</Box>
|
113
|
-
);
|
121
|
+
return <Box {...labelProps}>{children}</Box>;
|
114
122
|
}
|
115
123
|
|
116
124
|
/**
|
@@ -120,9 +128,10 @@ export function ItemLabel({ children }: { children: React.ReactNode }) {
|
|
120
128
|
*/
|
121
129
|
export function ItemDescription({ children }: { children: React.ReactNode }) {
|
122
130
|
let { descriptionProps } = useOptionContext();
|
123
|
-
const
|
131
|
+
const recipe = useSlotRecipe({ key: "listbox" });
|
132
|
+
const styles = recipe({});
|
124
133
|
return (
|
125
|
-
<Box {...descriptionProps}
|
134
|
+
<Box {...descriptionProps} css={styles} fontSize={"xs"}>
|
126
135
|
{children}
|
127
136
|
</Box>
|
128
137
|
);
|
@@ -144,7 +153,9 @@ function Option({ item, state }: OptionProps) {
|
|
144
153
|
descriptionProps,
|
145
154
|
} = useOption({ key: item.key }, state, ref);
|
146
155
|
|
147
|
-
const
|
156
|
+
const recipe = useSlotRecipe({ key: "listBox" });
|
157
|
+
const styles = recipe({});
|
158
|
+
|
148
159
|
let dataFields: Record<string, boolean> = {};
|
149
160
|
if (isSelected) {
|
150
161
|
dataFields["data-selected"] = true;
|
@@ -173,10 +184,9 @@ function Option({ item, state }: OptionProps) {
|
|
173
184
|
{ passive: false, once: true },
|
174
185
|
);
|
175
186
|
}, []);
|
176
|
-
|
177
187
|
return (
|
178
188
|
<OptionContext.Provider value={{ labelProps, descriptionProps }}>
|
179
|
-
<ListItem {...optionProps} {...dataFields} ref={ref}
|
189
|
+
<ListItem {...optionProps} {...dataFields} ref={ref} css={styles.item}>
|
180
190
|
{item.rendered}
|
181
191
|
</ListItem>
|
182
192
|
</OptionContext.Provider>
|
@@ -209,29 +219,32 @@ function ListBoxSection({ section, state }: ListBoxSectionProps) {
|
|
209
219
|
|
210
220
|
const isFirstSection = section.key === state.collection.getFirstKey();
|
211
221
|
const titleColor = useColorModeValue("darkGrey", "white");
|
222
|
+
|
212
223
|
return (
|
213
|
-
<
|
214
|
-
{
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
<List {...groupProps} padding={0} listStyleType="none">
|
229
|
-
{Array.from(state.collection.getChildren(section.key)).map(
|
230
|
-
(item: any) => (
|
231
|
-
<Option key={item.key} item={item} state={state} />
|
232
|
-
),
|
224
|
+
<List>
|
225
|
+
<ListItem {...itemProps} listStyleType={"none"}>
|
226
|
+
{section.rendered && (
|
227
|
+
<Box
|
228
|
+
fontSize="mobile.xs"
|
229
|
+
color={titleColor}
|
230
|
+
paddingX={3}
|
231
|
+
paddingTop={1}
|
232
|
+
marginTop={isFirstSection ? 0 : 2}
|
233
|
+
textTransform="uppercase"
|
234
|
+
fontWeight="bold"
|
235
|
+
{...headingProps}
|
236
|
+
>
|
237
|
+
{section.rendered}
|
238
|
+
</Box>
|
233
239
|
)}
|
234
|
-
|
235
|
-
|
240
|
+
<List {...groupProps} padding={0} listStyleType="none">
|
241
|
+
{Array.from(state.collection.getChildren(section.key)).map(
|
242
|
+
(item: any) => (
|
243
|
+
<Option key={item.key} item={item} state={state} />
|
244
|
+
),
|
245
|
+
)}
|
246
|
+
</List>
|
247
|
+
</ListItem>
|
248
|
+
</List>
|
236
249
|
);
|
237
250
|
}
|
@@ -1,43 +1,78 @@
|
|
1
|
+
"use client";
|
1
2
|
import {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
useMultiStyleConfig,
|
3
|
+
RecipeVariantProps,
|
4
|
+
NativeSelect as ChakraNativeSelect,
|
5
|
+
useSlotRecipe,
|
6
6
|
} from "@chakra-ui/react";
|
7
|
-
import
|
8
|
-
import
|
7
|
+
import { DropdownDownFill18Icon } from "@vygruppen/spor-icon-react";
|
8
|
+
import * as React from "react";
|
9
|
+
import { nativeSelectSlotRecipe } from "../theme/slot-recipes/native-select";
|
10
|
+
import { Field } from "./Field";
|
11
|
+
|
12
|
+
type NativeSelectVariantProps = RecipeVariantProps<
|
13
|
+
typeof nativeSelectSlotRecipe
|
14
|
+
>;
|
15
|
+
|
16
|
+
type NativeSelectRootProps =
|
17
|
+
React.PropsWithChildren<NativeSelectVariantProps> & {
|
18
|
+
icon?: React.ReactNode;
|
19
|
+
label: string;
|
20
|
+
invalid?: boolean;
|
21
|
+
disabled?: boolean;
|
22
|
+
};
|
9
23
|
|
10
|
-
export type NativeSelectProps = Exclude<
|
11
|
-
ChakraSelectProps,
|
12
|
-
"colorScheme" | "variant" | "size"
|
13
|
-
> & { label?: string };
|
14
24
|
/**
|
15
25
|
* Selects let you choose between several options
|
16
26
|
*
|
17
27
|
* You should consider only using the Select component when you have more than 4 options. Otherwise, you should use the `<Radio>` component.
|
18
28
|
*
|
19
|
-
*
|
20
|
-
*
|
21
|
-
* <option>
|
22
|
-
* <option>
|
23
|
-
* <option>
|
24
|
-
* <option>
|
29
|
+
* <NativeSelect label="Choose language">
|
30
|
+
* <option>Norwegian (Bokmål)</option>
|
31
|
+
* <option>Norwegian (Nynorsk)</option>
|
32
|
+
* <option>Sami</option>
|
33
|
+
* <option>Swedish</option>
|
34
|
+
* <option>Danish</option>
|
35
|
+
* <option>Finnish</option>
|
36
|
+
* <option>English</option>
|
25
37
|
* </NativeSelect>
|
26
|
-
*
|
38
|
+
*
|
27
39
|
*/
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
);
|
40
|
+
|
41
|
+
export const NativeSelect = React.forwardRef<
|
42
|
+
HTMLDivElement,
|
43
|
+
NativeSelectRootProps
|
44
|
+
>(function NativeSelect(props, ref) {
|
45
|
+
const {
|
46
|
+
icon,
|
47
|
+
children,
|
48
|
+
variant = "core",
|
49
|
+
label,
|
50
|
+
invalid,
|
51
|
+
disabled,
|
52
|
+
...rest
|
53
|
+
} = props;
|
54
|
+
|
55
|
+
const recipe = useSlotRecipe({ recipe: nativeSelectSlotRecipe });
|
56
|
+
const styles = recipe({ variant });
|
57
|
+
|
58
|
+
return (
|
59
|
+
<Field label={label} invalid={invalid} disabled={disabled}>
|
60
|
+
<ChakraNativeSelect.Root
|
61
|
+
ref={ref}
|
62
|
+
css={styles.root}
|
63
|
+
aria-disabled={disabled}
|
64
|
+
>
|
65
|
+
<ChakraNativeSelect.Field
|
66
|
+
css={styles.field}
|
67
|
+
aria-invalid={invalid}
|
68
|
+
{...rest}
|
69
|
+
>
|
70
|
+
{children}
|
71
|
+
</ChakraNativeSelect.Field>
|
72
|
+
<ChakraNativeSelect.Indicator css={styles.icon}>
|
73
|
+
<DropdownDownFill18Icon />
|
74
|
+
</ChakraNativeSelect.Indicator>
|
75
|
+
</ChakraNativeSelect.Root>
|
76
|
+
</Field>
|
77
|
+
);
|
78
|
+
});
|