@simplybusiness/mobius 5.3.1 → 5.5.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/cjs/components/Checkbox/Checkbox.js +16 -22
  3. package/dist/cjs/components/Checkbox/Checkbox.js.map +1 -1
  4. package/dist/cjs/components/Checkbox/CheckboxGroup.js +29 -11
  5. package/dist/cjs/components/Checkbox/CheckboxGroup.js.map +1 -1
  6. package/dist/cjs/components/Combobox/Combobox.js +129 -0
  7. package/dist/cjs/components/Combobox/Combobox.js.map +1 -0
  8. package/dist/cjs/components/Combobox/fixtures.js +244 -0
  9. package/dist/cjs/components/Combobox/fixtures.js.map +1 -0
  10. package/dist/cjs/components/Combobox/index.js +21 -0
  11. package/dist/cjs/components/Combobox/index.js.map +1 -0
  12. package/dist/cjs/components/Combobox/types.js +6 -0
  13. package/dist/cjs/components/Combobox/types.js.map +1 -0
  14. package/dist/cjs/components/index.js +1 -0
  15. package/dist/cjs/components/index.js.map +1 -1
  16. package/dist/cjs/hooks/index.js +1 -0
  17. package/dist/cjs/hooks/index.js.map +1 -1
  18. package/dist/cjs/hooks/useRenderCount/index.js +20 -0
  19. package/dist/cjs/hooks/useRenderCount/index.js.map +1 -0
  20. package/dist/cjs/hooks/useRenderCount/useRenderCount.js +20 -0
  21. package/dist/cjs/hooks/useRenderCount/useRenderCount.js.map +1 -0
  22. package/dist/cjs/hooks/useTextField/useTextField.js +1 -0
  23. package/dist/cjs/hooks/useTextField/useTextField.js.map +1 -1
  24. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  25. package/dist/esm/components/Checkbox/Checkbox.js +17 -23
  26. package/dist/esm/components/Checkbox/Checkbox.js.map +1 -1
  27. package/dist/esm/components/Checkbox/CheckboxGroup.js +29 -11
  28. package/dist/esm/components/Checkbox/CheckboxGroup.js.map +1 -1
  29. package/dist/esm/components/Checkbox/types.js.map +1 -1
  30. package/dist/esm/components/Combobox/Combobox.js +114 -0
  31. package/dist/esm/components/Combobox/Combobox.js.map +1 -0
  32. package/dist/esm/components/Combobox/fixtures.js +226 -0
  33. package/dist/esm/components/Combobox/fixtures.js.map +1 -0
  34. package/dist/esm/components/Combobox/index.js +4 -0
  35. package/dist/esm/components/Combobox/index.js.map +1 -0
  36. package/dist/esm/components/Combobox/types.js +3 -0
  37. package/dist/esm/components/Combobox/types.js.map +1 -0
  38. package/dist/esm/components/index.js +1 -0
  39. package/dist/esm/components/index.js.map +1 -1
  40. package/dist/esm/hooks/index.js +1 -0
  41. package/dist/esm/hooks/index.js.map +1 -1
  42. package/dist/esm/hooks/useRenderCount/index.js +3 -0
  43. package/dist/esm/hooks/useRenderCount/index.js.map +1 -0
  44. package/dist/esm/hooks/useRenderCount/useRenderCount.js +10 -0
  45. package/dist/esm/hooks/useRenderCount/useRenderCount.js.map +1 -0
  46. package/dist/esm/hooks/useTextField/types.js.map +1 -1
  47. package/dist/esm/hooks/useTextField/useTextField.js +1 -0
  48. package/dist/esm/hooks/useTextField/useTextField.js.map +1 -1
  49. package/dist/types/components/Checkbox/CheckboxGroup.stories.d.ts +1 -0
  50. package/dist/types/components/Checkbox/types.d.ts +10 -6
  51. package/dist/types/components/Combobox/Combobox.d.ts +3 -0
  52. package/dist/types/components/Combobox/Combobox.stories.d.ts +7 -0
  53. package/dist/types/components/Combobox/Combobox.test.d.ts +1 -0
  54. package/dist/types/components/Combobox/fixtures.d.ts +5 -0
  55. package/dist/types/components/Combobox/index.d.ts +2 -0
  56. package/dist/types/components/Combobox/types.d.ts +16 -0
  57. package/dist/types/components/index.d.ts +1 -0
  58. package/dist/types/hooks/index.d.ts +1 -0
  59. package/dist/types/hooks/useRenderCount/index.d.ts +1 -0
  60. package/dist/types/hooks/useRenderCount/useRenderCount.d.ts +1 -0
  61. package/dist/types/hooks/useRenderCount/useRenderCount.test.d.ts +1 -0
  62. package/dist/types/hooks/useTextField/types.d.ts +3 -2
  63. package/package.json +17 -17
  64. package/src/components/Checkbox/Checkbox.tsx +18 -28
  65. package/src/components/Checkbox/CheckboxGroup.stories.tsx +15 -0
  66. package/src/components/Checkbox/CheckboxGroup.test.tsx +107 -1
  67. package/src/components/Checkbox/CheckboxGroup.tsx +45 -15
  68. package/src/components/Checkbox/types.ts +13 -6
  69. package/src/components/Combobox/Combobox.css +30 -0
  70. package/src/components/Combobox/Combobox.stories.tsx +26 -0
  71. package/src/components/Combobox/Combobox.test.tsx +578 -0
  72. package/src/components/Combobox/Combobox.tsx +154 -0
  73. package/src/components/Combobox/fixtures.tsx +93 -0
  74. package/src/components/Combobox/index.tsx +2 -0
  75. package/src/components/Combobox/types.tsx +20 -0
  76. package/src/components/index.tsx +1 -0
  77. package/src/hooks/index.tsx +1 -0
  78. package/src/hooks/useRenderCount/index.ts +1 -0
  79. package/src/hooks/useRenderCount/useRenderCount.test.ts +26 -0
  80. package/src/hooks/useRenderCount/useRenderCount.ts +9 -0
  81. package/src/hooks/useTextField/types.tsx +7 -1
  82. package/src/hooks/useTextField/useTextField.test.tsx +1 -0
  83. package/src/hooks/useTextField/useTextField.tsx +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - af05836: Adds `role` attribute to `useTextfield` hook
8
+ - ec04e00: Fix `Checkbox` is not checked when clicked
9
+ - a0d927d: Add keyboard events to `useTextField` props
10
+ - cc9aad5: Add `Combobox` component
11
+ - d1b33b1: Add Rocket Lawyer theme
12
+
13
+ ## 5.4.0
14
+
15
+ ### Minor Changes
16
+
17
+ - b4eec50: Add support for `lastItemDisables` on `CheckboxGroup` component
18
+
19
+ ### Patch Changes
20
+
21
+ - 2085451: Prevent calling `onChange` on `CheckboxGroup` on initial render
22
+ - 37bf8fa: Package updates
23
+ - Updated dependencies [5bc73ef]
24
+ - @simplybusiness/icons@4.15.0
25
+
3
26
  ## 5.3.1
