@openedx/paragon 21.11.1 → 21.11.3

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.
@@ -3,7 +3,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
3
3
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
4
4
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
5
5
  function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
6
- import React, { useCallback, useEffect } from 'react';
6
+ import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import classNames from 'classnames';
9
9
  import { HexColorPicker } from 'react-colorful';
@@ -22,23 +22,52 @@ function ColorPicker(_ref) {
22
22
  } = _ref;
23
23
  const [isOpen, open, close] = useToggle(false);
24
24
  const [target, setTarget] = React.useState(null);
25
- const [hexValid, setHexValid] = React.useState(true);
26
- const validateHex = useCallback(input => {
25
+ const colorIsValid = colorToValidate => {
27
26
  const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
28
- if (input.length > 1 && !input.startsWith('#')) {
29
- setColor(`#${input}`);
30
- } else {
31
- setColor(input);
27
+ return hexRegex.test(colorToValidate);
28
+ };
29
+ const formatHexColorString = colorString => {
30
+ if (!colorString.startsWith('#')) {
31
+ return `#${colorString}`.slice(0, 7);
32
32
  }
33
- if (input === '' || hexRegex.test(input) === true) {
33
+ return colorString.slice(0, 7);
34
+ };
35
+ const [hexValid, setHexValid] = React.useState(() => color === '' || colorIsValid(formatHexColorString(color)));
36
+ const [hexColorString, setHexColorString] = React.useState(() => {
37
+ if (color === '') {
38
+ return '';
39
+ }
40
+ return formatHexColorString(color);
41
+ });
42
+ const [colorToDisplay, setColorToDisplay] = React.useState(() => {
43
+ const formattedColor = formatHexColorString(color);
44
+ if (colorIsValid(formattedColor)) {
45
+ return formattedColor;
46
+ }
47
+ return '#fff';
48
+ });
49
+ const setValidatedColor = newColor => {
50
+ if (newColor === '') {
51
+ setHexValid(true);
52
+ setColor('');
53
+ setHexColorString('');
54
+ setColorToDisplay('#fff');
55
+ return;
56
+ }
57
+ const formattedColor = formatHexColorString(newColor);
58
+ if (colorIsValid(formattedColor)) {
34
59
  setHexValid(true);
35
- } else {
36
- setHexValid(false);
60
+ setColor(formattedColor);
61
+ setHexColorString(formattedColor);
62
+ setColorToDisplay(formattedColor);
63
+ return;
37
64
  }
38
- }, [setColor]);
65
+ setHexValid(false);
66
+ setHexColorString(formattedColor);
39
67
 
40
- // this is needed for when a user changes the color through the sliders
41
- useEffect(() => validateHex(color), [validateHex, color]);
68
+ // ensure the picker value stays in sync with the textbox
69
+ setColor(formattedColor);
70
+ };
42
71
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
43
72
  className: "d-flex"
44
73
  }, /*#__PURE__*/React.createElement(OverlayTrigger, {
@@ -66,8 +95,8 @@ function ColorPicker(_ref) {
66
95
  textAlign: 'start'
67
96
  }
68
97
  }, /*#__PURE__*/React.createElement(HexColorPicker, {
69
- color: color || '',
70
- onChange: setColor
98
+ color: colorToDisplay,
99
+ onChange: setValidatedColor
71
100
  }), /*#__PURE__*/React.createElement(Form.Group, {
72
101
  className: "pgn__hex-form",
73
102
  size: "sm"
@@ -76,9 +105,10 @@ function ColorPicker(_ref) {
76
105
  }, "Hex"), /*#__PURE__*/React.createElement(Form.Control, {
77
106
  className: "pgn__hex-field",
78
107
  isInvalid: !hexValid,
79
- value: color,
80
- onChange: e => validateHex(e.target.value),
81
- "data-testid": "hex-input"
108
+ value: hexColorString,
109
+ onChange: e => setValidatedColor(e.target.value),
110
+ "data-testid": "hex-input",
111
+ spellCheck: "false"
82
112
  })), !hexValid && /*#__PURE__*/React.createElement(Form.Control.Feedback, {
83
113
  className: "pgn__color-error",
84
114
  type: "invalid"
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["React","useCallback","useEffect","PropTypes","classNames","HexColorPicker","Button","Form","ModalPopup","OverlayTrigger","Tooltip","useToggle","ColorPicker","_ref","color","setColor","className","size","isOpen","open","close","target","setTarget","useState","hexValid","setHexValid","validateHex","input","hexRegex","length","startsWith","test","createElement","Fragment","placement","overlay","id","ref","style","_objectSpread","background","onClick","positionRef","onClose","textAlign","onChange","Group","Label","Control","isInvalid","value","e","Feedback","type","defaultProps","undefined","propTypes","string","func","isRequired","oneOf"],"sources":["../../src/ColorPicker/index.jsx"],"sourcesContent":["import React, { useCallback, useEffect } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { HexColorPicker } from 'react-colorful';\n\nimport Button from '../Button';\nimport Form from '../Form';\nimport ModalPopup from '../Modal/ModalPopup';\nimport { OverlayTrigger } from '../Overlay';\nimport Tooltip from '../Tooltip';\nimport useToggle from '../hooks/useToggle';\n\nfunction ColorPicker({\n color, setColor, className, size,\n}) {\n const [isOpen, open, close] = useToggle(false);\n const [target, setTarget] = React.useState(null);\n const [hexValid, setHexValid] = React.useState(true);\n\n const validateHex = useCallback((input) => {\n const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;\n if (input.length > 1 && !input.startsWith('#')) {\n setColor(`#${input}`);\n } else {\n setColor(input);\n }\n if (input === '' || hexRegex.test(input) === true) {\n setHexValid(true);\n } else {\n setHexValid(false);\n }\n }, [setColor]);\n\n // this is needed for when a user changes the color through the sliders\n useEffect(() => validateHex(color), [validateHex, color]);\n\n return (\n <>\n <span className=\"d-flex\">\n <OverlayTrigger\n placement=\"top\"\n overlay={<Tooltip id=\"color-picker-tooltip\">Color picker</Tooltip>}\n >\n <Button\n ref={setTarget}\n className={classNames(\n className,\n 'pgn__color-picker',\n `pgn__color-picker-${size}`,\n )}\n style={{\n ...(color && hexValid ? { background: `${color}` } : {}),\n }}\n onClick={open}\n />\n </OverlayTrigger>\n </span>\n <ModalPopup\n positionRef={target}\n isOpen={isOpen}\n style={{ background: 'black' }}\n onClose={close}\n >\n <div\n className=\"pgn__color-modal rounded shadow\"\n style={{ textAlign: 'start' }}\n >\n <HexColorPicker color={color || ''} onChange={setColor} />\n <Form.Group className=\"pgn__hex-form\" size=\"sm\">\n <div>\n <Form.Label className=\"pgn__hex-label\">Hex</Form.Label>\n <Form.Control\n className=\"pgn__hex-field\"\n isInvalid={!hexValid}\n value={color}\n onChange={(e) => validateHex(e.target.value)}\n data-testid=\"hex-input\"\n />\n </div>\n {!hexValid && (\n <Form.Control.Feedback\n className=\"pgn__color-error\"\n type=\"invalid\"\n >\n Colors must be in hexadecimal format.\n </Form.Control.Feedback>\n )}\n </Form.Group>\n </div>\n </ModalPopup>\n </>\n );\n}\n\nColorPicker.defaultProps = {\n color: '',\n className: undefined,\n size: 'md',\n};\n\nColorPicker.propTypes = {\n /** A default hex code to preset the picker to display. */\n color: PropTypes.string,\n /** Passing setState function allows parent to alter the color. */\n setColor: PropTypes.func.isRequired,\n /** A class name to append to the base element. */\n className: PropTypes.string,\n /** Size of the color picker */\n size: PropTypes.oneOf(['sm', 'md']),\n};\n\nexport default ColorPicker;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["React","PropTypes","classNames","HexColorPicker","Button","Form","ModalPopup","OverlayTrigger","Tooltip","useToggle","ColorPicker","_ref","color","setColor","className","size","isOpen","open","close","target","setTarget","useState","colorIsValid","colorToValidate","hexRegex","test","formatHexColorString","colorString","startsWith","slice","hexValid","setHexValid","hexColorString","setHexColorString","colorToDisplay","setColorToDisplay","formattedColor","setValidatedColor","newColor","createElement","Fragment","placement","overlay","id","ref","style","_objectSpread","background","onClick","positionRef","onClose","textAlign","onChange","Group","Label","Control","isInvalid","value","e","spellCheck","Feedback","type","defaultProps","undefined","propTypes","string","func","isRequired","oneOf"],"sources":["../../src/ColorPicker/index.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { HexColorPicker } from 'react-colorful';\n\nimport Button from '../Button';\nimport Form from '../Form';\nimport ModalPopup from '../Modal/ModalPopup';\nimport { OverlayTrigger } from '../Overlay';\nimport Tooltip from '../Tooltip';\nimport useToggle from '../hooks/useToggle';\n\nfunction ColorPicker({\n color, setColor, className, size,\n}) {\n const [isOpen, open, close] = useToggle(false);\n const [target, setTarget] = React.useState(null);\n\n const colorIsValid = (colorToValidate) => {\n const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;\n return hexRegex.test(colorToValidate);\n };\n\n const formatHexColorString = (colorString) => {\n if (!colorString.startsWith('#')) {\n return `#${colorString}`.slice(0, 7);\n }\n\n return colorString.slice(0, 7);\n };\n\n const [hexValid, setHexValid] = React.useState(() => (color === '' || colorIsValid(formatHexColorString(color))));\n\n const [hexColorString, setHexColorString] = React.useState(() => {\n if (color === '') {\n return '';\n }\n\n return formatHexColorString(color);\n });\n const [colorToDisplay, setColorToDisplay] = React.useState(() => {\n const formattedColor = formatHexColorString(color);\n if (colorIsValid(formattedColor)) {\n return formattedColor;\n }\n\n return '#fff';\n });\n\n const setValidatedColor = (newColor) => {\n if (newColor === '') {\n setHexValid(true);\n setColor('');\n setHexColorString('');\n setColorToDisplay('#fff');\n return;\n }\n\n const formattedColor = formatHexColorString(newColor);\n\n if (colorIsValid(formattedColor)) {\n setHexValid(true);\n setColor(formattedColor);\n setHexColorString(formattedColor);\n setColorToDisplay(formattedColor);\n return;\n }\n\n setHexValid(false);\n setHexColorString(formattedColor);\n\n // ensure the picker value stays in sync with the textbox\n setColor(formattedColor);\n };\n\n return (\n <>\n <span className=\"d-flex\">\n <OverlayTrigger\n placement=\"top\"\n overlay={<Tooltip id=\"color-picker-tooltip\">Color picker</Tooltip>}\n >\n <Button\n ref={setTarget}\n className={classNames(\n className,\n 'pgn__color-picker',\n `pgn__color-picker-${size}`,\n )}\n style={{\n ...(color && hexValid ? { background: `${color}` } : {}),\n }}\n onClick={open}\n />\n </OverlayTrigger>\n </span>\n <ModalPopup\n positionRef={target}\n isOpen={isOpen}\n style={{ background: 'black' }}\n onClose={close}\n >\n <div\n className=\"pgn__color-modal rounded shadow\"\n style={{ textAlign: 'start' }}\n >\n <HexColorPicker color={colorToDisplay} onChange={setValidatedColor} />\n <Form.Group className=\"pgn__hex-form\" size=\"sm\">\n <div>\n <Form.Label className=\"pgn__hex-label\">Hex</Form.Label>\n <Form.Control\n className=\"pgn__hex-field\"\n isInvalid={!hexValid}\n value={hexColorString}\n onChange={(e) => setValidatedColor(e.target.value)}\n data-testid=\"hex-input\"\n spellCheck=\"false\"\n />\n </div>\n {!hexValid && (\n <Form.Control.Feedback\n className=\"pgn__color-error\"\n type=\"invalid\"\n >\n Colors must be in hexadecimal format.\n </Form.Control.Feedback>\n )}\n </Form.Group>\n </div>\n </ModalPopup>\n </>\n );\n}\n\nColorPicker.defaultProps = {\n color: '',\n className: undefined,\n size: 'md',\n};\n\nColorPicker.propTypes = {\n /** A default hex code to preset the picker to display. */\n color: PropTypes.string,\n /** Passing setState function allows parent to alter the color. */\n setColor: PropTypes.func.isRequired,\n /** A class name to append to the base element. */\n className: PropTypes.string,\n /** Size of the color picker */\n size: PropTypes.oneOf(['sm', 'md']),\n};\n\nexport default ColorPicker;\n"],"mappings":"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"}
@@ -14,7 +14,7 @@ import { v4 as uuidv4 } from 'uuid';
14
14
  import { useIntl } from 'react-intl';
15
15
  import { KeyboardArrowUp, KeyboardArrowDown } from '../../icons';
16
16
  import Icon from '../Icon';
17
- import FormGroup from './FormGroup';
17
+ import { FormGroupContextProvider, useFormGroupContext } from './FormGroupContext';
18
18
  import FormControl from './FormControl';
19
19
  import FormControlFeedback from './FormControlFeedback';
20
20
  import IconButton from '../IconButton';
@@ -198,6 +198,10 @@ function FormAutosuggest(_ref) {
198
198
  }
199
199
  setDisplayValue(e.target.value);
200
200
  };
201
+ const {
202
+ getControlProps
203
+ } = useFormGroupContext();
204
+ const controlProps = getControlProps(props);
201
205
  return /*#__PURE__*/React.createElement("div", {
202
206
  className: "pgn__form-autosuggest__wrapper",
203
207
  ref: parentRef
@@ -205,7 +209,8 @@ function FormAutosuggest(_ref) {
205
209
  "aria-live": "assertive",
206
210
  className: "sr-only",
207
211
  "data-testid": "autosuggest-screen-reader-options-count"
208
- }, `${state.dropDownItems.length} options found`), /*#__PURE__*/React.createElement(FormGroup, {
212
+ }, `${state.dropDownItems.length} options found`), /*#__PURE__*/React.createElement(FormGroupContextProvider, {
213
+ controlId: controlProps.id,
209
214
  isInvalid: !!state.errorMessage
210
215
  }, /*#__PURE__*/React.createElement(FormControl, _extends({
211
216
  ref: formControlRef,
@@ -221,11 +226,11 @@ function FormAutosuggest(_ref) {
221
226
  onClick: handleClick,
222
227
  trailingElement: iconToggle,
223
228
  "data-testid": "autosuggest-textbox-input"
224
- }, props)), helpMessage && !state.errorMessage && /*#__PURE__*/React.createElement(FormControlFeedback, {
229
+ }, controlProps)), helpMessage && !state.errorMessage && /*#__PURE__*/React.createElement(FormControlFeedback, {
225
230
  type: "default"
226
231
  }, helpMessage), state.errorMessage && /*#__PURE__*/React.createElement(FormControlFeedback, {
227
232
  type: "invalid",
228
- "feedback-for": props.name
233
+ "feedback-for": controlProps.name
229
234
  }, errorMessageText)), /*#__PURE__*/React.createElement("ul", {
230
235
  id: "pgn__form-autosuggest__dropdown-box",
231
236
  className: "pgn__form-autosuggest__dropdown",
@@ -1 +1 @@
1
- {"version":3,"file":"FormAutosuggest.js","names":["React","useEffect","useState","useRef","PropTypes","v4","uuidv4","useIntl","KeyboardArrowUp","KeyboardArrowDown","Icon","FormGroup","FormControl","FormControlFeedback","IconButton","Spinner","useArrowKeyNavigation","messages","FormAutosuggest","_ref","children","arrowKeyNavigationSelector","ignoredArrowKeysNames","screenReaderText","value","isLoading","errorMessageText","onChange","onSelected","helpMessage","props","_objectWithoutProperties","_excluded","intl","formControlRef","parentRef","selectors","ignoredKeys","isMenuClosed","setIsMenuClosed","isActive","setIsActive","state","setState","displayValue","errorMessage","dropDownItems","activeMenuItemId","setActiveMenuItemId","handleMenuItemFocus","menuItemId","handleItemClick","e","onClick","clickedValue","currentTarget","getAttribute","prevState","_objectSpread","getItems","strToFind","arguments","length","undefined","childrenOpt","Children","map","child","_child$props","rest","_excluded2","cloneElement","id","onFocus","filter","opt","toLowerCase","includes","handleExpand","newState","iconToggle","createElement","className","tabindex","src","iconAs","size","variant","alt","formatMessage","iconButtonOpened","iconButtonClosed","leaveControl","handleDocumentClick","current","contains","target","keyDownHandler","key","preventDefault","focus","document","addEventListener","removeEventListener","setDisplayValue","itemValue","optValue","forEach","push","normalized","find","o","handleClick","handleOnChange","findStr","filteredItems","ref","isInvalid","_extends","toString","role","autoComplete","trailingElement","type","name","animation","defaultProps","floatingLabel","placeholder","readOnly","propTypes","string","arrayOf","bool","func","node"],"sources":["../../src/Form/FormAutosuggest.jsx"],"sourcesContent":["import React, {\n useEffect, useState, useRef,\n} from 'react';\nimport PropTypes from 'prop-types';\nimport { v4 as uuidv4 } from 'uuid';\nimport { useIntl } from 'react-intl';\nimport { KeyboardArrowUp, KeyboardArrowDown } from '../../icons';\nimport Icon from '../Icon';\nimport FormGroup from './FormGroup';\nimport FormControl from './FormControl';\nimport FormControlFeedback from './FormControlFeedback';\nimport IconButton from '../IconButton';\nimport Spinner from '../Spinner';\nimport useArrowKeyNavigation from '../hooks/useArrowKeyNavigation';\nimport messages from './messages';\n\nfunction FormAutosuggest({\n children,\n arrowKeyNavigationSelector,\n ignoredArrowKeysNames,\n screenReaderText,\n value,\n isLoading,\n errorMessageText,\n onChange,\n onSelected,\n helpMessage,\n ...props\n}) {\n const intl = useIntl();\n const formControlRef = useRef();\n const parentRef = useArrowKeyNavigation({\n selectors: arrowKeyNavigationSelector,\n ignoredKeys: ignoredArrowKeysNames,\n });\n const [isMenuClosed, setIsMenuClosed] = useState(true);\n const [isActive, setIsActive] = useState(false);\n const [state, setState] = useState({\n displayValue: value || '',\n errorMessage: '',\n dropDownItems: [],\n });\n const [activeMenuItemId, setActiveMenuItemId] = useState(null);\n\n const handleMenuItemFocus = (menuItemId) => {\n setActiveMenuItemId(menuItemId);\n };\n\n const handleItemClick = (e, onClick) => {\n const clickedValue = e.currentTarget.getAttribute('data-value');\n\n if (onSelected && clickedValue !== value) {\n onSelected(clickedValue);\n }\n\n setState(prevState => ({\n ...prevState,\n dropDownItems: [],\n displayValue: clickedValue,\n }));\n\n setIsMenuClosed(true);\n\n if (onClick) {\n onClick(e);\n }\n };\n\n function getItems(strToFind = '') {\n let childrenOpt = React.Children.map(children, (child) => {\n // eslint-disable-next-line no-shadow\n const { children, onClick, ...rest } = child.props;\n const menuItemId = uuidv4();\n\n return React.cloneElement(child, {\n ...rest,\n children,\n 'data-value': children,\n onClick: (e) => handleItemClick(e, onClick),\n id: menuItemId,\n onFocus: () => handleMenuItemFocus(menuItemId),\n });\n });\n\n if (strToFind.length > 0) {\n childrenOpt = childrenOpt\n .filter((opt) => (opt.props.children.toLowerCase().includes(strToFind.toLowerCase())));\n }\n\n return childrenOpt;\n }\n\n const handleExpand = () => {\n setIsMenuClosed(!isMenuClosed);\n\n const newState = {\n dropDownItems: [],\n };\n\n if (isMenuClosed) {\n setIsActive(true);\n newState.dropDownItems = getItems(state.displayValue);\n newState.errorMessage = '';\n }\n\n setState(prevState => ({\n ...prevState,\n ...newState,\n }));\n };\n\n const iconToggle = (\n <IconButton\n className=\"pgn__form-autosuggest__icon-button\"\n data-testid=\"autosuggest-iconbutton\"\n tabindex=\"-1\"\n src={isMenuClosed ? KeyboardArrowDown : KeyboardArrowUp}\n iconAs={Icon}\n size=\"sm\"\n variant=\"secondary\"\n alt={isMenuClosed\n ? intl.formatMessage(messages.iconButtonOpened)\n : intl.formatMessage(messages.iconButtonClosed)}\n onClick={(e) => handleExpand(e, isMenuClosed)}\n />\n );\n\n const leaveControl = () => {\n setIsActive(false);\n\n setState(prevState => ({\n ...prevState,\n dropDownItems: [],\n errorMessage: !state.displayValue ? errorMessageText : '',\n }));\n\n setIsMenuClosed(true);\n };\n\n const handleDocumentClick = (e) => {\n if (parentRef.current && !parentRef.current.contains(e.target) && isActive) {\n leaveControl();\n }\n };\n\n const keyDownHandler = e => {\n if (e.key === 'Escape' && isActive) {\n e.preventDefault();\n\n if (formControlRef) {\n formControlRef.current.focus();\n }\n\n setState(prevState => ({\n ...prevState,\n dropDownItems: [],\n }));\n\n setIsMenuClosed(true);\n }\n if (e.key === 'Tab' && isActive) {\n leaveControl();\n }\n };\n\n useEffect(() => {\n document.addEventListener('keydown', keyDownHandler);\n document.addEventListener('click', handleDocumentClick, true);\n\n return () => {\n document.removeEventListener('click', handleDocumentClick, true);\n document.removeEventListener('keydown', keyDownHandler);\n };\n });\n\n useEffect(() => {\n if (value || value === '') {\n setState(prevState => ({\n ...prevState,\n displayValue: value,\n }));\n }\n }, [value]);\n\n const setDisplayValue = (itemValue) => {\n const optValue = [];\n\n children.forEach(opt => {\n optValue.push(opt.props.children);\n });\n\n const normalized = itemValue.toLowerCase();\n const opt = optValue.find((o) => o.toLowerCase() === normalized);\n\n setState(prevState => ({\n ...prevState,\n displayValue: opt || itemValue,\n }));\n };\n\n const handleClick = (e) => {\n setIsActive(true);\n const dropDownItems = getItems(e.target.value);\n\n if (dropDownItems.length > 1) {\n setState(prevState => ({\n ...prevState,\n dropDownItems,\n errorMessage: '',\n }));\n\n setIsMenuClosed(false);\n }\n };\n\n const handleOnChange = (e) => {\n const findStr = e.target.value;\n\n if (onChange) { onChange(findStr); }\n\n if (findStr.length) {\n const filteredItems = getItems(findStr);\n setState(prevState => ({\n ...prevState,\n dropDownItems: filteredItems,\n errorMessage: '',\n }));\n\n setIsMenuClosed(false);\n } else {\n setState(prevState => ({\n ...prevState,\n dropDownItems: [],\n }));\n\n setIsMenuClosed(true);\n }\n\n setDisplayValue(e.target.value);\n };\n\n return (\n <div className=\"pgn__form-autosuggest__wrapper\" ref={parentRef}>\n <div aria-live=\"assertive\" className=\"sr-only\" data-testid=\"autosuggest-screen-reader-options-count\">\n {`${state.dropDownItems.length} options found`}\n </div>\n <FormGroup isInvalid={!!state.errorMessage}>\n <FormControl\n ref={formControlRef}\n aria-expanded={(state.dropDownItems.length > 0).toString()}\n aria-owns=\"pgn__form-autosuggest__dropdown-box\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n value={state.displayValue}\n aria-invalid={state.errorMessage}\n aria-activedescendant={activeMenuItemId}\n onChange={handleOnChange}\n onClick={handleClick}\n trailingElement={iconToggle}\n data-testid=\"autosuggest-textbox-input\"\n {...props}\n />\n\n {helpMessage && !state.errorMessage && (\n <FormControlFeedback type=\"default\">\n {helpMessage}\n </FormControlFeedback>\n )}\n\n {state.errorMessage && (\n <FormControlFeedback type=\"invalid\" feedback-for={props.name}>\n {errorMessageText}\n </FormControlFeedback>\n )}\n </FormGroup>\n\n <ul\n id=\"pgn__form-autosuggest__dropdown-box\"\n className=\"pgn__form-autosuggest__dropdown\"\n role=\"listbox\"\n >\n {isLoading ? (\n <div className=\"pgn__form-autosuggest__dropdown-loading\">\n <Spinner\n animation=\"border\"\n variant=\"dark\"\n screenReaderText={screenReaderText}\n data-testid=\"autosuggest-loading-spinner\"\n />\n </div>\n ) : state.dropDownItems.length > 0 && state.dropDownItems}\n </ul>\n </div>\n );\n}\n\nFormAutosuggest.defaultProps = {\n arrowKeyNavigationSelector: 'a:not(:disabled),li:not(:disabled, .btn-icon),input:not(:disabled)',\n ignoredArrowKeysNames: ['ArrowRight', 'ArrowLeft'],\n isLoading: false,\n className: null,\n floatingLabel: null,\n onChange: null,\n onSelected: null,\n helpMessage: '',\n placeholder: '',\n value: null,\n errorMessageText: null,\n readOnly: false,\n children: null,\n name: 'form-autosuggest',\n screenReaderText: 'loading',\n};\n\nFormAutosuggest.propTypes = {\n /**\n * Specifies the CSS selector string that indicates to which elements\n * the user can navigate using the arrow keys\n */\n arrowKeyNavigationSelector: PropTypes.string,\n /** Specifies ignored hook keys. */\n ignoredArrowKeysNames: PropTypes.arrayOf(PropTypes.string),\n /** Specifies loading state. */\n isLoading: PropTypes.bool,\n /** Specifies class name to append to the base element. */\n className: PropTypes.string,\n /** Specifies floating label to display for the input component. */\n floatingLabel: PropTypes.string,\n /** Specifies onChange event handler. */\n onChange: PropTypes.func,\n /** Specifies help information for the user. */\n helpMessage: PropTypes.string,\n /** Specifies the placeholder text for the input. */\n placeholder: PropTypes.string,\n /** Specifies values for the input. */\n value: PropTypes.string,\n /** Informs user has errors. */\n errorMessageText: PropTypes.string,\n /** Specifies the name of the base input element. */\n name: PropTypes.string,\n /** Selected list item is read-only. */\n readOnly: PropTypes.bool,\n /** Specifies the content of the `FormAutosuggest`. */\n children: PropTypes.node,\n /** Specifies the screen reader text */\n screenReaderText: PropTypes.string,\n /** Function that receives the selected value. */\n onSelected: PropTypes.func,\n};\n\nexport default FormAutosuggest;\n"],"mappings":"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"}
1
+ {"version":3,"file":"FormAutosuggest.js","names":["React","useEffect","useState","useRef","PropTypes","v4","uuidv4","useIntl","KeyboardArrowUp","KeyboardArrowDown","Icon","FormGroupContextProvider","useFormGroupContext","FormControl","FormControlFeedback","IconButton","Spinner","useArrowKeyNavigation","messages","FormAutosuggest","_ref","children","arrowKeyNavigationSelector","ignoredArrowKeysNames","screenReaderText","value","isLoading","errorMessageText","onChange","onSelected","helpMessage","props","_objectWithoutProperties","_excluded","intl","formControlRef","parentRef","selectors","ignoredKeys","isMenuClosed","setIsMenuClosed","isActive","setIsActive","state","setState","displayValue","errorMessage","dropDownItems","activeMenuItemId","setActiveMenuItemId","handleMenuItemFocus","menuItemId","handleItemClick","e","onClick","clickedValue","currentTarget","getAttribute","prevState","_objectSpread","getItems","strToFind","arguments","length","undefined","childrenOpt","Children","map","child","_child$props","rest","_excluded2","cloneElement","id","onFocus","filter","opt","toLowerCase","includes","handleExpand","newState","iconToggle","createElement","className","tabindex","src","iconAs","size","variant","alt","formatMessage","iconButtonOpened","iconButtonClosed","leaveControl","handleDocumentClick","current","contains","target","keyDownHandler","key","preventDefault","focus","document","addEventListener","removeEventListener","setDisplayValue","itemValue","optValue","forEach","push","normalized","find","o","handleClick","handleOnChange","findStr","filteredItems","getControlProps","controlProps","ref","controlId","isInvalid","_extends","toString","role","autoComplete","trailingElement","type","name","animation","defaultProps","floatingLabel","placeholder","readOnly","propTypes","string","arrayOf","bool","func","node"],"sources":["../../src/Form/FormAutosuggest.jsx"],"sourcesContent":["import React, {\n useEffect, useState, useRef,\n} from 'react';\nimport PropTypes from 'prop-types';\nimport { v4 as uuidv4 } from 'uuid';\nimport { useIntl } from 'react-intl';\nimport { KeyboardArrowUp, KeyboardArrowDown } from '../../icons';\nimport Icon from '../Icon';\nimport { FormGroupContextProvider, useFormGroupContext } from './FormGroupContext';\nimport FormControl from './FormControl';\nimport FormControlFeedback from './FormControlFeedback';\nimport IconButton from '../IconButton';\nimport Spinner from '../Spinner';\nimport useArrowKeyNavigation from '../hooks/useArrowKeyNavigation';\nimport messages from './messages';\n\nfunction FormAutosuggest({\n children,\n arrowKeyNavigationSelector,\n ignoredArrowKeysNames,\n screenReaderText,\n value,\n isLoading,\n errorMessageText,\n onChange,\n onSelected,\n helpMessage,\n ...props\n}) {\n const intl = useIntl();\n const formControlRef = useRef();\n const parentRef = useArrowKeyNavigation({\n selectors: arrowKeyNavigationSelector,\n ignoredKeys: ignoredArrowKeysNames,\n });\n const [isMenuClosed, setIsMenuClosed] = useState(true);\n const [isActive, setIsActive] = useState(false);\n const [state, setState] = useState({\n displayValue: value || '',\n errorMessage: '',\n dropDownItems: [],\n });\n const [activeMenuItemId, setActiveMenuItemId] = useState(null);\n\n const handleMenuItemFocus = (menuItemId) => {\n setActiveMenuItemId(menuItemId);\n };\n\n const handleItemClick = (e, onClick) => {\n const clickedValue = e.currentTarget.getAttribute('data-value');\n\n if (onSelected && clickedValue !== value) {\n onSelected(clickedValue);\n }\n\n setState(prevState => ({\n ...prevState,\n dropDownItems: [],\n displayValue: clickedValue,\n }));\n\n setIsMenuClosed(true);\n\n if (onClick) {\n onClick(e);\n }\n };\n\n function getItems(strToFind = '') {\n let childrenOpt = React.Children.map(children, (child) => {\n // eslint-disable-next-line no-shadow\n const { children, onClick, ...rest } = child.props;\n const menuItemId = uuidv4();\n\n return React.cloneElement(child, {\n ...rest,\n children,\n 'data-value': children,\n onClick: (e) => handleItemClick(e, onClick),\n id: menuItemId,\n onFocus: () => handleMenuItemFocus(menuItemId),\n });\n });\n\n if (strToFind.length > 0) {\n childrenOpt = childrenOpt\n .filter((opt) => (opt.props.children.toLowerCase().includes(strToFind.toLowerCase())));\n }\n\n return childrenOpt;\n }\n\n const handleExpand = () => {\n setIsMenuClosed(!isMenuClosed);\n\n const newState = {\n dropDownItems: [],\n };\n\n if (isMenuClosed) {\n setIsActive(true);\n newState.dropDownItems = getItems(state.displayValue);\n newState.errorMessage = '';\n }\n\n setState(prevState => ({\n ...prevState,\n ...newState,\n }));\n };\n\n const iconToggle = (\n <IconButton\n className=\"pgn__form-autosuggest__icon-button\"\n data-testid=\"autosuggest-iconbutton\"\n tabindex=\"-1\"\n src={isMenuClosed ? KeyboardArrowDown : KeyboardArrowUp}\n iconAs={Icon}\n size=\"sm\"\n variant=\"secondary\"\n alt={isMenuClosed\n ? intl.formatMessage(messages.iconButtonOpened)\n : intl.formatMessage(messages.iconButtonClosed)}\n onClick={(e) => handleExpand(e, isMenuClosed)}\n />\n );\n\n const leaveControl = () => {\n setIsActive(false);\n\n setState(prevState => ({\n ...prevState,\n dropDownItems: [],\n errorMessage: !state.displayValue ? errorMessageText : '',\n }));\n\n setIsMenuClosed(true);\n };\n\n const handleDocumentClick = (e) => {\n if (parentRef.current && !parentRef.current.contains(e.target) && isActive) {\n leaveControl();\n }\n };\n\n const keyDownHandler = e => {\n if (e.key === 'Escape' && isActive) {\n e.preventDefault();\n\n if (formControlRef) {\n formControlRef.current.focus();\n }\n\n setState(prevState => ({\n ...prevState,\n dropDownItems: [],\n }));\n\n setIsMenuClosed(true);\n }\n if (e.key === 'Tab' && isActive) {\n leaveControl();\n }\n };\n\n useEffect(() => {\n document.addEventListener('keydown', keyDownHandler);\n document.addEventListener('click', handleDocumentClick, true);\n\n return () => {\n document.removeEventListener('click', handleDocumentClick, true);\n document.removeEventListener('keydown', keyDownHandler);\n };\n });\n\n useEffect(() => {\n if (value || value === '') {\n setState(prevState => ({\n ...prevState,\n displayValue: value,\n }));\n }\n }, [value]);\n\n const setDisplayValue = (itemValue) => {\n const optValue = [];\n\n children.forEach(opt => {\n optValue.push(opt.props.children);\n });\n\n const normalized = itemValue.toLowerCase();\n const opt = optValue.find((o) => o.toLowerCase() === normalized);\n\n setState(prevState => ({\n ...prevState,\n displayValue: opt || itemValue,\n }));\n };\n\n const handleClick = (e) => {\n setIsActive(true);\n const dropDownItems = getItems(e.target.value);\n\n if (dropDownItems.length > 1) {\n setState(prevState => ({\n ...prevState,\n dropDownItems,\n errorMessage: '',\n }));\n\n setIsMenuClosed(false);\n }\n };\n\n const handleOnChange = (e) => {\n const findStr = e.target.value;\n\n if (onChange) { onChange(findStr); }\n\n if (findStr.length) {\n const filteredItems = getItems(findStr);\n setState(prevState => ({\n ...prevState,\n dropDownItems: filteredItems,\n errorMessage: '',\n }));\n\n setIsMenuClosed(false);\n } else {\n setState(prevState => ({\n ...prevState,\n dropDownItems: [],\n }));\n\n setIsMenuClosed(true);\n }\n\n setDisplayValue(e.target.value);\n };\n\n const { getControlProps } = useFormGroupContext();\n const controlProps = getControlProps(props);\n\n return (\n <div className=\"pgn__form-autosuggest__wrapper\" ref={parentRef}>\n <div aria-live=\"assertive\" className=\"sr-only\" data-testid=\"autosuggest-screen-reader-options-count\">\n {`${state.dropDownItems.length} options found`}\n </div>\n <FormGroupContextProvider\n controlId={controlProps.id}\n isInvalid={!!state.errorMessage}\n >\n <FormControl\n ref={formControlRef}\n aria-expanded={(state.dropDownItems.length > 0).toString()}\n aria-owns=\"pgn__form-autosuggest__dropdown-box\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n value={state.displayValue}\n aria-invalid={state.errorMessage}\n aria-activedescendant={activeMenuItemId}\n onChange={handleOnChange}\n onClick={handleClick}\n trailingElement={iconToggle}\n data-testid=\"autosuggest-textbox-input\"\n {...controlProps}\n />\n\n {helpMessage && !state.errorMessage && (\n <FormControlFeedback type=\"default\">\n {helpMessage}\n </FormControlFeedback>\n )}\n\n {state.errorMessage && (\n <FormControlFeedback type=\"invalid\" feedback-for={controlProps.name}>\n {errorMessageText}\n </FormControlFeedback>\n )}\n </FormGroupContextProvider>\n\n <ul\n id=\"pgn__form-autosuggest__dropdown-box\"\n className=\"pgn__form-autosuggest__dropdown\"\n role=\"listbox\"\n >\n {isLoading ? (\n <div className=\"pgn__form-autosuggest__dropdown-loading\">\n <Spinner\n animation=\"border\"\n variant=\"dark\"\n screenReaderText={screenReaderText}\n data-testid=\"autosuggest-loading-spinner\"\n />\n </div>\n ) : state.dropDownItems.length > 0 && state.dropDownItems}\n </ul>\n </div>\n );\n}\n\nFormAutosuggest.defaultProps = {\n arrowKeyNavigationSelector: 'a:not(:disabled),li:not(:disabled, .btn-icon),input:not(:disabled)',\n ignoredArrowKeysNames: ['ArrowRight', 'ArrowLeft'],\n isLoading: false,\n className: null,\n floatingLabel: null,\n onChange: null,\n onSelected: null,\n helpMessage: '',\n placeholder: '',\n value: null,\n errorMessageText: null,\n readOnly: false,\n children: null,\n name: 'form-autosuggest',\n screenReaderText: 'loading',\n};\n\nFormAutosuggest.propTypes = {\n /**\n * Specifies the CSS selector string that indicates to which elements\n * the user can navigate using the arrow keys\n */\n arrowKeyNavigationSelector: PropTypes.string,\n /** Specifies ignored hook keys. */\n ignoredArrowKeysNames: PropTypes.arrayOf(PropTypes.string),\n /** Specifies loading state. */\n isLoading: PropTypes.bool,\n /** Specifies class name to append to the base element. */\n className: PropTypes.string,\n /** Specifies floating label to display for the input component. */\n floatingLabel: PropTypes.string,\n /** Specifies onChange event handler. */\n onChange: PropTypes.func,\n /** Specifies help information for the user. */\n helpMessage: PropTypes.string,\n /** Specifies the placeholder text for the input. */\n placeholder: PropTypes.string,\n /** Specifies values for the input. */\n value: PropTypes.string,\n /** Informs user has errors. */\n errorMessageText: PropTypes.string,\n /** Specifies the name of the base input element. */\n name: PropTypes.string,\n /** Selected list item is read-only. */\n readOnly: PropTypes.bool,\n /** Specifies the content of the `FormAutosuggest`. */\n children: PropTypes.node,\n /** Specifies the screen reader text */\n screenReaderText: PropTypes.string,\n /** Function that receives the selected value. */\n onSelected: PropTypes.func,\n};\n\nexport default FormAutosuggest;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openedx/paragon",
3
- "version": "21.11.1",
3
+ "version": "21.11.3",
4
4
  "description": "Accessible, responsive UI component library based on Bootstrap.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -100,11 +100,11 @@
100
100
  "@formatjs/cli": "^5.0.2",
101
101
  "@semantic-release/changelog": "^6.0.1",
102
102
  "@semantic-release/git": "^10.0.1",
103
- "@testing-library/jest-dom": "^5.16.3",
103
+ "@testing-library/jest-dom": "^6.1.4",
104
104
  "@testing-library/react": "^12.1.4",
105
105
  "@testing-library/react-hooks": "^8.0.1",
106
106
  "@testing-library/user-event": "^13.5.0",
107
- "@types/jest": "^27.5.0",
107
+ "@types/jest": "^29.5.10",
108
108
  "@types/react": "17.0.0",
109
109
  "@types/react-dom": "17.0.11",
110
110
  "@types/react-test-renderer": "^18.0.0",
@@ -29,13 +29,35 @@ describe('picker works as expected', () => {
29
29
  const color = 'wassap';
30
30
  const setColor = jest.fn();
31
31
  it('validates hex color', async () => {
32
- const { rerender } = render(<ColorPicker color={color} setColor={setColor} />);
32
+ render(<ColorPicker color={color} setColor={setColor} />);
33
+
33
34
  await act(async () => {
34
35
  await userEvent.click(screen.getByRole('button'));
35
36
  });
37
+ expect(screen.queryByTestId('hex-input').value).toEqual('#wassap');
36
38
  expect(screen.queryByText('Colors must be in hexadecimal format.')).toBeInTheDocument();
37
39
 
38
- rerender(<ColorPicker color="#32116c" setColor={setColor} />);
40
+ await act(async () => {
41
+ await userEvent.clear(screen.getByTestId('hex-input'));
42
+ await userEvent.paste(screen.getByTestId('hex-input'), '32116c');
43
+ });
44
+ expect(screen.queryByTestId('hex-input').value).toEqual('#32116c');
45
+ expect(screen.queryByText('Colors must be in hexadecimal format.')).not.toBeInTheDocument();
46
+
47
+ await act(async () => {
48
+ await userEvent.clear(screen.getByTestId('hex-input'));
49
+ await userEvent.paste(screen.getByTestId('hex-input'), 'yuk');
50
+ });
51
+
52
+ expect(screen.queryByTestId('hex-input').value).toEqual('#yuk');
53
+ expect(screen.queryByText('Colors must be in hexadecimal format.')).toBeInTheDocument();
54
+
55
+ await act(async () => {
56
+ await userEvent.clear(screen.getByTestId('hex-input'));
57
+ await userEvent.paste(screen.getByTestId('hex-input'), '#fad');
58
+ });
59
+
60
+ expect(screen.queryByTestId('hex-input').value).toEqual('#fad');
39
61
  expect(screen.queryByText('Colors must be in hexadecimal format.')).not.toBeInTheDocument();
40
62
  });
41
63
  });
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect } from 'react';
1
+ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import classNames from 'classnames';
4
4
  import { HexColorPicker } from 'react-colorful';
@@ -15,24 +15,63 @@ function ColorPicker({
15
15
  }) {
16
16
  const [isOpen, open, close] = useToggle(false);
17
17
  const [target, setTarget] = React.useState(null);
18
- const [hexValid, setHexValid] = React.useState(true);
19
18
 
20
- const validateHex = useCallback((input) => {
19
+ const colorIsValid = (colorToValidate) => {
21
20
  const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
22
- if (input.length > 1 && !input.startsWith('#')) {
23
- setColor(`#${input}`);
24
- } else {
25
- setColor(input);
21
+ return hexRegex.test(colorToValidate);
22
+ };
23
+
24
+ const formatHexColorString = (colorString) => {
25
+ if (!colorString.startsWith('#')) {
26
+ return `#${colorString}`.slice(0, 7);
27
+ }
28
+
29
+ return colorString.slice(0, 7);
30
+ };
31
+
32
+ const [hexValid, setHexValid] = React.useState(() => (color === '' || colorIsValid(formatHexColorString(color))));
33
+
34
+ const [hexColorString, setHexColorString] = React.useState(() => {
35
+ if (color === '') {
36
+ return '';
37
+ }
38
+
39
+ return formatHexColorString(color);
40
+ });
41
+ const [colorToDisplay, setColorToDisplay] = React.useState(() => {
42
+ const formattedColor = formatHexColorString(color);
43
+ if (colorIsValid(formattedColor)) {
44
+ return formattedColor;
26
45
  }
27
- if (input === '' || hexRegex.test(input) === true) {
46
+
47
+ return '#fff';
48
+ });
49
+
50
+ const setValidatedColor = (newColor) => {
51
+ if (newColor === '') {
28
52
  setHexValid(true);
29
- } else {
30
- setHexValid(false);
53
+ setColor('');
54
+ setHexColorString('');
55
+ setColorToDisplay('#fff');
56
+ return;
31
57
  }
32
- }, [setColor]);
33
58
 
34
- // this is needed for when a user changes the color through the sliders
35
- useEffect(() => validateHex(color), [validateHex, color]);
59
+ const formattedColor = formatHexColorString(newColor);
60
+
61
+ if (colorIsValid(formattedColor)) {
62
+ setHexValid(true);
63
+ setColor(formattedColor);
64
+ setHexColorString(formattedColor);
65
+ setColorToDisplay(formattedColor);
66
+ return;
67
+ }
68
+
69
+ setHexValid(false);
70
+ setHexColorString(formattedColor);
71
+
72
+ // ensure the picker value stays in sync with the textbox
73
+ setColor(formattedColor);
74
+ };
36
75
 
37
76
  return (
38
77
  <>
@@ -65,16 +104,17 @@ function ColorPicker({
65
104
  className="pgn__color-modal rounded shadow"
66
105
  style={{ textAlign: 'start' }}
67
106
  >
68
- <HexColorPicker color={color || ''} onChange={setColor} />
107
+ <HexColorPicker color={colorToDisplay} onChange={setValidatedColor} />
69
108
  <Form.Group className="pgn__hex-form" size="sm">
70
109
  <div>
71
110
  <Form.Label className="pgn__hex-label">Hex</Form.Label>
72
111
  <Form.Control
73
112
  className="pgn__hex-field"
74
113
  isInvalid={!hexValid}
75
- value={color}
76
- onChange={(e) => validateHex(e.target.value)}
114
+ value={hexColorString}
115
+ onChange={(e) => setValidatedColor(e.target.value)}
77
116
  data-testid="hex-input"
117
+ spellCheck="false"
78
118
  />
79
119
  </div>
80
120
  {!hexValid && (
@@ -6,7 +6,7 @@ import { v4 as uuidv4 } from 'uuid';
6
6
  import { useIntl } from 'react-intl';
7
7
  import { KeyboardArrowUp, KeyboardArrowDown } from '../../icons';
8
8
  import Icon from '../Icon';
9
- import FormGroup from './FormGroup';
9
+ import { FormGroupContextProvider, useFormGroupContext } from './FormGroupContext';
10
10
  import FormControl from './FormControl';
11
11
  import FormControlFeedback from './FormControlFeedback';
12
12
  import IconButton from '../IconButton';
@@ -239,12 +239,18 @@ function FormAutosuggest({
239
239
  setDisplayValue(e.target.value);
240
240
  };
241
241
 
242
+ const { getControlProps } = useFormGroupContext();
243
+ const controlProps = getControlProps(props);
244
+
242
245
  return (
243
246
  <div className="pgn__form-autosuggest__wrapper" ref={parentRef}>
244
247
  <div aria-live="assertive" className="sr-only" data-testid="autosuggest-screen-reader-options-count">
245
248
  {`${state.dropDownItems.length} options found`}
246
249
  </div>
247
- <FormGroup isInvalid={!!state.errorMessage}>
250
+ <FormGroupContextProvider
251
+ controlId={controlProps.id}
252
+ isInvalid={!!state.errorMessage}
253
+ >
248
254
  <FormControl
249
255
  ref={formControlRef}
250
256
  aria-expanded={(state.dropDownItems.length > 0).toString()}
@@ -259,7 +265,7 @@ function FormAutosuggest({
259
265
  onClick={handleClick}
260
266
  trailingElement={iconToggle}
261
267
  data-testid="autosuggest-textbox-input"
262
- {...props}
268
+ {...controlProps}
263
269
  />
264
270
 
265
271
  {helpMessage && !state.errorMessage && (
@@ -269,11 +275,11 @@ function FormAutosuggest({
269
275
  )}
270
276
 
271
277
  {state.errorMessage && (
272
- <FormControlFeedback type="invalid" feedback-for={props.name}>
278
+ <FormControlFeedback type="invalid" feedback-for={controlProps.name}>
273
279
  {errorMessageText}
274
280
  </FormControlFeedback>
275
281
  )}
276
- </FormGroup>
282
+ </FormGroupContextProvider>
277
283
 
278
284
  <ul
279
285
  id="pgn__form-autosuggest__dropdown-box"
@@ -19,93 +19,101 @@ Form auto-suggest enables users to manually select or type to find matching opti
19
19
 
20
20
  ```jsx live
21
21
  () => {
22
- const [selected, setSelected] = useState('');
22
+ const [selected, setSelected] = useState('');
23
23
 
24
- return (
25
- <Form.Autosuggest
26
- floatingLabel="Programming language"
27
- aria-label="form autosuggest"
28
- helpMessage="Select language"
29
- errorMessageText="Error, no selected value"
30
- value={selected}
31
- onSelected={(value) => setSelected(value)}
32
- >
33
- <Form.AutosuggestOption>JavaScript</Form.AutosuggestOption>
34
- <Form.AutosuggestOption>Python</Form.AutosuggestOption>
35
- <Form.AutosuggestOption>Rube</Form.AutosuggestOption>
36
- <Form.AutosuggestOption onClick={(e) => alert(e.currentTarget.getAttribute('data-value'))}>
37
- Option with custom onClick
38
- </Form.AutosuggestOption>
39
- </Form.Autosuggest>
40
- );
41
- }
24
+ return (
25
+ <Form.Group>
26
+ <Form.Label>
27
+ <h4>Programming language</h4>
28
+ </Form.Label>
29
+ <Form.Autosuggest
30
+ aria-label="form autosuggest"
31
+ helpMessage="Select language"
32
+ errorMessageText="Error, no selected value"
33
+ value={selected}
34
+ onSelected={(value) => setSelected(value)}
35
+ >
36
+ <Form.AutosuggestOption>JavaScript</Form.AutosuggestOption>
37
+ <Form.AutosuggestOption>Python</Form.AutosuggestOption>
38
+ <Form.AutosuggestOption>Rube</Form.AutosuggestOption>
39
+ <Form.AutosuggestOption onClick={(e) => alert(e.currentTarget.getAttribute('data-value'))}>
40
+ Option with custom onClick
41
+ </Form.AutosuggestOption>
42
+ </Form.Autosuggest>
43
+ </Form.Group>
44
+ );
45
+ };
42
46
  ```
43
47
 
44
48
  ## Search Usage
45
49
 
46
50
  ```jsx live
47
51
  () => {
48
- const [selected, setSelected] = useState('');
52
+ const [selected, setSelected] = useState('');
49
53
 
50
- return (
51
- <Form.Autosuggest
52
- placeholder="Type 'T'"
53
- aria-label="form autosuggest"
54
- errorMessageText="Error, no selected value"
55
- helpMessage="Select language"
56
- value={selected}
57
- onSelected={(value) => setSelected(value)}
58
- >
59
- <Form.AutosuggestOption>PHP</Form.AutosuggestOption>
60
- <Form.AutosuggestOption>Java</Form.AutosuggestOption>
61
- <Form.AutosuggestOption>Turbo Pascal</Form.AutosuggestOption>
62
- <Form.AutosuggestOption>Flask</Form.AutosuggestOption>
63
- </Form.Autosuggest>
64
- );
65
- }
54
+ return (
55
+ <Form.Autosuggest
56
+ placeholder="Type 'T'"
57
+ aria-label="form autosuggest"
58
+ errorMessageText="Error, no selected value"
59
+ helpMessage="Select language"
60
+ value={selected}
61
+ onSelected={(value) => setSelected(value)}
62
+ >
63
+ <Form.AutosuggestOption>PHP</Form.AutosuggestOption>
64
+ <Form.AutosuggestOption>Java</Form.AutosuggestOption>
65
+ <Form.AutosuggestOption>Turbo Pascal</Form.AutosuggestOption>
66
+ <Form.AutosuggestOption>Flask</Form.AutosuggestOption>
67
+ </Form.Autosuggest>
68
+ );
69
+ };
66
70
  ```
67
71
 
68
72
  ## Loading state
69
73
 
70
74
  ```jsx live
71
75
  () => {
72
- const [data, setData] = useState([]);
73
- const [showLoading, setShowLoading] = useState(false);
76
+ const [data, setData] = useState([]);
77
+ const [showLoading, setShowLoading] = useState(false);
74
78
 
75
- useEffect(() => {
76
- setShowLoading(true);
77
- fetch('https://api.sampleapis.com/coffee/hot')
78
- .then(data => data.json())
79
- .then(items => {
80
- setTimeout(() => {
81
- setData(items);
82
- setShowLoading(false);
83
- }, 1500);
84
- });
85
- }, [])
79
+ useEffect(() => {
80
+ setShowLoading(true);
81
+ fetch('https://api.sampleapis.com/coffee/hot')
82
+ .then(data => data.json())
83
+ .then(items => {
84
+ setTimeout(() => {
85
+ setData(items);
86
+ setShowLoading(false);
87
+ }, 1500);
88
+ });
89
+ }, []);
86
90
 
87
- const searchCoffee = (title) => {
88
- setShowLoading(true);
89
- fetch('https://api.sampleapis.com/coffee/hot')
90
- .then(data => data.json())
91
- .then(items => setTimeout(() => {
92
- const filteredCoffee = items.filter(res => res.title.toLowerCase().includes(title.toLowerCase()));
93
- setShowLoading(false);
94
- if (filteredCoffee) { return filteredCoffee }
95
- return { ...title, filteredCoffee }
96
- }, 1500));
97
- };
91
+ const searchCoffee = (title) => {
92
+ setShowLoading(true);
93
+ fetch('https://api.sampleapis.com/coffee/hot')
94
+ .then(data => data.json())
95
+ .then(items => setTimeout(() => {
96
+ const filteredCoffee = items.filter(res => res.title.toLowerCase().includes(title.toLowerCase()));
97
+ setShowLoading(false);
98
+ if (filteredCoffee) { return filteredCoffee; }
99
+ return { ...title, filteredCoffee };
100
+ }, 1500));
101
+ };
98
102
 
99
- return (
100
- <Form.Autosuggest
101
- isLoading={showLoading}
102
- placeholder="This is placeholder"
103
- floatingLabel="This is floating label"
104
- screenReaderText="Loading..."
105
- onChange={searchCoffee}
106
- >
107
- {data.map((item, index) => <Form.AutosuggestOption key={index}>{item.title}</Form.AutosuggestOption>)}
108
- </Form.Autosuggest>
109
- );
110
- }
103
+ return (
104
+ <Form.Group>
105
+ <Form.Label>
106
+ <h4>Café API</h4>
107
+ </Form.Label>
108
+ <Form.Autosuggest
109
+ isLoading={showLoading}
110
+ placeholder="This is placeholder"
111
+ screenReaderText="Loading..."
112
+ onChange={searchCoffee}
113
+ >
114
+ {data.map((item, index) => <Form.AutosuggestOption key={index}>{item.title}</Form.AutosuggestOption>)}
115
+ </Form.Autosuggest>
116
+ </Form.Group>
117
+ );
118
+ };
111
119
  ```
@@ -6,6 +6,8 @@ import userEvent from '@testing-library/user-event';
6
6
  import { IntlProvider } from 'react-intl';
7
7
  import FormAutosuggest from '../FormAutosuggest';
8
8
  import FormAutosuggestOption from '../FormAutosuggestOption';
9
+ import FormGroup from '../FormGroup';
10
+ import FormLabel from '../FormLabel';
9
11
 
10
12
  function FormAutosuggestWrapper(props) {
11
13
  return (
@@ -31,6 +33,19 @@ function FormAutosuggestTestComponent(props) {
31
33
  );
32
34
  }
33
35
 
36
+ function FormAutosuggestLabelTestComponent() {
37
+ return (
38
+ <FormGroup>
39
+ <FormLabel data-testid="autosuggest-label">
40
+ <h3>Label</h3>
41
+ </FormLabel>
42
+ <FormAutosuggestWrapper>
43
+ <FormAutosuggestOption>Option</FormAutosuggestOption>
44
+ </FormAutosuggestWrapper>
45
+ </FormGroup>
46
+ );
47
+ }
48
+
34
49
  FormAutosuggestTestComponent.defaultProps = {
35
50
  onSelected: jest.fn(),
36
51
  onClick: jest.fn(),
@@ -112,6 +127,12 @@ describe('render behavior', () => {
112
127
 
113
128
  expect(getByText('3 options found')).toBeInTheDocument();
114
129
  });
130
+
131
+ it('associates labels with the input textbox', () => {
132
+ const { getByTestId } = render(<FormAutosuggestLabelTestComponent />);
133
+
134
+ expect(getByTestId('autosuggest-label').getAttribute('for')).toEqual(getByTestId('autosuggest-textbox-input').getAttribute('id'));
135
+ });
115
136
  });
116
137
 
117
138
  describe('controlled behavior', () => {
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
- import '@testing-library/jest-dom/extend-expect';
3
+ import '@testing-library/jest-dom';
4
4
  import userEvent from '@testing-library/user-event';
5
5
  import SelectableBox from '..';
6
6