@vygruppen/spor-react 12.2.0 → 12.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vygruppen/spor-react",
3
- "version": "12.2.0",
3
+ "version": "12.3.0",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -35,8 +35,8 @@
35
35
  "react-stately": "^3.31.1",
36
36
  "react-swipeable": "^7.0.1",
37
37
  "usehooks-ts": "^3.1.0",
38
- "@vygruppen/spor-design-tokens": "4.0.5",
39
- "@vygruppen/spor-icon-react": "4.0.3",
38
+ "@vygruppen/spor-design-tokens": "4.0.6",
39
+ "@vygruppen/spor-icon-react": "4.0.4",
40
40
  "@vygruppen/spor-loader": "0.6.0"
41
41
  },
42
42
  "devDependencies": {
@@ -56,8 +56,8 @@
56
56
  "vitest": "^0.26.3",
57
57
  "vitest-axe": "^0.1.0",
58
58
  "vitest-canvas-mock": "^0.2.2",
59
- "@vygruppen/tsconfig": "0.1.0",
60
- "@vygruppen/eslint-config": "1.0.1"
59
+ "@vygruppen/eslint-config": "1.0.1",
60
+ "@vygruppen/tsconfig": "0.1.0"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "react": ">=18.0.0 <19.0.0",
@@ -9,13 +9,7 @@ import {
9
9
  useFieldContext,
10
10
  useSlotRecipe,
11
11
  } from "@chakra-ui/react";
12
- import React, {
13
- forwardRef,
14
- PropsWithChildren,
15
- ReactNode,
16
- useId,
17
- useRef,
18
- } from "react";
12
+ import React, { forwardRef, PropsWithChildren, useId, useRef } from "react";
19
13
  import {
20
14
  AriaDatePickerProps,
21
15
  DateValue,
@@ -24,7 +18,7 @@ import {
24
18
  } from "react-aria";
25
19
  import { useDatePickerState } from "react-stately";
26
20
 
27
- import { Field } from "@/input/Field";
21
+ import { Field, FieldBaseProps } from "@/input/Field";
28
22
 
29
23
  import { datePickerSlotRecipe } from "../theme/slot-recipes/datepicker";
30
24
  import { Calendar } from "./Calendar";
@@ -46,8 +40,7 @@ type DatePickerProps = Omit<AriaDatePickerProps<DateValue>, "onChange"> &
46
40
  showYearNavigation?: boolean;
47
41
  withPortal?: boolean;
48
42
  onChange?: (value: DateValue | null) => void;
49
- errorMessage?: ReactNode;
50
- };
43
+ } & FieldBaseProps;
51
44
 