4
27
 
5
28
  ### Patch Changes
@@ -24,18 +24,27 @@ function _interop_require_default(obj) {
24
24
  };
25
25
  }
26
26
  const Checkbox = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
27
- const { id, label, isDisabled, isRequired, validationState, isInvalid, onChange, className, errorMessage, defaultSelected = false, isReadOnly, name, value, ["aria-describedby"]: ariaDescribedBy, ...rest } = props;
28
- const [selected, setSelected] = (0, _react.useState)(defaultSelected);
27
+ const { id, label, isDisabled, isRequired, validationState, isInvalid, onChange, className, errorMessage, selected, defaultSelected = false, isReadOnly, isLastItem, name, value, ["aria-describedby"]: ariaDescribedBy, ...rest } = props;
28
+ const [checked, setChecked] = (0, _react.useState)(defaultSelected);
29
29
  const fallbackRef = (0, _react.useRef)(null);
30
30
  const refObj = ref || fallbackRef;
31
31
  const inputId = (0, _react.useId)();
32
+ const isControlled = typeof selected === "boolean";
33
+ (0, _react.useEffect)(()=>{
34
+ if (isControlled) {
35
+ setChecked(selected);
36
+ }
37
+ }, [
38
+ selected,
39
+ isControlled
40
+ ]);
32
41
  const validationClasses = (0, _hooks.useValidationClasses)({
33
42
  validationState,
34
43
  isInvalid
35
44
  });
36
45
  const sharedClasses = (0, _dedupe.default)({
37
46
  "--is-disabled": isDisabled,
38
- "--is-selected": selected,
47
+ "--is-selected": checked,
39
48
  "--is-required": typeof isRequired === "boolean" && isRequired,
40
49
  "--is-optional": typeof isRequired === "boolean" && !isRequired
41
50
  }, validationClasses);
@@ -51,23 +60,10 @@ const Checkbox = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
51
60
  ariaDescribedBy
52
61
  ]);
53
62
  const labelId = (0, _react.useId)();
54
- const toggleState = ()=>{
55
- setSelected(!selected);
56
- };
57
- const handleClick = (event)=>{
58
- const isMouseEvent = event.clientX;
59
- if (isMouseEvent) {
60
- toggleState();
61
- }
62
- };
63
63
  const handleChange = (event)=>{
64
+ setChecked(!checked);
64
65
  if (onChange) {
65
- onChange(event);
66
- }
67
- };
68
- const handleKeyDown = (event)=>{
69
- if (event.code === "Space") {
70
- toggleState();
66
+ onChange(event, isLastItem);
71
67
  }
72
68
  };
73
69
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_Stack.Stack, {
@@ -86,11 +82,9 @@ const Checkbox = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
86
82
  disabled: isDisabled,
87
83
  ref: refObj,
88
84
  className: inputClasses,
89
- onClick: handleClick,
90
85
  onChange: handleChange,
91
- onKeyDown: handleKeyDown,
92
86
  type: "checkbox",
93
- defaultChecked: defaultSelected,
87
+ checked: checked,
94
88
  required: isRequired,
95
89
  id: id || inputId,
96
90
  name: name,
@@ -98,7 +92,7 @@ const Checkbox = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
98
92
  ...rest
99
93
  }),
