@entur/form 9.0.1 → 9.1.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/dist/form.esm.js CHANGED
@@ -84,13 +84,11 @@ const InputGroupContext = React.createContext({
84
84
  });
85
85
  const InputGroupContextProvider = ({ children }) => {
86
86
  const [filled, setFilled] = React.useState(false);
87
- return /* @__PURE__ */ jsx(
88
- InputGroupContext.Provider,
89
- {
90
- value: { isFilled: filled, setFilled },
91
- children
92
- }
87
+ const value = React.useMemo(
88
+ () => ({ isFilled: filled, setFilled }),
89
+ [filled, setFilled]
93
90
  );
91
+ return /* @__PURE__ */ jsx(InputGroupContext.Provider, { value, children });
94
92
  };
95
93
  const useInputGroupContext = () => React.useContext(InputGroupContext);
96
94
  const InputGroupLabel = ({
@@ -251,7 +249,7 @@ const BaseFormControl = React__default.forwardRef(
251
249
  FeedbackText,
252
250
  {
253
251
  variant: currentVariant,
254
- role: ariaAlertOnFeedback ? "alert" : void 0,
252
+ role: ariaAlertOnFeedback === true || ariaAlertOnFeedback === "alert" ? "alert" : ariaAlertOnFeedback === "status" ? "status" : void 0,
255
253
  children: feedback
256
254
  }
257
255
  ),
@@ -284,7 +282,7 @@ const Checkbox = React__default.forwardRef(
284
282
  return /* @__PURE__ */ jsxs(
285
283
  "label",
286
284
  {
287
- className: classNames("eds-checkbox__container", className, {
285
+ className: classNames("eds-checkbox", "eds-checkbox__container", className, {
288
286
  "eds-checkbox--disabled": disabled,
289
287
  "eds-checkbox--readonly": readOnly,
290
288
  "eds-checkbox__container--reduced-click-area": reduceClickArea
@@ -426,13 +424,18 @@ const InputPanelBase = React__default.forwardRef(
426
424
  style,
427
425
  id,
428
426
  disabled = false,
427
+ readOnly = false,
429
428
  type = "radio",
430
429
  onChange,
431
430
  checked,
432
431
  name,
433
432
  ...rest
434
433
  }, ref) => {
435
- const classList = classNames(
434
+ const classList = classNames("eds-input-panel", {
435
+ "eds-input-panel--readonly": readOnly,
436
+ "eds-input-panel--disabled": disabled
437
+ });
438
+ const panelClassList = classNames(
436
439
  className,
437
440
  "eds-input-panel__container",
438
441
  `eds-input-panel--${size}`
@@ -442,10 +445,28 @@ const InputPanelBase = React__default.forwardRef(
442
445
  const inputPanelId = id || defaultId;
443
446
  const forceUpdate = useForceUpdate();
444
447
  const handleOnChange = (e) => {
445
- if (onChange === void 0) forceUpdate();
448
+ if (readOnly) {
449
+ e.preventDefault();
450
+ return;
451
+ }
452
+ if (onChange === void 0) {
453
+ forceUpdate();
454
+ }
446
455
  onChange?.(e);
447
456
  };
448
- return /* @__PURE__ */ jsxs("label", { className: "eds-input-panel", htmlFor: inputPanelId, children: [
457
+ const handleOnClick = (e) => {
458
+ if (readOnly) {
459
+ e.preventDefault();
460
+ e.stopPropagation();
461
+ }
462
+ };
463
+ const handleOnKeyDown = (e) => {
464
+ if (readOnly && (e.key === " " || e.key === "Enter")) {
465
+ e.preventDefault();
466
+ e.stopPropagation();
467
+ }
468
+ };
469
+ return /* @__PURE__ */ jsxs("label", { className: classList, htmlFor: inputPanelId, children: [
449
470
  /* @__PURE__ */ jsx(
450
471
  "input",
451
472
  {
@@ -455,17 +476,20 @@ const InputPanelBase = React__default.forwardRef(
455
476
  value,
456
477
  checked,
457
478
  onChange: handleOnChange,
479
+ onClick: handleOnClick,
480
+ onKeyDown: handleOnKeyDown,
458
481
  id: inputPanelId,
459
482
  disabled,
483
+ readOnly,
460
484
  ...rest
461
485
  }
462
486
  ),
463
- /* @__PURE__ */ jsxs("div", { className: classList, style, children: [
487
+ /* @__PURE__ */ jsxs("div", { className: panelClassList, style, children: [
464
488
  /* @__PURE__ */ jsxs("div", { className: "eds-input-panel__title-wrapper", children: [
465
489
  /* @__PURE__ */ jsx("div", { className: "eds-input-panel__title", children: title }),
466
490
  /* @__PURE__ */ jsxs("div", { className: "eds-input-panel__secondary-label-and-icon-wrapper", children: [
467
491
  secondaryLabel !== void 0 && /* @__PURE__ */ jsx(Fragment, { children: secondaryLabel }),
468
- /* @__PURE__ */ jsx("span", { style: { pointerEvents: "none" }, children: !(disabled || hideSelectionIndicator) && (type === "radio" ? /* @__PURE__ */ jsx(
492
+ /* @__PURE__ */ jsx("span", { style: { pointerEvents: "none" }, children: !hideSelectionIndicator && (type === "radio" ? /* @__PURE__ */ jsx(
469
493
  Radio,
470
494
  {
471
495
  name: "",
@@ -474,6 +498,8 @@ const InputPanelBase = React__default.forwardRef(
474
498
  onChange: () => {
475
499
  return;
476
500
  },
501
+ disabled,
502
+ readOnly,
477
503
  "aria-hidden": "true",
478
504
  tabIndex: -1
479
505
  }
@@ -482,6 +508,8 @@ const InputPanelBase = React__default.forwardRef(
482
508
  {
483
509
  checked: checked ?? inputRef.current?.checked ?? false,
484
510
  onChange: () => null,
511
+ disabled,
512
+ readOnly,
485
513
  "aria-hidden": "true",
486
514
  tabIndex: -1
487
515
  }
@@ -504,10 +532,17 @@ const RadioPanel = React__default.forwardRef(
504
532
  hideRadioButton = false,
505
533
  style,
506
534
  id,
507
- disabled = false,
535
+ disabled,
536
+ readOnly,
508
537
  ...rest
509
538
  }, ref) => {
510
- const { name, value: selected, onChange } = useRadioGroupContext();
539
+ const {
540
+ name,
541
+ value: selected,
542
+ onChange,
543
+ readOnly: groupReadOnly,
544
+ disabled: groupDisabled
545
+ } = useRadioGroupContext();
511
546
  return /* @__PURE__ */ jsx(
512
547
  InputPanelBase,
513
548
  {
@@ -523,7 +558,8 @@ const RadioPanel = React__default.forwardRef(
523
558
  hideSelectionIndicator: hideRadioButton,
524
559
  style,
525
560
  id,
526
- disabled,
561
+ disabled: disabled ?? groupDisabled,
562
+ readOnly: readOnly ?? groupReadOnly,
527
563
  ...rest,
528
564
  ref,
529
565
  children
@@ -546,6 +582,7 @@ const CheckboxPanel = React__default.forwardRef(
546
582
  style,
547
583
  id,
548
584
  disabled = false,
585
+ readOnly = false,
549
586
  ...rest
550
587
  }, ref) => {
551
588
  return /* @__PURE__ */ jsx(
@@ -564,6 +601,7 @@ const CheckboxPanel = React__default.forwardRef(
564
601
  style,
565
602
  id,
566
603
  disabled,
604
+ readOnly,
567
605
  ...rest,
568
606
  ref,
569
607
  children
@@ -578,11 +616,12 @@ const RadioGroup = ({
578
616
  onChange,
579
617
  label,
580
618
  readOnly = false,
619
+ disabled = false,
581
620
  ...rest
582
621
  }) => {
583
622
  const contextValue = React__default.useMemo(
584
- () => ({ name, value, onChange, readOnly }),
585
- [name, value, onChange, readOnly]
623
+ () => ({ name, value, onChange, readOnly, disabled }),
624
+ [name, value, onChange, readOnly, disabled]
586
625
  );
587
626
  return /* @__PURE__ */ jsx(RadioGroupContextProvider, { value: contextValue, children: label ? /* @__PURE__ */ jsx(Fieldset, { label, ...rest, children }) : children });
588
627
  };
@@ -650,7 +689,21 @@ function hasValue(value) {
650
689
  return value != null && !(Array.isArray(value) && value.length === 0);
651
690
  }
652
691
  function isFilled(obj, SSR = false) {
653
- return obj && (hasValue(obj.value) && obj.value !== "" || SSR && hasValue(obj.defaultValue) && obj.defaultValue !== "");
692
+ if (obj == null) {
693
+ return false;
694
+ }
695
+ if (typeof obj === "string") {
696
+ return obj !== "";
697
+ }
698
+ if (obj && typeof obj === "object") {
699
+ if (hasValue(obj.value) && obj.value !== "") {
700
+ return true;
701
+ }
702
+ if (SSR && hasValue(obj.defaultValue) && obj.defaultValue !== "") {
703
+ return true;
704
+ }
705
+ }
706
+ return false;
654
707
  }
655
708
  const TextArea = React__default.forwardRef(
656
709
  ({
@@ -766,6 +819,7 @@ const TextField = React__default.forwardRef(
766
819
  labelProps,
767
820
  clearable = false,
768
821
  onClear,
822
+ clearButtonAriaLabel = "Tøm felt",
769
823
  value,
770
824
  ariaAlertOnFeedback = false,
771
825
  ...rest
@@ -773,6 +827,29 @@ const TextField = React__default.forwardRef(
773
827
  const randomId = useRandomId("eds-textfield");
774
828
  const textFieldId = labelProps && labelProps.id ? labelProps.id : randomId;
775
829
  const textFieldRef = React__default.useRef(null);
830
+ const { setFilled } = useInputGroupContext();
831
+ const handleClear = () => {
832
+ const inputElement = textFieldRef.current;
833
+ if (inputElement) {
834
+ const setNativeInputValue = Object.getOwnPropertyDescriptor(
835
+ window.HTMLInputElement.prototype,
836
+ "value"
837
+ )?.set;
838
+ setNativeInputValue?.call(inputElement, "");
839
+ const inputEvent = new Event("input", { bubbles: true });
840
+ inputElement.dispatchEvent(inputEvent);
841
+ inputElement.focus();
842
+ setFilled(false);
843
+ }
844
+ onClear?.();
845
+ };
846
+ const _append = React__default.useMemo(() => {
847
+ if (!clearable) return append ?? null;
848
+ return /* @__PURE__ */ jsxs("div", { className: "eds-textfield__append", children: [
849
+ append,
850
+ /* @__PURE__ */ jsx(ClearButton, { onClear: handleClear, ariaLabel: clearButtonAriaLabel })
851
+ ] });
852
+ }, [append, clearable]);
776
853
  return /* @__PURE__ */ jsx(
777
854
  BaseFormControl,
778
855
  {
@@ -780,7 +857,7 @@ const TextField = React__default.forwardRef(
780
857
  readOnly,
781
858
  variant,
782
859
  prepend,
783
- append: clearable && onClear ? /* @__PURE__ */ jsx(ClearButton, { onClear }) : append,
860
+ append: _append,
784
861
  className: classNames(className, "eds-textfield__wrapper"),
785
862
  style,
786
863
  size,
@@ -819,21 +896,21 @@ const TextFieldBase = React__default.forwardRef(
819
896
  const contextVariant = useVariant();
820
897
  const currentVariant = variant || contextVariant;
821
898
  const { isFilled: isInputFilled, setFilled: setFiller } = useInputGroupContext();
822
- useOnMount(() => {
823
- if (value?.toString() || rest.defaultValue) {
824
- setFiller && !isInputFilled && setFiller(true);
825
- }
826
- });
899
+ const inputRef = React__default.useRef(null);
827
900
  React__default.useEffect(() => {
828
- if (value?.toString() && setFiller && !isInputFilled) {
829
- setFiller(true);
901
+ if (setFiller) {
902
+ const filled = isFilled({ value }) || isFilled(inputRef.current, true);
903
+ if (filled !== isInputFilled) {
904
+ setFiller(filled);
905
+ }
830
906
  }
831
907
  }, [value, setFiller, isInputFilled]);
832
908
  const handleChange = (event) => {
833
- if (isFilled(event.target)) {
834
- setFiller && !isInputFilled && setFiller(true);
835
- } else {
836
- setFiller && isInputFilled && setFiller(false);
909
+ if (setFiller && value === void 0) {
910
+ const filled = isFilled(event.target);
911
+ if (filled !== isInputFilled) {
912
+ setFiller(filled);
913
+ }
837
914
  }
838
915
  if (onChange) {
839
916
  onChange(event);
@@ -846,7 +923,7 @@ const TextFieldBase = React__default.forwardRef(
846
923
  className: "eds-form-control",
847
924
  disabled,
848
925
  readOnly,
849
- ref: forwardRef,
926
+ ref: mergeRefs(forwardRef, inputRef),
850
927
  placeholder,
851
928
  onChange: handleChange,
852
929
  value,
@@ -855,25 +932,24 @@ const TextFieldBase = React__default.forwardRef(
855
932
  );
856
933
  }
857
934
  );
858
- const ClearButton = ({ onClear, ...props }) => {
859
- const { isFilled: hasValue2, setFilled } = useInputGroupContext();
860
- return /* @__PURE__ */ jsxs("div", { className: "eds-textfield__clear-button-wrapper", children: [
861
- hasValue2 && /* @__PURE__ */ jsx("div", { className: "eds-textfield__divider" }),
862
- hasValue2 && /* @__PURE__ */ jsx(
863
- "button",
864
- {
865
- className: "eds-textfield__clear-button",
866
- type: "button",
867
- tabIndex: -1,
868
- onClick: () => {
869
- setFilled(false);
870
- onClear();
871
- },
872
- ...props,
873
- children: /* @__PURE__ */ jsx(CloseSmallIcon, {})
874
- }
875
- )
876
- ] });
935
+ const ClearButton = ({ onClear, ariaLabel }) => {
936
+ const { isFilled: isFilled2 } = useInputGroupContext();
937
+ if (isFilled2) {
938
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
939
+ /* @__PURE__ */ jsx("div", { className: "eds-textfield__divider" }),
940
+ /* @__PURE__ */ jsx(
941
+ IconButton,
942
+ {
943
+ className: "eds-textfield__clear-button",
944
+ type: "button",
945
+ "aria-label": ariaLabel,
946
+ onClick: onClear,
947
+ children: /* @__PURE__ */ jsx(CloseSmallIcon, { "aria-hidden": true })
948
+ }
949
+ )
950
+ ] });
951
+ }
952
+ return null;
877
953
  };
878
954
  const SegmentedContext = React__default.createContext(
879
955
  null