52
45
  /**
53
46
  * A date picker component.
@@ -63,11 +56,13 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
63
56
  (
64
57
  {
65
58
  variant,
66
- errorMessage,
59
+ errorText,
67
60
  minHeight,
68
61
  showYearNavigation,
69
62
  withPortal = true,
70
63
  width = "auto",
64
+ invalid = false,
65
+ helperText,
71
66
  ...props
72
67
  },
73
68
  externalRef,
@@ -76,7 +71,7 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
76
71
  const state = useDatePickerState({
77
72
  ...props,
78
73
  shouldCloseOnSelect: true,
79
- errorMessage,
74
+ errorMessage: errorText,
80
75
  isRequired: props.isRequired ?? chakraFieldProps?.required,
81
76
  validationState: chakraFieldProps?.invalid ? "invalid" : "valid",
82
77
  });
@@ -130,7 +125,9 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
130
125
  display="inline-flex"
131
126
  id={inputGroupId}
132
127
  aria-labelledby={labelId}
133
- errorText={errorMessage}
128
+ errorText={errorText}
129
+ invalid={invalid}
130
+ helperText={helperText}
134
131
  >
135
132
  <PopoverAnchor>
136
133
  <StyledField
@@ -18,7 +18,7 @@ import {
18
18
  } from "react-aria";
19
19
  import { useDateRangePickerState } from "react-stately";
20
20
 
21
- import { Field } from "../input/Field";
21
+ import { Field, FieldBaseProps } from "../input/Field";
22
22
  import { datePickerSlotRecipe } from "../theme/slot-recipes/datepicker";
23
23
  import { CalendarTriggerButton } from "./CalendarTriggerButton";
24
24
  import { DateField } from "./DateField";
@@ -30,7 +30,7 @@ import { useCurrentLocale } from "./utils";
30
30
 
31
31
  type DateRangePickerProps = Omit<
32
32
  AriaDateRangePickerProps<DateValue>,
33
- "onChange"
33
+ "onChange" | "errorMessage" | "isInvalid" | "isRequired"
34
34
  > &
35
35
  Pick<BoxProps, "minHeight"> &
36
36
  PropsWithChildren<DatePickerVariantProps> &
@@ -46,7 +46,7 @@ type DateRangePickerProps = Omit<
46
46
  end: DateValue | null;
47
47
  } | null,
48
48
  ) => void;
49
- };
49
+ } & FieldBaseProps;
50
50
  /**
51
51
  * A date range picker component.
52
52
  *
@@ -61,13 +61,19 @@ type DateRangePickerProps = Omit<
61
61
  startName,
62
62
  endName,
63
63
  withPortal = true,
64
+ errorText,
65
+ helperText,
66
+ invalid,
64
67
  ...props
65
68
  }: DateRangePickerProps) {
66
69
  const fieldContextPRops = useFieldContext();
67
70
  const state = useDateRangePickerState({
68
71
  ...props,
69
72
  shouldCloseOnSelect: true,
70
- isRequired: props.isRequired ?? fieldContextPRops?.required,
73
+ isInvalid: invalid,
74
+ errorMessage: errorText,
75
+
76
+ isRequired: props.required ?? fieldContextPRops?.required,
71
77
  validationState: fieldContextPRops?.invalid ? "invalid" : "valid",
72
78
  });
73
79
  const ref = useRef(null);
@@ -113,7 +119,14 @@ type DateRangePickerProps = Omit<
113
119
  </label>
114
120
  )}
115
121
  <ChakraPopover.Root {...dialogProps}>
116
- <Field width="auto" display="inline-flex" id={datePickerId}>
122
+ <Field
123
+ width="auto"
124
+ display="inline-flex"
125
+ id={datePickerId}
126
+ errorText={errorText}
127
+ helperText={helperText}
128
+ invalid={invalid}
129
+ >
117
130
  <PopoverAnchor>
118
131
  <StyledField
119
132
  alignItems="center"
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { BoxProps } from "@chakra-ui/react";
2
+ import { BoxProps, useFieldContext } from "@chakra-ui/react";
3
3
  import { CalendarDateTime } from "@internationalized/date";
4
4
  import { TimeValue } from "@react-types/datepicker";
5
5
  import {
@@ -8,43 +8,44 @@ import {
8
8
  } from "@vygruppen/spor-icon-react";
9
9
  import { useTimeFieldState } from "react-stately";
10
10
 
11
- import { Field } from "@/input/Field";
11
+ import { Field, FieldBaseProps } from "@/input/Field";
12
12
 
13
13
  import { createTexts, IconButton, useTranslation } from "..";
14
14
  import { StyledField } from "./StyledField";
15
15
  import { TimeField } from "./TimeField";
16
16
  import { getCurrentTime, useCurrentLocale } from "./utils";
17
17
 
18
- type TimePickerProps = Omit<BoxProps, "defaultValue" | "onChange"> & {
19
- /** The label. Defaults to a localized version of "Time" */
20
- label?: string;
21
- /** The name of the form field, if used in a regular form */
22
- name?: string;
23
- /** The controlled value, if any.
24
- *
25
- * A `new Time(hours, minutes)` should be passed.
26
- * Or `null` if the time should be unset.
27
- **/
28
- value?: TimeValue | null;
29
- /** A default value, if any.
30
- *
31
- * A `new Time(hours, minutes)` should be passed.
32
- * Defaults to the current time if not provided.
33
- * Can be set to null if you don't want a time to be selected by default.
34
- **/
35
- defaultValue?: TimeValue | null;
36
- /** Callback for when the time changes */
37
- onChange?: (value: TimeValue | null) => void;
38
- /** The maxiumum number of minutes to move when the step buttons are used.
39
- *
40
- * Defaults to 30 minutes.
41
- *
42
- * An example: If the time is at 13:37 and the minuteInterval is 15, clicking the step forwards button will move the time to 13:45. Next click will move it to 14:00.
43
- */
44
- minuteInterval?: number;
45
- /** Whether or not the field is disabled */
46
- disabled?: boolean;
47
- };
18
+ type TimePickerProps = Omit<BoxProps, "defaultValue" | "onChange"> &
19
+ FieldBaseProps & {
20
+ /** The label. Defaults to a localized version of "Time" */
21
+ label?: string;
22
+ /** The name of the form field, if used in a regular form */
23
+ name?: string;
24
+ /** The controlled value, if any.
25
+ *
26
+ * A `new Time(hours, minutes)` should be passed.
27
+ * Or `null` if the time should be unset.
28
+ **/
29
+ value?: TimeValue | null;
30
+ /** A default value, if any.
31
+ *
32
+ * A `new Time(hours, minutes)` should be passed.
33
+ * Defaults to the current time if not provided.
34
+ * Can be set to null if you don't want a time to be selected by default.
35
+ **/
36
+ defaultValue?: TimeValue | null;
37
+ /** Callback for when the time changes */
38
+ onChange?: (value: TimeValue | null) => void;
39
+ /** The maxiumum number of minutes to move when the step buttons are used.
40
+ *
41
+ * Defaults to 30 minutes.
42
+ *
43
+ * An example: If the time is at 13:37 and the minuteInterval is 15, clicking the step forwards button will move the time to 13:45. Next click will move it to 14:00.
44
+ */
45
+ minuteInterval?: number;
46
+ /** Whether or not the field is disabled */
47
+ disabled?: boolean;
48
+ };
48
49
  /** A time picker component.
49
50
  *
50
51
  * This lets the user select a time of day, either through typing it in, using the up and down arrows to select the hour and minute, or by clicking the step buttons to move the time forwards or backwards in pre-defined increments.
@@ -126,6 +127,7 @@ export const TimePicker = ({
126
127
  const ariaLabel = `${inputLabel} – ${t(
127
128
  texts.selectedTimeIs(`${dateTime?.hour ?? 0} ${dateTime?.minute ?? 0}`),
128
129
  )}`;
130
+
129
131
  return (
130
132
  <Field as="time" {...boxProps}>
131
133
  <StyledField
@@ -201,6 +203,3 @@ const texts = createTexts({
201
203
  sv: "minuter",
202
204
  },
203
205
  });
204
- function useFieldContext(): { disabled: unknown; invalid: unknown } {
205
- throw new Error("Function not implemented.");
206
- }
@@ -1,12 +1,15 @@
1
1
  "use client";
2
2
 
3
- import { chakra, Group, RecipeVariantProps } from "@chakra-ui/react";
3
+ import {
4
+ chakra,
5
+ Group,
6
+ GroupProps,
7
+ RecipeVariantProps,
8
+ } from "@chakra-ui/react";
4
9
  import { forwardRef } from "react";
5
10
 
6
11
  import { attachedInputsRecipe } from "@/theme/recipes/attached-inputs";
7
12
 
8
- import { InputGroupProps } from "./InputGroup";
9
-
10
13
  /**
11
14
  * Attaches several inputs together, so that they look like one input.
12
15
  *
@@ -23,7 +26,7 @@ import { InputGroupProps } from "./InputGroup";
23
26
  export type AttachedInputsProps = RecipeVariantProps<
24
27
  typeof attachedInputsRecipe
25
28
  > &
26
- InputGroupProps;
29
+ GroupProps;
27
30
 
28
31
  const StyledGroup = chakra(Group, attachedInputsRecipe);
29
32
 
@@ -1,30 +1,20 @@
1
1
  "use client";
2
- import {
3
- chakra,
4
- RecipeVariantProps,
5
- Span,
6
- useCheckbox,
7
- } from "@chakra-ui/react";
2
+ import { CheckboxCard, CheckboxCardRootProps, Span } from "@chakra-ui/react";
8
3
  import { CloseOutline24Icon } from "@vygruppen/spor-icon-react";
9
- import React, { ChangeEvent, PropsWithChildren } from "react";
4
+ import React, { forwardRef } from "react";
10
5
 
11
- import { choiceChipRecipe } from "@/theme/recipes/choice-chip";
12
-
13
- type ChoiceChipVariantProps = RecipeVariantProps<typeof choiceChipRecipe>;
6
+ type CheckBoxIcon = {
7
+ default: React.ReactNode;
8
+ checked: React.ReactNode;
9
+ };
14
10
 
15
- export type ChoiceChipProps = PropsWithChildren<ChoiceChipVariantProps> & {
16
- onChange?: (value: ChangeEvent<HTMLInputElement>) => void;
17
- checked?: boolean;
18
- disabled?: boolean;
19
- defaultChecked?: boolean;
20
- /** The button text */
21
- children: React.ReactNode;
22
- icon?: {
23
- default: React.ReactNode;
24
- checked: React.ReactNode;
25
- };
26
- chipType?: "icon" | "choice" | "filter";
27
- "aria-label"?: string;
11
+ export type ChoiceChipProps = Omit<
12
+ CheckboxCardRootProps,
13
+ "onCheckedChange" | "checked"
14
+ > & {
15
+ icon?: CheckBoxIcon;
16
+ onCheckedChange?: (checked: boolean) => void;
17
+ checked: boolean;
28
18
  };