100
94
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_Icon.Icon, {
101
- icon: selected ? _icons.squareTick : _icons.square,
95
+ icon: checked ? _icons.squareTick : _icons.square,
102
96
  size: "md",
103
97
  className: iconClasses
104
98
  }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n ChangeEvent,\n forwardRef,\n useRef,\n useState,\n KeyboardEvent,\n MouseEvent,\n useId,\n} from \"react\";\nimport classNames from \"classnames/dedupe\";\nimport { squareTick, square } from \"@simplybusiness/icons\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport { CheckboxElementType, CheckboxProps, CheckboxRef } from \"./types\";\nimport { spaceDelimitedList } from \"../../utils/spaceDelimitedList\";\nimport { useValidationClasses } from \"../../hooks\";\nimport { Icon } from \"../Icon\";\nimport { Stack } from \"../Stack\";\n\nexport const Checkbox: ForwardedRefComponent<\n CheckboxProps,\n CheckboxElementType\n> = forwardRef((props: CheckboxProps, ref: CheckboxRef) => {\n const {\n id,\n label,\n isDisabled,\n isRequired,\n validationState,\n isInvalid,\n onChange,\n className,\n errorMessage,\n defaultSelected = false,\n isReadOnly,\n name,\n value,\n [\"aria-describedby\"]: ariaDescribedBy,\n ...rest\n } = props;\n const [selected, setSelected] = useState<boolean>(defaultSelected);\n const fallbackRef = useRef<HTMLInputElement>(null);\n const refObj = ref || fallbackRef;\n const inputId = useId();\n const validationClasses = useValidationClasses({\n validationState,\n isInvalid,\n });\n const sharedClasses = classNames(\n {\n \"--is-disabled\": isDisabled,\n \"--is-selected\": selected,\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n },\n validationClasses,\n );\n // Append an additional wrapper class name to differenitate from input\n const wrapperClasses = classNames(\n \"mobius\",\n \"mobius-checkbox\",\n sharedClasses,\n className,\n );\n const labelClasses = classNames(\"mobius-checkbox__label\", sharedClasses);\n const inputClasses = classNames(\"mobius-checkbox__input\", sharedClasses);\n const iconClasses = classNames(\"mobius-checkbox__icon\", sharedClasses);\n const errorMessageId = useId();\n const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;\n const describedBy = spaceDelimitedList([\n shouldErrorMessageShow,\n ariaDescribedBy,\n ]);\n const labelId = useId();\n\n const toggleState = () => {\n setSelected(!selected);\n };\n\n const handleClick = (event: MouseEvent<CheckboxElementType>) => {\n const isMouseEvent = event.clientX;\n\n if (isMouseEvent) {\n toggleState();\n }\n };\n\n const handleChange = (event: ChangeEvent<CheckboxElementType>) => {\n if (onChange) {\n onChange(event);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.code === \"Space\") {\n toggleState();\n }\n };\n\n return (\n <Stack gap=\"xs\" className={wrapperClasses}>\n <label className={labelClasses}>\n <input\n aria-describedby={describedBy}\n aria-errormessage={shouldErrorMessageShow}\n aria-invalid={isInvalid}\n aria-labelledby={labelId}\n readOnly={isReadOnly}\n disabled={isDisabled}\n ref={refObj}\n className={inputClasses}\n onClick={handleClick}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n type=\"checkbox\"\n defaultChecked={defaultSelected}\n required={isRequired}\n id={id || inputId}\n name={name}\n value={value}\n {...rest}\n />\n <Icon\n icon={selected ? squareTick : square}\n size=\"md\"\n className={iconClasses}\n />\n <span id={labelId} className=\"mobius-checkbox__visible-label\">\n {label}\n </span>\n </label>\n <ErrorMessage id={errorMessageId} errorMessage={errorMessage} />\n </Stack>\n );\n});\n"],"names":["Checkbox","forwardRef","props","ref","id","label","isDisabled","isRequired","validationState","isInvalid","onChange","className","errorMessage","defaultSelected","isReadOnly","name","value","ariaDescribedBy","rest","selected","setSelected","useState","fallbackRef","useRef","refObj","inputId","useId","validationClasses","useValidationClasses","sharedClasses","classNames","wrapperClasses","labelClasses","inputClasses","iconClasses","errorMessageId","shouldErrorMessageShow","undefined","describedBy","spaceDelimitedList","labelId","toggleState","handleClick","event","isMouseEvent","clientX","handleChange","handleKeyDown","code","Stack","gap","input","aria-describedby","aria-errormessage","aria-invalid","aria-labelledby","readOnly","disabled","onClick","onKeyDown","type","defaultChecked","required","Icon","icon","squareTick","square","size","span","ErrorMessage"],"mappings":"AAAA;;;;;+BAqBaA;;;eAAAA;;;;uBAXN;+DACgB;uBACY;8BACN;oCAGM;uBACE;sBAChB;uBACC;;;;;;AAEf,MAAMA,yBAGTC,IAAAA,iBAAU,EAAC,CAACC,OAAsBC;IACpC,MAAM,EACJC,EAAE,EACFC,KAAK,EACLC,UAAU,EACVC,UAAU,EACVC,eAAe,EACfC,SAAS,EACTC,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,kBAAkB,KAAK,EACvBC,UAAU,EACVC,IAAI,EACJC,KAAK,EACL,CAAC,mBAAmB,EAAEC,eAAe,EACrC,GAAGC,MACJ,GAAGhB;IACJ,MAAM,CAACiB,UAAUC,YAAY,GAAGC,IAAAA,eAAQ,EAAUR;IAClD,MAAMS,cAAcC,IAAAA,aAAM,EAAmB;IAC7C,MAAMC,SAASrB,OAAOmB;IACtB,MAAMG,UAAUC,IAAAA,YAAK;IACrB,MAAMC,oBAAoBC,IAAAA,2BAAoB,EAAC;QAC7CpB;QACAC;IACF;IACA,MAAMoB,gBAAgBC,IAAAA,eAAU,EAC9B;QACE,iBAAiBxB;QACjB,iBAAiBa;QACjB,iBAAiB,OAAOZ,eAAe,aAAaA;QACpD,iBAAiB,OAAOA,eAAe,aAAa,CAACA;IACvD,GACAoB;IAEF,sEAAsE;IACtE,MAAMI,iBAAiBD,IAAAA,eAAU,EAC/B,UACA,mBACAD,eACAlB;IAEF,MAAMqB,eAAeF,IAAAA,eAAU,EAAC,0BAA0BD;IAC1D,MAAMI,eAAeH,IAAAA,eAAU,EAAC,0BAA0BD;IAC1D,MAAMK,cAAcJ,IAAAA,eAAU,EAAC,yBAAyBD;IACxD,MAAMM,iBAAiBT,IAAAA,YAAK;IAC5B,MAAMU,yBAAyBxB,eAAeuB,iBAAiBE;IAC/D,MAAMC,cAAcC,IAAAA,sCAAkB,EAAC;QACrCH;QACAnB;KACD;IACD,MAAMuB,UAAUd,IAAAA,YAAK;IAErB,MAAMe,cAAc;QAClBrB,YAAY,CAACD;IACf;IAEA,MAAMuB,cAAc,CAACC;QACnB,MAAMC,eAAeD,MAAME,OAAO;QAElC,IAAID,cAAc;YAChBH;QACF;IACF;IAEA,MAAMK,eAAe,CAACH;QACpB,IAAIjC,UAAU;YACZA,SAASiC;QACX;IACF;IAEA,MAAMI,gBAAgB,CAACJ;QACrB,IAAIA,MAAMK,IAAI,KAAK,SAAS;YAC1BP;QACF;IACF;IAEA,qBACE,sBAACQ,YAAK;QAACC,KAAI;QAAKvC,WAAWoB;;0BACzB,sBAAC1B;gBAAMM,WAAWqB;;kCAChB,qBAACmB;wBACCC,oBAAkBd;wBAClBe,qBAAmBjB;wBACnBkB,gBAAc7C;wBACd8C,mBAAiBf;wBACjBgB,UAAU1C;wBACV2C,UAAUnD;wBACVH,KAAKqB;wBACLb,WAAWsB;wBACXyB,SAAShB;wBACThC,UAAUoC;wBACVa,WAAWZ;wBACXa,MAAK;wBACLC,gBAAgBhD;wBAChBiD,UAAUvD;wBACVH,IAAIA,MAAMqB;wBACVV,MAAMA;wBACNC,OAAOA;wBACN,GAAGE,IAAI;;kCAEV,qBAAC6C,UAAI;wBACHC,MAAM7C,WAAW8C,iBAAU,GAAGC,aAAM;wBACpCC,MAAK;wBACLxD,WAAWuB;;kCAEb,qBAACkC;wBAAKhE,IAAIoC;wBAAS7B,WAAU;kCAC1BN;;;;0BAGL,qBAACgE,0BAAY;gBAACjE,IAAI+B;gBAAgBvB,cAAcA;;;;AAGtD"}
