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