29
19
 
30
20
  /**
@@ -59,49 +49,42 @@ export type ChoiceChipProps = PropsWithChildren<ChoiceChipVariantProps> & {
59
49
  * ```
60
50
  */
61
51
 
62
- const ChoiceChipStyledDiv = chakra("div", choiceChipRecipe);
52
+ export const ChoiceChip = forwardRef<HTMLInputElement, ChoiceChipProps>(
53
+ ({ children, icon, onCheckedChange, ...rootProps }, ref) => {
54
+ return (
55
+ <CheckboxCard.Root
56
+ {...rootProps}
57
+ {...(onCheckedChange && {
58
+ onCheckedChange: (details) => onCheckedChange(!!details.checked),
59
+ })}
60
+ >
61
+ <CheckboxCard.Context>
62
+ {({ checked }) => (
63
+ <>
64
+ <CheckboxCard.HiddenInput ref={ref} />
65
+ <CheckboxCard.Control>
66
+ <CheckboxCard.Content>
67
+ <CheckboxCard.Label>
68
+ {icon && (
69
+ <Span width="24px">
70
+ {checked ? icon.checked : icon.default}
71
+ </Span>
72
+ )}
63
73
 
64
- export const ChoiceChip = ({
65
- children,
66
- icon,
67
- size = "sm",
68
- chipType = "choice",
69
- variant = "core",
70
- ...props
71
- }: ChoiceChipProps) => {
72
- const {
73
- getControlProps,
74
- disabled,
75
- getLabelProps,
76
- getHiddenInputProps,
77
- setChecked,
78
- checked,
79
- } = useCheckbox(props);
74
+ {rootProps.chipType !== "icon" && children}
80
75
 
81
- return (
82
- <chakra.label
83
- {...getLabelProps()}
84
- aria-label={props["aria-label"] ?? String(children)}
85
- >
86
- <chakra.input
87
- {...getHiddenInputProps()}
88
- disabled={disabled}
89
- defaultChecked={checked}
90
- value={checked ? "on" : "off"}
91
- type="checkbox"
92
- aria-checked={checked}
93
- onClick={() => {
94
- setChecked(!checked);
95
- }}
96
- />
97
- <ChoiceChipStyledDiv {...getControlProps()} size={size} variant={variant}>
98
- {icon && <Span>{checked ? icon.checked : icon.default}</Span>}
99
- {chipType !== "icon" && <Span>{children}</Span>}
76
+ {rootProps.chipType === "filter" && checked && (
77
+ <CloseOutline24Icon />
78
+ )}
79
+ </CheckboxCard.Label>
80
+ </CheckboxCard.Content>
81
+ </CheckboxCard.Control>
82
+ </>
83
+ )}
84
+ </CheckboxCard.Context>
85
+ </CheckboxCard.Root>
86
+ );
87
+ },
88
+ );
100
89
 
101
- {chipType === "filter" && checked && (
102
- <CloseOutline24Icon marginLeft={1.5} />
103
- )}
104
- </ChoiceChipStyledDiv>
105
- </chakra.label>
106
- );
107
- };
90
+ ChoiceChip.displayName = "ChoiceChip";
@@ -140,6 +140,11 @@ export const Combobox = forwardRef<HTMLDivElement, ComboboxProps<object>>(
140
140
  aria-haspopup="listbox"
141
141
  ref={inputRef}
142
142
  role="combobox"
143
+ errorText={props.errorText}
144
+ helperText={props.helperText}
145
+ required={props.required}
146
+ disabled={props.disabled}
147
+ invalid={props.invalid}
143
148
  label={label}
144
149
  variant={variant}
145
150
  aria-expanded={state.isOpen}
@@ -3,23 +3,34 @@
3
3
  import {
4
4
  Field as ChakraField,
5
5
  RecipeVariantProps,
6
+ Stack,
6
7
  useSlotRecipe,
7
8
  } from "@chakra-ui/react";
8
9
  import * as React from "react";
9
10
 
11
+ import { Text } from "@/typography";
12
+
10
13
  import { fieldSlotRecipe } from "../theme/slot-recipes/field";
14
+ import { FloatingLabel } from "./FloatingLabel";
15
+ import { Label } from "./Label";
11
16
 
12
17
  type FieldVariantProps = RecipeVariantProps<typeof fieldSlotRecipe>;
13
18
 
19
+ export type FieldBaseProps = {
20
+ direction?: "row" | "column";
21
+ disabled?: boolean;
22
+ invalid?: boolean;
23
+ readOnly?: boolean;
24
+ required?: boolean;
25
+ label?: React.ReactNode;
26
+ helperText?: React.ReactNode;
27
+ errorText?: React.ReactNode;
28
+ floatingLabel?: boolean;
29
+ };
30
+
14
31
  export type FieldProps = Omit<ChakraField.RootProps, "label"> &
15
- React.PropsWithChildren<FieldVariantProps> & {
16
- /** Label for the component */
17
- label?: React.ReactNode;
18
- /** Add helpertext underneath the input */
19
- helperText?: React.ReactNode;
20
- /** Add error text underneath the input */
21
- errorText?: React.ReactNode;
22
- };
32
+ React.PropsWithChildren<FieldVariantProps> &
33
+ FieldBaseProps;
23
34
 
24
35
  /**
25
36
  *
@@ -40,22 +51,47 @@ export type FieldProps = Omit<ChakraField.RootProps, "label"> &
40
51
 
41
52
  export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
42
53
  (props, ref) => {
43
- const { label, children, helperText, errorText, ...rest } = props;
54
+ const {
55
+ label,
56
+ children,
57
+ helperText,
58
+ errorText,
59
+ floatingLabel = false,
60
+ disabled,
61
+ invalid,
62
+ readOnly,
63
+ required,
64
+ direction,
65
+ ...rest
66
+ } = props;
44
67
  const recipe = useSlotRecipe({ key: "field" });
45
- const styles = recipe({ label, helperText, errorText });
68
+ const styles = recipe();
69
+
46
70
  return (
47
- <ChakraField.Root ref={ref} {...rest} css={styles.root}>
48
- {children}
71
+ <Stack gap="2" ref={ref} {...rest} width="100%">
72
+ <ChakraField.Root
73
+ disabled={disabled}
74
+ invalid={invalid}
75
+ readOnly={readOnly}
76
+ required={required}
77
+ css={styles.root}
78
+ direction={direction}
79
+ >
80
+ {label && !floatingLabel && <Label>{label}</Label>}
81
+
82
+ {children}
83
+
84
+ {label && floatingLabel && <FloatingLabel>{label}</FloatingLabel>}
85
+ {errorText && (
86
+ <ChakraField.ErrorText>{errorText}</ChakraField.ErrorText>
87
+ )}
88
+ </ChakraField.Root>
49
89
  {helperText && (
50
- <ChakraField.HelperText>{helperText}</ChakraField.HelperText>
51
- )}
52
- {label && (
53
- <ChakraField.Label css={styles.label}>{label}</ChakraField.Label>
54
- )}
55
- {errorText && (
56
- <ChakraField.ErrorText>{errorText}</ChakraField.ErrorText>
90
+ <Text fontSize="sm" color="text.tertiary">
91
+ {helperText}
92
+ </Text>
57
93
  )}
58
- </ChakraField.Root>
94
+ </Stack>
59
95
  );
60
96
  },
61
97
  );
@@ -0,0 +1,38 @@
1
+ import { defineStyle, Field, FieldLabelProps } from "@chakra-ui/react";
2
+ import { forwardRef } from "react";
3
+
4
+ export const FloatingLabel = forwardRef<HTMLLabelElement, FieldLabelProps>(
5
+ (props, ref) => (
6
+ <Field.Label ref={ref} {...props} css={floatingLabelStyles} />
7
+ ),
8
+ );
9
+
10
+ FloatingLabel.displayName = "FloatingLabel";
11
+
12
+ const floatingLabelStyles = defineStyle({
13
+ paddingX: 3,
14
+ fontWeight: "normal",
15
+ fontSize: ["mobile.xs", "desktop.xs"],
16
+ color: "text",
17
+ pointerEvents: "none",
18
+ zIndex: "docked",
19
+ _disabled: {
20
+ opacity: 0.4,
21
+ },
22
+
23
+ pos: "absolute",
24
+ top: "0.3rem",
25
+ transition: "position",
26
+ _peerPlaceholderShown: {
27
+ /* For when input is not in focus */
28
+ top: "0.9rem",
29
+ color: "text",
30
+ fontSize: ["mobile.sm", "desktop.sm"],
31
+ },
32
+ _peerFocusVisible: {
33
+ /* For when input is in focus */
34
+ fontSize: ["mobile.xs", "desktop.xs"],
35
+ color: "text",
36
+ top: "0.3rem",
37
+ },
38
+ });
@@ -1,24 +1,26 @@
1
1
  "use client";