1
+ {"version":3,"sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n ChangeEvent,\n forwardRef,\n useRef,\n useId,\n useState,\n useEffect,\n} from \"react\";\nimport classNames from \"classnames/dedupe\";\nimport { squareTick, square } from \"@simplybusiness/icons\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport { CheckboxElementType, CheckboxProps, CheckboxRef } from \"./types\";\nimport { spaceDelimitedList } from \"../../utils/spaceDelimitedList\";\nimport { useValidationClasses } from \"../../hooks\";\nimport { Icon } from \"../Icon\";\nimport { Stack } from \"../Stack\";\n\nexport const Checkbox: ForwardedRefComponent<\n CheckboxProps,\n CheckboxElementType\n> = forwardRef((props: CheckboxProps, ref: CheckboxRef) => {\n const {\n id,\n label,\n isDisabled,\n isRequired,\n validationState,\n isInvalid,\n onChange,\n className,\n errorMessage,\n selected,\n defaultSelected = false,\n isReadOnly,\n isLastItem,\n name,\n value,\n [\"aria-describedby\"]: ariaDescribedBy,\n ...rest\n } = props;\n const [checked, setChecked] = useState<boolean>(defaultSelected);\n const fallbackRef = useRef<HTMLInputElement>(null);\n const refObj = ref || fallbackRef;\n const inputId = useId();\n\n const isControlled = typeof selected === \"boolean\";\n useEffect(() => {\n if (isControlled) {\n setChecked(selected);\n }\n }, [selected, isControlled]);\n\n const validationClasses = useValidationClasses({\n validationState,\n isInvalid,\n });\n const sharedClasses = classNames(\n {\n \"--is-disabled\": isDisabled,\n \"--is-selected\": checked,\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n },\n validationClasses,\n );\n // Append an additional wrapper class name to differenitate from input\n const wrapperClasses = classNames(\n \"mobius\",\n \"mobius-checkbox\",\n sharedClasses,\n className,\n );\n const labelClasses = classNames(\"mobius-checkbox__label\", sharedClasses);\n const inputClasses = classNames(\"mobius-checkbox__input\", sharedClasses);\n const iconClasses = classNames(\"mobius-checkbox__icon\", sharedClasses);\n const errorMessageId = useId();\n const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;\n const describedBy = spaceDelimitedList([\n shouldErrorMessageShow,\n ariaDescribedBy,\n ]);\n const labelId = useId();\n\n const handleChange = (event: ChangeEvent<CheckboxElementType>) => {\n setChecked(!checked);\n if (onChange) {\n onChange(event, isLastItem);\n }\n };\n\n return (\n <Stack gap=\"xs\" className={wrapperClasses}>\n <label className={labelClasses}>\n <input\n aria-describedby={describedBy}\n aria-errormessage={shouldErrorMessageShow}\n aria-invalid={isInvalid}\n aria-labelledby={labelId}\n readOnly={isReadOnly}\n disabled={isDisabled}\n ref={refObj}\n className={inputClasses}\n onChange={handleChange}\n type=\"checkbox\"\n checked={checked}\n required={isRequired}\n id={id || inputId}\n name={name}\n value={value}\n {...rest}\n />\n <Icon\n icon={checked ? squareTick : square}\n size=\"md\"\n className={iconClasses}\n />\n <span id={labelId} className=\"mobius-checkbox__visible-label\">\n {label}\n </span>\n </label>\n <ErrorMessage id={errorMessageId} errorMessage={errorMessage} />\n </Stack>\n );\n});\n"],"names":["Checkbox","forwardRef","props","ref","id","label","isDisabled","isRequired","validationState","isInvalid","onChange","className","errorMessage","selected","defaultSelected","isReadOnly","isLastItem","name","value","ariaDescribedBy","rest","checked","setChecked","useState","fallbackRef","useRef","refObj","inputId","useId","isControlled","useEffect","validationClasses","useValidationClasses","sharedClasses","classNames","wrapperClasses","labelClasses","inputClasses","iconClasses","errorMessageId","shouldErrorMessageShow","undefined","describedBy","spaceDelimitedList","labelId","handleChange","event","Stack","gap","input","aria-describedby","aria-errormessage","aria-invalid","aria-labelledby","readOnly","disabled","type","required","Icon","icon","squareTick","square","size","span","ErrorMessage"],"mappings":"AAAA;;;;;+BAoBaA;;;eAAAA;;;;uBAXN;+DACgB;uBACY;8BACN;oCAGM;uBACE;sBAChB;uBACC;;;;;;AAEf,MAAMA,yBAGTC,IAAAA,iBAAU,EAAC,CAACC,OAAsBC;IACpC,MAAM,EACJC,EAAE,EACFC,KAAK,EACLC,UAAU,EACVC,UAAU,EACVC,eAAe,EACfC,SAAS,EACTC,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,QAAQ,EACRC,kBAAkB,KAAK,EACvBC,UAAU,EACVC,UAAU,EACVC,IAAI,EACJC,KAAK,EACL,CAAC,mBAAmB,EAAEC,eAAe,EACrC,GAAGC,MACJ,GAAGlB;IACJ,MAAM,CAACmB,SAASC,WAAW,GAAGC,IAAAA,eAAQ,EAAUT;IAChD,MAAMU,cAAcC,IAAAA,aAAM,EAAmB;IAC7C,MAAMC,SAASvB,OAAOqB;IACtB,MAAMG,UAAUC,IAAAA,YAAK;IAErB,MAAMC,eAAe,OAAOhB,aAAa;IACzCiB,IAAAA,gBAAS,EAAC;QACR,IAAID,cAAc;YAChBP,WAAWT;QACb;IACF,GAAG;QAACA;QAAUgB;KAAa;IAE3B,MAAME,oBAAoBC,IAAAA,2BAAoB,EAAC;QAC7CxB;QACAC;IACF;IACA,MAAMwB,gBAAgBC,IAAAA,eAAU,EAC9B;QACE,iBAAiB5B;QACjB,iBAAiBe;QACjB,iBAAiB,OAAOd,eAAe,aAAaA;QACpD,iBAAiB,OAAOA,eAAe,aAAa,CAACA;IACvD,GACAwB;IAEF,sEAAsE;IACtE,MAAMI,iBAAiBD,IAAAA,eAAU,EAC/B,UACA,mBACAD,eACAtB;IAEF,MAAMyB,eAAeF,IAAAA,eAAU,EAAC,0BAA0BD;IAC1D,MAAMI,eAAeH,IAAAA,eAAU,EAAC,0BAA0BD;IAC1D,MAAMK,cAAcJ,IAAAA,eAAU,EAAC,yBAAyBD;IACxD,MAAMM,iBAAiBX,IAAAA,YAAK;IAC5B,MAAMY,yBAAyB5B,eAAe2B,iBAAiBE;IAC/D,MAAMC,cAAcC,IAAAA,sCAAkB,EAAC;QACrCH;QACArB;KACD;IACD,MAAMyB,UAAUhB,IAAAA,YAAK;IAErB,MAAMiB,eAAe,CAACC;QACpBxB,WAAW,CAACD;QACZ,IAAIX,UAAU;YACZA,SAASoC,OAAO9B;QAClB;IACF;IAEA,qBACE,sBAAC+B,YAAK;QAACC,KAAI;QAAKrC,WAAWwB;;0BACzB,sBAAC9B;gBAAMM,WAAWyB;;kCAChB,qBAACa;wBACCC,oBAAkBR;wBAClBS,qBAAmBX;wBACnBY,gBAAc3C;wBACd4C,mBAAiBT;wBACjBU,UAAUvC;wBACVwC,UAAUjD;wBACVH,KAAKuB;wBACLf,WAAW0B;wBACX3B,UAAUmC;wBACVW,MAAK;wBACLnC,SAASA;wBACToC,UAAUlD;wBACVH,IAAIA,MAAMuB;wBACVV,MAAMA;wBACNC,OAAOA;wBACN,GAAGE,IAAI;;kCAEV,qBAACsC,UAAI;wBACHC,MAAMtC,UAAUuC,iBAAU,GAAGC,aAAM;wBACnCC,MAAK;wBACLnD,WAAW2B;;kCAEb,qBAACyB;wBAAK3D,IAAIwC;wBAASjC,WAAU;kCAC1BN;;;;0BAGL,qBAAC2D,0BAAY;gBAAC5D,IAAImC;gBAAgB3B,cAAcA;;;;AAGtD"}
@@ -10,19 +10,20 @@ Object.defineProperty(exports, "CheckboxGroup", {
10
10
  }
11
11
  });
12
12
  const _jsxruntime = require("react/jsx-runtime");
