@openedx/paragon 21.8.0 → 21.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DataTable/CollapsibleButtonGroup.js +1 -1
- package/dist/DataTable/CollapsibleButtonGroup.js.map +1 -1
- package/dist/DataTable/TableFilters.js +1 -1
- package/dist/DataTable/TableFilters.js.map +1 -1
- package/dist/DataTable/TableFooter.js +1 -1
- package/dist/DataTable/TableFooter.js.map +1 -1
- package/dist/DataTable/filters/CheckboxFilter.js +1 -1
- package/dist/DataTable/filters/CheckboxFilter.js.map +1 -1
- package/dist/DataTable/filters/DropdownFilter.js +1 -1
- package/dist/DataTable/filters/DropdownFilter.js.map +1 -1
- package/dist/DataTable/filters/MultiSelectDropdownFilter.js +1 -1
- package/dist/DataTable/filters/MultiSelectDropdownFilter.js.map +1 -1
- package/dist/DataTable/filters/TextFilter.js +1 -1
- package/dist/DataTable/filters/TextFilter.js.map +1 -1
- package/dist/DataTable/index.js +13 -13
- package/dist/DataTable/index.js.map +1 -1
- package/dist/Form/FormControl.js +12 -6
- package/dist/Form/FormControl.js.map +1 -1
- package/dist/ProductTour/Checkpoint.js +1 -0
- package/dist/ProductTour/Checkpoint.js.map +1 -1
- package/package.json +6 -2
- package/src/ActionRow/README.md +4 -2
- package/src/DataTable/CollapsibleButtonGroup.jsx +1 -1
- package/src/DataTable/TableFilters.jsx +1 -1
- package/src/DataTable/TableFooter.jsx +1 -5
- package/src/DataTable/filters/CheckboxFilter.jsx +1 -1
- package/src/DataTable/filters/DropdownFilter.jsx +1 -1
- package/src/DataTable/filters/MultiSelectDropdownFilter.jsx +1 -1
- package/src/DataTable/filters/TextFilter.jsx +1 -1
- package/src/DataTable/index.jsx +13 -13
- package/src/DataTable/tests/TableActions.test.jsx +5 -4
- package/src/Form/FormControl.jsx +7 -1
- package/src/Form/form-control.mdx +142 -1
- package/src/Form/tests/FormControl.test.jsx +40 -3
- package/src/ProductTour/Checkpoint.jsx +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormControl.js","names":["React","useCallback","useEffect","PropTypes","classNames","RBFormControl","useFormGroupContext","FormControlFeedback","FormControlDecoratorGroup","callAllHandlers","useHasValue","FormControl","forwardRef","_ref","ref","as","className","controlClassName","leadingElement","trailingElement","floatingLabel","autoResize","onChange","props","_objectWithoutProperties","_excluded","_useFormGroupContext","isInvalid","isValid","getControlProps","formGroupContext","_excluded2","inputRef","useRef","resolvedRef","size","hasValue","checkInputEventValue","defaultValue","value","handleResize","current","initialHeight","offsets","offsetHeight","clientHeight","style","height","scrollHeight","controlProps","_objectSpread","onBlur","handleOnChange","e","createElement","_extends","SIZE_CHOICES","Feedback","Description","propTypes","string","elementType","func","oneOfType","number","id","oneOf","node","plaintext","bool","defaultProps","undefined"],"sources":["../../src/Form/FormControl.jsx"],"sourcesContent":["import React, { useCallback, useEffect } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport RBFormControl from 'react-bootstrap/FormControl';\nimport { useFormGroupContext } from './FormGroupContext';\nimport FormControlFeedback from './FormControlFeedback';\nimport FormControlDecoratorGroup from './FormControlDecoratorGroup';\n\nimport { callAllHandlers, useHasValue } from './fieldUtils';\n\nconst FormControl = React.forwardRef(({\n as,\n className,\n controlClassName,\n leadingElement,\n trailingElement,\n floatingLabel,\n autoResize,\n onChange,\n ...props\n}, ref) => {\n const {\n isInvalid,\n isValid,\n getControlProps,\n ...formGroupContext\n } = useFormGroupContext();\n const inputRef = React.useRef();\n const resolvedRef = ref || inputRef;\n const size = props.size || formGroupContext.size;\n\n const [hasValue, checkInputEventValue] = useHasValue({\n defaultValue: props.defaultValue,\n value: props.value,\n });\n\n const handleResize = useCallback(() => {\n if (as === 'textarea' && autoResize) {\n if (!resolvedRef.current.initialHeight && !resolvedRef.current.offsets) {\n resolvedRef.current.initialHeight = resolvedRef.current.offsetHeight;\n resolvedRef.current.offsets = resolvedRef.current.offsetHeight - resolvedRef.current.clientHeight;\n }\n resolvedRef.current.style.height = `${resolvedRef.current.initialHeight}px`;\n resolvedRef.current.style.height = `${resolvedRef.current.scrollHeight + resolvedRef.current.offsets}px`;\n }\n }, [as, autoResize, resolvedRef]);\n\n useEffect(() => {\n handleResize();\n }, [handleResize]);\n\n const controlProps = getControlProps({\n ...props,\n // eslint-disable-next-line react/prop-types\n onBlur: callAllHandlers(checkInputEventValue, props.onBlur),\n });\n\n const handleOnChange = (e) => {\n handleResize();\n if (onChange) {\n onChange(e);\n }\n };\n\n return (\n <FormControlDecoratorGroup\n size={size}\n leadingElement={leadingElement}\n trailingElement={trailingElement}\n floatingLabel={floatingLabel}\n className={className}\n >\n <RBFormControl\n as={as}\n ref={resolvedRef}\n size={size}\n isInvalid={isInvalid}\n isValid={isValid}\n className={classNames(controlClassName, {\n 'has-value': hasValue,\n })}\n onChange={handleOnChange}\n {...controlProps}\n />\n </FormControlDecoratorGroup>\n );\n});\n\nconst SIZE_CHOICES = ['sm', 'lg'];\n\nFormControl.Feedback = FormControlFeedback;\nFormControl.Description = FormControlFeedback;\n\nFormControl.propTypes = {\n /** Specifies class name to append to the base element. */\n className: PropTypes.string,\n /** Specifies base element for the control component. */\n as: PropTypes.elementType,\n /** Specifies function that is triggered on input value change. */\n onChange: PropTypes.func,\n /** Specifies default value of the input component. */\n defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n /** Specifies current value of the input component. */\n value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n /** Specifies id of the control component. */\n id: PropTypes.string,\n /** Specifies class name for the control component. */\n controlClassName: PropTypes.string,\n /** Specifies size for the control component. */\n size: PropTypes.oneOf(SIZE_CHOICES),\n /** Specifies leading element to display for the input component. */\n leadingElement: PropTypes.node,\n /** Specifies trailing element to display for the input component. */\n trailingElement: PropTypes.node,\n /** Specifies floating label to display for the input component. */\n floatingLabel: PropTypes.node,\n /** Specifies whether to render input as plain text. */\n plaintext: PropTypes.bool,\n /** Specifies whether to display control in valid state, this affects styling. */\n isValid: PropTypes.bool,\n /** Specifies whether to display control in invalid state, this affects styling. */\n isInvalid: PropTypes.bool,\n /** Only for `as=\"textarea\"`. Specifies whether the input can be resized according to the height of content. */\n autoResize: PropTypes.bool,\n};\n\nFormControl.defaultProps = {\n as: 'input',\n className: undefined,\n id: undefined,\n controlClassName: undefined,\n onChange: undefined,\n defaultValue: undefined,\n value: undefined,\n size: undefined,\n leadingElement: undefined,\n trailingElement: undefined,\n floatingLabel: undefined,\n plaintext: false,\n isValid: undefined,\n isInvalid: undefined,\n autoResize: false,\n};\n\nexport default FormControl;\n"],"mappings":";;;;;;;;;;AAAA,OAAOA,KAAK,IAAIC,WAAW,EAAEC,SAAS,QAAQ,OAAO;AACrD,OAAOC,SAAS,MAAM,YAAY;AAClC,OAAOC,UAAU,MAAM,YAAY;AACnC,OAAOC,aAAa,MAAM,6BAA6B;AACvD,SAASC,mBAAmB,QAAQ,oBAAoB;AACxD,OAAOC,mBAAmB,MAAM,uBAAuB;AACvD,OAAOC,yBAAyB,MAAM,6BAA6B;AAEnE,SAASC,eAAe,EAAEC,WAAW,QAAQ,cAAc;AAE3D,MAAMC,WAAW,
|
|
1
|
+
{"version":3,"file":"FormControl.js","names":["React","useCallback","useEffect","PropTypes","classNames","RBFormControl","IMaskInput","useFormGroupContext","FormControlFeedback","FormControlDecoratorGroup","callAllHandlers","useHasValue","FormControl","forwardRef","_ref","ref","as","className","controlClassName","leadingElement","trailingElement","floatingLabel","autoResize","onChange","inputMask","props","_objectWithoutProperties","_excluded","_useFormGroupContext","isInvalid","isValid","getControlProps","formGroupContext","_excluded2","inputRef","useRef","resolvedRef","size","hasValue","checkInputEventValue","defaultValue","value","handleResize","current","initialHeight","offsets","offsetHeight","clientHeight","style","height","scrollHeight","controlProps","_objectSpread","onBlur","handleOnChange","e","createElement","_extends","mask","SIZE_CHOICES","Feedback","Description","propTypes","string","elementType","func","oneOfType","number","id","oneOf","node","plaintext","bool","defaultProps","undefined"],"sources":["../../src/Form/FormControl.jsx"],"sourcesContent":["import React, { useCallback, useEffect } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport RBFormControl from 'react-bootstrap/FormControl';\nimport { IMaskInput } from 'react-imask';\nimport { useFormGroupContext } from './FormGroupContext';\nimport FormControlFeedback from './FormControlFeedback';\nimport FormControlDecoratorGroup from './FormControlDecoratorGroup';\n\nimport { callAllHandlers, useHasValue } from './fieldUtils';\n\nconst FormControl = React.forwardRef(({\n as,\n className,\n controlClassName,\n leadingElement,\n trailingElement,\n floatingLabel,\n autoResize,\n onChange,\n inputMask,\n ...props\n}, ref) => {\n const {\n isInvalid,\n isValid,\n getControlProps,\n ...formGroupContext\n } = useFormGroupContext();\n const inputRef = React.useRef();\n const resolvedRef = ref || inputRef;\n const size = props.size || formGroupContext.size;\n\n const [hasValue, checkInputEventValue] = useHasValue({\n defaultValue: props.defaultValue,\n value: props.value,\n });\n\n const handleResize = useCallback(() => {\n if (as === 'textarea' && autoResize) {\n if (!resolvedRef.current.initialHeight && !resolvedRef.current.offsets) {\n resolvedRef.current.initialHeight = resolvedRef.current.offsetHeight;\n resolvedRef.current.offsets = resolvedRef.current.offsetHeight - resolvedRef.current.clientHeight;\n }\n resolvedRef.current.style.height = `${resolvedRef.current.initialHeight}px`;\n resolvedRef.current.style.height = `${resolvedRef.current.scrollHeight + resolvedRef.current.offsets}px`;\n }\n }, [as, autoResize, resolvedRef]);\n\n useEffect(() => {\n handleResize();\n }, [handleResize]);\n\n const controlProps = getControlProps({\n ...props,\n // eslint-disable-next-line react/prop-types\n onBlur: callAllHandlers(checkInputEventValue, props.onBlur),\n });\n\n const handleOnChange = (e) => {\n handleResize();\n if (onChange) {\n onChange(e);\n }\n };\n\n return (\n <FormControlDecoratorGroup\n size={size}\n leadingElement={leadingElement}\n trailingElement={trailingElement}\n floatingLabel={floatingLabel}\n className={className}\n >\n <RBFormControl\n as={inputMask ? IMaskInput : as}\n ref={resolvedRef}\n size={size}\n isInvalid={isInvalid}\n isValid={isValid}\n className={classNames(controlClassName, {\n 'has-value': hasValue,\n })}\n onChange={handleOnChange}\n mask={inputMask}\n {...controlProps}\n />\n </FormControlDecoratorGroup>\n );\n});\n\nconst SIZE_CHOICES = ['sm', 'lg'];\n\nFormControl.Feedback = FormControlFeedback;\nFormControl.Description = FormControlFeedback;\n\nFormControl.propTypes = {\n /** Specifies class name to append to the base element. */\n className: PropTypes.string,\n /** Specifies base element for the control component. */\n as: PropTypes.elementType,\n /** Specifies function that is triggered on input value change. */\n onChange: PropTypes.func,\n /** Specifies default value of the input component. */\n defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n /** Specifies current value of the input component. */\n value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n /** Specifies id of the control component. */\n id: PropTypes.string,\n /** Specifies class name for the control component. */\n controlClassName: PropTypes.string,\n /** Specifies size for the control component. */\n size: PropTypes.oneOf(SIZE_CHOICES),\n /** Specifies leading element to display for the input component. */\n leadingElement: PropTypes.node,\n /** Specifies trailing element to display for the input component. */\n trailingElement: PropTypes.node,\n /** Specifies floating label to display for the input component. */\n floatingLabel: PropTypes.node,\n /** Specifies whether to render input as plain text. */\n plaintext: PropTypes.bool,\n /** Specifies whether to display control in valid state, this affects styling. */\n isValid: PropTypes.bool,\n /** Specifies whether to display control in invalid state, this affects styling. */\n isInvalid: PropTypes.bool,\n /** Only for `as=\"textarea\"`. Specifies whether the input can be resized according to the height of content. */\n autoResize: PropTypes.bool,\n /** Specifies what format to use for the input mask. */\n inputMask: PropTypes.string,\n};\n\nFormControl.defaultProps = {\n as: 'input',\n className: undefined,\n id: undefined,\n controlClassName: undefined,\n onChange: undefined,\n defaultValue: undefined,\n value: undefined,\n size: undefined,\n leadingElement: undefined,\n trailingElement: undefined,\n floatingLabel: undefined,\n plaintext: false,\n isValid: undefined,\n isInvalid: undefined,\n autoResize: false,\n inputMask: undefined,\n};\n\nexport default FormControl;\n"],"mappings":";;;;;;;;;;AAAA,OAAOA,KAAK,IAAIC,WAAW,EAAEC,SAAS,QAAQ,OAAO;AACrD,OAAOC,SAAS,MAAM,YAAY;AAClC,OAAOC,UAAU,MAAM,YAAY;AACnC,OAAOC,aAAa,MAAM,6BAA6B;AACvD,SAASC,UAAU,QAAQ,aAAa;AACxC,SAASC,mBAAmB,QAAQ,oBAAoB;AACxD,OAAOC,mBAAmB,MAAM,uBAAuB;AACvD,OAAOC,yBAAyB,MAAM,6BAA6B;AAEnE,SAASC,eAAe,EAAEC,WAAW,QAAQ,cAAc;AAE3D,MAAMC,WAAW,gBAAGZ,KAAK,CAACa,UAAU,CAAC,CAAAC,IAAA,EAWlCC,GAAG,KAAK;EAAA,IAX2B;MACpCC,EAAE;MACFC,SAAS;MACTC,gBAAgB;MAChBC,cAAc;MACdC,eAAe;MACfC,aAAa;MACbC,UAAU;MACVC,QAAQ;MACRC;IAEF,CAAC,GAAAV,IAAA;IADIW,KAAK,GAAAC,wBAAA,CAAAZ,IAAA,EAAAa,SAAA;EAER,MAAAC,oBAAA,GAKIrB,mBAAmB,CAAC,CAAC;IALnB;MACJsB,SAAS;MACTC,OAAO;MACPC;IAEF,CAAC,GAAAH,oBAAA;IADII,gBAAgB,GAAAN,wBAAA,CAAAE,oBAAA,EAAAK,UAAA;EAErB,MAAMC,QAAQ,GAAGlC,KAAK,CAACmC,MAAM,CAAC,CAAC;EAC/B,MAAMC,WAAW,GAAGrB,GAAG,IAAImB,QAAQ;EACnC,MAAMG,IAAI,GAAGZ,KAAK,CAACY,IAAI,IAAIL,gBAAgB,CAACK,IAAI;EAEhD,MAAM,CAACC,QAAQ,EAAEC,oBAAoB,CAAC,GAAG5B,WAAW,CAAC;IACnD6B,YAAY,EAAEf,KAAK,CAACe,YAAY;IAChCC,KAAK,EAAEhB,KAAK,CAACgB;EACf,CAAC,CAAC;EAEF,MAAMC,YAAY,GAAGzC,WAAW,CAAC,MAAM;IACrC,IAAIe,EAAE,KAAK,UAAU,IAAIM,UAAU,EAAE;MACnC,IAAI,CAACc,WAAW,CAACO,OAAO,CAACC,aAAa,IAAI,CAACR,WAAW,CAACO,OAAO,CAACE,OAAO,EAAE;QACtET,WAAW,CAACO,OAAO,CAACC,aAAa,GAAGR,WAAW,CAACO,OAAO,CAACG,YAAY;QACpEV,WAAW,CAACO,OAAO,CAACE,OAAO,GAAGT,WAAW,CAACO,OAAO,CAACG,YAAY,GAAGV,WAAW,CAACO,OAAO,CAACI,YAAY;MACnG;MACAX,WAAW,CAACO,OAAO,CAACK,KAAK,CAACC,MAAM,GAAI,GAAEb,WAAW,CAACO,OAAO,CAACC,aAAc,IAAG;MAC3ER,WAAW,CAACO,OAAO,CAACK,KAAK,CAACC,MAAM,GAAI,GAAEb,WAAW,CAACO,OAAO,CAACO,YAAY,GAAGd,WAAW,CAACO,OAAO,CAACE,OAAQ,IAAG;IAC1G;EACF,CAAC,EAAE,CAAC7B,EAAE,EAAEM,UAAU,EAAEc,WAAW,CAAC,CAAC;EAEjClC,SAAS,CAAC,MAAM;IACdwC,YAAY,CAAC,CAAC;EAChB,CAAC,EAAE,CAACA,YAAY,CAAC,CAAC;EAElB,MAAMS,YAAY,GAAGpB,eAAe,CAAAqB,aAAA,CAAAA,aAAA,KAC/B3B,KAAK;IACR;IACA4B,MAAM,EAAE3C,eAAe,CAAC6B,oBAAoB,EAAEd,KAAK,CAAC4B,MAAM;EAAC,EAC5D,CAAC;EAEF,MAAMC,cAAc,GAAIC,CAAC,IAAK;IAC5Bb,YAAY,CAAC,CAAC;IACd,IAAInB,QAAQ,EAAE;MACZA,QAAQ,CAACgC,CAAC,CAAC;IACb;EACF,CAAC;EAED,oBACEvD,KAAA,CAAAwD,aAAA,CAAC/C,yBAAyB;IACxB4B,IAAI,EAAEA,IAAK;IACXlB,cAAc,EAAEA,cAAe;IAC/BC,eAAe,EAAEA,eAAgB;IACjCC,aAAa,EAAEA,aAAc;IAC7BJ,SAAS,EAAEA;EAAU,gBAErBjB,KAAA,CAAAwD,aAAA,CAACnD,aAAa,EAAAoD,QAAA;IACZzC,EAAE,EAAEQ,SAAS,GAAGlB,UAAU,GAAGU,EAAG;IAChCD,GAAG,EAAEqB,WAAY;IACjBC,IAAI,EAAEA,IAAK;IACXR,SAAS,EAAEA,SAAU;IACrBC,OAAO,EAAEA,OAAQ;IACjBb,SAAS,EAAEb,UAAU,CAACc,gBAAgB,EAAE;MACtC,WAAW,EAAEoB;IACf,CAAC,CAAE;IACHf,QAAQ,EAAE+B,cAAe;IACzBI,IAAI,EAAElC;EAAU,GACZ2B,YAAY,CACjB,CACwB,CAAC;AAEhC,CAAC,CAAC;AAEF,MAAMQ,YAAY,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC;AAEjC/C,WAAW,CAACgD,QAAQ,GAAGpD,mBAAmB;AAC1CI,WAAW,CAACiD,WAAW,GAAGrD,mBAAmB;AAE7CI,WAAW,CAACkD,SAAS,GAAG;EACtB;EACA7C,SAAS,EAAEd,SAAS,CAAC4D,MAAM;EAC3B;EACA/C,EAAE,EAAEb,SAAS,CAAC6D,WAAW;EACzB;EACAzC,QAAQ,EAAEpB,SAAS,CAAC8D,IAAI;EACxB;EACAzB,YAAY,EAAErC,SAAS,CAAC+D,SAAS,CAAC,CAAC/D,SAAS,CAAC4D,MAAM,EAAE5D,SAAS,CAACgE,MAAM,CAAC,CAAC;EACvE;EACA1B,KAAK,EAAEtC,SAAS,CAAC+D,SAAS,CAAC,CAAC/D,SAAS,CAAC4D,MAAM,EAAE5D,SAAS,CAACgE,MAAM,CAAC,CAAC;EAChE;EACAC,EAAE,EAAEjE,SAAS,CAAC4D,MAAM;EACpB;EACA7C,gBAAgB,EAAEf,SAAS,CAAC4D,MAAM;EAClC;EACA1B,IAAI,EAAElC,SAAS,CAACkE,KAAK,CAACV,YAAY,CAAC;EACnC;EACAxC,cAAc,EAAEhB,SAAS,CAACmE,IAAI;EAC9B;EACAlD,eAAe,EAAEjB,SAAS,CAACmE,IAAI;EAC/B;EACAjD,aAAa,EAAElB,SAAS,CAACmE,IAAI;EAC7B;EACAC,SAAS,EAAEpE,SAAS,CAACqE,IAAI;EACzB;EACA1C,OAAO,EAAE3B,SAAS,CAACqE,IAAI;EACvB;EACA3C,SAAS,EAAE1B,SAAS,CAACqE,IAAI;EACzB;EACAlD,UAAU,EAAEnB,SAAS,CAACqE,IAAI;EAC1B;EACAhD,SAAS,EAAErB,SAAS,CAAC4D;AACvB,CAAC;AAEDnD,WAAW,CAAC6D,YAAY,GAAG;EACzBzD,EAAE,EAAE,OAAO;EACXC,SAAS,EAAEyD,SAAS;EACpBN,EAAE,EAAEM,SAAS;EACbxD,gBAAgB,EAAEwD,SAAS;EAC3BnD,QAAQ,EAAEmD,SAAS;EACnBlC,YAAY,EAAEkC,SAAS;EACvBjC,KAAK,EAAEiC,SAAS;EAChBrC,IAAI,EAAEqC,SAAS;EACfvD,cAAc,EAAEuD,SAAS;EACzBtD,eAAe,EAAEsD,SAAS;EAC1BrD,aAAa,EAAEqD,SAAS;EACxBH,SAAS,EAAE,KAAK;EAChBzC,OAAO,EAAE4C,SAAS;EAClB7C,SAAS,EAAE6C,SAAS;EACpBpD,UAAU,EAAE,KAAK;EACjBE,SAAS,EAAEkD;AACb,CAAC;AAED,eAAe9D,WAAW"}
|
|
@@ -33,6 +33,7 @@ const Checkpoint = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
33
33
|
// Use the Popper library to translate the Checkpoint to its target's coordinates
|
|
34
34
|
const checkpointPopper = createPopper(targetElement, checkpoint, {
|
|
35
35
|
placement: isMobile ? 'top' : placement,
|
|
36
|
+
strategy: 'fixed',
|
|
36
37
|
modifiers: [{
|
|
37
38
|
name: 'arrow',
|
|
38
39
|
options: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkpoint.js","names":["React","useEffect","useState","useMediaQuery","PropTypes","createPopper","FormattedMessage","breakpoints","CheckpointActionRow","CheckpointBody","CheckpointBreadcrumbs","CheckpointTitle","Checkpoint","forwardRef","_ref","ref","body","index","placement","target","title","totalCheckpoints","props","_objectWithoutProperties","_excluded","checkpointVisible","setCheckpointVisible","isMobile","maxWidth","small","targetElement","document","querySelector","checkpoint","checkpointPopper","modifiers","name","options","padding","offset","tetherOffset","forceUpdate","targetOffset","getBoundingClientRect","top","bottom","global","innerHeight","includes","scrollTo","behavior","button","focus","isLastCheckpoint","isOnlyCheckpoint","createElement","id","className","role","style","visibility","pointerEvents","defaultMessage","value","step","description","currentIndex","_extends","defaultProps","advanceButtonText","dismissButtonText","endButtonText","showDismissButton","undefined","propTypes","node","number","isRequired","onAdvance","func","onDismiss","onEnd","oneOf","string","bool"],"sources":["../../src/ProductTour/Checkpoint.jsx"],"sourcesContent":["import React, { useEffect, useState } from 'react';\nimport { useMediaQuery } from 'react-responsive';\nimport PropTypes from 'prop-types';\nimport { createPopper } from '@popperjs/core';\nimport { FormattedMessage } from 'react-intl';\n\nimport breakpoints from '../utils/breakpoints';\n\nimport CheckpointActionRow from './CheckpointActionRow';\nimport CheckpointBody from './CheckpointBody';\nimport CheckpointBreadcrumbs from './CheckpointBreadcrumbs';\nimport CheckpointTitle from './CheckpointTitle';\n\nconst Checkpoint = React.forwardRef(({\n body,\n index,\n placement,\n target,\n title,\n totalCheckpoints,\n ...props\n}, ref) => {\n const [checkpointVisible, setCheckpointVisible] = useState(false);\n const isMobile = useMediaQuery({ maxWidth: breakpoints.small.maxWidth });\n\n useEffect(() => {\n const targetElement = document.querySelector(target);\n const checkpoint = document.querySelector('#pgn__checkpoint');\n if (targetElement && checkpoint) {\n // Use the Popper library to translate the Checkpoint to its target's coordinates\n const checkpointPopper = createPopper(targetElement, checkpoint, {\n placement: isMobile ? 'top' : placement,\n modifiers: [\n {\n name: 'arrow',\n options: {\n padding: 25,\n },\n },\n {\n name: 'offset',\n options: {\n offset: [0, 20],\n },\n },\n {\n name: 'preventOverflow',\n options: {\n padding: 20,\n tetherOffset: 35,\n },\n },\n ],\n });\n setCheckpointVisible(true);\n if (checkpointPopper) {\n checkpointPopper.forceUpdate();\n }\n }\n }, [target, isMobile, placement]);\n\n useEffect(() => {\n if (checkpointVisible) {\n // Scroll the Checkpoint into view once its rendered\n const targetElement = document.querySelector(target);\n let targetOffset = targetElement.getBoundingClientRect().top;\n if ((targetOffset < 0) || (targetElement.getBoundingClientRect().bottom > global.innerHeight)) {\n if (placement.includes('top')) {\n if (targetOffset < 0) {\n targetOffset *= -1;\n }\n targetOffset -= 280;\n } else {\n targetOffset -= 80;\n }\n\n global.scrollTo({\n top: targetOffset, behavior: 'smooth',\n });\n }\n\n const button = document.querySelector('.pgn__checkpoint-button_advance');\n button.focus();\n }\n }, [target, checkpointVisible, placement]);\n\n const isLastCheckpoint = index + 1 === totalCheckpoints;\n const isOnlyCheckpoint = totalCheckpoints === 1;\n\n return (\n <div\n id=\"pgn__checkpoint\"\n className=\"pgn__checkpoint\"\n aria-labelledby=\"pgn__checkpoint-title\"\n ref={ref}\n role=\"dialog\"\n style={{ visibility: checkpointVisible ? 'visible' : 'hidden', pointerEvents: checkpointVisible ? 'auto' : 'none' }}\n >\n <span className=\"sr-only\">\n <FormattedMessage\n id=\"pgn.ProductTour.Checkpoint.position-text\"\n defaultMessage=\"Top of step {step}\"\n value={{ step: index + 1 }}\n description=\"Screen-reader message to indicate the user's position in a sequence of checkpoints.\"\n />\n </span>\n {(title || !isOnlyCheckpoint) && (\n <div className=\"pgn__checkpoint-header\">\n <CheckpointTitle>{title}</CheckpointTitle>\n <CheckpointBreadcrumbs currentIndex={index} totalCheckpoints={totalCheckpoints} />\n </div>\n )}\n <CheckpointBody>{body}</CheckpointBody>\n <CheckpointActionRow\n isLastCheckpoint={isLastCheckpoint}\n index={index}\n {...props}\n />\n <div id=\"pgn__checkpoint-arrow\" data-popper-arrow />\n {/* This text is not translated due to Paragon's lack of i18n support */}\n <span className=\"sr-only\">Bottom of step {index + 1}</span>\n </div>\n );\n});\n\nCheckpoint.defaultProps = {\n advanceButtonText: null,\n body: null,\n dismissButtonText: null,\n endButtonText: null,\n placement: 'top',\n title: null,\n showDismissButton: undefined,\n};\n\nCheckpoint.propTypes = {\n /** The text displayed on the button used to advance the tour for the given Checkpoint. */\n advanceButtonText: PropTypes.node,\n /** The text displayed in the body of the Checkpoint */\n body: PropTypes.node,\n /** The text displayed on the button used to dismiss the tour for the given Checkpoint. */\n dismissButtonText: PropTypes.node,\n /** The text displayed on the button used to end the tour for the given Checkpoint. */\n endButtonText: PropTypes.node,\n /** The current index of the given Checkpoint */\n index: PropTypes.number.isRequired,\n /** A function that runs when triggering the `onClick` event of the advance\n * button for the given Checkpoint. */\n onAdvance: PropTypes.func.isRequired,\n /** A function that runs when triggering the `onClick` event of the dismiss\n * button for the given Checkpoint. */\n onDismiss: PropTypes.func.isRequired,\n /** A function that runs when triggering the `onClick` event of the advance\n * button if the given Checkpoint is the only or last Checkpoint in a tour. */\n onEnd: PropTypes.func.isRequired,\n /** A string that dictates the alignment of the Checkpoint around its target. */\n placement: PropTypes.oneOf([\n 'top', 'top-start', 'top-end', 'right-start', 'right', 'right-end',\n 'left-start', 'left', 'left-end', 'bottom', 'bottom-start', 'bottom-end',\n ]),\n /** The CSS selector for the Checkpoint's desired target. */\n target: PropTypes.string.isRequired,\n /** The text displayed in the title of the Checkpoint */\n title: PropTypes.node,\n /** The total number of Checkpoints in a tour */\n totalCheckpoints: PropTypes.number.isRequired,\n /** Enforces visibility of the dismiss button under all circumstances */\n showDismissButton: PropTypes.bool,\n};\n\nexport default Checkpoint;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Checkpoint.js","names":["React","useEffect","useState","useMediaQuery","PropTypes","createPopper","FormattedMessage","breakpoints","CheckpointActionRow","CheckpointBody","CheckpointBreadcrumbs","CheckpointTitle","Checkpoint","forwardRef","_ref","ref","body","index","placement","target","title","totalCheckpoints","props","_objectWithoutProperties","_excluded","checkpointVisible","setCheckpointVisible","isMobile","maxWidth","small","targetElement","document","querySelector","checkpoint","checkpointPopper","strategy","modifiers","name","options","padding","offset","tetherOffset","forceUpdate","targetOffset","getBoundingClientRect","top","bottom","global","innerHeight","includes","scrollTo","behavior","button","focus","isLastCheckpoint","isOnlyCheckpoint","createElement","id","className","role","style","visibility","pointerEvents","defaultMessage","value","step","description","currentIndex","_extends","defaultProps","advanceButtonText","dismissButtonText","endButtonText","showDismissButton","undefined","propTypes","node","number","isRequired","onAdvance","func","onDismiss","onEnd","oneOf","string","bool"],"sources":["../../src/ProductTour/Checkpoint.jsx"],"sourcesContent":["import React, { useEffect, useState } from 'react';\nimport { useMediaQuery } from 'react-responsive';\nimport PropTypes from 'prop-types';\nimport { createPopper } from '@popperjs/core';\nimport { FormattedMessage } from 'react-intl';\n\nimport breakpoints from '../utils/breakpoints';\n\nimport CheckpointActionRow from './CheckpointActionRow';\nimport CheckpointBody from './CheckpointBody';\nimport CheckpointBreadcrumbs from './CheckpointBreadcrumbs';\nimport CheckpointTitle from './CheckpointTitle';\n\nconst Checkpoint = React.forwardRef(({\n body,\n index,\n placement,\n target,\n title,\n totalCheckpoints,\n ...props\n}, ref) => {\n const [checkpointVisible, setCheckpointVisible] = useState(false);\n const isMobile = useMediaQuery({ maxWidth: breakpoints.small.maxWidth });\n\n useEffect(() => {\n const targetElement = document.querySelector(target);\n const checkpoint = document.querySelector('#pgn__checkpoint');\n if (targetElement && checkpoint) {\n // Use the Popper library to translate the Checkpoint to its target's coordinates\n const checkpointPopper = createPopper(targetElement, checkpoint, {\n placement: isMobile ? 'top' : placement,\n strategy: 'fixed',\n modifiers: [\n {\n name: 'arrow',\n options: {\n padding: 25,\n },\n },\n {\n name: 'offset',\n options: {\n offset: [0, 20],\n },\n },\n {\n name: 'preventOverflow',\n options: {\n padding: 20,\n tetherOffset: 35,\n },\n },\n ],\n });\n setCheckpointVisible(true);\n if (checkpointPopper) {\n checkpointPopper.forceUpdate();\n }\n }\n }, [target, isMobile, placement]);\n\n useEffect(() => {\n if (checkpointVisible) {\n // Scroll the Checkpoint into view once its rendered\n const targetElement = document.querySelector(target);\n let targetOffset = targetElement.getBoundingClientRect().top;\n if ((targetOffset < 0) || (targetElement.getBoundingClientRect().bottom > global.innerHeight)) {\n if (placement.includes('top')) {\n if (targetOffset < 0) {\n targetOffset *= -1;\n }\n targetOffset -= 280;\n } else {\n targetOffset -= 80;\n }\n\n global.scrollTo({\n top: targetOffset, behavior: 'smooth',\n });\n }\n\n const button = document.querySelector('.pgn__checkpoint-button_advance');\n button.focus();\n }\n }, [target, checkpointVisible, placement]);\n\n const isLastCheckpoint = index + 1 === totalCheckpoints;\n const isOnlyCheckpoint = totalCheckpoints === 1;\n\n return (\n <div\n id=\"pgn__checkpoint\"\n className=\"pgn__checkpoint\"\n aria-labelledby=\"pgn__checkpoint-title\"\n ref={ref}\n role=\"dialog\"\n style={{ visibility: checkpointVisible ? 'visible' : 'hidden', pointerEvents: checkpointVisible ? 'auto' : 'none' }}\n >\n <span className=\"sr-only\">\n <FormattedMessage\n id=\"pgn.ProductTour.Checkpoint.position-text\"\n defaultMessage=\"Top of step {step}\"\n value={{ step: index + 1 }}\n description=\"Screen-reader message to indicate the user's position in a sequence of checkpoints.\"\n />\n </span>\n {(title || !isOnlyCheckpoint) && (\n <div className=\"pgn__checkpoint-header\">\n <CheckpointTitle>{title}</CheckpointTitle>\n <CheckpointBreadcrumbs currentIndex={index} totalCheckpoints={totalCheckpoints} />\n </div>\n )}\n <CheckpointBody>{body}</CheckpointBody>\n <CheckpointActionRow\n isLastCheckpoint={isLastCheckpoint}\n index={index}\n {...props}\n />\n <div id=\"pgn__checkpoint-arrow\" data-popper-arrow />\n {/* This text is not translated due to Paragon's lack of i18n support */}\n <span className=\"sr-only\">Bottom of step {index + 1}</span>\n </div>\n );\n});\n\nCheckpoint.defaultProps = {\n advanceButtonText: null,\n body: null,\n dismissButtonText: null,\n endButtonText: null,\n placement: 'top',\n title: null,\n showDismissButton: undefined,\n};\n\nCheckpoint.propTypes = {\n /** The text displayed on the button used to advance the tour for the given Checkpoint. */\n advanceButtonText: PropTypes.node,\n /** The text displayed in the body of the Checkpoint */\n body: PropTypes.node,\n /** The text displayed on the button used to dismiss the tour for the given Checkpoint. */\n dismissButtonText: PropTypes.node,\n /** The text displayed on the button used to end the tour for the given Checkpoint. */\n endButtonText: PropTypes.node,\n /** The current index of the given Checkpoint */\n index: PropTypes.number.isRequired,\n /** A function that runs when triggering the `onClick` event of the advance\n * button for the given Checkpoint. */\n onAdvance: PropTypes.func.isRequired,\n /** A function that runs when triggering the `onClick` event of the dismiss\n * button for the given Checkpoint. */\n onDismiss: PropTypes.func.isRequired,\n /** A function that runs when triggering the `onClick` event of the advance\n * button if the given Checkpoint is the only or last Checkpoint in a tour. */\n onEnd: PropTypes.func.isRequired,\n /** A string that dictates the alignment of the Checkpoint around its target. */\n placement: PropTypes.oneOf([\n 'top', 'top-start', 'top-end', 'right-start', 'right', 'right-end',\n 'left-start', 'left', 'left-end', 'bottom', 'bottom-start', 'bottom-end',\n ]),\n /** The CSS selector for the Checkpoint's desired target. */\n target: PropTypes.string.isRequired,\n /** The text displayed in the title of the Checkpoint */\n title: PropTypes.node,\n /** The total number of Checkpoints in a tour */\n totalCheckpoints: PropTypes.number.isRequired,\n /** Enforces visibility of the dismiss button under all circumstances */\n showDismissButton: PropTypes.bool,\n};\n\nexport default Checkpoint;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openedx/paragon",
|
|
3
|
-
"version": "21.
|
|
3
|
+
"version": "21.9.1",
|
|
4
4
|
"description": "Accessible, responsive UI component library based on Bootstrap.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"react-colorful": "^5.6.1",
|
|
69
69
|
"react-dropzone": "^14.2.1",
|
|
70
70
|
"react-focus-on": "^3.5.4",
|
|
71
|
+
"react-imask": "^7.1.3",
|
|
71
72
|
"react-loading-skeleton": "^3.1.0",
|
|
72
73
|
"react-popper": "^2.2.5",
|
|
73
74
|
"react-proptype-conditional-require": "^1.0.4",
|
|
@@ -190,5 +191,8 @@
|
|
|
190
191
|
"www",
|
|
191
192
|
"icons",
|
|
192
193
|
"dependent-usage-analyzer"
|
|
193
|
-
]
|
|
194
|
+
],
|
|
195
|
+
"overrides": {
|
|
196
|
+
"@testing-library/dom": "9.3.3"
|
|
197
|
+
}
|
|
194
198
|
}
|
package/src/ActionRow/README.md
CHANGED
|
@@ -17,6 +17,7 @@ A layout utility for the common use case of aligning buttons, links or text
|
|
|
17
17
|
in a row in a control bar or nav.
|
|
18
18
|
|
|
19
19
|
ActionRow assumes that its last child is the primary action and lays out actions so that the last item is in a primary location. If horizontal, the primary action sits on the right. If stacked, the primary action sits at the top of the stack (this is done via `flex-direction: column-reverse;`).
|
|
20
|
+
|
|
20
21
|
## Basic Usage
|
|
21
22
|
|
|
22
23
|
```jsx live
|
|
@@ -36,7 +37,9 @@ ActionRow can also be used with a helper component ``ActionRow.Spacer`` to inser
|
|
|
36
37
|
|
|
37
38
|
```jsx live
|
|
38
39
|
<ActionRow>
|
|
39
|
-
<Form.Checkbox className="flex-column flex-sm-row">
|
|
40
|
+
<Form.Checkbox className="flex-column flex-sm-row">
|
|
41
|
+
Don't ask me again.
|
|
42
|
+
</Form.Checkbox>
|
|
40
43
|
<ActionRow.Spacer />
|
|
41
44
|
<Button variant="tertiary">
|
|
42
45
|
Cancel
|
|
@@ -49,7 +52,6 @@ ActionRow can also be used with a helper component ``ActionRow.Spacer`` to inser
|
|
|
49
52
|
|
|
50
53
|
## Stacked Usage
|
|
51
54
|
|
|
52
|
-
|
|
53
55
|
```jsx live
|
|
54
56
|
<ActionRow isStacked>
|
|
55
57
|
<p className="x-small">
|
|
@@ -102,7 +102,7 @@ CollapsibleButtonGroup.propTypes = {
|
|
|
102
102
|
className: PropTypes.string,
|
|
103
103
|
/** Array of action objects, containing a component and their callback args */
|
|
104
104
|
actions: PropTypes.arrayOf(PropTypes.shape({
|
|
105
|
-
component: PropTypes.oneOfType([PropTypes.
|
|
105
|
+
component: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]).isRequired,
|
|
106
106
|
args: PropTypes.shape({}),
|
|
107
107
|
})).isRequired,
|
|
108
108
|
};
|
|
@@ -30,7 +30,7 @@ TableFilters.defaultProps = {
|
|
|
30
30
|
|
|
31
31
|
TableFilters.propTypes = {
|
|
32
32
|
columns: PropTypes.arrayOf(PropTypes.shape({
|
|
33
|
-
Header: PropTypes.oneOfType([PropTypes.
|
|
33
|
+
Header: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]).isRequired,
|
|
34
34
|
canFilter: PropTypes.bool,
|
|
35
35
|
render: PropTypes.func.isRequired,
|
|
36
36
|
})).isRequired,
|
|
@@ -25,11 +25,7 @@ function TableFooter({ className, children }) {
|
|
|
25
25
|
|
|
26
26
|
TableFooter.propTypes = {
|
|
27
27
|
/** Specifies the content of the `TableFooter` */
|
|
28
|
-
children: PropTypes.
|
|
29
|
-
PropTypes.func,
|
|
30
|
-
PropTypes.node,
|
|
31
|
-
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.node])),
|
|
32
|
-
]),
|
|
28
|
+
children: PropTypes.node,
|
|
33
29
|
/** Specifies class name to append to the base element. */
|
|
34
30
|
className: PropTypes.string,
|
|
35
31
|
};
|
|
@@ -62,7 +62,7 @@ CheckboxFilter.propTypes = {
|
|
|
62
62
|
*/
|
|
63
63
|
column: PropTypes.shape({
|
|
64
64
|
setFilter: PropTypes.func.isRequired,
|
|
65
|
-
Header: PropTypes.oneOfType([PropTypes.
|
|
65
|
+
Header: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]).isRequired,
|
|
66
66
|
filterChoices: PropTypes.arrayOf(PropTypes.shape({
|
|
67
67
|
name: PropTypes.string.isRequired,
|
|
68
68
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
@@ -50,7 +50,7 @@ DropdownFilter.propTypes = {
|
|
|
50
50
|
*/
|
|
51
51
|
column: PropTypes.shape({
|
|
52
52
|
setFilter: PropTypes.func.isRequired,
|
|
53
|
-
Header: PropTypes.oneOfType([PropTypes.
|
|
53
|
+
Header: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]).isRequired,
|
|
54
54
|
filterChoices: PropTypes.arrayOf(PropTypes.shape({
|
|
55
55
|
name: PropTypes.string.isRequired,
|
|
56
56
|
number: PropTypes.number,
|
|
@@ -66,7 +66,7 @@ MultiSelectDropdownFilter.propTypes = {
|
|
|
66
66
|
/** Function to set the filter value */
|
|
67
67
|
setFilter: PropTypes.func.isRequired,
|
|
68
68
|
/** Column header used for labels and placeholders */
|
|
69
|
-
Header: PropTypes.oneOfType([PropTypes.
|
|
69
|
+
Header: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]).isRequired,
|
|
70
70
|
/** Names and values for the select options */
|
|
71
71
|
filterChoices: PropTypes.arrayOf(PropTypes.shape({
|
|
72
72
|
name: PropTypes.string.isRequired,
|
|
@@ -52,7 +52,7 @@ TextFilter.propTypes = {
|
|
|
52
52
|
*/
|
|
53
53
|
column: PropTypes.shape({
|
|
54
54
|
setFilter: PropTypes.func.isRequired,
|
|
55
|
-
Header: PropTypes.oneOfType([PropTypes.
|
|
55
|
+
Header: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]).isRequired,
|
|
56
56
|
getHeaderProps: PropTypes.func.isRequired,
|
|
57
57
|
filterValue: PropTypes.string,
|
|
58
58
|
}).isRequired,
|
package/src/DataTable/index.jsx
CHANGED
|
@@ -270,13 +270,13 @@ DataTable.propTypes = {
|
|
|
270
270
|
/** Definition of table columns */
|
|
271
271
|
columns: PropTypes.arrayOf(PropTypes.shape({
|
|
272
272
|
/** User visible column name */
|
|
273
|
-
Header: PropTypes.oneOfType([PropTypes.
|
|
273
|
+
Header: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]).isRequired,
|
|
274
274
|
/** String used to access the correct cell data for this column */
|
|
275
275
|
accessor: requiredWhenNot(PropTypes.string, 'Cell'),
|
|
276
276
|
/** Specifies a function that receives `row` as argument and returns cell content */
|
|
277
|
-
Cell: PropTypes.oneOfType([PropTypes.
|
|
277
|
+
Cell: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]),
|
|
278
278
|
/** Specifies filter component */
|
|
279
|
-
Filter: PropTypes.
|
|
279
|
+
Filter: PropTypes.elementType,
|
|
280
280
|
/** Specifies filter type */
|
|
281
281
|
filter: PropTypes.string,
|
|
282
282
|
/** Specifies filter choices */
|
|
@@ -293,8 +293,8 @@ DataTable.propTypes = {
|
|
|
293
293
|
/** Alternate column for selecting rows. See react table useSort docs for more information */
|
|
294
294
|
manualSelectColumn: PropTypes.shape({
|
|
295
295
|
id: PropTypes.string.isRequired,
|
|
296
|
-
Header: PropTypes.oneOfType([PropTypes.
|
|
297
|
-
Cell: PropTypes.
|
|
296
|
+
Header: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]).isRequired,
|
|
297
|
+
Cell: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]),
|
|
298
298
|
disableSortBy: PropTypes.bool.isRequired,
|
|
299
299
|
}),
|
|
300
300
|
/** Table columns can be sorted */
|
|
@@ -315,16 +315,16 @@ DataTable.propTypes = {
|
|
|
315
315
|
/** defaults that will be set on each column. Will be overridden by individual column values */
|
|
316
316
|
defaultColumnValues: PropTypes.shape({
|
|
317
317
|
/** A default filter component for the column */
|
|
318
|
-
Filter: PropTypes.
|
|
318
|
+
Filter: PropTypes.elementType,
|
|
319
319
|
}),
|
|
320
320
|
/** Actions or other additional non-data columns can be added here */
|
|
321
321
|
additionalColumns: PropTypes.arrayOf(PropTypes.shape({
|
|
322
322
|
/** id must be unique from other columns ids */
|
|
323
323
|
id: PropTypes.string.isRequired,
|
|
324
324
|
/** column header that will be displayed to the user */
|
|
325
|
-
Header: PropTypes.oneOfType([PropTypes.
|
|
325
|
+
Header: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]),
|
|
326
326
|
/** Component that renders in the added column. It will receive the row as a prop */
|
|
327
|
-
Cell: PropTypes.oneOfType([PropTypes.
|
|
327
|
+
Cell: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]),
|
|
328
328
|
})),
|
|
329
329
|
/** Function that will fetch table data. Called when page size, page index or filters change.
|
|
330
330
|
* Meant to be used with manual filters and pagination */
|
|
@@ -401,15 +401,15 @@ DataTable.propTypes = {
|
|
|
401
401
|
/** Number between one and four filters that can be shown on the top row. */
|
|
402
402
|
numBreakoutFilters: PropTypes.oneOf([1, 2, 3, 4]),
|
|
403
403
|
/** Component to be displayed when the table is empty */
|
|
404
|
-
EmptyTableComponent: PropTypes.
|
|
404
|
+
EmptyTableComponent: PropTypes.elementType,
|
|
405
405
|
/** Component to be displayed for row status, ie, 10 of 20 rows. Displayed by default in the TableControlBar */
|
|
406
|
-
RowStatusComponent: PropTypes.
|
|
406
|
+
RowStatusComponent: PropTypes.elementType,
|
|
407
407
|
/** Component to be displayed for selection status. Displayed when there are selected rows and no active filters */
|
|
408
|
-
SelectionStatusComponent: PropTypes.
|
|
408
|
+
SelectionStatusComponent: PropTypes.elementType,
|
|
409
409
|
/** Component to be displayed for filter status. Displayed when there are active filters. */
|
|
410
|
-
FilterStatusComponent: PropTypes.
|
|
410
|
+
FilterStatusComponent: PropTypes.elementType,
|
|
411
411
|
/** If children are not provided a table with control bar and footer will be rendered */
|
|
412
|
-
children: PropTypes.
|
|
412
|
+
children: PropTypes.node,
|
|
413
413
|
/** If true filters will be shown on sidebar instead */
|
|
414
414
|
showFiltersInSidebar: PropTypes.bool,
|
|
415
415
|
/** options for data view toggle */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
3
|
import userEvent from '@testing-library/user-event';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import TableActions from '../TableActions';
|
|
@@ -216,9 +216,10 @@ describe('<TableActions />', () => {
|
|
|
216
216
|
expect(overflowToggle).toBeInTheDocument();
|
|
217
217
|
|
|
218
218
|
userEvent.click(overflowToggle);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
219
|
+
waitFor(() => {
|
|
220
|
+
const buttons = screen.getAllByRole('button');
|
|
221
|
+
expect(buttons.length).toBeGreaterThan(1);
|
|
222
|
+
});
|
|
222
223
|
});
|
|
223
224
|
|
|
224
225
|
it('renders the correct alt text for the dropdown', () => {
|
package/src/Form/FormControl.jsx
CHANGED
|
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect } from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import RBFormControl from 'react-bootstrap/FormControl';
|
|
5
|
+
import { IMaskInput } from 'react-imask';
|
|
5
6
|
import { useFormGroupContext } from './FormGroupContext';
|
|
6
7
|
import FormControlFeedback from './FormControlFeedback';
|
|
7
8
|
import FormControlDecoratorGroup from './FormControlDecoratorGroup';
|
|
@@ -17,6 +18,7 @@ const FormControl = React.forwardRef(({
|
|
|
17
18
|
floatingLabel,
|
|
18
19
|
autoResize,
|
|
19
20
|
onChange,
|
|
21
|
+
inputMask,
|
|
20
22
|
...props
|
|
21
23
|
}, ref) => {
|
|
22
24
|
const {
|
|
@@ -71,7 +73,7 @@ const FormControl = React.forwardRef(({
|
|
|
71
73
|
className={className}
|
|
72
74
|
>
|
|
73
75
|
<RBFormControl
|
|
74
|
-
as={as}
|
|
76
|
+
as={inputMask ? IMaskInput : as}
|
|
75
77
|
ref={resolvedRef}
|
|
76
78
|
size={size}
|
|
77
79
|
isInvalid={isInvalid}
|
|
@@ -80,6 +82,7 @@ const FormControl = React.forwardRef(({
|
|
|
80
82
|
'has-value': hasValue,
|
|
81
83
|
})}
|
|
82
84
|
onChange={handleOnChange}
|
|
85
|
+
mask={inputMask}
|
|
83
86
|
{...controlProps}
|
|
84
87
|
/>
|
|
85
88
|
</FormControlDecoratorGroup>
|
|
@@ -122,6 +125,8 @@ FormControl.propTypes = {
|
|
|
122
125
|
isInvalid: PropTypes.bool,
|
|
123
126
|
/** Only for `as="textarea"`. Specifies whether the input can be resized according to the height of content. */
|
|
124
127
|
autoResize: PropTypes.bool,
|
|
128
|
+
/** Specifies what format to use for the input mask. */
|
|
129
|
+
inputMask: PropTypes.string,
|
|
125
130
|
};
|
|
126
131
|
|
|
127
132
|
FormControl.defaultProps = {
|
|
@@ -140,6 +145,7 @@ FormControl.defaultProps = {
|
|
|
140
145
|
isValid: undefined,
|
|
141
146
|
isInvalid: undefined,
|
|
142
147
|
autoResize: false,
|
|
148
|
+
inputMask: undefined,
|
|
143
149
|
};
|
|
144
150
|
|
|
145
151
|
export default FormControl;
|
|
@@ -43,7 +43,6 @@ or [select attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element
|
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
47
46
|
## Input types
|
|
48
47
|
|
|
49
48
|
```jsx live
|
|
@@ -163,6 +162,148 @@ or [select attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element
|
|
|
163
162
|
}
|
|
164
163
|
```
|
|
165
164
|
|
|
165
|
+
## Input masks
|
|
166
|
+
Paragon uses the [react-imask](https://www.npmjs.com/package/react-imask) library,
|
|
167
|
+
which allows you to add masks of different types for inputs.
|
|
168
|
+
To create your own mask, you need to pass the required mask pattern (`+{1} (000) 000-0000`) to the `inputMask` property. <br />
|
|
169
|
+
See [react-imask](https://imask.js.org) for documentation on available props.
|
|
170
|
+
|
|
171
|
+
```jsx live
|
|
172
|
+
() => {
|
|
173
|
+
{/* start example state */}
|
|
174
|
+
const [maskType, setMaskType] = useState('phone');
|
|
175
|
+
{/* end example state */}
|
|
176
|
+
|
|
177
|
+
const inputsWithMask = {
|
|
178
|
+
phone: (
|
|
179
|
+
<>
|
|
180
|
+
<h3>Phone</h3>
|
|
181
|
+
<Form.Group>
|
|
182
|
+
<Form.Control
|
|
183
|
+
inputMask="+{1} (000) 000-0000"
|
|
184
|
+
value={value}
|
|
185
|
+
onChange={handleChange}
|
|
186
|
+
leadingElement={<Icon src={FavoriteBorder} />}
|
|
187
|
+
floatingLabel="What is your phone number?"
|
|
188
|
+
/>
|
|
189
|
+
</Form.Group>
|
|
190
|
+
</>
|
|
191
|
+
),
|
|
192
|
+
creditCard: (<>
|
|
193
|
+
<h3>Credit card</h3>
|
|
194
|
+
<Form.Group>
|
|
195
|
+
<Form.Control
|
|
196
|
+
inputMask="0000 0000 0000 0000"
|
|
197
|
+
value={value}
|
|
198
|
+
onChange={handleChange}
|
|
199
|
+
leadingElement={<Icon src={FavoriteBorder} />}
|
|
200
|
+
floatingLabel="What is your credit card number?"
|
|
201
|
+
/>
|
|
202
|
+
</Form.Group>
|
|
203
|
+
</>),
|
|
204
|
+
securePassword: (<>
|
|
205
|
+
<h3>Secure password</h3>
|
|
206
|
+
<Form.Group>
|
|
207
|
+
<Form.Control
|
|
208
|
+
inputMask="XXX-XX-0000"
|
|
209
|
+
value={value}
|
|
210
|
+
definitions={{
|
|
211
|
+
X: {
|
|
212
|
+
mask: '0',
|
|
213
|
+
displayChar: 'X',
|
|
214
|
+
placeholderChar: '#',
|
|
215
|
+
},
|
|
216
|
+
}}
|
|
217
|
+
onChange={handleChange}
|
|
218
|
+
leadingElement={<Icon src={FavoriteBorder} />}
|
|
219
|
+
floatingLabel="What is your password?"
|
|
220
|
+
/>
|
|
221
|
+
</Form.Group>
|
|
222
|
+
</>),
|
|
223
|
+
OTPpassword: (<>
|
|
224
|
+
<h3>OTP password</h3>
|
|
225
|
+
<Form.Group>
|
|
226
|
+
<Form.Control
|
|
227
|
+
inputMask="G-00000"
|
|
228
|
+
value={value}
|
|
229
|
+
onChange={handleChange}
|
|
230
|
+
leadingElement={<Icon src={FavoriteBorder} />}
|
|
231
|
+
floatingLabel="What is your OPT password?"
|
|
232
|
+
/>
|
|
233
|
+
</Form.Group>
|
|
234
|
+
</>),
|
|
235
|
+
price: (
|
|
236
|
+
<>
|
|
237
|
+
<h3>Course priсe</h3>
|
|
238
|
+
<Form.Group>
|
|
239
|
+
<Form.Control
|
|
240
|
+
inputMask="$num"
|
|
241
|
+
blocks={{
|
|
242
|
+
num: {
|
|
243
|
+
// nested masks are available!
|
|
244
|
+
mask: Number,
|
|
245
|
+
thousandsSeparator: ' '
|
|
246
|
+
}
|
|
247
|
+
}}
|
|
248
|
+
value={value}
|
|
249
|
+
onChange={handleChange}
|
|
250
|
+
leadingElement={<Icon src={FavoriteBorder} />}
|
|
251
|
+
floatingLabel="What is the price of this course?"
|
|
252
|
+
/>
|
|
253
|
+
</Form.Group>
|
|
254
|
+
</>
|
|
255
|
+
),
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const [value, setValue] = useState('');
|
|
259
|
+
|
|
260
|
+
const handleChange = (e) => setValue(e.target.value);
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<>
|
|
264
|
+
{/* start example form block */}
|
|
265
|
+
<ExamplePropsForm
|
|
266
|
+
inputs={[
|
|
267
|
+
{ value: maskType, setValue: setMaskType, options: Object.keys(inputsWithMask), name: 'Mask variants' },
|
|
268
|
+
]}
|
|
269
|
+
/>
|
|
270
|
+
{/* end example form block */}
|
|
271
|
+
|
|
272
|
+
{inputsWithMask[maskType]}
|
|
273
|
+
</>
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Input masks with clear value
|
|
279
|
+
To get a value without a mask, you need to use `onChange` instead of `onAccept` to handle changes.
|
|
280
|
+
|
|
281
|
+
```jsx live
|
|
282
|
+
() => {
|
|
283
|
+
const [value, setValue] = useState('');
|
|
284
|
+
|
|
285
|
+
return (
|
|
286
|
+
<>
|
|
287
|
+
<Form.Group>
|
|
288
|
+
<Form.Control
|
|
289
|
+
inputMask="+{1} (000) 000-0000"
|
|
290
|
+
leadingElement={<Icon src={FavoriteBorder} />}
|
|
291
|
+
trailingElement={<Icon src={Verified} />}
|
|
292
|
+
floatingLabel="What is your phone number?"
|
|
293
|
+
value={value}
|
|
294
|
+
// depending on prop above first argument is
|
|
295
|
+
// `value` if `unmask=false`,
|
|
296
|
+
// `unmaskedValue` if `unmask=true`,
|
|
297
|
+
// `typedValue` if `unmask='typed'`
|
|
298
|
+
onAccept={(_, mask) => setValue(mask._unmaskedValue)}
|
|
299
|
+
/>
|
|
300
|
+
</Form.Group>
|
|
301
|
+
Unmasked value: {JSON.stringify(value)}
|
|
302
|
+
</>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
166
307
|
## Textarea autoResize
|
|
167
308
|
|
|
168
309
|
`autoResize` prop allows input to be resized according to the content height.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import userEvent from '@testing-library/user-event';
|
|
4
4
|
|
|
@@ -8,8 +8,27 @@ const ref = {
|
|
|
8
8
|
current: null,
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
let unmaskedInputValue;
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line react/prop-types
|
|
14
|
+
function Component({ isClearValue }) {
|
|
15
|
+
const [inputValue, setInputValue] = useState('');
|
|
16
|
+
unmaskedInputValue = inputValue;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<FormControl
|
|
20
|
+
inputMask="+{1} (000) 000-0000"
|
|
21
|
+
value={inputValue}
|
|
22
|
+
onChange={(e) => (!isClearValue ? setInputValue(e.target.value) : null)}
|
|
23
|
+
/* eslint-disable-next-line no-underscore-dangle */
|
|
24
|
+
onAccept={(_, mask) => (isClearValue ? setInputValue(mask._unmaskedValue) : null)}
|
|
25
|
+
data-testid="form-control-with-mask"
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
describe('FormControl', () => {
|
|
12
|
-
it('textarea changes its height with autoResize prop',
|
|
31
|
+
it('textarea changes its height with autoResize prop', () => {
|
|
13
32
|
const useReferenceSpy = jest.spyOn(React, 'useRef').mockReturnValue(ref);
|
|
14
33
|
const onChangeFunc = jest.fn();
|
|
15
34
|
const inputText = 'new text';
|
|
@@ -26,9 +45,27 @@ describe('FormControl', () => {
|
|
|
26
45
|
expect(useReferenceSpy).toHaveBeenCalledTimes(1);
|
|
27
46
|
expect(ref.current.style.height).toBe('0px');
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
userEvent.type(textarea, inputText);
|
|
30
49
|
|
|
31
50
|
expect(onChangeFunc).toHaveBeenCalledTimes(inputText.length);
|
|
32
51
|
expect(ref.current.style.height).toEqual(`${ref.current.scrollHeight + ref.current.offsetHeight}px`);
|
|
33
52
|
});
|
|
53
|
+
|
|
54
|
+
it('should apply and accept input mask for phone numbers', () => {
|
|
55
|
+
render(<Component />);
|
|
56
|
+
|
|
57
|
+
const input = screen.getByTestId('form-control-with-mask');
|
|
58
|
+
userEvent.type(input, '5555555555');
|
|
59
|
+
expect(input.value).toBe('+1 (555) 555-5555');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should be cleared from the mask elements value', () => {
|
|
63
|
+
render(<Component isClearValue />);
|
|
64
|
+
|
|
65
|
+
const input = screen.getByTestId('form-control-with-mask');
|
|
66
|
+
userEvent.type(input, '5555555555');
|
|
67
|
+
|
|
68
|
+
expect(input.value).toBe('+1 (555) 555-5555');
|
|
69
|
+
expect(unmaskedInputValue).toBe('15555555555');
|
|
70
|
+
});
|
|
34
71
|
});
|
|
@@ -30,6 +30,7 @@ const Checkpoint = React.forwardRef(({
|
|
|
30
30
|
// Use the Popper library to translate the Checkpoint to its target's coordinates
|
|
31
31
|
const checkpointPopper = createPopper(targetElement, checkpoint, {
|
|
32
32
|
placement: isMobile ? 'top' : placement,
|
|
33
|
+
strategy: 'fixed',
|
|
33
34
|
modifiers: [
|
|
34
35
|
{
|
|
35
36
|
name: 'arrow',
|