2
2
 
3
3
  import {
4
+ Box,
4
5
  chakra,
6
+ Flex,
5
7
  Input as ChakraInput,
8
+ InputElement,
6
9
  InputProps as ChakraInputProps,
7
10
  } from "@chakra-ui/react";
8
- import React, { forwardRef } from "react";
11
+ import React, { forwardRef, ReactNode } from "react";
9
12
 
10
13
  import { inputRecipe } from "@/theme/recipes/input";
11
14
 
12
15
  import { Field, FieldProps } from "./Field";
13
- import { InputGroup } from "./InputGroup";
14
16
 
15
17
  export type InputProps = Exclude<
16
18
  ChakraInputProps,
17
- "size" | "label" | "colorPalette"
19
+ "size" | "label" | "colorPalette" | "placeholder"
18
20
  > &
19
21
  FieldProps & {
20
22
  /** The input's label */
21
- label: string;
23
+ label: ReactNode;
22
24
  /** Element that shows up to the left */
23
25
  startElement?: React.ReactNode;
24
26
  /** Element that shows up to the right */
@@ -70,25 +72,40 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
70
72
  ref,
71
73
  ) => {
72
74
  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}
80
- >
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>
75
+ <Field
76
+ invalid={invalid}
77
+ helperText={helperText}
78
+ errorText={errorText}
79
+ label={
80
+ // Render startElement invisibly to align label text with input content when an icon is present
81
+ <Flex>
82
+ <Box visibility="hidden">{startElement}</Box>
83
+ {label}
84
+ </Flex>
85
+ }
86
+ floatingLabel={true}
87
+ >
88
+ {startElement && (
89
+ <InputElement pointerEvents="none" paddingX={2}>
90
+ {startElement}
91
+ </InputElement>
92
+ )}
93
+ <StyledInput
94
+ data-attachable
95
+ ref={ref}
96
+ focusVisibleRing="outside"
97
+ overflow="hidden"
98
+ paddingLeft={startElement ? "2.6rem" : undefined}
99
+ paddingRight={endElement ? "2.6rem" : undefined}
100
+ {...props}
101
+ className={`peer ${props.className}`}
102
+ placeholder=""
103
+ />
104
+ {endElement && (
105
+ <InputElement placement="end" paddingX={2}>
106
+ {endElement}
107
+ </InputElement>
108
+ )}
92
109
  </Field>
93
110
  );
94
111
  },