13
- const _react = require("react");
14
13
  const _dedupe = /*#__PURE__*/ _interop_require_default(require("classnames/dedupe"));
15
- const _Label = require("../Label");
16
- const _ErrorMessage = require("../ErrorMessage");
17
- const _spaceDelimitedList = require("../../utils/spaceDelimitedList");
14
+ const _react = require("react");
18
15
  const _hooks = require("../../hooks");
16
+ const _spaceDelimitedList = require("../../utils/spaceDelimitedList");
17
+ const _ErrorMessage = require("../ErrorMessage");
18
+ const _Label = require("../Label");
19
+ const _Checkbox = require("./Checkbox");
19
20
  function _interop_require_default(obj) {
20
21
  return obj && obj.__esModule ? obj : {
21
22
  default: obj
22
23
  };
23
24
  }
24
25
  const CheckboxGroup = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
25
- const { label, isDisabled = false, isRequired, validationState, isInvalid, orientation = "vertical", onChange, className, errorMessage, children, defaultValue = [], isReadOnly, itemsPerRow, ...rest } = props;
26
+ const { label, isDisabled = false, isRequired, validationState, isInvalid, orientation = "vertical", onChange, className, errorMessage, children, defaultValue = [], isReadOnly, itemsPerRow, lastItemDisables = false, ...rest } = props;
26
27
  const [selected, setSelected] = (0, _react.useState)(defaultValue);
27
28
  const checkboxGroupClasses = (0, _dedupe.default)("mobius", "mobius-checkbox-group", className, {
28
29
  "--is-horizontal": orientation === "horizontal",
@@ -44,11 +45,17 @@ const CheckboxGroup = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
44
45
  props["aria-describedby"]
45
46
  ]);
46
47
  const labelId = (0, _react.useId)();
