@entur/form 8.4.2 → 9.0.1

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.
@@ -4,6 +4,7 @@ export type InputGroupLabelProps = {
4
4
  required?: boolean;
5
5
  labelTooltip?: string;
6
6
  labelId: string;
7
+ isFilled?: boolean;
7
8
  staticAnimation?: boolean;
8
9
  } & React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>;
9
10
  export declare const InputGroupLabel: React.FC<InputGroupLabelProps>;
package/dist/form.cjs.js CHANGED
@@ -116,15 +116,18 @@ const InputGroupLabel = ({
116
116
  required,
117
117
  labelId,
118
118
  staticAnimation = false,
119
+ className,
120
+ isFilled: forceIsFilled,
119
121
  ...rest
120
122
  }) => {
121
123
  const { isFilled: isFilled2 } = useInputGroupContext();
122
- const filler = staticAnimation || isFilled2;
124
+ const filler = staticAnimation || (forceIsFilled ?? isFilled2);
123
125
  return /* @__PURE__ */ jsxRuntime.jsx(
124
126
  "label",
125
127
  {
126
- className: classNames(rest.className, {
127
- "eds-input-group-label-wrapper--filled": filler
128
+ className: classNames(className, {
129
+ "eds-input-group-label-wrapper--filled": filler,
130
+ "eds-input-group-label-wrapper--controlled-label-position": forceIsFilled !== void 0
128
131
  }),
129
132
  id: labelId,
130
133
  ...rest,
@@ -893,142 +896,217 @@ const ClearButton = ({ onClear, ...props }) => {
893
896
  const SegmentedContext = React.createContext(
894
897
  null
895
898
  );
896
- const SegmentedProvider = ({
897
- name,
898
- onChange = () => void 0,
899
- selectedValue,
900
- multiple,
901
- size,
902
- ...rest
903
- }) => {
904
- const generatedName = utils.useRandomId("eds-segmented-control");
905
- const contextValue = React.useMemo(
906
- () => ({
907
- name: name || generatedName,
908
- onChange,
909
- multiple,
910
- selectedValue,
911
- size
912
- }),
913
- [generatedName, multiple, name, onChange, selectedValue, size]
914
- );
915
- return /* @__PURE__ */ jsxRuntime.jsx(SegmentedContext.Provider, { value: contextValue, ...rest });
916
- };
917
899
  const useSegmentedContext = () => {
918
900
  const context = React.useContext(SegmentedContext);
919
901
  if (!context) {
920
902
  throw new Error(
921
- "You need to wrap your SegmentedChoice in either SegmentedControl or MultipleSegmentedControl"
903
+ "You need to wrap your SegmentedChoice in SegmentedControl"
922
904
  );
923
905
  }
924
906
  return context;
925
907
  };
926
- const SegmentedChoice = React.forwardRef(
908
+ const SegmentedControl = React.forwardRef(
927
909
  ({
928
910
  children,
929
- className,
930
- style,
931
- value,
911
+ label,
932
912
  name,
933
- onChange = () => void 0,
913
+ onChange,
914
+ value,
915
+ defaultValue,
916
+ size = "medium",
917
+ className,
918
+ selectedValue: deprecatedValue,
934
919
  ...rest
935
920
  }, ref) => {
936
- const {
937
- name: commonName,
938
- selectedValue,
939
- onChange: commonOnChange,
940
- multiple,
941
- size
942
- } = useSegmentedContext();
943
- const isChecked = multiple ? selectedValue[value] : selectedValue === value;
944
- const handleChange = (e) => {
945
- onChange(e);
946
- if (multiple) {
947
- commonOnChange({
948
- ...selectedValue,
949
- [value]: e.target.checked
950
- });
951
- } else if (e.target.checked) {
952
- commonOnChange(value);
953
- }
954
- };
955
- return /* @__PURE__ */ jsxRuntime.jsxs(
956
- "label",
921
+ const [internalValue, setInternalValue] = React.useState(
922
+ defaultValue ?? null
923
+ );
924
+ const [focusedValue, setFocusedValue] = React.useState(null);
925
+ const id = utils.useRandomId("eds-segmented-control");
926
+ const isControlled = deprecatedValue !== void 0 || value !== void 0;
927
+ const currentValue = deprecatedValue !== void 0 ? deprecatedValue : value !== void 0 ? value : internalValue;
928
+ const handleChange = React.useCallback(
929
+ (newValue) => {
930
+ if (!isControlled) {
931
+ setInternalValue(newValue);
932
+ }
933
+ onChange?.(newValue);
934
+ },
935
+ [isControlled, onChange]
936
+ );
937
+ const contextValue = React.useMemo(
938
+ () => ({
939
+ name: name ?? label ?? id,
940
+ onChange: handleChange,
941
+ value: currentValue,
942
+ size,
943
+ focusedValue,
944
+ setFocusedValue
945
+ }),
946
+ [id, name, handleChange, currentValue, size, focusedValue, label]
947
+ );
948
+ const labelId = `${id}-label`;
949
+ return /* @__PURE__ */ jsxRuntime.jsx(SegmentedContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
950
+ "div",
957
951
  {
958
- className: classNames("eds-segmented-choice", className),
959
- style,
952
+ className: classNames("eds-segmented-control", className),
953
+ role: "radiogroup",
954
+ "aria-labelledby": label ? labelId : void 0,
955
+ ref,
956
+ ...rest,
960
957
  children: [
958
+ label !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(typography.Label, { htmlFor: id, id: labelId, children: label }),
961
959
  /* @__PURE__ */ jsxRuntime.jsx(
962
960
  "input",
963
961
  {
964
- type: multiple ? "checkbox" : "radio",
965
- name: name || commonName,
966
- checked: isChecked,
967
- value,
968
- onChange: handleChange,
969
- ref,
970
- ...rest
962
+ name: name ?? label ?? id,
963
+ value: currentValue ?? void 0,
964
+ type: "hidden",
965
+ id
971
966
  }
972
967
  ),
973
- /* @__PURE__ */ jsxRuntime.jsx(
974
- "div",
975
- {
976
- className: classNames("eds-base-segmented", {
977
- "eds-base-segmented--large": size === "large"
978
- }),
979
- children
980
- }
981
- )
968
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "eds-segmented-control__choices", children: React.Children.map(children, (child, index) => {
969
+ if (index === 0 && React.isValidElement(child))
970
+ return React.cloneElement(child, {
971
+ "data-first-child": true
972
+ });
973
+ return child;
974
+ }) })
982
975
  ]
983
976
  }
984
- );
977
+ ) });
985
978
  }
986
979
  );
987
- const SegmentedControl = ({
980
+ const defaultElement = "button";
981
+ const SegmentedChoice = React.forwardRef(function SegmentedChoice2({
988
982
  children,
989
- label,
990
- name,
991
- onChange,
992
- selectedValue,
993
- size = "medium",
994
983
  className,
984
+ style,
985
+ value,
986
+ as,
987
+ onChange,
988
+ "data-first-child": isFirstChild,
995
989
  ...rest
996
- }) => {
997
- return /* @__PURE__ */ jsxRuntime.jsx(
998
- SegmentedProvider,
999
- {
1000
- name,
1001
- selectedValue,
1002
- onChange,
1003
- multiple: false,
1004
- size,
1005
- children: /* @__PURE__ */ jsxRuntime.jsx(Fieldset, { label, children: /* @__PURE__ */ jsxRuntime.jsx(
1006
- "div",
1007
- {
1008
- className: classNames("eds-segmented-control", className),
1009
- ...rest,
1010
- children
990
+ }, ref) {
991
+ const Element = as || defaultElement;
992
+ const {
993
+ value: selectedValue,
994
+ onChange: contextOnChange,
995
+ size,
996
+ focusedValue,
997
+ setFocusedValue
998
+ } = useSegmentedContext();
999
+ const isChecked = selectedValue === value;
1000
+ const tabIndex = React.useMemo(() => {
1001
+ if (selectedValue !== null) return isChecked ? 0 : -1;
1002
+ return isFirstChild ? 0 : -1;
1003
+ }, [isChecked, selectedValue, isFirstChild]);
1004
+ const handleSelection = () => {
1005
+ contextOnChange(value);
1006
+ onChange?.(value);
1007
+ };
1008
+ const handleKeyDown = (e) => {
1009
+ switch (e.key) {
1010
+ case "ArrowLeft":
1011
+ case "ArrowUp": {
1012
+ e.preventDefault();
1013
+ const prevSibling = e.currentTarget.previousElementSibling;
1014
+ if (prevSibling && prevSibling instanceof HTMLElement) {
1015
+ prevSibling.focus();
1016
+ setFocusedValue(prevSibling.getAttribute("data-value") || null);
1017
+ }
1018
+ break;
1019
+ }
1020
+ case "ArrowRight":
1021
+ case "ArrowDown": {
1022
+ e.preventDefault();
1023
+ const nextSibling = e.currentTarget.nextElementSibling;
1024
+ if (nextSibling && nextSibling instanceof HTMLElement) {
1025
+ nextSibling.focus();
1026
+ setFocusedValue(nextSibling.getAttribute("data-value") || null);
1027
+ }
1028
+ break;
1029
+ }
1030
+ case "Home": {
1031
+ e.preventDefault();
1032
+ const firstSibling = e.currentTarget.parentElement?.firstElementChild;
1033
+ if (firstSibling && firstSibling instanceof HTMLElement) {
1034
+ firstSibling.focus();
1035
+ setFocusedValue(firstSibling.getAttribute("data-value") || null);
1036
+ }
1037
+ break;
1038
+ }
1039
+ case "End": {
1040
+ e.preventDefault();
1041
+ const lastSibling = e.currentTarget.parentElement?.lastElementChild;
1042
+ if (lastSibling && lastSibling instanceof HTMLElement) {
1043
+ lastSibling.focus();
1044
+ setFocusedValue(lastSibling.getAttribute("data-value") || null);
1011
1045
  }
1012
- ) })
1046
+ break;
1047
+ }
1048
+ case " ":
1049
+ e.preventDefault();
1050
+ if (as === "a") {
1051
+ handleSelection();
1052
+ const linkElement = e.currentTarget;
1053
+ if (linkElement.href) {
1054
+ queueMicrotask(() => {
1055
+ linkElement.click();
1056
+ });
1057
+ }
1058
+ } else {
1059
+ handleSelection();
1060
+ }
1061
+ break;
1062
+ case "Enter":
1063
+ handleSelection();
1064
+ break;
1065
+ case "Escape":
1066
+ e.preventDefault();
1067
+ setFocusedValue(null);
1068
+ break;
1013
1069
  }
1014
- );
1015
- };
1016
- const MultipleSegmentedControl = ({ children, label, name, onChange, selectedValue, ...rest }) => {
1017
- return /* @__PURE__ */ jsxRuntime.jsxs(
1018
- SegmentedProvider,
1019
- {
1020
- name,
1021
- selectedValue,
1022
- onChange,
1023
- multiple: true,
1024
- size: "medium",
1025
- children: [
1026
- /* @__PURE__ */ jsxRuntime.jsx(typography.Label, { as: "div", children: label }),
1027
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "eds-segmented-control", ...rest, children })
1028
- ]
1070
+ };
1071
+ const onFocus = React.useCallback(() => {
1072
+ setFocusedValue(value);
1073
+ }, [setFocusedValue, value]);
1074
+ const onBlur = React.useCallback(() => {
1075
+ if (focusedValue === value) {
1076
+ setFocusedValue(null);
1029
1077
  }
1030
- );
1031
- };
1078
+ }, [focusedValue, value, setFocusedValue]);
1079
+ const elementProps = {
1080
+ className: classNames(
1081
+ "eds-segmented-choice",
1082
+ {
1083
+ "eds-segmented-choice--large": size === "large"
1084
+ },
1085
+ className
1086
+ ),
1087
+ style,
1088
+ "aria-checked": isChecked,
1089
+ "data-value": value,
1090
+ ref,
1091
+ tabIndex,
1092
+ onClick: handleSelection,
1093
+ onKeyDown: handleKeyDown,
1094
+ onFocus,
1095
+ onBlur,
1096
+ role: "radio",
1097
+ // For defaultElement button we override type submit
1098
+ ...as === void 0 && { type: "button" },
1099
+ ...rest
1100
+ };
1101
+ return /* @__PURE__ */ jsxRuntime.jsx(Element, { ...elementProps, children });
1102
+ });
1103
+ const SegmentedControlComponent = Object.assign(
1104
+ SegmentedControl,
1105
+ {
1106
+ Item: SegmentedChoice
1107
+ }
1108
+ );
1109
+ SegmentedControlComponent.Item.displayName = "SegmentedControl.Item";
1032
1110
  utils.warnAboutMissingStyles("form", "icons", "typography");
1033
1111
  exports.BaseFormControl = BaseFormControl;
1034
1112
  exports.Checkbox = Checkbox;
@@ -1037,12 +1115,12 @@ exports.FeedbackText = FeedbackText;
1037
1115
  exports.Fieldset = Fieldset;
1038
1116
  exports.InputGroupContextProvider = InputGroupContextProvider;
1039
1117
  exports.InputGroupLabel = InputGroupLabel;
1040
- exports.MultipleSegmentedControl = MultipleSegmentedControl;
1041
1118
  exports.Radio = Radio;
1042
1119
  exports.RadioGroup = RadioGroup;
1043
1120
  exports.RadioPanel = RadioPanel;
1044
1121
  exports.SegmentedChoice = SegmentedChoice;
1045
- exports.SegmentedControl = SegmentedControl;
1122
+ exports.SegmentedControl = SegmentedControlComponent;
1123
+ exports.SegmentedControlComponent = SegmentedControlComponent;
1046
1124
  exports.Switch = Switch;
1047
1125
  exports.TextArea = TextArea;
1048
1126
  exports.TextField = TextField;