47
- const handleChange = (event)=>{
48
+ const handleChange = (event, isLastItem = false)=>{
48
49
  const { target: { value, checked } } = event;
49
50
  if (!checked) {
50
51
  setSelected(selected.filter((item)=>item !== value));
51
52
  }
53
+ if (checked && lastItemDisables && isLastItem) {
54
+ setSelected([
55
+ value
56
+ ]);
57
+ return;
58
+ }
52
59
  if (checked) {
53
60
  setSelected([
54
61
  ...selected,
@@ -56,14 +63,21 @@ const CheckboxGroup = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
56
63
  ]);
57
64
  }
58
65
  };
66
+ // HACK: This is a workaround to ensure that the onChange event is not
67
+ // fired on the initial render.
68
+ const renderCount = (0, _hooks.useRenderCount)();
59
69
  (0, _react.useEffect)(()=>{
60
- if (onChange) {
70
+ if (onChange && renderCount > 1) {
61
71
  onChange(selected);
62
72
  }
63
73
  }, [
64
74
  selected,
65
- onChange
75
+ onChange,
76
+ renderCount
66
77
  ]);
78
+ const childrenArray = _react.Children.toArray(children);
79
+ const lastCheckbox = childrenArray.filter((child)=>/*#__PURE__*/ (0, _react.isValidElement)(child) && child.type === _Checkbox.Checkbox).pop();
80
+ const lastCheckboxIsChecked = lastCheckbox && selected.includes(lastCheckbox.props.value);
67
81
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)("div", {
68
82
  ...rest,
69
83
  "aria-labelledby": props["aria-labelledby"] || labelId,
@@ -82,14 +96,18 @@ const CheckboxGroup = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
82
96
  }),
83
97
  /*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
84
98
  className: "mobius-checkbox-group__wrapper",
85
- children: _react.Children.map(children, (child)=>{
99
+ children: childrenArray.map((child)=>{
86
100
  if (/*#__PURE__*/ (0, _react.isValidElement)(child)) {
101
+ // lastItemDisables support
102
+ const isLastItem = child === lastCheckbox;
103
+ const isChildDisabled = isDisabled || lastItemDisables && lastCheckboxIsChecked && !isLastItem;
87
104
  return /*#__PURE__*/ (0, _react.cloneElement)(child, {
88
- isDisabled,
105
+ isDisabled: isChildDisabled,
89
106
  isRequired,
90
107
  isReadOnly,
91
108
  isInvalid,
92
- defaultSelected: selected.includes(child.props.value),
109
+ isLastItem,
110
+ selected: selected.includes(child.props.value),
93
111
  onChange: handleChange,
94
112
  "aria-describedby": describedBy
95
113
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/Checkbox/CheckboxGroup.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Children,\n forwardRef,\n ReactElement,\n cloneElement,\n isValidElement,\n useId,\n ChangeEvent,\n useState,\n useEffect,\n} from \"react\";\nimport classNames from \"classnames/dedupe\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport {\n CheckboxElementType,\n CheckboxGroupElementType,\n CheckboxGroupProps,\n CheckboxGroupRef,\n} from \"./types\";\nimport { Label } from \"../Label\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { spaceDelimitedList } from \"../../utils/spaceDelimitedList\";\nimport { useValidationClasses } from \"../../hooks\";\n\nexport const CheckboxGroup: ForwardedRefComponent<\n CheckboxGroupProps,\n CheckboxGroupElementType\n> = forwardRef((props: CheckboxGroupProps, ref: CheckboxGroupRef) => {\n const {\n label,\n isDisabled = false,\n isRequired,\n validationState,\n isInvalid,\n orientation = \"vertical\",\n onChange,\n className,\n errorMessage,\n children,\n defaultValue = [],\n isReadOnly,\n itemsPerRow,\n ...rest\n } = props;\n const [selected, setSelected] = useState<string[]>(defaultValue);\n const checkboxGroupClasses = classNames(\n \"mobius\",\n \"mobius-checkbox-group\",\n className,\n {\n \"--is-horizontal\": orientation === \"horizontal\",\n \"--is-vertical\": orientation === \"vertical\",\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n },\n );\n const validationClasses = useValidationClasses({\n validationState,\n isInvalid,\n });\n const labelClasses = classNames(\n {\n \"--is-disabled\": isDisabled,\n },\n validationClasses,\n );\n const errorMessageId = useId();\n const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;\n const describedBy = spaceDelimitedList([\n shouldErrorMessageShow,\n props[\"aria-describedby\"],\n ]);\n const labelId = useId();\n\n const handleChange = (event: ChangeEvent<CheckboxElementType>) => {\n const {\n target: { value, checked },\n } = event;\n\n if (!checked) {\n setSelected(selected.filter(item => item !== value));\n }\n\n if (checked) {\n setSelected([...selected, value]);\n }\n };\n\n useEffect(() => {\n if (onChange) {\n onChange(selected);\n }\n }, [selected, onChange]);\n\n return (\n <div\n {...rest}\n aria-labelledby={props[\"aria-labelledby\"] || labelId}\n ref={ref}\n className={checkboxGroupClasses}\n role=\"group\"\n style={\n {\n \"--checkbox-items-per-row\": itemsPerRow || Children.count(children),\n } as React.CSSProperties\n }\n >\n {label && (\n <Label elementType=\"span\" id={labelId} className={labelClasses}>\n {label}\n </Label>\n )}\n <div className=\"mobius-checkbox-group__wrapper\">\n {Children.map(children, child => {\n if (isValidElement(child)) {\n return cloneElement(child as ReactElement, {\n isDisabled,\n isRequired,\n isReadOnly,\n isInvalid,\n defaultSelected: selected.includes(child.props.value),\n onChange: handleChange,\n \"aria-describedby\": describedBy,\n });\n }\n\n return child;\n })}\n </div>\n {errorMessage && (\n <ErrorMessage id={errorMessageId} errorMessage={errorMessage} />\n )}\n </div>\n );\n});\n"],"names":["CheckboxGroup","forwardRef","props","ref","label","isDisabled","isRequired","validationState","isInvalid","orientation","onChange","className","errorMessage","children","defaultValue","isReadOnly","itemsPerRow","rest","selected","setSelected","useState","checkboxGroupClasses","classNames","validationClasses","useValidationClasses","labelClasses","errorMessageId","useId","shouldErrorMessageShow","undefined","describedBy","spaceDelimitedList","labelId","handleChange","event","target","value","checked","filter","item","useEffect","div","aria-labelledby","role","style","Children","count","Label","elementType","id","map","child","isValidElement","cloneElement","defaultSelected","includes","ErrorMessage"],"mappings":"AAAA;;;;;+BA0BaA;;;eAAAA;;;;uBAdN;+DACgB;uBAQD;8BACO;oCACM;uBACE;;;;;;AAE9B,MAAMA,8BAGTC,IAAAA,iBAAU,EAAC,CAACC,OAA2BC;IACzC,MAAM,EACJC,KAAK,EACLC,aAAa,KAAK,EAClBC,UAAU,EACVC,eAAe,EACfC,SAAS,EACTC,cAAc,UAAU,EACxBC,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,QAAQ,EACRC,eAAe,EAAE,EACjBC,UAAU,EACVC,WAAW,EACX,GAAGC,MACJ,GAAGf;IACJ,MAAM,CAACgB,UAAUC,YAAY,GAAGC,IAAAA,eAAQ,EAAWN;IACnD,MAAMO,uBAAuBC,IAAAA,eAAU,EACrC,UACA,yBACAX,WACA;QACE,mBAAmBF,gBAAgB;QACnC,iBAAiBA,gBAAgB;QACjC,iBAAiB,OAAOH,eAAe,aAAaA;QACpD,iBAAiB,OAAOA,eAAe,aAAa,CAACA;IACvD;IAEF,MAAMiB,oBAAoBC,IAAAA,2BAAoB,EAAC;QAC7CjB;QACAC;IACF;IACA,MAAMiB,eAAeH,IAAAA,eAAU,EAC7B;QACE,iBAAiBjB;IACnB,GACAkB;IAEF,MAAMG,iBAAiBC,IAAAA,YAAK;IAC5B,MAAMC,yBAAyBhB,eAAec,iBAAiBG;IAC/D,MAAMC,cAAcC,IAAAA,sCAAkB,EAAC;QACrCH;QACA1B,KAAK,CAAC,mBAAmB;KAC1B;IACD,MAAM8B,UAAUL,IAAAA,YAAK;IAErB,MAAMM,eAAe,CAACC;QACpB,MAAM,EACJC,QAAQ,EAAEC,KAAK,EAAEC,OAAO,EAAE,EAC3B,GAAGH;QAEJ,IAAI,CAACG,SAAS;YACZlB,YAAYD,SAASoB,MAAM,CAACC,CAAAA,OAAQA,SAASH;QAC/C;QAEA,IAAIC,SAAS;YACXlB,YAAY;mBAAID;gBAAUkB;aAAM;QAClC;IACF;IAEAI,IAAAA,gBAAS,EAAC;QACR,IAAI9B,UAAU;YACZA,SAASQ;QACX;IACF,GAAG;QAACA;QAAUR;KAAS;IAEvB,qBACE,sBAAC+B;QACE,GAAGxB,IAAI;QACRyB,mBAAiBxC,KAAK,CAAC,kBAAkB,IAAI8B;QAC7C7B,KAAKA;QACLQ,WAAWU;QACXsB,MAAK;QACLC,OACE;YACE,4BAA4B5B,eAAe6B,eAAQ,CAACC,KAAK,CAACjC;QAC5D;;YAGDT,uBACC,qBAAC2C,YAAK;gBAACC,aAAY;gBAAOC,IAAIjB;gBAASrB,WAAWc;0BAC/CrB;;0BAGL,qBAACqC;gBAAI9B,WAAU;0BACZkC,eAAQ,CAACK,GAAG,CAACrC,UAAUsC,CAAAA;oBACtB,kBAAIC,IAAAA,qBAAc,EAACD,QAAQ;wBACzB,qBAAOE,IAAAA,mBAAY,EAACF,OAAuB;4BACzC9C;4BACAC;4BACAS;4BACAP;4BACA8C,iBAAiBpC,SAASqC,QAAQ,CAACJ,MAAMjD,KAAK,CAACkC,KAAK;4BACpD1B,UAAUuB;4BACV,oBAAoBH;wBACtB;oBACF;oBAEA,OAAOqB;gBACT;;YAEDvC,8BACC,qBAAC4C,0BAAY;gBAACP,IAAIvB;gBAAgBd,cAAcA;;;;AAIxD"}
1
+ {"version":3,"sources":["../../../../src/components/Checkbox/CheckboxGroup.tsx"],"sourcesContent":["\"use client\";\n\nimport classNames from \"classnames/dedupe\";\nimport {\n type ChangeEvent,\n type ReactElement,\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n useEffect,\n useId,\n useState,\n} from \"react\";\nimport { useRenderCount, useValidationClasses } from \"../../hooks\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport { spaceDelimitedList } from \"../../utils/spaceDelimitedList\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { Label } from \"../Label\";\nimport { Checkbox } from \"./Checkbox\";\nimport {\n CheckboxElementType,\n CheckboxGroupElementType,\n CheckboxGroupProps,\n CheckboxGroupRef,\n} from \"./types\";\n\nexport const CheckboxGroup: ForwardedRefComponent<\n CheckboxGroupProps,\n CheckboxGroupElementType\n> = forwardRef((props: CheckboxGroupProps, ref: CheckboxGroupRef) => {\n const {\n label,\n isDisabled = false,\n isRequired,\n validationState,\n isInvalid,\n orientation = \"vertical\",\n onChange,\n className,\n errorMessage,\n children,\n defaultValue = [],\n isReadOnly,\n itemsPerRow,\n lastItemDisables = false,\n ...rest\n } = props;\n const [selected, setSelected] = useState<string[]>(defaultValue);\n const checkboxGroupClasses = classNames(\n \"mobius\",\n \"mobius-checkbox-group\",\n className,\n {\n \"--is-horizontal\": orientation === \"horizontal\",\n \"--is-vertical\": orientation === \"vertical\",\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n },\n );\n const validationClasses = useValidationClasses({\n validationState,\n isInvalid,\n });\n const labelClasses = classNames(\n {\n \"--is-disabled\": isDisabled,\n },\n validationClasses,\n );\n const errorMessageId = useId();\n const shouldErrorMessageShow = errorMessage ? errorMessageId : undefined;\n const describedBy = spaceDelimitedList([\n shouldErrorMessageShow,\n props[\"aria-describedby\"],\n ]);\n const labelId = useId();\n\n const handleChange = (\n event: ChangeEvent<CheckboxElementType>,\n isLastItem = false,\n ) => {\n const {\n target: { value, checked },\n } = event;\n\n if (!checked) {\n setSelected(selected.filter(item => item !== value));\n }\n\n if (checked && lastItemDisables && isLastItem) {\n setSelected([value]);\n return;\n }\n\n if (checked) {\n setSelected([...selected, value]);\n }\n };\n\n // HACK: This is a workaround to ensure that the onChange event is not\n // fired on the initial render.\n const renderCount = useRenderCount();\n useEffect(() => {\n if (onChange && renderCount > 1) {\n onChange(selected);\n }\n }, [selected, onChange, renderCount]);\n\n const childrenArray = Children.toArray(children);\n const lastCheckbox = childrenArray\n .filter(\n child =>\n isValidElement(child) && (child as ReactElement).type === Checkbox,\n )\n .pop() as ReactElement<CheckboxElementType> | undefined;\n const lastCheckboxIsChecked =\n lastCheckbox && selected.includes(lastCheckbox.props.value);\n\n return (\n <div\n {...rest}\n aria-labelledby={props[\"aria-labelledby\"] || labelId}\n ref={ref}\n className={checkboxGroupClasses}\n role=\"group\"\n style={\n {\n \"--checkbox-items-per-row\": itemsPerRow || Children.count(children),\n } as React.CSSProperties\n }\n >\n {label && (\n <Label elementType=\"span\" id={labelId} className={labelClasses}>\n {label}\n </Label>\n )}\n <div className=\"mobius-checkbox-group__wrapper\">\n {childrenArray.map(child => {\n if (isValidElement(child)) {\n // lastItemDisables support\n const isLastItem = child === lastCheckbox;\n const isChildDisabled =\n isDisabled ||\n (lastItemDisables && lastCheckboxIsChecked && !isLastItem);\n\n return cloneElement(child as ReactElement, {\n isDisabled: isChildDisabled,\n isRequired,\n isReadOnly,\n isInvalid,\n isLastItem,\n selected: selected.includes(child.props.value),\n onChange: handleChange,\n \"aria-describedby\": describedBy,\n });\n }\n\n return child;\n })}\n </div>\n {errorMessage && (\n <ErrorMessage id={errorMessageId} errorMessage={errorMessage} />\n )}\n </div>\n );\n});\n"],"names":["CheckboxGroup","forwardRef","props","ref","label","isDisabled","isRequired","validationState","isInvalid","orientation","onChange","className","errorMessage","children","defaultValue","isReadOnly","itemsPerRow","lastItemDisables","rest","selected","setSelected","useState","checkboxGroupClasses","classNames","validationClasses","useValidationClasses","labelClasses","errorMessageId","useId","shouldErrorMessageShow","undefined","describedBy","spaceDelimitedList","labelId","handleChange","event","isLastItem","target","value","checked","filter","item","renderCount","useRenderCount","useEffect","childrenArray","Children","toArray","lastCheckbox","child","isValidElement","type","Checkbox","pop","lastCheckboxIsChecked","includes","div","aria-labelledby","role","style","count","Label","elementType","id","map","isChildDisabled","cloneElement","ErrorMessage"],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "Combobox", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return Combobox;
9
+ }
10
+ });
11
+ const _jsxruntime = require("react/jsx-runtime");
12
+ const _react = require("react");
13
+ const _dedupe = /*#__PURE__*/ _interop_require_default(require("classnames/dedupe"));
14
+ const _TextField = require("../TextField");
15
+ function _interop_require_default(obj) {
16
+ return obj && obj.__esModule ? obj : {
17
+ default: obj
18
+ };
19
+ }
20
+ const getOptionValue = (option)=>typeof option === "string" ? option : option.value;
21
+ const getOptionLabel = (option)=>typeof option === "string" ? option : option.label;
22
+ const Combobox = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
23
+ const { defaultValue, options, onSelected } = props;
24
+ const fallbackRef = (0, _react.useRef)();
25
+ const [inputValue, setInputValue] = (0, _react.useState)(defaultValue || "");
26
+ const [isOpen, setIsOpen] = (0, _react.useState)(false);
27
+ const [highlightedIndex, setHighlightedIndex] = (0, _react.useState)(-1);
28
+ const [filteredOptions, setFilteredOptions] = (0, _react.useState)([]);
29
+ const inputRef = ref || fallbackRef;
30
+ const listboxId = (0, _react.useId)();
31
+ (0, _react.useEffect)(()=>{
32
+ const fetchOptions = async ()=>{
33
+ if (typeof options === "function") {
34
+ const result = await options(inputValue);
35
+ setFilteredOptions(result);
36
+ } else {
37
+ setFilteredOptions(options.filter((option)=>getOptionLabel(option).toLowerCase().includes(inputValue.toLowerCase())));
38
+ }
39
+ };
40
+ fetchOptions();
41
+ }, [
42
+ inputValue,
43
+ options
44
+ ]);
45
+ const handleFocus = ()=>{
46
+ setIsOpen(true);
47
+ };
48
+ const handleBlur = ()=>{
49
+ setIsOpen(false);
50
+ };
51
+ const handleInputChange = (e)=>{
52
+ const newValue = e.target.value;
53
+ setInputValue(newValue);
54
+ setIsOpen(true);
55
+ setHighlightedIndex(-1);
56
+ };
57
+ const handleOptionSelect = (option)=>{
58
+ const value = getOptionValue(option);
59
+ setIsOpen(false);
60
+ setInputValue(value);
61
+ onSelected === null || onSelected === void 0 ? void 0 : onSelected(value);
62
+ };
63
+ const handleKeyDown = (e)=>{
64
+ switch(e.key){
65
+ case "ArrowDown":
66
+ e.preventDefault();
67
+ setIsOpen(true);
68
+ setHighlightedIndex((prev)=>prev < filteredOptions.length - 1 ? prev + 1 : 0);
69
+ break;
70
+ case "ArrowUp":
71
+ e.preventDefault();
72
+ setIsOpen(true);
73
+ setHighlightedIndex((prev)=>prev > 0 ? prev - 1 : filteredOptions.length - 1);
74
+ break;
75
+ case "Enter":
76
+ e.preventDefault();
77
+ if (isOpen && highlightedIndex >= 0) {
78
+ handleOptionSelect(filteredOptions[highlightedIndex]);
79
+ } else if (isOpen && highlightedIndex === -1 && filteredOptions.length > 0) {
80
+ handleOptionSelect(filteredOptions[0]);
81
+ }
82
+ break;
83
+ case "Escape":
84
+ e.preventDefault();
85
+ setIsOpen(false);
86
+ setHighlightedIndex(-1);
87
+ break;
88
+ default:
89
+ }
90
+ };
91
+ return /*#__PURE__*/ (0, _jsxruntime.jsxs)("div", {
92
+ className: "mobius mobius-combobox",
93
+ children: [
94
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_TextField.TextField, {
95
+ className: "mobius-combobox__input",
96
+ role: "combobox",
97
+ value: inputValue,
98
+ onFocus: handleFocus,
99
+ onBlur: handleBlur,
100
+ onKeyDown: handleKeyDown,
101
+ onChange: handleInputChange,
102
+ "aria-autocomplete": "list",
103
+ "aria-haspopup": "listbox",
104
+ "aria-controls": listboxId,
105
+ "aria-expanded": isOpen,
106
+ "aria-activedescendant": highlightedIndex === -1 ? undefined : `${listboxId}-option-${highlightedIndex}`,
107
+ // @ts-expect-error I have no idea how ref typing works
108
+ ref: inputRef
109
+ }),
110
+ isOpen && /*#__PURE__*/ (0, _jsxruntime.jsx)("ul", {
111
+ role: "listbox",
112
+ id: listboxId,
113
+ className: "mobius-combobox__list",
114
+ children: filteredOptions.map((option, index)=>/*#__PURE__*/ (0, _jsxruntime.jsx)("li", {
115
+ role: "option",
116
+ id: `${listboxId}-option-${index}`,
117
+ "aria-selected": highlightedIndex === index,
118
+ onMouseDown: ()=>handleOptionSelect(option),
119
+ className: (0, _dedupe.default)("mobius-combobox__option", {
120
+ "mobius-combobox__option--is-highlighted": highlightedIndex === index
121
+ }),
122
+ children: getOptionLabel(option)
123
+ }, getOptionValue(option)))
124
+ })
125
+ ]
126
+ });
127
+ });
128
+
129
+ //# sourceMappingURL=Combobox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import { forwardRef, useId, useRef, useState, useEffect } from \"react\";\nimport classNames from \"classnames/dedupe\";\nimport { TextField } from \"../TextField\";\nimport type {\n ComboboxProps,\n ComboboxElementType,\n ComboboxRef,\n ComboboxOption,\n} from \"./types\";\nimport type { ForwardedRefComponent } from \"../../types\";\n\nconst getOptionValue = (option: ComboboxOption) =>\n typeof option === \"string\" ? option : option.value;\n\nconst getOptionLabel = (option: ComboboxOption) =>\n typeof option === \"string\" ? option : option.label;\n\nexport const Combobox: ForwardedRefComponent<\n ComboboxProps,\n ComboboxElementType\n> = forwardRef((props: ComboboxProps, ref: ComboboxRef) => {\n const { defaultValue, options, onSelected } = props;\n\n const fallbackRef = useRef();\n const [inputValue, setInputValue] = useState(defaultValue || \"\");\n const [isOpen, setIsOpen] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const [filteredOptions, setFilteredOptions] = useState<ComboboxOption[]>([]);\n const inputRef = ref || fallbackRef;\n const listboxId = useId();\n\n useEffect(() => {\n const fetchOptions = async () => {\n if (typeof options === \"function\") {\n const result = await options(inputValue);\n setFilteredOptions(result);\n } else {\n setFilteredOptions(\n options.filter(option =>\n getOptionLabel(option)\n .toLowerCase()\n .includes(inputValue.toLowerCase()),\n ),\n );\n }\n };\n\n fetchOptions();\n }, [inputValue, options]);\n\n const handleFocus = () => {\n setIsOpen(true);\n };\n\n const handleBlur = () => {\n setIsOpen(false);\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setInputValue(newValue);\n setIsOpen(true);\n setHighlightedIndex(-1);\n };\n\n const handleOptionSelect = (option: ComboboxOption) => {\n const value = getOptionValue(option);\n setIsOpen(false);\n setInputValue(value);\n onSelected?.(value);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n setIsOpen(true);\n setHighlightedIndex(prev =>\n prev < filteredOptions.length - 1 ? prev + 1 : 0,\n );\n break;\n case \"ArrowUp\":\n e.preventDefault();\n setIsOpen(true);\n setHighlightedIndex(prev =>\n prev > 0 ? prev - 1 : filteredOptions.length - 1,\n );\n break;\n case \"Enter\":\n e.preventDefault();\n if (isOpen && highlightedIndex >= 0) {\n handleOptionSelect(filteredOptions[highlightedIndex]);\n } else if (\n isOpen &&\n highlightedIndex === -1 &&\n filteredOptions.length > 0\n ) {\n handleOptionSelect(filteredOptions[0]);\n }\n break;\n case \"Escape\":\n e.preventDefault();\n setIsOpen(false);\n setHighlightedIndex(-1);\n break;\n default:\n // Do nothing\n }\n };\n\n return (\n <div className=\"mobius mobius-combobox\">\n <TextField\n className=\"mobius-combobox__input\"\n role=\"combobox\"\n value={inputValue}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n onChange={handleInputChange}\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-controls={listboxId}\n aria-expanded={isOpen}\n aria-activedescendant={\n highlightedIndex === -1\n ? undefined\n : `${listboxId}-option-${highlightedIndex}`\n }\n // @ts-expect-error I have no idea how ref typing works\n ref={inputRef}\n />\n {isOpen && (\n <ul role=\"listbox\" id={listboxId} className=\"mobius-combobox__list\">\n {filteredOptions.map((option, index) => (\n <li\n role=\"option\"\n key={getOptionValue(option)}\n id={`${listboxId}-option-${index}`}\n aria-selected={highlightedIndex === index}\n onMouseDown={() => handleOptionSelect(option)}\n className={classNames(\"mobius-combobox__option\", {\n \"mobius-combobox__option--is-highlighted\":\n highlightedIndex === index,\n })}\n >\n {getOptionLabel(option)}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n});\n"],"names":["Combobox","getOptionValue","option","value","getOptionLabel","label","forwardRef","props","ref","defaultValue","options","onSelected","fallbackRef","useRef","inputValue","setInputValue","useState","isOpen","setIsOpen","highlightedIndex","setHighlightedIndex","filteredOptions","setFilteredOptions","inputRef","listboxId","useId","useEffect","fetchOptions","result","filter","toLowerCase","includes","handleFocus","handleBlur","handleInputChange","e","newValue","target","handleOptionSelect","handleKeyDown","key","preventDefault","prev","length","div","className","TextField","role","onFocus","onBlur","onKeyDown","onChange","aria-autocomplete","aria-haspopup","aria-controls","aria-expanded","aria-activedescendant","undefined","ul","id","map","index","li","aria-selected","onMouseDown","classNames"],"mappings":"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"}