- {!error && isLoading && SpinnerExtended}
+ {!error && isLoading && spinner && (
+
{spinner}
+ )}
{error && (
)}
@@ -148,7 +146,7 @@ AtomImage.propTypes = {
skeleton: PropTypes.string,
/** Spinner (component) displayed while the final image is being loaded */
- spinner: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
+ spinner: PropTypes.node,
/** Icon (component) to be displayed in an Error Box when the image cannot be loaded */
errorIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
diff --git a/components/atom/image/src/types.js b/components/atom/image/src/types.js
index 8f121030f6..9ecf420d98 100644
--- a/components/atom/image/src/types.js
+++ b/components/atom/image/src/types.js
@@ -11,6 +11,7 @@ const htmlImgProps = {
referrerpolicy: PropTypes.string,
sizes: PropTypes.string,
srcset: PropTypes.string,
+ title: PropTypes.string,
usemap: PropTypes.string,
width: PropTypes.string
}
diff --git a/components/atom/input/CHANGELOG.md b/components/atom/input/CHANGELOG.md
index 8fb06f2a0c..52d0ebbfeb 100644
--- a/components/atom/input/CHANGELOG.md
+++ b/components/atom/input/CHANGELOG.md
@@ -1,5 +1,14 @@
# CHANGELOG
+# 5.22.0 (2022-10-04)
+
+
+### Bug Fixes
+
+* **components/atom/input:** Add input validator function for input type number ([c72b340](https://github.com/SUI-Components/sui-components/commit/c72b3402d65cad1a467828c4b9de06de29603fb4))
+
+
+
# 5.21.0 (2022-08-26)
diff --git a/components/atom/input/demo/index.js b/components/atom/input/demo/index.js
index 0ec18c7d12..670911343d 100644
--- a/components/atom/input/demo/index.js
+++ b/components/atom/input/demo/index.js
@@ -1,17 +1,9 @@
-import {useState} from 'react'
-
-import AtomInput, {
- inputShapes,
- inputSizes,
- inputStates,
- inputTypes
-} from 'components/atom/input/src/index.js'
+import {Fragment, useState} from 'react'
import {
Anchor,
AntDesignIcon,
Article,
- Box,
Button,
Cell,
Code,
@@ -29,6 +21,12 @@ import {
UnorderedList
} from '@s-ui/documentation-library'
+import AtomInput, {
+ inputShapes,
+ inputSizes,
+ inputStates,
+ inputTypes
+} from '../../input/src/index.js'
import {flexCenteredStyle, stackMap} from './settings.js'
const DefaultDemo = () => (
@@ -166,7 +164,7 @@ const TypeDemo = () => {
'MASK',
{
type: inputTypes.MASK,
- mask: 'ES00 0000 0000 00 0000000000',
+ mask: {mask: 'ES00 0000 0000 00 0000000000'},
placeholder: 'ES00 0000 0000 00 0000000000',
charsSize: 31
},
@@ -429,7 +427,7 @@ const BorderlessDemo = () => {
const [border, setBorder] = useState(true)
const [mode, setMode] = useState('light')
return (
-
+
No border
The border of the input can be removed using the boolean prop{' '}
@@ -453,9 +451,7 @@ const BorderlessDemo = () => {
/>
-
-
-
+
|
@@ -525,7 +521,9 @@ const InlineFormDemo = () => (
Input have its own way of provide a submision using the{' '}
button
prop, you can pass a React node.
- Send} />
+ Send}
+ />
)
@@ -562,7 +560,7 @@ const ShapeDemo = () => (
))}
{Object.entries({default: undefined, ...inputSizes}).map(
([sizeKey, sizeValue]) => (
- <>
+
{`${sizeKey}`}
|
@@ -578,7 +576,7 @@ const ShapeDemo = () => (
)
)}
- >
+
)
)}
diff --git a/components/atom/input/package.json b/components/atom/input/package.json
index c07fe87751..c1a80955d0 100644
--- a/components/atom/input/package.json
+++ b/components/atom/input/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-input",
- "version": "5.21.0",
+ "version": "5.21.0-beta.4",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -11,7 +11,7 @@
"dependencies": {
"@s-ui/react-hooks": "1",
"@s-ui/react-primitive-polymorphic-element": "1",
- "imask": "3.4.0"
+ "react-imask": "6.4.3"
},
"peerDependencies": {
"@s-ui/component-dependencies": "1"
diff --git a/components/atom/input/src/Input/Component/index.scss b/components/atom/input/src/Input/Component/index.scss
index 17bfbf0236..3fd7e18269 100644
--- a/components/atom/input/src/Input/Component/index.scss
+++ b/components/atom/input/src/Input/Component/index.scss
@@ -7,77 +7,29 @@ $class-read-only: '#{$base-class-input}--readOnly';
-webkit-appearance: none;
@include sui-atom-input-input;
- border-radius: $bdrs-atom-input;
+ background-color: transparent;
min-height: auto;
text-overflow: $tov-atom-input-placeholder;
- &--charsSize {
+ padding-left: 0;
+ padding-right: 0;
+ border: 0 solid transparent;
+ {$base-class-input}--charsSize {
width: inherit;
}
- &--hidden {
+ {$base-class-input}--hidden {
display: none;
}
- &--readOnly {
- background: $bgc-atom-input-read-only;
- border: $bd-atom-input-read-only;
- color: $c-atom-input-read-only;
- }
-
- @include atom-input-shape-wrapper(
- $base-class,
- $base-class-input,
- $bdrs-atom-input-shapes,
- $sizes-atom-input,
- $bdrs-atom-input,
- $h-atom-input--m
- );
-
- {$base-class-input}--noBorder,
- {$base-class-input}--noBorder:disabled {
- border: 0;
- &:focus {
- border: 0;
- box-shadow: none;
- outline: 0;
- }
- }
-
&::placeholder {
color: $c-atom-input-placeholder;
}
- &:disabled {
- pointer-events: none;
-
- &:not(#{$class-read-only}) {
- -webkit-text-fill-color: $c-atom-input-disabled;
-
- background: $bgc-atom-input-disabled;
- border: $bd-atom-input-disabled;
- color: $c-atom-input-disabled;
- }
- }
-
&:focus {
- @include sui-atom-input-input-focus;
- }
-
- @each $type, $attr in $sizes-atom-input {
- &-size-#{$type} {
- height: $attr;
- min-height: $attr;
- }
+ box-shadow: none;
}
-
- @each $state, $color in $states-atom-input {
- &.sui-AtomInput-input--#{$state} {
- border-color: $color;
-
- &:focus {
- box-shadow: $bxsh-atom-input-size $color;
- }
- }
+ &:focus-visible {
+ outline: 0;
}
&[type='number'] {
diff --git a/components/atom/input/src/Input/Wrappers/Addons/InputAddons.js b/components/atom/input/src/Input/Wrappers/Addons/InputAddons.js
index af4999be14..8fb49f887e 100644
--- a/components/atom/input/src/Input/Wrappers/Addons/InputAddons.js
+++ b/components/atom/input/src/Input/Wrappers/Addons/InputAddons.js
@@ -1,21 +1,14 @@
-import cx from 'classnames'
import PropTypes from 'prop-types'
import {INPUT_SHAPES, SIZES} from '../../../config.js'
-import {ADDON_TYPES, BASE_CLASS_ADDON_WRAPPER, getClassName} from './config.js'
+import {ADDON_TYPES, getClassName} from './config.js'
const InputAddon = ({leftAddon, rightAddon, shape, size, children}) => {
if (!(leftAddon || rightAddon)) {
return children
}
return (
-
+ <>
{leftAddon && (
{leftAddon}
@@ -27,7 +20,7 @@ const InputAddon = ({leftAddon, rightAddon, shape, size, children}) => {
{rightAddon}
)}
-
+ >
)
}
diff --git a/components/atom/input/src/Input/Wrappers/Addons/config.js b/components/atom/input/src/Input/Wrappers/Addons/config.js
index f561c5393b..2f4478da23 100644
--- a/components/atom/input/src/Input/Wrappers/Addons/config.js
+++ b/components/atom/input/src/Input/Wrappers/Addons/config.js
@@ -1,13 +1,12 @@
import cx from 'classnames'
-import {BASE} from '../../../config.js'
+import {BASE, BASE_CLASS_ITEM} from '../../../config.js'
export const BASE_CLASS_ADDON = `${BASE}--withAddon`
-export const BASE_CLASS_ADDON_WRAPPER = `${BASE_CLASS_ADDON}Wrapper`
export const ADDON_TYPES = {
LEFT: 'left',
RIGHT: 'right'
}
export const getClassName = ({type}) =>
- cx(BASE_CLASS_ADDON, `${BASE_CLASS_ADDON}--${type}`)
+ cx(BASE_CLASS_ITEM, BASE_CLASS_ADDON, `${BASE_CLASS_ADDON}--${type}`)
diff --git a/components/atom/input/src/Input/Wrappers/Addons/index.scss b/components/atom/input/src/Input/Wrappers/Addons/index.scss
index e66319f7d0..aacf641e4e 100644
--- a/components/atom/input/src/Input/Wrappers/Addons/index.scss
+++ b/components/atom/input/src/Input/Wrappers/Addons/index.scss
@@ -1,34 +1,56 @@
-#{$base-class}--withAddon {
- align-items: center;
- background-color: $bgc-atom-input-addon;
- border-color: $bdc-atom-input-addon;
- border-style: solid;
- color: $c-atom-input-addon;
- display: flex;
- flex-direction: column;
- height: inherit;
- justify-content: center;
- line-height: inherit;
- padding-left: $p-atom-input-addon-left;
- padding-right: $p-atom-input-addon-right;
+$base-class-addon: '#{$base-class}--withAddon';
- &--right {
- border-width: $bdw-atom-input-addon-right;
- }
+#{$base-class} {
+ #{$base-class-addon} {
+ align-items: center;
+ background-color: $bgc-atom-input-addon;
+ border-color: $bdc-atom-input-addon;
+ border-style: solid;
+ color: $c-atom-input-addon;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ line-height: inherit;
+ padding-left: $p-atom-input-addon-left;
+ padding-right: $p-atom-input-addon-right;
+ width: auto;
- &--left {
- border-width: $bdw-atom-input-addon-left;
- }
+ {$base-class-addon}--right {
+ border-left-width: 0;
+ }
- &Wrapper {
- display: flex;
- @include atom-input-shape-wrapper(
- $base-class,
- #{'.sui-AtomInput--withAddonWrapper'},
- $bdrs-atom-input-shapes,
- $sizes-atom-input,
- $bdrs-atom-input,
- $h-atom-input--m
- );
+ {$base-class-addon}--left {
+ border-right-width: 0;
+ }
+ }
+ @each $state, $color in $states-atom-input {
+ {$base-class}--status-#{$state} {
+ #{$base-class}-item {
+ {$base-class-addon} {
+ border-color: $bdc-atom-input-addon;
+ {$base-class-addon}--right {
+ border-left-color: $color;
+ }
+ {$base-class-addon}--left {
+ border-right-color: $color;
+ }
+ }
+ }
+ }
+ }
+ @each $state, $color in $states-atom-input {
+ {$base-class}--status-#{$state} {
+ #{$base-class}-item {
+ {$base-class-addon} {
+ border-color: $bdc-atom-input-addon;
+ {$base-class-addon}--right {
+ border-left-color: $color;
+ }
+ {$base-class-addon}--left {
+ border-right-color: $color;
+ }
+ }
+ }
+ }
}
}
diff --git a/components/atom/input/src/Input/Wrappers/Button/InputButton.js b/components/atom/input/src/Input/Wrappers/Button/InputButton.js
index fc6a62a687..87d1d5626a 100644
--- a/components/atom/input/src/Input/Wrappers/Button/InputButton.js
+++ b/components/atom/input/src/Input/Wrappers/Button/InputButton.js
@@ -1,6 +1,7 @@
+import cx from 'classnames'
import PropTypes from 'prop-types'
-import {BASE_CLASS_BUTTON} from './config.js'
+import {BASE_CLASS_BUTTON, BASE_CLASS_ITEM} from './config.js'
const InputButton = ({button, children}) => {
if (button === undefined) {
@@ -8,10 +9,12 @@ const InputButton = ({button, children}) => {
}
return (
-
-
{children}
-
{button}
-
+ <>
+ {children}
+
+ {button}
+
+ >
)
}
InputButton.propTypes = {
diff --git a/components/atom/input/src/Input/Wrappers/Button/config.js b/components/atom/input/src/Input/Wrappers/Button/config.js
index 86a66b2c31..da59c18f38 100644
--- a/components/atom/input/src/Input/Wrappers/Button/config.js
+++ b/components/atom/input/src/Input/Wrappers/Button/config.js
@@ -1,3 +1,4 @@
-import {BASE} from '../../../config.js'
+import {BASE, BASE_CLASS_ITEM} from '../../../config.js'
+export {BASE_CLASS_ITEM}
export const BASE_CLASS_BUTTON = `${BASE}--withButton`
diff --git a/components/atom/input/src/Input/Wrappers/Button/index.scss b/components/atom/input/src/Input/Wrappers/Button/index.scss
index ca26941a34..5274fe8589 100644
--- a/components/atom/input/src/Input/Wrappers/Button/index.scss
+++ b/components/atom/input/src/Input/Wrappers/Button/index.scss
@@ -1,13 +1,3 @@
-#{$base-class}--withButton {
- display: flex;
- width: 100%;
-
- &-input {
- flex: 1;
- width: 100%;
- }
-
- &-button {
- margin-left: $m-m;
- }
+#{$base-class}--withButton-button {
+ overflow: hidden;
}
diff --git a/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js b/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js
index 22010b5f94..ce09bab509 100644
--- a/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js
+++ b/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js
@@ -2,13 +2,11 @@ import cx from 'classnames'
import PropTypes from 'prop-types'
import {
- BASE_CLASS_ICON,
BASE_CLASS_ICON_COMPONENT,
BASE_CLASS_ICON_COMPONENT_HANDLER,
BASE_CLASS_ICON_COMPONENT_LEFT,
BASE_CLASS_ICON_COMPONENT_RIGHT,
- BASE_CLASS_ICON_LEFT,
- BASE_CLASS_ICON_RIGHT
+ BASE_CLASS_ICON_CONTENT_COMPONENT
} from './config.js'
const InputIcons = ({
@@ -18,9 +16,6 @@ const InputIcons = ({
onClickRightIcon,
children
}) => {
- if (!(leftIcon || rightIcon)) {
- return children
- }
const handleLeftClick = event => {
onClickLeftIcon && onClickLeftIcon(event)
}
@@ -30,24 +25,22 @@ const InputIcons = ({
}
return (
-
+ <>
{leftIcon && (
- {leftIcon}
+
+ {leftIcon}
+
)}
{children}
@@ -55,17 +48,20 @@ const InputIcons = ({
- {rightIcon}
+
+ {rightIcon}
+
)}
-
+ >
)
}
diff --git a/components/atom/input/src/Input/Wrappers/Icons/config.js b/components/atom/input/src/Input/Wrappers/Icons/config.js
index 4d415eb0d6..73e045e57b 100644
--- a/components/atom/input/src/Input/Wrappers/Icons/config.js
+++ b/components/atom/input/src/Input/Wrappers/Icons/config.js
@@ -1,14 +1,18 @@
-import {BASE} from '../../../config.js'
+import {
+ BASE,
+ BASE_CLASS_AREA_FOCUSABLE,
+ BASE_CLASS_ITEM
+} from '../../../config.js'
export const ICON_TYPES = {
LEFT: 'left',
RIGHT: 'right'
}
+export {BASE_CLASS_ITEM, BASE_CLASS_AREA_FOCUSABLE}
export const BASE_CLASS_ICON = `${BASE}--withIcon`
-export const BASE_CLASS_ICON_LEFT = `${BASE_CLASS_ICON}--${ICON_TYPES.LEFT}`
-export const BASE_CLASS_ICON_RIGHT = `${BASE_CLASS_ICON}--${ICON_TYPES.RIGHT}`
export const BASE_CLASS_ICON_COMPONENT = `${BASE_CLASS_ICON}-icon`
+export const BASE_CLASS_ICON_CONTENT_COMPONENT = `${BASE_CLASS_ICON_COMPONENT}--content`
export const BASE_CLASS_ICON_COMPONENT_HANDLER = `${BASE_CLASS_ICON_COMPONENT}--withHandler`
export const BASE_CLASS_ICON_COMPONENT_LEFT = `${BASE_CLASS_ICON_COMPONENT}--${ICON_TYPES.LEFT}`
export const BASE_CLASS_ICON_COMPONENT_RIGHT = `${BASE_CLASS_ICON_COMPONENT}--${ICON_TYPES.RIGHT}`
diff --git a/components/atom/input/src/Input/Wrappers/Icons/index.scss b/components/atom/input/src/Input/Wrappers/Icons/index.scss
index f493df3295..f2e5d51fb6 100644
--- a/components/atom/input/src/Input/Wrappers/Icons/index.scss
+++ b/components/atom/input/src/Input/Wrappers/Icons/index.scss
@@ -1,25 +1,14 @@
-#{$base-class}--withIcon {
- position: relative;
- width: 100%;
+@use 'sass:math';
- &--left #{$base-class-input} {
- padding-left: $pl-atom-input-input;
- }
-
- &--right #{$base-class-input} {
- padding-right: $pr-atom-input-input;
- }
+$base-class-with-icon: '#{$base-class}--withIcon';
- &-icon {
+#{$base-class} {
+ #{$base-class-with-icon}-icon {
align-items: center;
color: $c-atom-input-icon;
display: flex;
fill: $c-atom-input-icon;
- height: $w-atom-input-icon;
justify-content: center;
- position: absolute;
- top: $t-atom-input-icon;
- transform: translateY($trf-ty-atom-input-icon);
width: $w-atom-input-icon;
pointer-events: none;
@@ -29,16 +18,25 @@
}
&--left {
- left: $l-atom-input-icon;
+ #{$base-class-with-icon}-icon--content {
+ width: $w-atom-input-icon;
+ }
}
&--right {
- right: $r-atom-input-icon;
+ #{$base-class-with-icon}-icon--content {
+ width: $w-atom-input-icon;
+ }
}
-
- & > * {
- height: 100%;
- width: 100%;
+ }
+ @each $state, $color in $states-atom-input {
+ {$base-class}--status-#{$state} {
+ #{$base-class-with-icon}-icon {
+ #{$base-class-with-icon}-icon--content {
+ color: $color;
+ fill: $color;
+ }
+ }
}
}
}
diff --git a/components/atom/input/src/Input/index.js b/components/atom/input/src/Input/index.js
index 1bdf066e20..c7e7348592 100644
--- a/components/atom/input/src/Input/index.js
+++ b/components/atom/input/src/Input/index.js
@@ -1,16 +1,31 @@
import {forwardRef} from 'react'
+import cx from 'classnames'
import PropTypes from 'prop-types'
-import {SIZES} from '../config.js'
-import Input, {inputSizes, inputStates} from './Component/index.js'
+import {
+ BASE_CLASS_AREA_FOCUSABLE,
+ BASE_CLASS_ITEM,
+ SIZES,
+ TYPES
+} from '../config.js'
+import Mask from '../Mask/index.js'
+import Password from '../Password/index.js'
+import Input from './Component/index.js'
import InputAddons from './Wrappers/Addons/InputAddons.js'
import InputButton from './Wrappers/Button/InputButton.js'
import InputIcons from './Wrappers/Icons/InputIcons.js'
+const componentType = {
+ undefined: props => [Input, props],
+ [TYPES.SUI_PASSWORD]: ({type, ...props}) => [Password, {...props}],
+ [TYPES.MASK]: ({type, ...props}) => [Mask, {...props}]
+}
+
const BaseInput = forwardRef(
(
{
+ type,
button,
leftAddon,
rightAddon,
@@ -24,6 +39,10 @@ const BaseInput = forwardRef(
},
forwardedRef
) => {
+ const [Component, passedProps] = componentType[type]
+ ? componentType[type]({type, size, ...inputProps})
+ : componentType[undefined]({type, size, ...inputProps})
+
return (
-
-
- {children}
-
-
+
+
+
+ {children}
+
+
+
)
@@ -49,6 +70,8 @@ const BaseInput = forwardRef(
)
BaseInput.propTypes = {
+ /* text, password, date or number */
+ type: PropTypes.string,
/** button html element */
button: PropTypes.node,
/* inner react node element */
@@ -70,4 +93,4 @@ BaseInput.propTypes = {
}
export default BaseInput
-export {inputSizes, inputStates, BaseInput}
+export {BaseInput}
diff --git a/components/atom/input/src/Mask/index.js b/components/atom/input/src/Mask/index.js
index 1259d696a3..c79c26becf 100644
--- a/components/atom/input/src/Mask/index.js
+++ b/components/atom/input/src/Mask/index.js
@@ -1,50 +1,44 @@
-import {forwardRef, useEffect, useRef, useState} from 'react'
+import {forwardRef} from 'react'
import PropTypes from 'prop-types'
-import Input from '../Input/index.js'
+import Input from '../Input/Component/index.js'
+
+import useMask from './useMask.js'
const MaskInput = forwardRef(
- ({name, onChange, mask: maskOptions, ...props}, forwardedRef) => {
- const [mask, setMask] = useState(null)
- const refInput = useRef(null)
-
- useEffect(() => () => mask && mask.destroy(), [mask])
-
- const handleChange = (ev, {value}) => {
- typeof onChange === 'function' && onChange(ev, {value})
- }
-
- const handleFocus = () => {
- if (!mask) {
- import('imask').then(({default: IMask}) => {
- setMask(new IMask(refInput.current, maskOptions))
- })
- }
- }
-
- return (
-
- )
+ (
+ {name, onChange, onComplete, mask, value, defaultValue, ...props},
+ forwardedRef
+ ) => {
+ const {maskedValue, ref} = useMask({
+ value,
+ defaultValue,
+ mask,
+ onChange,
+ onComplete,
+ forwardedRef
+ })
+
+ return
}
)
MaskInput.displayName = 'MaskInput'
MaskInput.propTypes = {
+ /* The value of the control */
+ value: PropTypes.string,
+ /* default value of the control */
+ defaultValue: PropTypes.string,
/* mask object, see https://unmanner.github.io/imaskjs/ */
mask: PropTypes.object.isRequired,
/* The name of the control */
name: PropTypes.string,
/* Event launched on every input change */
- onChange: PropTypes.func
+ onChange: PropTypes.func,
+ /* Event fired every onChange which completes teh mask */
+ onComplete: PropTypes.func
}
export default MaskInput
diff --git a/components/atom/input/src/Mask/useMask.js b/components/atom/input/src/Mask/useMask.js
new file mode 100644
index 0000000000..d7d6327743
--- /dev/null
+++ b/components/atom/input/src/Mask/useMask.js
@@ -0,0 +1,43 @@
+import {useEffect} from 'react'
+
+import {useIMask} from 'react-imask'
+
+import useMergeRefs from '@s-ui/react-hooks/lib/useMergeRefs'
+import useMountedState from '@s-ui/react-hooks/lib/useMountedState'
+
+import {isFunction} from '../config.js'
+
+const useMask = ({
+ value: argValue,
+ defaultValue: argDefaultValue,
+ mask,
+ onChange,
+ onComplete,
+ forwardedRef
+}) => {
+ const [value] = useMountedState(argValue, argDefaultValue)
+ const {
+ ref: refInput,
+ value: maskedValue = '',
+ setValue
+ } = useIMask(
+ {...mask},
+ {
+ onAccept: (value, maskRef, event, ...args) =>
+ isFunction(onChange) && onChange(event, {value, maskRef, ...args}),
+ onComplete: (value, maskRef, event, ...args) =>
+ isFunction(onComplete) && onComplete(event, {value, maskRef, ...args})
+ }
+ )
+ useEffect(() => {
+ if (value !== maskedValue) {
+ setValue(value)
+ }
+ }, [argValue, setValue, maskedValue])
+
+ const ref = useMergeRefs(refInput, forwardedRef)
+
+ return Object.assign([maskedValue, ref])
+}
+
+export default useMask
diff --git a/components/atom/input/src/Password/config.js b/components/atom/input/src/Password/config.js
index c18b7ba0a2..e2bec087f5 100644
--- a/components/atom/input/src/Password/config.js
+++ b/components/atom/input/src/Password/config.js
@@ -1,6 +1,7 @@
-import {BASE_CLASS} from '../config.js'
+import {BASE, BASE_CLASS_ITEM} from '../config.js'
-export const BASE_CLASS_PASSWORD = `${BASE_CLASS}-password`
+export {BASE_CLASS_ITEM}
+export const BASE_CLASS_PASSWORD = `${BASE}-password`
export const BASE_CLASS_PASSWORD_TOGGLE_BUTTON = `${BASE_CLASS_PASSWORD}--toggleButton`
export const TEXT = 'text'
diff --git a/components/atom/input/src/Password/index.js b/components/atom/input/src/Password/index.js
index f26592e398..e6e4a69912 100644
--- a/components/atom/input/src/Password/index.js
+++ b/components/atom/input/src/Password/index.js
@@ -1,16 +1,12 @@
import {forwardRef, useState} from 'react'
+import cx from 'classnames'
import PropTypes from 'prop-types'
import useControlledState from '@s-ui/react-hooks/lib/useControlledState'
-import Input from '../Input/index.js'
-import {
- BASE_CLASS_PASSWORD,
- BASE_CLASS_PASSWORD_TOGGLE_BUTTON,
- PASSWORD,
- TEXT
-} from './config.js'
+import Input from '../Input/Component/index.js'
+import {BASE_CLASS_PASSWORD_TOGGLE_BUTTON, PASSWORD, TEXT} from './config.js'
const Password = forwardRef(
(
@@ -38,7 +34,7 @@ const Password = forwardRef(
}
return (
-
+ <>
-
+
{type === PASSWORD ? pwShowLabel : pwHideLabel}
-
-
+
+ >
)
}
)
diff --git a/components/atom/input/src/Password/styles/index.scss b/components/atom/input/src/Password/styles/index.scss
index 6da24f47f1..ce2e2dbb0c 100644
--- a/components/atom/input/src/Password/styles/index.scss
+++ b/components/atom/input/src/Password/styles/index.scss
@@ -1,16 +1,11 @@
-$base-class-password: '#{$base-class-input}-password';
+$base-class-password: '#{$base-class}-password';
#{$base-class-password} {
- position: relative;
- width: 100%;
-
&--toggleButton {
color: $c-atom-input-password-toggle-button;
cursor: pointer;
- position: absolute;
- right: $r-atom-input-password-toggle-button;
- top: 50%;
- transform: translateY(-50%);
user-select: none;
+ display: flex;
+ align-items: center;
}
}
diff --git a/components/atom/input/src/config.js b/components/atom/input/src/config.js
index 75c4f7aef1..97ad8f508e 100644
--- a/components/atom/input/src/config.js
+++ b/components/atom/input/src/config.js
@@ -6,6 +6,8 @@ export const COMPONENT = 'Input'
export const BASE = `${PREFIX}-${CATEGORY}${COMPONENT}`
+export const BASE_CLASS_ITEM = `${BASE}-item`
+export const BASE_CLASS_AREA_FOCUSABLE = `${BASE}-area-focusable`
export const BASE_CLASS = `${BASE}-input`
// Enums
@@ -59,9 +61,14 @@ export const getClassNames = ({
hideInput && `${BASE_CLASS}--hidden`,
noBorder && `${BASE_CLASS}--noBorder`,
readOnly && `${BASE_CLASS}--readOnly`,
- errorState && `${BASE_CLASS}--${INPUT_STATES.ERROR}`,
- errorState === false && `${BASE_CLASS}--${INPUT_STATES.SUCCESS}`,
- state && `${BASE_CLASS}--${state}`,
+ errorState && `${BASE_CLASS}--status-${INPUT_STATES.ERROR}`,
+ errorState === false && `${BASE_CLASS}--status-${INPUT_STATES.SUCCESS}`,
+ state && `${BASE_CLASS}--status-${state}`,
shape && `${BASE_CLASS}-shape-${shape}`
)
}
+
+export const isFunction = fn => typeof fn === 'function'
+
+export const isValidSize = charSize =>
+ Number.isInteger(charSize) && charSize >= 0
diff --git a/components/atom/input/src/helper.js b/components/atom/input/src/helper.js
new file mode 100644
index 0000000000..882d809f56
--- /dev/null
+++ b/components/atom/input/src/helper.js
@@ -0,0 +1,7 @@
+export const checkIfValidNumberInput = event => {
+ // Check if input type number is valid as input type number doesn't currently work in browsers like Safari and Firefox
+ // Allowing: Integers | Backspace | Tab | Delete | Left & Right arrow keys
+ const allowedCharacter = /(^\d*$)|(Backspace|Tab|Delete|ArrowLeft|ArrowRight)/
+
+ return !event.key.match(allowedCharacter) && event.preventDefault()
+}
diff --git a/components/atom/input/src/index.js b/components/atom/input/src/index.js
index 382998bf1d..ba3a1a5017 100644
--- a/components/atom/input/src/index.js
+++ b/components/atom/input/src/index.js
@@ -1,22 +1,61 @@
import {forwardRef} from 'react'
+import cx from 'classnames'
import PropTypes from 'prop-types'
-import Input, {inputSizes, inputStates} from './Input/index.js'
-import Mask from './Mask/index.js'
-import Password from './Password/index.js'
-import {INPUT_SHAPES, TYPES} from './config.js'
-
-const AtomInput = forwardRef(({type, ...props}, ref) => {
- switch (type) {
- case 'sui-password':
- return
- case 'mask':
- return
- default:
- return
- }
-})
+import Input from './Input/index.js'
+import {BASE, INPUT_SHAPES, INPUT_STATES, SIZES, TYPES, isValidSize} from './config.js'
+import {checkIfValidNumberInput} from './helper.js'
+
+const AtomInput = forwardRef(({
+ type,
+ shape,
+ charsSize,
+ size = SIZES.MEDIUM,
+ noBorder,
+ errorState,
+ state,
+ disabled,
+ readOnly,
+ ...props
+ },
+ ref
+ ) => {
+ return (
+
+
+
+ )
+ }
+)
AtomInput.propTypes = {
/** native types (text, date, ...), 'sui-password' */
@@ -77,7 +116,7 @@ AtomInput.propTypes = {
disabled: PropTypes.bool,
/** 's' or 'm', default: 'm' */
- size: PropTypes.oneOf(Object.values(inputSizes)),
+ size: PropTypes.oneOf(Object.values(SIZES)),
/** width of input based in number of characters (native "size" attribute) */
charsSize: PropTypes.number,
@@ -107,7 +146,7 @@ AtomInput.propTypes = {
errorState: PropTypes.bool,
/** 'success', 'error' or 'alert' */
- state: PropTypes.oneOf(Object.values(inputStates)),
+ state: PropTypes.oneOf(Object.values(INPUT_STATES)),
/** value of the control */
value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
@@ -131,7 +170,13 @@ AtomInput.propTypes = {
inputMode: PropTypes.string,
/** Sets the shape of the input field. It can be 'rounded', 'square' or 'circle' */
- shape: PropTypes.string
+ shape: PropTypes.string,
+
+ /** Wether to hide the input border or not */
+ noBorder: PropTypes.bool,
+
+ /* This Boolean attribute prevents the user from interacting with the input but without disabled styles */
+ readOnly: PropTypes.bool
}
AtomInput.displayName = 'AtomInput'
@@ -139,8 +184,8 @@ AtomInput.displayName = 'AtomInput'
export default AtomInput
export {
- inputSizes,
- inputStates,
+ SIZES as inputSizes,
+ INPUT_STATES as inputStates,
TYPES as inputTypes,
INPUT_SHAPES as inputShapes
}
diff --git a/components/atom/input/src/mixins.scss b/components/atom/input/src/mixins.scss
deleted file mode 100644
index 9985338e36..0000000000
--- a/components/atom/input/src/mixins.scss
+++ /dev/null
@@ -1,75 +0,0 @@
-@mixin atom-input-shape-wrapper(
- $baseClass,
- $baseClassName,
- $shapeMap,
- $sizesMap,
- $bdrs-defaultValue,
- $sz-defaultValue
-) {
- $this: &;
- @if #{'sui-AtomInput-input'} == $baseClassName {
- @each $shapeMapKey, $shapeMapValue in $shapeMap {
- @if $shapeMapKey != 'circle' {
- {$baseClassName}-shape-#{$shapeMapKey} {
- border-radius: $shapeMapValue;
- }
- } @else {
- @each $sizeKey, $sizeValue in $sizesMap {
- {$baseClassName}-shape-#{$shapeMapKey}#{$baseClassName}-size-#{$sizeKey} {
- border-radius: $sizeValue * 0.5;
- }
- }
- }
- }
- } @else {
- > *,
- #{$baseClass}-input {
- border-radius: 0;
- }
- > *:first-child {
- border-top-left-radius: $bdrs-defaultValue;
- border-bottom-left-radius: $bdrs-defaultValue;
- }
- > *:last-child {
- border-top-right-radius: $bdrs-defaultValue;
- border-bottom-right-radius: $bdrs-defaultValue;
- }
- @each $shapeMapKey, $shapeMapValue in $shapeMap {
- {$baseClassName}-shape-#{$shapeMapKey} {
- > *,
- #{$baseClass}-input {
- border-radius: 0;
- }
- @if $shapeMapKey != 'circle' {
- border-radius: $shapeMapValue;
- > *:first-child {
- border-top-left-radius: $shapeMapValue;
- border-bottom-left-radius: $shapeMapValue;
- }
- > *:last-child {
- border-top-right-radius: $shapeMapValue;
- border-bottom-right-radius: $shapeMapValue;
- }
- } @else {
- @each $sizeKey, $sizeValue in $sizesMap {
- {$baseClassName}-shape-#{$shapeMapKey}#{$baseClassName}-size-#{$sizeKey} {
- border-radius: $sizeValue * 0.5;
- > *,
- #{$baseClass}-input {
- border-radius: 0;
- }
- > *:first-child {
- border-top-left-radius: $sizeValue * 0.5;
- border-bottom-left-radius: $sizeValue * 0.5;
- }
- > *:last-child {
- border-top-right-radius: $sizeValue * 0.5;
- border-bottom-right-radius: $sizeValue * 0.5;
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/components/atom/input/src/styles/index.scss b/components/atom/input/src/styles/index.scss
index 6d42d354f5..cb92baa520 100644
--- a/components/atom/input/src/styles/index.scss
+++ b/components/atom/input/src/styles/index.scss
@@ -1,5 +1,115 @@
+@use 'sass:math';
+
$base-class: '.sui-AtomInput';
+$base-class-area-focusable: '.sui-AtomInput-area-focusable';
@import '../Input/Component/index';
@import '../Input/Wrappers/index';
@import '../Password/index';
+
+#{$base-class} {
+ display: flex;
+ align-items: stretch;
+ flex-grow: 1;
+
+ #{$base-class}-item {
+ border: $bd-atom-input-base;
+ &:first-child {
+ border-bottom-left-radius: $bdrs-atom-input;
+ border-top-left-radius: $bdrs-atom-input;
+ border-left-width: $bdw-s;
+ }
+ &:last-child {
+ border-bottom-right-radius: $bdrs-atom-input;
+ border-top-right-radius: $bdrs-atom-input;
+ border-right-width: $bdw-s;
+ }
+ }
+
+ &:not(#{$base-class}--has-charSize) {
+ #{$base-class-area-focusable} {
+ flex-grow: 1;
+ }
+ }
+
+ @each $shapeMapKey, $shapeMapValue in $bdrs-atom-input-shapes {
+ {$base-class}-shape-#{$shapeMapKey} {
+ #{$base-class}-item {
+ &:first-child {
+ border-bottom-left-radius: $shapeMapValue;
+ border-top-left-radius: $shapeMapValue;
+ }
+ &:last-child {
+ border-bottom-right-radius: $shapeMapValue;
+ border-top-right-radius: $shapeMapValue;
+ }
+ }
+ }
+ }
+
+ #{$base-class-area-focusable} {
+ display: flex;
+ padding-left: $pl-atom-input;
+ padding-right: $pr-atom-input;
+ background: $bgc-atom-input;
+ gap: math.div($p-l, 2);
+ &:focus-within {
+ border: $bd-atom-input-focus;
+ box-shadow: $bxsh-atom-input;
+ outline: 0 none;
+ }
+ }
+
+ @each $state, $color in $states-atom-input {
+ {$base-class}--status-#{$state} {
+ #{$base-class}-item {
+ border-color: $color;
+ }
+ }
+ }
+
+ {$base-class}--is-read-only {
+ #{$base-class-area-focusable} {
+ background: $bgc-atom-input-read-only;
+ border: $bd-atom-input-read-only;
+ color: $c-atom-input-read-only;
+ }
+ }
+
+ {$base-class}--is-disabled {
+ #{$base-class-area-focusable} {
+ pointer-events: none;
+ }
+ &:not(#{$base-class}--is-read-only) {
+ #{$base-class-area-focusable} {
+ -webkit-text-fill-color: $c-atom-input-disabled;
+ background: $bgc-atom-input-disabled;
+ border: $bd-atom-input-disabled;
+ color: $c-atom-input-disabled;
+ }
+ }
+ }
+
+ @each $type, $attr in $sizes-atom-input {
+ {$base-class}-size-#{$type} {
+ height: $attr;
+ min-height: $attr;
+ }
+ }
+
+ {$base-class}-borderless {
+ &,
+ {$base-class}--is-disabled:not(#{$base-class}--is-read-only) {
+ #{$base-class}-item {
+ border-width: 0;
+ }
+ #{$base-class-area-focusable} {
+ padding-left: $pl-atom-input + $bdw-s;
+ padding-right: $pr-atom-input + $bdw-s;
+ &:focus-within {
+ box-shadow: none;
+ }
+ }
+ }
+ }
+}
diff --git a/components/atom/input/src/styles/settings.scss b/components/atom/input/src/styles/settings.scss
index 13012356cd..72501a9dc4 100644
--- a/components/atom/input/src/styles/settings.scss
+++ b/components/atom/input/src/styles/settings.scss
@@ -1,3 +1 @@
@import '../settings.scss';
-
-@import '../mixins.scss';
diff --git a/components/atom/label/CHANGELOG.md b/components/atom/label/CHANGELOG.md
index e971a2468a..6b0068587a 100644
--- a/components/atom/label/CHANGELOG.md
+++ b/components/atom/label/CHANGELOG.md
@@ -1,5 +1,16 @@
# CHANGELOG
+# 1.22.0 (2022-09-29)
+
+
+### Features
+
+* **components/atom/label:** add opacity token ([#2338](https://github.com/SUI-Components/sui-components/issues/2338)) ([56540fa](https://github.com/SUI-Components/sui-components/commit/56540fa9d5ea7625eb91d273ab87c5f7285f6bd4))
+* **Root:** Delete undefined dependencies ([c145905](https://github.com/SUI-Components/sui-components/commit/c145905350328925ba6fda2a462d7f8b508c8ea0))
+* **Root:** Merge commit ([d3735d0](https://github.com/SUI-Components/sui-components/commit/d3735d0644332e674d5a5b6291680697f0d6f7c4))
+
+
+
# 1.21.0 (2022-06-30)
diff --git a/components/atom/label/package.json b/components/atom/label/package.json
index 8daaaa0e40..4307553392 100644
--- a/components/atom/label/package.json
+++ b/components/atom/label/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-label",
- "version": "1.21.0",
+ "version": "1.22.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/label/src/styles/index.scss b/components/atom/label/src/styles/index.scss
index 4ae987b8bb..9e55e68aa3 100644
--- a/components/atom/label/src/styles/index.scss
+++ b/components/atom/label/src/styles/index.scss
@@ -40,7 +40,7 @@ $base-class: '.sui-AtomLabel';
&--disabled {
cursor: default;
- opacity: 0.3;
+ opacity: $o-atom-label-disabled;
pointer-events: none;
}
diff --git a/components/atom/label/src/styles/settings.scss b/components/atom/label/src/styles/settings.scss
index e5960402bc..6157875b58 100644
--- a/components/atom/label/src/styles/settings.scss
+++ b/components/atom/label/src/styles/settings.scss
@@ -2,6 +2,7 @@ $c-atom-label: inherit !default;
$c-atom-label-optional: $c-gray-light !default;
$c-atom-label-contrast: $c-white !default;
$c-atom-label-disabled: inherit !default;
+$o-atom-label-disabled: 0.3 !default;
$fw-atom-label: inherit !default;
$c-atom-label-type: success $c-success, error $c-error, alert $c-alert,
contrast $c-atom-label-contrast, disabled $c-atom-label-disabled !default;
diff --git a/components/atom/pinInput/CHANGELOG.md b/components/atom/pinInput/CHANGELOG.md
index 28495d9be8..1c14c4970d 100644
--- a/components/atom/pinInput/CHANGELOG.md
+++ b/components/atom/pinInput/CHANGELOG.md
@@ -1,5 +1,15 @@
# CHANGELOG
+# 1.11.0 (2022-10-11)
+
+
+### Features
+
+* **components/atom/pinInput:** create new token to be able to overwrite the placeholder color ([513ae8a](https://github.com/SUI-Components/sui-components/commit/513ae8acc0728d6aa9e1a5780871985de2b52b3d))
+* **components/atom/pinInput:** replace inherit by auto ([c2f410e](https://github.com/SUI-Components/sui-components/commit/c2f410e589644bcbb1a26c5c107a73f336442d82))
+
+
+
# 1.10.0 (2022-09-05)
diff --git a/components/atom/pinInput/package.json b/components/atom/pinInput/package.json
index 2a30c11ba6..107a9be070 100644
--- a/components/atom/pinInput/package.json
+++ b/components/atom/pinInput/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-pin-input",
- "version": "1.10.0",
+ "version": "1.11.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/pinInput/src/PinInputField.scss b/components/atom/pinInput/src/PinInputField.scss
index 9ab9a55566..0617600774 100644
--- a/components/atom/pinInput/src/PinInputField.scss
+++ b/components/atom/pinInput/src/PinInputField.scss
@@ -10,6 +10,10 @@
padding: 0;
text-align: center;
+ &::placeholder {
+ color: $c-pin-input-placeholder;
+ }
+
&:focus {
border: $bdw-s solid $c-primary-dark;
cursor: text;
diff --git a/components/atom/pinInput/src/config.scss b/components/atom/pinInput/src/config.scss
index 6ddd06549d..ac371a24cd 100644
--- a/components/atom/pinInput/src/config.scss
+++ b/components/atom/pinInput/src/config.scss
@@ -4,6 +4,7 @@ $bdw-pin-input-field: $bdw-s !default;
$fw-pin-input-field: $fw-regular !default;
$lh-pin-input-field: $lh-m !default;
$m-pin-input-children: $m-m !default;
+$c-pin-input-placeholder: auto !default;
$s-pin-input-field: (
// 64px
diff --git a/components/atom/popover/CHANGELOG.md b/components/atom/popover/CHANGELOG.md
index 403d0c5c29..e825a143e7 100644
--- a/components/atom/popover/CHANGELOG.md
+++ b/components/atom/popover/CHANGELOG.md
@@ -1,5 +1,18 @@
# CHANGELOG
+# 3.13.0 (2022-10-07)
+
+
+### Features
+
+* **components/atom/popover:** add icon color type ([a6dac91](https://github.com/SUI-Components/sui-components/commit/a6dac91162387b0aa7e5fb99557d76f061ba034b))
+
+
+
+# 3.12.0 (2022-10-06)
+
+
+
# 3.11.0 (2022-06-20)
diff --git a/components/atom/popover/demo/ArticleType.js b/components/atom/popover/demo/ArticleType.js
index 6c6e07f4bb..1883d94147 100644
--- a/components/atom/popover/demo/ArticleType.js
+++ b/components/atom/popover/demo/ArticleType.js
@@ -1,32 +1,68 @@
import AtomPopover from 'components/atom/popover/src/index.js'
import PropTypes from 'prop-types'
-import {Article, Button, H2, Paragraph} from '@s-ui/documentation-library'
+import IconClose from './Icons/IconClose.js'
+import {
+ Article,
+ Button,
+ H2,
+ Paragraph,
+ Grid,
+ Cell
+} from '@s-ui/documentation-library'
const ArticleType = ({className, content: Content}) => {
return (
-
-
-
Custom Types
-
- You can even define some other extra types defining your own vertical
- custom types and looping this defined keys through scss.
-
-
-
-
- {}}
- outline
- style={{
- display: 'inline-block',
- margin: '0 auto',
- height: 'fit-content'
- }}
- >
- Target
-
-
+
+ Custom Types
+
+ You can even define some other extra types defining your own vertical
+ custom types and looping this defined keys through scss.
+
+
+
+ }
+ content={Content}
+ hideArrow={false}
+ >
+ {}}
+ outline
+ style={{
+ display: 'inline-block',
+ margin: '0 auto',
+ height: 'fit-content'
+ }}
+ >
+ Target
+
+
+ |
+
+ }
+ content={Content}
+ hideArrow={false}
+ >
+ {}}
+ outline
+ style={{
+ display: 'inline-block',
+ margin: '0 auto',
+ height: 'fit-content'
+ }}
+ >
+ Target
+
+
+ |
+
)
}
diff --git a/components/atom/popover/demo/index.scss b/components/atom/popover/demo/index.scss
index 4b02526904..4d4706421a 100644
--- a/components/atom/popover/demo/index.scss
+++ b/components/atom/popover/demo/index.scss
@@ -1,13 +1,21 @@
@import '~@s-ui/theme/lib/index';
+@import '../src/styles/settings';
+
$popover-type: (
dark: (
bgc: $c-gray-dark-3,
- bdc: $c-gray-dark-3
+ bdc: $c-gray-dark-3,
+ c-icon: $c-white
+ ),
+ alert: (
+ bgc: $c-alert-dark-3,
+ bdc: $c-alert-dark-3,
+ c-icon: $c-white
)
);
-@import '../src/index';
+@import '../src/styles/index';
.DemoAtomPopover-section {
.blink {
diff --git a/components/atom/popover/package.json b/components/atom/popover/package.json
index a3f91f9816..38568d53ad 100644
--- a/components/atom/popover/package.json
+++ b/components/atom/popover/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-popover",
- "version": "3.11.0",
+ "version": "3.13.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/popover/src/styles/index.scss b/components/atom/popover/src/styles/index.scss
index 27181642ae..c077193dc0 100644
--- a/components/atom/popover/src/styles/index.scss
+++ b/components/atom/popover/src/styles/index.scss
@@ -27,10 +27,16 @@ $class-arrow: '#{$base-class}-arrow';
@each $type-key, $type-value in $popover-type {
$bgc: map-get($type-value, bgc);
$bdc: map-get($type-value, bdc);
+ $c-icon: map-get($type-value, c-icon);
&--type-#{$type-key} {
background-color: $bgc;
border-color: $bdc;
+ #{$base-class}-closeIcon {
+ svg {
+ fill: $c-icon;
+ }
+ }
}
}
}
@@ -43,7 +49,7 @@ $class-arrow: '#{$base-class}-arrow';
z-index: $z-tooltips;
svg {
- fill: $c-atom-popover-close-icon !important;
+ fill: $c-atom-popover-close-icon;
height: $sz-atom-popover-close-icon;
width: $sz-atom-popover-close-icon;
}
diff --git a/components/atom/progressBar/CHANGELOG.md b/components/atom/progressBar/CHANGELOG.md
index 4c55159eae..344e25d3fa 100644
--- a/components/atom/progressBar/CHANGELOG.md
+++ b/components/atom/progressBar/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 2.9.0 (2022-10-06)
+
+
+
# 2.8.0 (2022-06-20)
diff --git a/components/atom/progressBar/package.json b/components/atom/progressBar/package.json
index 47e3d64066..93d78fe5df 100644
--- a/components/atom/progressBar/package.json
+++ b/components/atom/progressBar/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-progress-bar",
- "version": "2.8.0",
+ "version": "2.9.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/radioButton/CHANGELOG.md b/components/atom/radioButton/CHANGELOG.md
index e0f53f2f9e..8ea6a9c73e 100644
--- a/components/atom/radioButton/CHANGELOG.md
+++ b/components/atom/radioButton/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 1.10.0 (2022-10-06)
+
+
+
# 1.9.0 (2022-06-20)
diff --git a/components/atom/radioButton/package.json b/components/atom/radioButton/package.json
index cf7c144b0a..1adf827dc3 100644
--- a/components/atom/radioButton/package.json
+++ b/components/atom/radioButton/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-radio-button",
- "version": "1.9.0",
+ "version": "1.10.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/skeleton/CHANGELOG.md b/components/atom/skeleton/CHANGELOG.md
index ec75638849..c8496da3a9 100644
--- a/components/atom/skeleton/CHANGELOG.md
+++ b/components/atom/skeleton/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 1.6.0 (2022-10-06)
+
+
+
# 1.5.0 (2022-06-20)
diff --git a/components/atom/skeleton/demo/ArticleVariant.js b/components/atom/skeleton/demo/ArticleVariant.js
index d25fb1d0ac..2398e456e0 100644
--- a/components/atom/skeleton/demo/ArticleVariant.js
+++ b/components/atom/skeleton/demo/ArticleVariant.js
@@ -14,6 +14,9 @@ import {
import AtomSkeleton, {atomSkeletonVariants} from '../src/index.js'
+const height = 200
+const width = 200
+
const ArticleVariant = ({className}) => {
const [variantState, setVariantState] = useState()
return (
@@ -44,7 +47,11 @@ const ArticleVariant = ({className}) => {
-
+
)
}
diff --git a/components/atom/skeleton/package.json b/components/atom/skeleton/package.json
index 8193374e78..7ce157fec0 100644
--- a/components/atom/skeleton/package.json
+++ b/components/atom/skeleton/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-skeleton",
- "version": "1.5.0",
+ "version": "1.6.0",
"description": "Display the loading state of a component while avoding layout shift",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/slider/CHANGELOG.md b/components/atom/slider/CHANGELOG.md
index e53f1cab9b..858af22095 100644
--- a/components/atom/slider/CHANGELOG.md
+++ b/components/atom/slider/CHANGELOG.md
@@ -1,5 +1,25 @@
# CHANGELOG
+# 1.30.0 (2022-10-01)
+
+
+### Features
+
+* **components/atom/slider:** Remove -system ([4881c4b](https://github.com/SUI-Components/sui-components/commit/4881c4b79e5f2f4da5e6986c542ac36e253d1316))
+
+
+
+# 1.29.0 (2022-09-30)
+
+
+### Features
+
+* **components/atom/slider:** add z-index in tooltip ([8eeca33](https://github.com/SUI-Components/sui-components/commit/8eeca333bf1c944de479ed3c3383d5fba03b2dbc))
+* **Root:** Delete undefined dependencies ([c145905](https://github.com/SUI-Components/sui-components/commit/c145905350328925ba6fda2a462d7f8b508c8ea0))
+* **Root:** Merge commit ([d3735d0](https://github.com/SUI-Components/sui-components/commit/d3735d0644332e674d5a5b6291680697f0d6f7c4))
+
+
+
# 1.28.0 (2022-07-06)
diff --git a/components/atom/slider/README.md b/components/atom/slider/README.md
index 7d2e937fcf..7bb0500d3f 100644
--- a/components/atom/slider/README.md
+++ b/components/atom/slider/README.md
@@ -20,6 +20,16 @@ import AtomSlider from '@s-ui/react-atom-slider'
```
+### Basic usage with custom markers (only first and last position)
+
+```js
+
+```
+
### Step 25 and default value 50
```js
diff --git a/components/atom/slider/package.json b/components/atom/slider/package.json
index 3e78add891..b05be9a37f 100644
--- a/components/atom/slider/package.json
+++ b/components/atom/slider/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-slider",
- "version": "1.28.0",
+ "version": "1.30.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/slider/src/index.js b/components/atom/slider/src/index.js
index ace2d5779a..4eaeebfead 100644
--- a/components/atom/slider/src/index.js
+++ b/components/atom/slider/src/index.js
@@ -155,7 +155,7 @@ AtomSlider.propTypes = {
/* only if range=false, shows a position fixed label with the current value instead of a tooltip */
valueLabel: PropTypes.bool,
- /* Set your own mark labels */
+ /* Set your own mark labels, usually first and last positions */
marks: PropTypes.array,
/* callback to format the value shown as label */
diff --git a/components/atom/slider/src/styles/index.scss b/components/atom/slider/src/styles/index.scss
index ce98114ade..654bcec5db 100644
--- a/components/atom/slider/src/styles/index.scss
+++ b/components/atom/slider/src/styles/index.scss
@@ -147,6 +147,8 @@ $class-tooltip-hidden: '#{$class-tooltip}-hidden';
}
#{$class-tooltip} {
+ z-index: $z-atom-slider-tooltip;
+
#{$class-tooltip-inner} {
background: transparent;
border-color: transparent;
diff --git a/components/atom/slider/src/styles/settings.scss b/components/atom/slider/src/styles/settings.scss
index e49c28b540..c303d303f2 100644
--- a/components/atom/slider/src/styles/settings.scss
+++ b/components/atom/slider/src/styles/settings.scss
@@ -13,7 +13,7 @@ $ml-atom-slider-handle: 0 !default;
$ml-atom-slider-label: 0 !default;
$mb-atom-slider-label: $m-m !default;
$trf-atom-slider-label: translateX(-50%) !default;
-$c-atom-slider-label: $c-system !default;
+$c-atom-slider-label: $c-black !default;
$w-atom-slider-handle: 24px !default;
$b-atom-slider-handle: $bdw-s solid $c-primary !default;
$bxsh-atom-slider-handle: none !default;
@@ -22,3 +22,5 @@ $h-atom-slider-track: 8px !default;
$p-atom-slider: $p-l !default;
$mt-atom-slider-mark: 10px !default;
+
+$z-atom-slider-tooltip: auto !default;
diff --git a/components/atom/spinner/CHANGELOG.md b/components/atom/spinner/CHANGELOG.md
index 02a9f39827..d11c59e8ba 100644
--- a/components/atom/spinner/CHANGELOG.md
+++ b/components/atom/spinner/CHANGELOG.md
@@ -1,5 +1,15 @@
# CHANGELOG
+# 2.3.0 (2022-10-06)
+
+
+### Features
+
+* **Root:** Delete undefined dependencies ([c145905](https://github.com/SUI-Components/sui-components/commit/c145905350328925ba6fda2a462d7f8b508c8ea0))
+* **Root:** Merge commit ([d3735d0](https://github.com/SUI-Components/sui-components/commit/d3735d0644332e674d5a5b6291680697f0d6f7c4))
+
+
+
# 2.2.0 (2022-06-20)
diff --git a/components/atom/spinner/package.json b/components/atom/spinner/package.json
index 1acd22447d..54ffca2ff5 100644
--- a/components/atom/spinner/package.json
+++ b/components/atom/spinner/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-spinner",
- "version": "2.2.0",
+ "version": "2.3.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/switch/CHANGELOG.md b/components/atom/switch/CHANGELOG.md
index a0e9bdffb2..b63522fba0 100644
--- a/components/atom/switch/CHANGELOG.md
+++ b/components/atom/switch/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 1.28.0 (2022-10-06)
+
+
+
# 1.27.0 (2022-06-20)
diff --git a/components/atom/switch/package.json b/components/atom/switch/package.json
index e8af0fcd64..40fe1944ea 100644
--- a/components/atom/switch/package.json
+++ b/components/atom/switch/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-switch",
- "version": "1.27.0",
+ "version": "1.28.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/table/CHANGELOG.md b/components/atom/table/CHANGELOG.md
index 77f680d322..cdc85eaff5 100644
--- a/components/atom/table/CHANGELOG.md
+++ b/components/atom/table/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 1.14.0 (2022-10-06)
+
+
+
# 1.13.0 (2022-06-20)
diff --git a/components/atom/table/package.json b/components/atom/table/package.json
index c0e14f8150..fc033aa4ea 100644
--- a/components/atom/table/package.json
+++ b/components/atom/table/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-table",
- "version": "1.13.0",
+ "version": "1.14.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/tag/CHANGELOG.md b/components/atom/tag/CHANGELOG.md
index d26397c0f4..59795e42a7 100644
--- a/components/atom/tag/CHANGELOG.md
+++ b/components/atom/tag/CHANGELOG.md
@@ -1,5 +1,14 @@
# CHANGELOG
+# 2.44.0 (2022-10-01)
+
+
+### Features
+
+* **components/atom/tag:** Remove -system ([50ba722](https://github.com/SUI-Components/sui-components/commit/50ba7220a71b7b123bb8e93dd3db5dde3911e5cc))
+
+
+
# 2.43.0 (2022-07-27)
diff --git a/components/atom/tag/demo/articles/ArticleDesign.js b/components/atom/tag/demo/articles/ArticleDesign.js
index 99ff42eaea..43bf315fb1 100644
--- a/components/atom/tag/demo/articles/ArticleDesign.js
+++ b/components/atom/tag/demo/articles/ArticleDesign.js
@@ -34,28 +34,32 @@ const ArticleDesign = ({className}) => {
)}
{Object.values(atomTagDesigns)
.reverse()
- .map((size, index) => (
+ .map((design, index) => (
- {size}
+ {design}
|
-
+
|
-
+
|
-
+
|
|
diff --git a/components/atom/tag/package.json b/components/atom/tag/package.json
index 87c82d74b3..ac4c7ba2c3 100644
--- a/components/atom/tag/package.json
+++ b/components/atom/tag/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-tag",
- "version": "2.43.0",
+ "version": "2.43.0-beta.0",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -9,7 +9,7 @@
"build:styles": "cpx './src/**/*.scss' ./lib"
},
"dependencies": {
- "@s-ui/component-dependencies": "latest"
+ "@s-ui/component-dependencies": "1"
},
"keywords": [],
"author": "",
diff --git a/components/atom/tag/src/_settings.scss b/components/atom/tag/src/_settings.scss
index 6b0ff182d2..084cf259cc 100644
--- a/components/atom/tag/src/_settings.scss
+++ b/components/atom/tag/src/_settings.scss
@@ -3,18 +3,42 @@ $bgc-atom-tag: color-variation($c-gray, 3) !default;
$mw-label: 240px !default;
// sizes
+$h-atom-tag-xl: 48px !default;
$h-atom-tag-l: 40px !default;
$h-atom-tag-m: 32px !default;
$h-atom-tag-s: 24px !default;
+$h-atom-tag-xs: 16px !default;
$m-atom-tag: $m-m !default;
+$p-atom-tag-xl: 0 $p-l !default;
$p-atom-tag-l: 0 $p-l !default;
$p-atom-tag-m: 0 $p-l !default;
$p-atom-tag-s: 0 $p-m !default;
+$p-atom-tag-xs: 0 $p-m !default;
-$p-atom-tag-hasIcon-hasClose: (
+$atom-tag-sizes: (xlarge, large, medium, small, xsmall) !default;
+
+$h-atom-tags: (
+ xlarge: $h-atom-tag-xl,
+ large: $h-atom-tag-l,
+ medium: $h-atom-tag-m,
+ small: $h-atom-tag-s,
+ xsmall: $h-atom-tag-xs
+) !default;
+
+$p-atom-tags: (
+ xlarge: $p-atom-tag-xl,
+ large: $p-atom-tag-l,
+ medium: $p-atom-tag-m,
small: $p-atom-tag-s,
+ xsmall: $p-atom-tag-xs
+) !default;
+
+$p-atom-tag-hasIcon-hasClose: (
+ xlarge: $p-atom-tag-xl,
+ large: $p-atom-tag-l,
medium: $p-atom-tag-m,
- large: $p-atom-tag-l
+ small: $p-atom-tag-s,
+ xsmall: $p-atom-tag-xs
) !default;
// outline
@@ -37,7 +61,7 @@ $w-atom-tag-clickable: 32px !default;
// closable
$bgc-atom-tag-closable-icon: transparent !default;
-$c-atom-tag-closable-icon: $c-system !default;
+$c-atom-tag-closable-icon: $c-black !default;
$bgc-atom-tag-closable-icon--hover: $c-gray !default;
$c-atom-tag-closable-icon--hover: $c-gray-light-3 !default;
diff --git a/components/atom/tag/src/constants.js b/components/atom/tag/src/constants.js
index b4c93e45dc..325a796c8c 100644
--- a/components/atom/tag/src/constants.js
+++ b/components/atom/tag/src/constants.js
@@ -11,10 +11,12 @@ export const ACTIONABLE_ONLY_PROPS = [
export const STANDARD_ONLY_PROPS = ['closeIcon', 'onClose']
-export const SIZES = {
+export var SIZES = {
+ XLARGE: 'xlarge',
LARGE: 'large',
MEDIUM: 'medium',
- SMALL: 'small'
+ SMALL: 'small',
+ XSMALL: 'xsmall'
}
export const LINK_TYPES = {
diff --git a/components/atom/tag/src/index.js b/components/atom/tag/src/index.js
index 6304e2ab7e..6d118db803 100644
--- a/components/atom/tag/src/index.js
+++ b/components/atom/tag/src/index.js
@@ -11,43 +11,52 @@ import {
} from './constants.js'
import StandardTag from './Standard.js'
-const AtomTag = props => {
- const {
- design,
- href,
- icon,
- onClick,
- responsive,
- size,
- type,
- readOnly,
- disabled,
- isFitted = false
- } = props
+const AtomTag = ({
+ design,
+ href,
+ icon,
+ iconPlacement = 'left',
+ onClick,
+ responsive,
+ size = SIZES.MEDIUM,
+ type,
+ readOnly,
+ disabled,
+ isFitted = false,
+ ...props
+}) => {
const isActionable = onClick || href
- const classNames = cx(
- 'sui-AtomTag',
- `sui-AtomTag-${size}`,
- design && `sui-AtomTag--${design}`,
- icon && 'sui-AtomTag-hasIcon',
- responsive && 'sui-AtomTag--responsive',
- type && `sui-AtomTag--${type}`,
- isFitted && 'sui-AtomTag--isFitted'
- )
+ const [Component, getter] = isActionable
+ ? [ActionableTag, getActionableProps]
+ : [StandardTag, getStandardProps]
- return isActionable ? (
-
- ) : (
-
)
}
@@ -119,11 +128,6 @@ AtomTag.propTypes = {
isFitted: PropTypes.bool
}
-AtomTag.defaultProps = {
- iconPlacement: 'left',
- size: SIZES.MEDIUM
-}
-
export default AtomTag
export {DESIGNS as atomTagDesigns}
export {LINK_TYPES as linkTypes}
diff --git a/components/atom/tag/src/styles/index.scss b/components/atom/tag/src/styles/index.scss
index 20738051f5..c96f3d7246 100644
--- a/components/atom/tag/src/styles/index.scss
+++ b/components/atom/tag/src/styles/index.scss
@@ -6,7 +6,6 @@ $base-class: '.sui-AtomTag';
align-content: center;
background-color: $bgc-atom-tag;
border: $bd-atom-tag;
- border-radius: ceil($h-atom-tag-m * 0.5);
box-sizing: border-box;
cursor: default;
display: inline-flex;
@@ -103,7 +102,7 @@ $base-class: '.sui-AtomTag';
}
}
- {$self}--outline {
+ {$base-class}--design-outline {
border-color: $c-atom-tag-actionable-invert;
color: $c-atom-tag-actionable-invert;
fill: $c-atom-tag-actionable-invert;
@@ -119,50 +118,32 @@ $base-class: '.sui-AtomTag';
}
}
- &-small {
- height: $h-atom-tag-s;
- padding: $p-atom-tag-s;
- &.sui-AtomTag-hasIcon.sui-AtomTag-hasClose {
- padding: map-get($p-atom-tag-hasIcon-hasClose, 'small');
- }
-
- & .sui-AtomTag-label {
- line-height: $h-atom-tag-s;
- }
-
- .sui-AtomTag-closeable {
- @include icon-secondary-clickable-area($h-atom-tag-s);
- }
-
- .sui-AtomTag-icon {
- margin-left: 0;
- }
-
- .sui-AtomTag-secondary-icon {
- margin-right: 0;
- }
- }
+ @each $atom-tag-size in $atom-tag-sizes {
+ {$base-class}--size-#{$atom-tag-size} {
+ height: map-get($h-atom-tags, $atom-tag-size);
+ padding: map-get($p-atom-tags, $atom-tag-size);
+ border-radius: ceil(map-get($h-atom-tags, $atom-tag-size) * 0.5);
+ &.sui-AtomTag-hasIcon.sui-AtomTag-hasClose {
+ padding: map-get($p-atom-tag-hasIcon-hasClose, $atom-tag-size);
+ }
- &-medium {
- &.sui-AtomTag-hasIcon.sui-AtomTag-hasClose {
- padding: map-get($p-atom-tag-hasIcon-hasClose, 'medium');
- }
- }
+ & .sui-AtomTag-label {
+ line-height: map-get($h-atom-tags, $atom-tag-size);
+ }
- &-large {
- border-radius: ceil($h-atom-tag-l * 0.5);
- height: $h-atom-tag-l;
- padding: $p-atom-tag-l;
- &.sui-AtomTag-hasIcon.sui-AtomTag-hasClose {
- padding: map-get($p-atom-tag-hasIcon-hasClose, 'large');
- }
+ .sui-AtomTag-closeable {
+ @include icon-secondary-clickable-area(
+ map-get($h-atom-tags, $atom-tag-size)
+ );
+ }
- & .sui-AtomTag-label {
- line-height: $h-atom-tag-l;
- }
+ .sui-AtomTag-icon {
+ margin-left: 0;
+ }
- .sui-AtomTag-closeable {
- @include icon-secondary-clickable-area($h-atom-tag-l);
+ .sui-AtomTag-secondary-icon {
+ margin-right: 0;
+ }
}
}
@@ -182,22 +163,22 @@ $base-class: '.sui-AtomTag';
}
}
- &--outline {
+ &--design-outline {
background-color: $bgc-atom-tag-outline;
border: $bdw-atom-tag-outline solid $bc-atom-tag-outline;
}
- @each $name, $type in $atom-tag-types {
- $bgc: map-get($type, bgc);
- $c: map-get($type, c);
- $bgc-hover: map-get($type, bgc-hover);
- $c-hover: map-get($type, c-hover);
- $bdc: map-get($type, bdc);
- $bds: map-get($type, bds);
- $bdw: map-get($type, bdw);
- $bdc-hover: map-get($type, bdc-hover);
-
- &--#{$name} {
+ @each $type-name, $type-value in $atom-tag-types {
+ $bgc: map-get($type-value, bgc);
+ $c: map-get($type-value, c);
+ $bgc-hover: map-get($type-value, bgc-hover);
+ $c-hover: map-get($type-value, c-hover);
+ $bdc: map-get($type-value, bdc);
+ $bds: map-get($type-value, bds);
+ $bdw: map-get($type-value, bdw);
+ $bdc-hover: map-get($type-value, bdc-hover);
+
+ &--type-#{$type-name} {
background-color: $bgc;
border-color: $bdc;
border-style: $bds;
@@ -212,7 +193,7 @@ $base-class: '.sui-AtomTag';
fill: $c;
}
- {$self}--outline {
+ {$self}--design-outline {
border-color: $bgc;
color: $bgc;
background-color: $c;
diff --git a/components/atom/tag/test/index.test.js b/components/atom/tag/test/index.test.js
index d772bf9e56..ac1b5c9ea1 100644
--- a/components/atom/tag/test/index.test.js
+++ b/components/atom/tag/test/index.test.js
@@ -201,14 +201,16 @@ describe(json.name, () => {
// Given
const library = pkg
const expected = {
+ XLARGE: 'xlarge',
LARGE: 'large',
MEDIUM: 'medium',
- SMALL: 'small'
+ SMALL: 'small',
+ XSMALL: 'xsmall'
}
// When
const {atomTagSizes: actual} = library
- const {LARGE, MEDIUM, SMALL, ...others} = actual
+ const {XLARGE, LARGE, MEDIUM, SMALL, XSMALL, ...others} = actual
// Then
expect(Object.keys(others).length).to.equal(0)
diff --git a/components/atom/textarea/CHANGELOG.md b/components/atom/textarea/CHANGELOG.md
index fa3daf55f5..1412cdfef0 100644
--- a/components/atom/textarea/CHANGELOG.md
+++ b/components/atom/textarea/CHANGELOG.md
@@ -1,5 +1,15 @@
# CHANGELOG
+# 2.20.0 (2022-10-06)
+
+
+### Features
+
+* **Root:** Delete undefined dependencies ([c145905](https://github.com/SUI-Components/sui-components/commit/c145905350328925ba6fda2a462d7f8b508c8ea0))
+* **Root:** Merge commit ([d3735d0](https://github.com/SUI-Components/sui-components/commit/d3735d0644332e674d5a5b6291680697f0d6f7c4))
+
+
+
# 2.19.0 (2022-06-20)
diff --git a/components/atom/textarea/package.json b/components/atom/textarea/package.json
index 030c8143f7..b26903a7ff 100644
--- a/components/atom/textarea/package.json
+++ b/components/atom/textarea/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-textarea",
- "version": "2.19.0",
+ "version": "2.20.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/tooltip/CHANGELOG.md b/components/atom/tooltip/CHANGELOG.md
index 1cffe00e61..e838575023 100644
--- a/components/atom/tooltip/CHANGELOG.md
+++ b/components/atom/tooltip/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 2.5.0 (2022-10-06)
+
+
+
# 2.4.0 (2022-06-20)
diff --git a/components/atom/tooltip/package.json b/components/atom/tooltip/package.json
index a90bd6612c..ffbf00afda 100644
--- a/components/atom/tooltip/package.json
+++ b/components/atom/tooltip/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-tooltip",
- "version": "2.4.0",
+ "version": "2.5.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/upload/CHANGELOG.md b/components/atom/upload/CHANGELOG.md
index 954d5e3fd2..4d638f172e 100644
--- a/components/atom/upload/CHANGELOG.md
+++ b/components/atom/upload/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 3.10.0 (2022-10-06)
+
+
+
# 3.9.0 (2022-06-20)
diff --git a/components/atom/upload/package.json b/components/atom/upload/package.json
index 47b4097f76..95a208d30a 100644
--- a/components/atom/upload/package.json
+++ b/components/atom/upload/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-upload",
- "version": "3.9.0",
+ "version": "3.10.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/atom/validationText/CHANGELOG.md b/components/atom/validationText/CHANGELOG.md
index 1b8d657138..5d7afeed95 100644
--- a/components/atom/validationText/CHANGELOG.md
+++ b/components/atom/validationText/CHANGELOG.md
@@ -1,5 +1,26 @@
# CHANGELOG
+# 1.9.0 (2022-10-06)
+
+
+### Features
+
+* **components/atom/helpText:** admit react nodes as a text ([f41967e](https://github.com/SUI-Components/sui-components/commit/f41967ec354662dcc551562ccfe75aa729aff29e))
+* **components/atom/validationText:** admit react nodes as a text ([ba8379b](https://github.com/SUI-Components/sui-components/commit/ba8379babb0085e61f99de0e69740f749e558b88))
+
+
+
+# 1.8.0 (2022-09-20)
+
+
+### Features
+
+* **components/atom/validationText:** add margin top variable ([38cfc80](https://github.com/SUI-Components/sui-components/commit/38cfc8043787aaf23bf8a96cbbf97cdaed1ceeeb))
+* **components/atom/validationText:** update margin ([7a2e11e](https://github.com/SUI-Components/sui-components/commit/7a2e11ebac2eaf128eb06b0e9cde21e76a42f8ae))
+* **components/atom/validationText:** update margin variable ([1df0b7d](https://github.com/SUI-Components/sui-components/commit/1df0b7db3ae148d9f26a9ada6a71d6ea317ac72c))
+
+
+
# 1.7.0 (2022-06-20)
diff --git a/components/atom/validationText/demo/articles/ArticleDefault.js b/components/atom/validationText/demo/articles/ArticleDefault.js
new file mode 100644
index 0000000000..59d325f576
--- /dev/null
+++ b/components/atom/validationText/demo/articles/ArticleDefault.js
@@ -0,0 +1,69 @@
+import {useState} from 'react'
+
+import PropTypes from 'prop-types'
+
+import {
+ Article,
+ Cell,
+ Code,
+ Grid,
+ H2,
+ Input,
+ Label,
+ Paragraph,
+ RadioButton
+} from '@s-ui/documentation-library'
+
+import AtomValidationText, {AtomValidationTextTypes} from '../../src/index.js'
+import {flexCenteredStyle} from '../settings.js'
+
+const ArticleDefault = ({className}) => {
+ const [mode, setMode] = useState('light')
+ return (
+
+ Type
+
+ using the prop type
user can inherit the helpText color
+ styler for validation text usages.
+
+ setMode(mode === 'light' ? 'dark' : 'light')}
+ label={mode}
+ />
+
+
+
+ {Object.values(AtomValidationTextTypes).map((type, index) => (
+
+ {type}
+ |
+ ))}
+ {Object.values(AtomValidationTextTypes).map((type, index) => (
+
+
+
+ |
+ ))}
+
+
+ )
+}
+
+ArticleDefault.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleDefault
diff --git a/components/atom/validationText/demo/articles/ArticleNodes.js b/components/atom/validationText/demo/articles/ArticleNodes.js
new file mode 100644
index 0000000000..29a333dd28
--- /dev/null
+++ b/components/atom/validationText/demo/articles/ArticleNodes.js
@@ -0,0 +1,59 @@
+import PropTypes from 'prop-types'
+
+import {
+ Article,
+ Cell,
+ Grid,
+ H2,
+ Input,
+ Label,
+ Paragraph
+} from '@s-ui/documentation-library'
+
+import AtomValidationText, {AtomValidationTextTypes} from '../../src/index.js'
+import {flexCenteredStyle, nodeText} from '../settings.js'
+
+const ArticleNodes = ({className}) => {
+ return (
+
+ Node texts
+
+ The component is prepared for admit react node elements as a text.
+
+
+
+
+ {Object.values(AtomValidationTextTypes).map((type, index) => (
+
+ {type}
+ |
+ ))}
+ {Object.values(AtomValidationTextTypes).map((type, index) => (
+
+
+
+ |
+ ))}
+
+
+ )
+}
+
+ArticleNodes.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleNodes
diff --git a/components/atom/validationText/demo/index.js b/components/atom/validationText/demo/index.js
index 5c5d89f089..a48da57383 100644
--- a/components/atom/validationText/demo/index.js
+++ b/components/atom/validationText/demo/index.js
@@ -1,23 +1,10 @@
-import {useState} from 'react'
+import {H1, Paragraph} from '@s-ui/documentation-library'
-import {
- Article,
- Cell,
- Code,
- Grid,
- H1,
- H2,
- Input,
- Label,
- Paragraph,
- RadioButton
-} from '@s-ui/documentation-library'
-
-import AtomValidationText, {AtomValidationTextTypes} from '../src/index.js'
-import {flexCenteredStyle} from './settings.js'
+import ArticleDefault from './articles/ArticleDefault.js'
+import ArticleNodes from './articles/ArticleNodes.js'
+import {CLASS_SECTION} from './settings.js'
export default () => {
- const [mode, setMode] = useState('light')
return (
Validation Text
@@ -25,45 +12,9 @@ export default () => {
Validation text is used for indicating whether the entered data is
correct. It is provided by using the "Help Text" plus one color each.
-
- Type
-
- using the prop type
user can inherit the helpText color
- styler for validation text usages.
-
- setMode(mode === 'light' ? 'dark' : 'light')}
- label={mode}
- />
-
-
-
- {Object.values(AtomValidationTextTypes).map((type, index) => (
-
- {type}
- |
- ))}
- {Object.values(AtomValidationTextTypes).map((type, index) => (
-
-
-
- |
- ))}
-
-
+
+
+
)
}
diff --git a/components/atom/validationText/demo/package.json b/components/atom/validationText/demo/package.json
index 6ab06e87a2..eb54c97a6c 100644
--- a/components/atom/validationText/demo/package.json
+++ b/components/atom/validationText/demo/package.json
@@ -9,5 +9,8 @@
},
"keywords": [],
"author": "",
- "license": "ISC"
+ "license": "ISC",
+ "dependencies": {
+ "@s-ui/react-atom-icon": "1"
+ }
}
diff --git a/components/atom/validationText/demo/settings.js b/components/atom/validationText/demo/settings.js
index 566c484899..09e20c085c 100644
--- a/components/atom/validationText/demo/settings.js
+++ b/components/atom/validationText/demo/settings.js
@@ -1,3 +1,9 @@
+import {AntDesignIcon} from '@s-ui/documentation-library'
+import AtomIcon from '@s-ui/react-atom-icon'
+
+export const BASE_CLASS_DEMO = `DemoValidationText`
+export const CLASS_SECTION = `${BASE_CLASS_DEMO}-section`
+
export const flexCenteredStyle = {
display: 'flex',
justifyContent: 'center',
@@ -5,3 +11,15 @@ export const flexCenteredStyle = {
alignItems: 'center',
alignContent: 'center'
}
+
+export const checkIcon = (
+
+
+
+)
+
+export const nodeText = (
+
+ node text{checkIcon}
+
+)
diff --git a/components/atom/validationText/package.json b/components/atom/validationText/package.json
index 950be64da0..706a87e9dd 100644
--- a/components/atom/validationText/package.json
+++ b/components/atom/validationText/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-atom-validation-text",
- "version": "1.7.0",
+ "version": "1.9.0",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -9,7 +9,8 @@
"build:styles": "cpx './src/**/*.scss' ./lib"
},
"dependencies": {
- "@s-ui/component-dependencies": "1"
+ "@s-ui/component-dependencies": "1",
+ "@s-ui/react-primitive-injector": "1"
},
"keywords": [],
"author": "",
diff --git a/components/atom/validationText/src/index.js b/components/atom/validationText/src/index.js
index 1934f37fa6..2217690962 100644
--- a/components/atom/validationText/src/index.js
+++ b/components/atom/validationText/src/index.js
@@ -1,16 +1,30 @@
+import {forwardRef} from 'react'
+
import PropTypes from 'prop-types'
+import Injector from '@s-ui/react-primitive-injector'
+
import {getClassNames, TYPES} from './settings.js'
-const AtomValidationText = function ({type, text}) {
- return
{text}
-}
+const AtomValidationText = forwardRef(({type, text}, forwardedRef) => {
+ const isTextString = typeof text === 'string'
+ const Component = isTextString ? 'span' : Injector
+ return (
+
+ {text}
+
+ )
+})
AtomValidationText.displayName = 'AtomValidationText'
AtomValidationText.propTypes = {
type: PropTypes.oneOf(Object.values(TYPES)).isRequired,
- text: PropTypes.string.isRequired
+ text: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.bool])
+ .isRequired
}
export default AtomValidationText
diff --git a/components/atom/validationText/src/styles/index.scss b/components/atom/validationText/src/styles/index.scss
index f75156fb5d..1a729fa12e 100644
--- a/components/atom/validationText/src/styles/index.scss
+++ b/components/atom/validationText/src/styles/index.scss
@@ -3,7 +3,8 @@ $base-class: '.sui-AtomValidationText';
#{$base-class} {
display: block;
font-size: $fz-atom-validation-text;
- margin: $m-s 0 0;
+ margin: $m-atom-validation-text;
+
@each $type, $color in $validation {
&--#{$type} {
color: $color;
diff --git a/components/atom/validationText/src/styles/settings.scss b/components/atom/validationText/src/styles/settings.scss
index 7513bf9d1d..b05caeb484 100644
--- a/components/atom/validationText/src/styles/settings.scss
+++ b/components/atom/validationText/src/styles/settings.scss
@@ -1,2 +1,3 @@
$fz-atom-validation-text: $fz-xs !default;
+$m-atom-validation-text: $m-s 0 0 !default;
$validation: success $c-success, error $c-error, alert $c-alert;
diff --git a/components/behavior/sticky/CHANGELOG.md b/components/behavior/sticky/CHANGELOG.md
index e9ebbd7162..e6bfb59e20 100644
--- a/components/behavior/sticky/CHANGELOG.md
+++ b/components/behavior/sticky/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 1.9.0 (2022-10-06)
+
+
+
# 1.8.0 (2022-06-22)
diff --git a/components/behavior/sticky/package.json b/components/behavior/sticky/package.json
index fc28eccf7e..ba7c136438 100644
--- a/components/behavior/sticky/package.json
+++ b/components/behavior/sticky/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-behavior-sticky",
- "version": "1.8.0",
+ "version": "1.9.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/hook/usePortal/.gitignore b/components/hook/usePortal/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/components/hook/usePortal/.npmignore b/components/hook/usePortal/.npmignore
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/components/hook/usePortal/CHANGELOG.md b/components/hook/usePortal/CHANGELOG.md
new file mode 100644
index 0000000000..f2357b83a3
--- /dev/null
+++ b/components/hook/usePortal/CHANGELOG.md
@@ -0,0 +1,11 @@
+# CHANGELOG
+
+# 1.1.0 (2022-10-03)
+
+
+### Features
+
+* **components/hook/usePortal:** first version ([3462540](https://github.com/SUI-Components/sui-components/commit/34625400523cda7345e7d4d99666efa0f4bbd32b))
+
+
+
diff --git a/components/hook/usePortal/README.md b/components/hook/usePortal/README.md
new file mode 100644
index 0000000000..51d9faada5
--- /dev/null
+++ b/components/hook/usePortal/README.md
@@ -0,0 +1,98 @@
+# usePortal
+
+> Provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. ([doc](https://reactjs.org/docs/portals.html))
+
+## Installation
+
+```sh
+$ npm install @s-ui/react-hook-use-portal
+```
+
+## Usage
+
+### Basic usage
+
+```js
+// Array destructuring
+const Foo = props => {
+ const [Portal] = usePortal()
+ return (
+ <>
+ This content is rendered on the propper VDOM tree.
+
This content added at the end of the document.body
+ >
+ )
+}
+```
+
+```js
+// Object destructuring
+const Foo = props => {
+ const {Portal} = usePortal()
+ return (
+ <>
+ This content is rendered on the propper VDOM tree.
+
This content added at the end of the document.body
+ >
+ )
+}
+```
+
+### Target Configuration
+
+Target is the DOM place where the Portal might the appended. By default it is document.body. To set a different element, just add it to the hook configuration option arguments object:
+
+```js
+const Foo = props => {
+ const portalContainer = useRef()
+ const {Portal} = usePortal({target: portalContainer.current})
+ return (
+ <>
+
+ This content is rendered on the propper VDOM tree.
+
+ This content added at the end of the portalContainer element
+
+
+
{/** <-- this is the container where the portal children will be rendered **/}
+ >
+ )
+}
+```
+
+### Open and Close
+
+Portals can be opened and closed.
+
+```js
+// Statefull (uncontrolled)
+const Foo = props => {
+ const {Portal, open, close, isOpen} = usePortal()
+ return (
+ <>
+ {!isOpen &&
open }
+
+ This is added at the end of the document.body
+ close
+
+ >
+ )
+}
+```
+
+```js
+// Stateless (controlled)
+const Foo = props => {
+ const [isOpen, setIsOpen] = useState(true)
+ const {Portal} = usePortal()
+ return (
+ <>
+ {!isOpen &&
setIsOpen(true)}>open }
+
+ This is added at the end of the document.body
+ setIsOpen(false)}>close
+
+ >
+ )
+}
+```
\ No newline at end of file
diff --git a/components/hook/usePortal/demo/articles/ArticleCloseOnEvent.js b/components/hook/usePortal/demo/articles/ArticleCloseOnEvent.js
new file mode 100644
index 0000000000..afdc94f88e
--- /dev/null
+++ b/components/hook/usePortal/demo/articles/ArticleCloseOnEvent.js
@@ -0,0 +1,116 @@
+import {useRef, useState} from 'react'
+
+import PropTypes from 'prop-types'
+
+import {
+ Article,
+ Box,
+ Cell,
+ Code,
+ Grid,
+ H2,
+ H3,
+ ListItem,
+ Paragraph,
+ RadioButton,
+ UnorderedList
+} from '@s-ui/documentation-library'
+
+import usePortal from '../../src/index.js'
+
+const ArticleCloseOnEvent = ({className}) => {
+ // outside click
+ const targetedOutsideClickRef = useRef()
+ const [isOpenTargetedOutsideClick, setIsOpenTargetedOutsideClick] =
+ useState(false)
+ const {Portal: PortalOutsideClick} = usePortal({
+ hasCloseOnOutsideClick: true,
+ target: targetedOutsideClickRef.current,
+ isOpen: isOpenTargetedOutsideClick,
+ onClose: () => {
+ setIsOpenTargetedOutsideClick(!isOpenTargetedOutsideClick)
+ }
+ })
+
+ // esc press
+ const targetedEscPressRef = useRef()
+ const [isOpenCloseOnEsc, setIsOpenCloseOnEsc] = useState(false)
+ const {Portal: PortalEscPress} = usePortal({
+ hasCloseOnEsc: true,
+ target: targetedEscPressRef.current,
+ isOpen: isOpenCloseOnEsc,
+ onClose: () => {
+ setIsOpenCloseOnEsc(!isOpenCloseOnEsc)
+ }
+ })
+ return (
+
+ Configured event listeners
+
+ usePortal
hook has 2 configuration properties for event
+ triggers:
+
+
+
+ hasCloseOnOutsideClick
(bool|false)
+
+
+ hasCloseOnEsc
(bool|false)
+
+
+ hasCloseOnOutsideClick
+
+ If the hook is configured with this feature enabled (true), the portal
+ will close on every single clicking event out of its own bounding area.
+
+
+
+
+ setIsOpenTargetedOutsideClick(!isOpenTargetedOutsideClick)
+ }
+ />
+ |
+
+
+ |
+
+
+
+ This text is closed when clicking outside!
+
+
+ hasCloseOnEsc
+
+ If the hook is configured with this feature enabled (true), the portal
+ will close on every single 'Esc' keypress event.
+
+
+
+ setIsOpenCloseOnEsc(!isOpenCloseOnEsc)}
+ />
+ |
+
+
+ |
+
+
+
+ This text is closed when pressing Esc key!
+
+
+ Portals can use both behaviors enabled also.
+
+ )
+}
+
+ArticleCloseOnEvent.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleCloseOnEvent
diff --git a/components/hook/usePortal/demo/articles/ArticleCustom.js b/components/hook/usePortal/demo/articles/ArticleCustom.js
new file mode 100644
index 0000000000..c1697c4608
--- /dev/null
+++ b/components/hook/usePortal/demo/articles/ArticleCustom.js
@@ -0,0 +1,28 @@
+import PropTypes from 'prop-types'
+
+import {Article, Button, H2, Paragraph} from '@s-ui/documentation-library'
+
+import useTooltip from './ArticleCustom/useTooltip.js'
+
+const ArticleCustom = ({className}) => {
+ const [bind, Tooltip] = useTooltip()
+ return (
+
+ Custom
+
+ You can use the hook defining custom event handlers to extend its
+ functionalities to may other ways like creating tooltips.
+
+ button hovered
+
+ hello world
+
+
+ )
+}
+
+ArticleCustom.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleCustom
diff --git a/components/hook/usePortal/demo/articles/ArticleCustom/usePopper.js b/components/hook/usePortal/demo/articles/ArticleCustom/usePopper.js
new file mode 100644
index 0000000000..bc02ae8511
--- /dev/null
+++ b/components/hook/usePortal/demo/articles/ArticleCustom/usePopper.js
@@ -0,0 +1,136 @@
+import {useMemo, useRef, useState} from 'react'
+import isEqual from 'react-fast-compare'
+
+import {createPopper as defaultCreatePopper} from '@popperjs/core'
+
+import useIsomorphicLayoutEffect from '@s-ui/react-hooks/lib/useIsomorphicLayoutEffect'
+
+const EMPTY_MODIFIERS = []
+
+const usePopper = function usePopper(
+ referenceElement,
+ popperElement,
+ options = {}
+) {
+ const prevOptions = useRef(null)
+ const optionsWithDefaults = {
+ onFirstUpdate: options.onFirstUpdate,
+ placement: options.placement || 'bottom',
+ strategy: options.strategy || 'absolute',
+ modifiers: options.modifiers || EMPTY_MODIFIERS
+ }
+
+ const [state, setState] = useState({
+ styles: {
+ popper: {
+ position: optionsWithDefaults.strategy,
+ left: '0',
+ top: '0'
+ },
+ arrow: {
+ position: 'absolute'
+ }
+ },
+ attributes: {}
+ })
+
+ const updateStateModifier = useMemo(function () {
+ return {
+ name: 'updateState',
+ enabled: true,
+ phase: 'write',
+ fn: function fn({state}) {
+ const elements = Object.keys(state.elements)
+ setState({
+ styles: Object.fromEntries(
+ elements.map(function (element) {
+ return [element, state.styles[element] || {}]
+ })
+ ),
+ attributes: Object.fromEntries(
+ elements.map(function (element) {
+ return [element, state.attributes[element]]
+ })
+ )
+ })
+ },
+ requires: ['computeStyles']
+ }
+ }, [])
+
+ const popperOptions = useMemo(
+ function () {
+ const newOptions = {
+ onFirstUpdate: optionsWithDefaults.onFirstUpdate,
+ placement: optionsWithDefaults.placement,
+ strategy: optionsWithDefaults.strategy,
+ modifiers: [].concat(optionsWithDefaults.modifiers, [
+ updateStateModifier,
+ {
+ name: 'applyStyles',
+ enabled: false
+ }
+ ])
+ }
+
+ if (isEqual(prevOptions.current, newOptions)) {
+ return prevOptions.current || newOptions
+ } else {
+ prevOptions.current = newOptions
+ return newOptions
+ }
+ },
+ [
+ optionsWithDefaults.onFirstUpdate,
+ optionsWithDefaults.placement,
+ optionsWithDefaults.strategy,
+ optionsWithDefaults.modifiers,
+ updateStateModifier
+ ]
+ )
+ const popperInstanceRef = useRef()
+
+ useIsomorphicLayoutEffect(
+ function () {
+ if (popperInstanceRef.current) {
+ popperInstanceRef.current.setOptions(popperOptions)
+ }
+ },
+ [popperOptions]
+ )
+ useIsomorphicLayoutEffect(
+ function () {
+ if (
+ referenceElement == null ||
+ popperElement == null ||
+ popperInstanceRef.current
+ ) {
+ return
+ }
+
+ const createPopper = options.createPopper || defaultCreatePopper
+ const popperInstance = createPopper(
+ referenceElement,
+ popperElement,
+ popperOptions
+ )
+ popperInstanceRef.current = popperInstance
+ return function () {
+ popperInstance.destroy()
+ popperInstanceRef.current = null
+ }
+ },
+ [referenceElement, popperElement, options.createPopper]
+ )
+ return {
+ state: popperInstanceRef.current ? popperInstanceRef.current.state : null,
+ styles: state.styles,
+ attributes: state.attributes,
+ update: popperInstanceRef.current ? popperInstanceRef.current.update : null,
+ forceUpdate: popperInstanceRef.current
+ ? popperInstanceRef.current.forceUpdate
+ : null
+ }
+}
+
+export default usePopper
diff --git a/components/hook/usePortal/demo/articles/ArticleCustom/useTooltip.js b/components/hook/usePortal/demo/articles/ArticleCustom/useTooltip.js
new file mode 100644
index 0000000000..e752f29b0e
--- /dev/null
+++ b/components/hook/usePortal/demo/articles/ArticleCustom/useTooltip.js
@@ -0,0 +1,62 @@
+import {useCallback, useState} from 'react'
+
+import cx from 'classnames'
+
+import usePortal from '../../../src/index.js'
+import usePopper from './usePopper.js'
+
+const useTooltip = ({isOpen, ...config} = {}) => {
+ const [isVisible, setIsVisible] = useState(false)
+ const {
+ Portal,
+ onMouseEnter,
+ onMouseLeave,
+ portalRef,
+ open,
+ close,
+ isOpen: isOpened,
+ triggerRef
+ } = usePortal({
+ onMouseEnter: event => open(event),
+ onMouseLeave: event => close(event),
+ onOpen: () => setIsVisible(true),
+ onClose: () => setIsVisible(false),
+ isOpen: false,
+ ...config
+ })
+
+ const {styles, attributes} = usePopper(
+ triggerRef.current,
+ isVisible ? portalRef.current : null
+ )
+
+ const Tooltip = useCallback(
+ ({children, className, style = {}, ...props}) => {
+ return (
+
+ {children}
+
+ )
+ },
+ [isOpened, styles, attributes]
+ )
+
+ return [
+ {
+ ref: triggerRef,
+ onMouseEnter,
+ onMouseLeave
+ },
+ Tooltip
+ ]
+}
+
+export default useTooltip
diff --git a/components/hook/usePortal/demo/articles/ArticleDefault.js b/components/hook/usePortal/demo/articles/ArticleDefault.js
new file mode 100644
index 0000000000..a8f7e5f004
--- /dev/null
+++ b/components/hook/usePortal/demo/articles/ArticleDefault.js
@@ -0,0 +1,132 @@
+import {useRef} from 'react'
+
+import PropTypes from 'prop-types'
+
+import {
+ Anchor,
+ Article,
+ Bold,
+ Box,
+ Button,
+ Code,
+ H2,
+ H3,
+ H4,
+ ListItem,
+ OrderedList,
+ Paragraph,
+ UnorderedList
+} from '@s-ui/documentation-library'
+
+import usePortal from '../../src/index.js'
+
+const ArticleDefault = ({className}) => {
+ const {Portal, portalRef} = usePortal()
+ const articleRef = useRef()
+ return (
+
+ Default
+
+ The portal is default appended at the document body. It is default
+ opened unless you define its initial isOpen
configuration
+ settings to false.
+
+ portalRef.current.scrollIntoView()}>
+ Scroll into view
+
+
+
+ Default Portal Result
+
+ This text is portaled at the end of document.body from the{' '}
+ articleRef.current.scrollIntoView()}
+ style={{
+ border: 0,
+ padding: 0,
+ margin: 0,
+ backgroundColor: 'transparent'
+ }}
+ >
+ default demo
+
+ !
+
+
+
+
+ usePortal
hook admits many different options as an{' '}
+ object argument to configure the portal:
+
+
+
+ isOpen
(boolean|true): sets the initial state visible or
+ not.
+
+
+ onOpen
(func): opens the portal
+
+
+ onClose
(func): closes the portal
+
+
+ onToggle
(func): changes between open/close the portal
+
+
+ hasCloseOnOutsideClick
(boolean|false): auto-close the
+ portal on outside click
+
+
+ hasCloseOnEsc
(boolean|false): autoClose the portal on
+ 'Esc' press
+
+
+ Result
+
+ usePortal
hook result can be destructured using an array or
+ an object.
+
+ Array
+
+ const [Portal, open, close, isOpen, togglePortal, triggerRef, portalRef]
+ = usePortal()
+
+ Object
+
+ {
+ 'const {Portal, open, close, isOpen, togglePortal, triggerRef, portalRef} = usePortal()'
+ }
+
+
+
+ Portal
: The portal component
+
+
+ open
: The action to open the portal
+
+
+ close
: The action to close the portal
+
+
+ isOpen
: The portal current state
+
+
+ togglePortal
: The action to toggle the state
+
+
+ triggerRef
: The trigger element ref
+
+
+ portalRef
: The portal element ref
+
+
+
+ )
+}
+
+ArticleDefault.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleDefault
diff --git a/components/hook/usePortal/demo/articles/ArticleStateful.js b/components/hook/usePortal/demo/articles/ArticleStateful.js
new file mode 100644
index 0000000000..a6b45c15a3
--- /dev/null
+++ b/components/hook/usePortal/demo/articles/ArticleStateful.js
@@ -0,0 +1,52 @@
+import {useRef, useState} from 'react'
+
+import PropTypes from 'prop-types'
+
+import {
+ Article,
+ Box,
+ Button,
+ Code,
+ H2,
+ Paragraph
+} from '@s-ui/documentation-library'
+
+import usePortal from '../../src/index.js'
+
+const ArticleStateful = ({className}) => {
+ const targetedRef = useRef()
+ const [isOpened, setIsOpened] = useState(true)
+ const openHandler = () => setIsOpened(true)
+ const closeHandler = () => setIsOpened(false)
+ const {Portal} = usePortal({
+ target: targetedRef.current,
+ isOpen: isOpened,
+ onOpen: openHandler,
+ onClose: closeHandler
+ })
+ return (
+
+ Stateful Control
+
+ You can also define the Portal behavior under the isOpen
{' '}
+ (boolean) Portal prop as a controlled component.
+
+
+
+
+
+ This is the content of the portal stateful opened.
+
+ Close
+
+
+ {!isOpened && Open }
+
+ )
+}
+
+ArticleStateful.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleStateful
diff --git a/components/hook/usePortal/demo/articles/ArticleStateless.js b/components/hook/usePortal/demo/articles/ArticleStateless.js
new file mode 100644
index 0000000000..77c632d57a
--- /dev/null
+++ b/components/hook/usePortal/demo/articles/ArticleStateless.js
@@ -0,0 +1,43 @@
+import {useRef} from 'react'
+
+import PropTypes from 'prop-types'
+
+import {
+ Article,
+ Box,
+ Button,
+ Code,
+ H2,
+ Paragraph
+} from '@s-ui/documentation-library'
+
+import usePortal from '../../src/index.js'
+
+const ArticleStateless = ({className}) => {
+ const targetedRef = useRef()
+ const {Portal, open, close, isOpen} = usePortal({target: targetedRef.current})
+ return (
+
+ Stateless Control
+
+ You can use an stateless Portal
with its open
{' '}
+ and close
{' '}
+
+
+ {'const {Portal, open, close, isOpen} = usePortal()'}
+
+
+
+
+ Close
+
+
+ {!isOpen && Open }
+
+ )
+}
+ArticleStateless.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleStateless
diff --git a/components/hook/usePortal/demo/articles/ArticleTarget.js b/components/hook/usePortal/demo/articles/ArticleTarget.js
new file mode 100644
index 0000000000..940a5b7393
--- /dev/null
+++ b/components/hook/usePortal/demo/articles/ArticleTarget.js
@@ -0,0 +1,39 @@
+import {useRef} from 'react'
+
+import PropTypes from 'prop-types'
+
+import {Article, Box, Code, H2, Paragraph} from '@s-ui/documentation-library'
+
+import usePortal from '../../src/index.js'
+
+const ArticleTarget = ({className}) => {
+ const targetedRef = useRef()
+ const {Portal} = usePortal({target: targetedRef.current})
+ return (
+
+ Target
+
+ Providing a target
argument to the hook options will append
+ the declared Portal's children.
+
+
+ {'const { Portal } = usePortal({ target: element })'}
+
+
+
+
+
+ This text is portaled at the end of the defined target provided in
+ options!
+
+
+
+
+ )
+}
+
+ArticleTarget.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleTarget
diff --git a/components/hook/usePortal/demo/index.js b/components/hook/usePortal/demo/index.js
new file mode 100644
index 0000000000..ce56774d3a
--- /dev/null
+++ b/components/hook/usePortal/demo/index.js
@@ -0,0 +1,48 @@
+import {
+ Anchor,
+ Bold,
+ Code,
+ Emphasis,
+ H1,
+ Paragraph
+} from '@s-ui/documentation-library'
+
+import ArticleCloseOnEvent from './articles/ArticleCloseOnEvent.js'
+import ArticleCustom from './articles/ArticleCustom.js'
+import ArticleDefault from './articles/ArticleDefault.js'
+import ArticleStateful from './articles/ArticleStateful.js'
+import ArticleStateless from './articles/ArticleStateless.js'
+import ArticleTarget from './articles/ArticleTarget.js'
+import {CLASS_SECTION} from './settings.js'
+
+const Demo = () => {
+ return (
+
+
usePortal
+
+ The usePortal
hook offers the possibility to
+ create a{' '}
+ Portal set
+ where is defined (default: document.body).
+
+
+ * Portals will be displayed in a dark Box to identify them.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Demo
diff --git a/components/hook/usePortal/demo/index.scss b/components/hook/usePortal/demo/index.scss
new file mode 100644
index 0000000000..0164645161
--- /dev/null
+++ b/components/hook/usePortal/demo/index.scss
@@ -0,0 +1,10 @@
+@import '../src/index';
+
+.sui-DemoTooltip {
+ background-color: $c-primary-light;
+ border-radius: $bdrs-base;
+ padding: $p-base;
+ border-width: $bdw-m;
+ border-color: $c-primary;
+ border-style: solid;
+}
diff --git a/components/hook/usePortal/demo/package.json b/components/hook/usePortal/demo/package.json
new file mode 100644
index 0000000000..af4067ae9c
--- /dev/null
+++ b/components/hook/usePortal/demo/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "@s-ui/react-hook-use-portal-demo",
+ "private": true,
+ "version": "1.0.0",
+ "description": "",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "dependencies": {
+ "@popperjs/core": "2.11.6",
+ "@s-ui/react-hooks": "1",
+ "react-fast-compare": "3.2.0"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "MIT"
+}
diff --git a/components/hook/usePortal/demo/settings.js b/components/hook/usePortal/demo/settings.js
new file mode 100644
index 0000000000..633d43cc40
--- /dev/null
+++ b/components/hook/usePortal/demo/settings.js
@@ -0,0 +1,2 @@
+export const BASE_CLASS_DEMO = `DemoUsePortal`
+export const CLASS_SECTION = `${BASE_CLASS_DEMO}-section`
diff --git a/components/hook/usePortal/package.json b/components/hook/usePortal/package.json
new file mode 100644
index 0000000000..3355d1a14d
--- /dev/null
+++ b/components/hook/usePortal/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "@s-ui/react-hook-use-portal",
+ "version": "1.1.0",
+ "description": "",
+ "main": "lib/index.js",
+ "scripts": {
+ "prepublishOnly": "rimraf ./lib && npm run build:js && npm run build:styles",
+ "build:js": "babel --presets sui ./src --out-dir ./lib",
+ "build:styles": "cpx './src/**/*.scss' ./lib"
+ },
+ "dependencies": {
+ "use-ssr": "1.0.24",
+ "classnames": "2.2.5",
+ "@s-ui/react-hooks": "1"
+ },
+ "keywords": [
+ "react",
+ "hook",
+ "portal"
+ ],
+ "author": "",
+ "license": "MIT"
+}
diff --git a/components/hook/usePortal/src/index.js b/components/hook/usePortal/src/index.js
new file mode 100644
index 0000000000..c88893c9d4
--- /dev/null
+++ b/components/hook/usePortal/src/index.js
@@ -0,0 +1,235 @@
+/* eslint-disable react/prop-types */
+import {
+ forwardRef,
+ useCallback,
+ useEffect,
+ useMemo,
+ useRef,
+ useState
+} from 'react'
+import {createPortal, findDOMNode} from 'react-dom'
+import {isFragment} from 'react-is'
+
+import cx from 'classnames'
+import PropTypes from 'prop-types'
+import useSSR from 'use-ssr'
+
+import useMergeRefs from '@s-ui/react-hooks/lib/useMergeRefs'
+
+import {BASE_CLASS, DEFAULT_IS_OPEN} from './settings.js'
+
+const usePortal = ({
+ isOpen: defaultIsOpen = DEFAULT_IS_OPEN,
+ target = document.body,
+ onOpen,
+ onClose,
+ onToggle,
+ onClick,
+ hasCloseOnOutsideClick = false,
+ hasCloseOnEsc = false,
+ ...eventHandlers
+} = {}) => {
+ const {isServer} = useSSR()
+ const [isOpened, setIsOpened] = useState(defaultIsOpen)
+
+ const triggerElement = useRef() // this is the element you are clicking/hovering/whatever, to trigger opening the portal
+ const portal = useRef()
+
+ const elToMountTo = useMemo(() => {
+ if (isServer) return
+ return (target && findDOMNode(target)) || document.body
+ }, [isServer, target])
+
+ const createCustomEvent = event => {
+ if (!event) return {portal, triggerElement, event}
+ const response = event || {}
+ if (response.persist) response.persist()
+ response.portal = portal
+ response.triggerElement = triggerElement
+ response.event = event
+ return response
+ }
+
+ // this should handle all eventHandlers like onClick, onMouseOver, etc. passed into the config
+ const customEventHandlers = Object.entries(eventHandlers).reduce(
+ (acc, [handlerName, eventHandler]) => {
+ acc[handlerName] = event => {
+ if (isServer) return
+ eventHandler(createCustomEvent(event))
+ }
+ return acc
+ },
+ {}
+ )
+
+ const setIsOpen = useCallback(
+ value => event => {
+ if (isServer) return
+ const customEvent = createCustomEvent(event)
+ if (onOpen && value === true) setTimeout(() => onOpen(customEvent), 0)
+ if (onClose && value === false) onClose(customEvent)
+ setIsOpened(value)
+ },
+ [isServer, setIsOpened, onClose]
+ )
+
+ const openPortal = setIsOpen(true)
+ const closePortal = setIsOpen(false)
+
+ const togglePortal = event =>
+ isOpened ? closePortal(event) : openPortal(event)
+
+ const handleKeydown = useCallback(
+ event =>
+ event.key === 'Escape' && hasCloseOnEsc ? closePortal(event) : undefined,
+ [hasCloseOnEsc, closePortal]
+ )
+
+ const handleOutsideMouseClick = useCallback(
+ event => {
+ const containsTarget = target => target.current?.contains(event.target)
+ if (
+ containsTarget(portal) ||
+ event.button !== 0 ||
+ !isOpened ||
+ containsTarget(triggerElement)
+ ) {
+ return
+ }
+ if (hasCloseOnOutsideClick) {
+ closePortal(event)
+ }
+ },
+ [isServer, closePortal, hasCloseOnOutsideClick, portal]
+ )
+
+ const handleMouseDown = useCallback(
+ event => {
+ if (isServer || !(portal.current instanceof HTMLElement)) return
+ const customEvent = createCustomEvent(event)
+ if (portal.current.contains(customEvent.target) && onClick)
+ onClick(customEvent)
+ handleOutsideMouseClick(event)
+ },
+ [handleOutsideMouseClick]
+ )
+
+ // used to remove the event listeners on unmount
+ const eventListeners = useRef({})
+
+ useEffect(() => {
+ if (isServer) return
+ if (
+ !(elToMountTo instanceof HTMLElement) ||
+ !(portal.current instanceof HTMLElement)
+ ) {
+ return
+ }
+
+ // TODO: eventually will need to figure out a better solution for this.
+ // Surely we can find a way to map onScroll/onWheel -> scroll/wheel better,
+ // but for all other event handlers. For now this works.
+ const eventHandlerMap = {
+ onScroll: 'scroll',
+ onWheel: 'wheel'
+ }
+ Object.entries(eventHandlerMap).forEach(
+ ([handlerName /* onScroll */, eventListenerName /* scroll */]) => {
+ if (!eventHandlers[handlerName]) return
+ eventListeners.current[handlerName] = event =>
+ eventHandlers[handlerName](createCustomEvent(event))
+ document.addEventListener(
+ eventListenerName,
+ eventListeners.current[handlerName]
+ )
+ }
+ )
+ document.addEventListener('keydown', handleKeydown)
+ document.addEventListener('mousedown', handleMouseDown)
+
+ return () => {
+ // handles all special case handlers. Currently only onScroll and onWheel
+ Object.entries(eventHandlerMap).forEach(
+ ([handlerName, eventListenerName]) => {
+ if (!eventHandlers[handlerName]) return
+ document.removeEventListener(
+ eventListenerName,
+ eventListeners.current[handlerName]
+ )
+ delete eventListeners.current[handlerName]
+ }
+ )
+ document.removeEventListener('keydown', handleKeydown)
+ document.removeEventListener('mousedown', handleMouseDown)
+ }
+ }, [isServer, handleOutsideMouseClick, handleKeydown, elToMountTo, portal])
+
+ const Portal = useCallback(
+ forwardRef(
+ (
+ {as: As = 'div', children, isOpen: isOpenProp, className, ...props},
+ forwardedRef
+ ) => {
+ const ref = useMergeRefs(forwardedRef, portal)
+ useEffect(() => {
+ if (isServer) return
+ if (isOpenProp !== undefined) {
+ setIsOpened(isOpenProp)
+ }
+ }, [isOpenProp])
+
+ return isOpened
+ ? createPortal(
+
) && {
+ ref,
+ className: cx(BASE_CLASS, className),
+ ...props
+ })}
+ >
+ {children}
+ ,
+ target
+ )
+ : null
+ }
+ ),
+ [isOpened, portal, target]
+ )
+ Portal.propTypes = {
+ as: PropTypes.elementType,
+ children: PropTypes.node,
+ isOpen: PropTypes.bool,
+ className: PropTypes.string
+ }
+ Portal.displayName = 'Portal'
+
+ return Object.assign(
+ [
+ Portal,
+ openPortal,
+ closePortal,
+ isOpened,
+ togglePortal,
+ triggerElement,
+ portal
+ ],
+ {
+ isOpen: isOpened,
+ triggerRef: triggerElement,
+ open: openPortal,
+ close: closePortal,
+ toggle: togglePortal,
+ Portal,
+ portalRef: portal,
+ ...customEventHandlers,
+ bind: {
+ // used if you want to spread all html attributes onto the target element
+ ref: triggerElement,
+ ...customEventHandlers
+ }
+ }
+ )
+}
+
+export default usePortal
diff --git a/components/hook/usePortal/src/index.scss b/components/hook/usePortal/src/index.scss
new file mode 100644
index 0000000000..bd7f4f88aa
--- /dev/null
+++ b/components/hook/usePortal/src/index.scss
@@ -0,0 +1 @@
+@import '~@s-ui/theme/lib/index';
diff --git a/components/hook/usePortal/src/settings.js b/components/hook/usePortal/src/settings.js
new file mode 100644
index 0000000000..c0afc7796c
--- /dev/null
+++ b/components/hook/usePortal/src/settings.js
@@ -0,0 +1,3 @@
+export const BASE_CLASS = 'sui-Portal'
+
+export const DEFAULT_IS_OPEN = true
diff --git a/components/hook/usePortal/test/index.test.js b/components/hook/usePortal/test/index.test.js
new file mode 100644
index 0000000000..b5ea19f213
--- /dev/null
+++ b/components/hook/usePortal/test/index.test.js
@@ -0,0 +1,254 @@
+/*
+ * Remember: YOUR COMPONENT IS DEFINED GLOBALLY
+ * */
+
+/* eslint react/jsx-no-undef:0 */
+/* eslint no-undef:0 */
+
+import React, {useRef} from 'react'
+import ReactDOM from 'react-dom'
+
+import {/** chai, **/ expect} from 'chai'
+import PropTypes from 'prop-types'
+
+// import chaiDOM from 'chai-dom'
+// import sinon from 'sinon'
+// import {fireEvent} from '@testing-library/react'
+import json from '../package.json'
+import * as pkg from '../src/index.js'
+
+describe(json.name, () => {
+ const {default: usePortal} = pkg
+ const Component = ({children, isOpen: isOpenProps, ...handlers}) => {
+ const targetRef = useRef()
+ const {Portal, isOpen, open, close, toggle, bind} = usePortal({
+ target: targetRef.current,
+ isOpen: isOpenProps,
+ ...handlers
+ })
+
+ return (
+
+
+
+
open
+
close
+
toggle
+
bind
+
+ )
+ }
+
+ Component.propTypes = {
+ children: PropTypes.node,
+ isOpen: PropTypes.bool
+ }
+
+ const setup = setupEnvironment(Component)
+
+ it('library should include defined exported elements', () => {
+ // Given
+ const library = pkg
+ const libraryExportedMembers = ['default']
+
+ // When
+ const {default: usePortal, ...others} = library
+
+ // Then
+ expect(Object.keys(library).length).to.equal(libraryExportedMembers.length)
+ expect(Object.keys(library)).to.have.members(libraryExportedMembers)
+ expect(Object.keys(others).length).to.equal(0)
+ })
+
+ describe('hook', () => {
+ it('should render without crashing', () => {
+ // Given
+ const props = {as: 'h1'}
+
+ // When
+ const component =
+
+ // Then
+ const div = document.createElement('div')
+ ReactDOM.render(component, div)
+ ReactDOM.unmountComponentAtNode(div)
+ })
+
+ it('should first render null', () => {
+ // Given
+ const props = {}
+
+ // When
+ const {container, getByTestId} = setup(props)
+ const portalContainerElement = getByTestId('portal-test-container')
+ const portalContainerOriginElement = getByTestId(
+ 'portal-test-container-origin'
+ )
+ const portalContainerTargetElement = getByTestId(
+ 'portal-test-container-target'
+ )
+
+ // Then
+ expect(container.innerHTML).to.be.a('string')
+ expect(container.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerElement.innerHTML).to.be.a('string')
+ expect(portalContainerElement.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerOriginElement.innerHTML).to.be.a('string')
+ expect(portalContainerOriginElement.innerHTML).to.have.lengthOf(0)
+
+ expect(portalContainerTargetElement.innerHTML).to.be.a('string')
+ expect(portalContainerTargetElement.innerHTML).to.have.lengthOf(0)
+ })
+
+ it('should add portal to the right place', () => {
+ // Given
+ const props = {children: 'portal-content'}
+
+ // When
+ const {container, rerender, getByTestId} = setup(props)
+ const portalContainerElement = getByTestId('portal-test-container')
+ const portalContainerOriginElement = getByTestId(
+ 'portal-test-container-origin'
+ )
+ const portalContainerTargetElement = getByTestId(
+ 'portal-test-container-target'
+ )
+
+ // Then
+ expect(container.innerHTML).to.be.a('string')
+ expect(container.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerElement.innerHTML).to.be.a('string')
+ expect(portalContainerElement.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerOriginElement.innerHTML).to.be.a('string')
+ expect(portalContainerOriginElement.innerHTML).to.have.lengthOf(0)
+
+ expect(portalContainerTargetElement.innerHTML).to.be.a('string')
+ expect(portalContainerTargetElement.innerHTML).to.have.lengthOf(0)
+
+ // When
+ rerender(
)
+ expect(portalContainerElement.innerHTML).to.be.a('string')
+ expect(portalContainerElement.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerOriginElement.innerHTML).to.be.a('string')
+ expect(portalContainerOriginElement.innerHTML).to.have.lengthOf(0)
+
+ expect(portalContainerTargetElement.innerHTML).to.be.a('string')
+ expect(portalContainerTargetElement.innerHTML).to.not.have.lengthOf(0)
+ })
+
+ it('given isOpen=false should NOT add portal', () => {
+ // Given
+ const props = {children: 'portal-content', isOpen: false}
+
+ // When
+ const {container, rerender, getByTestId} = setup(props)
+ const portalContainerElement = getByTestId('portal-test-container')
+ const portalContainerOriginElement = getByTestId(
+ 'portal-test-container-origin'
+ )
+ const portalContainerTargetElement = getByTestId(
+ 'portal-test-container-target'
+ )
+
+ // Then
+ expect(container.innerHTML).to.be.a('string')
+ expect(container.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerElement.innerHTML).to.be.a('string')
+ expect(portalContainerElement.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerOriginElement.innerHTML).to.be.a('string')
+ expect(portalContainerOriginElement.innerHTML).to.have.lengthOf(0)
+
+ expect(portalContainerTargetElement.innerHTML).to.be.a('string')
+ expect(portalContainerTargetElement.innerHTML).to.have.lengthOf(0)
+
+ // When
+ rerender(
)
+ expect(portalContainerElement.innerHTML).to.be.a('string')
+ expect(portalContainerElement.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerOriginElement.innerHTML).to.be.a('string')
+ expect(portalContainerOriginElement.innerHTML).to.have.lengthOf(0)
+
+ expect(portalContainerTargetElement.innerHTML).to.be.a('string')
+ expect(portalContainerTargetElement.innerHTML).to.have.lengthOf(0)
+ })
+
+ it('given isOpen=true should add portal', () => {
+ // Given
+ const props = {children: 'portal-content', isOpen: true}
+
+ // When
+ const {container, rerender, getByTestId} = setup(props)
+ const portalContainerElement = getByTestId('portal-test-container')
+ const portalContainerOriginElement = getByTestId(
+ 'portal-test-container-origin'
+ )
+ const portalContainerTargetElement = getByTestId(
+ 'portal-test-container-target'
+ )
+
+ // Then
+ expect(container.innerHTML).to.be.a('string')
+ expect(container.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerElement.innerHTML).to.be.a('string')
+ expect(portalContainerElement.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerOriginElement.innerHTML).to.be.a('string')
+ expect(portalContainerOriginElement.innerHTML).to.have.lengthOf(0)
+
+ expect(portalContainerTargetElement.innerHTML).to.be.a('string')
+ expect(portalContainerTargetElement.innerHTML).to.have.lengthOf(0)
+
+ // When
+ rerender(
)
+ expect(portalContainerElement.innerHTML).to.be.a('string')
+ expect(portalContainerElement.innerHTML).to.not.have.lengthOf(0)
+
+ expect(portalContainerOriginElement.innerHTML).to.be.a('string')
+ expect(portalContainerOriginElement.innerHTML).to.have.lengthOf(0)
+
+ expect(portalContainerTargetElement.innerHTML).to.be.a('string')
+ expect(portalContainerTargetElement.innerHTML).to.not.have.lengthOf(0)
+ })
+
+ describe('fire events', () => {
+ it.skip('should fire onClose when it is triggered', () => {
+ // Given
+ // const spyOnClose = sinon.spy()
+ // const props = {children: 'portal-content', onClose: spyOnClose}
+ // When
+ // const {container, rerender, getByTestId, getByText} = setup(props)
+ // rerender(
)
+ // const portalContainerElement = getByTestId('portal-test-container')
+ // const portalContainerOriginElement = getByTestId(
+ // 'portal-test-container-origin'
+ // )
+ // const portalContainerTargetElement = getByTestId(
+ // 'portal-test-container-target'
+ // )
+ // Then
+ // expect(portalContainerElement.innerHTML).to.be.a('string')
+ // expect(portalContainerElement.innerHTML).to.not.have.lengthOf(0)
+ //
+ // expect(portalContainerOriginElement.innerHTML).to.be.a('string')
+ // expect(portalContainerOriginElement.innerHTML).to.have.lengthOf(0)
+ //
+ // expect(portalContainerTargetElement.innerHTML).to.be.a('string')
+ // expect(portalContainerTargetElement.innerHTML).to.not.have.lengthOf(0)
+ // And
+ // When
+ // fireEvent.click(getByText(props.children))
+ })
+ })
+ })
+})
diff --git a/components/layout/grid/CHANGELOG.md b/components/layout/grid/CHANGELOG.md
index 7cbd87cb73..425303fd24 100644
--- a/components/layout/grid/CHANGELOG.md
+++ b/components/layout/grid/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 2.13.0 (2022-10-06)
+
+
+
# 2.12.0 (2022-06-20)
diff --git a/components/layout/grid/package.json b/components/layout/grid/package.json
index 711b9d33ae..9ec365d7da 100644
--- a/components/layout/grid/package.json
+++ b/components/layout/grid/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-layout-grid",
- "version": "2.12.0",
+ "version": "2.13.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/accordion/CHANGELOG.md b/components/molecule/accordion/CHANGELOG.md
index d886fb855d..84f0106851 100644
--- a/components/molecule/accordion/CHANGELOG.md
+++ b/components/molecule/accordion/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 2.7.0 (2022-10-06)
+
+
+
# 2.6.0 (2022-06-20)
diff --git a/components/molecule/accordion/package.json b/components/molecule/accordion/package.json
index e1ca83b557..ab0aff5b7b 100644
--- a/components/molecule/accordion/package.json
+++ b/components/molecule/accordion/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-accordion",
- "version": "2.6.0",
+ "version": "2.7.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/accordion/src/styles/index.scss b/components/molecule/accordion/src/styles/index.scss
index ee8e226e96..1282c0f8ec 100644
--- a/components/molecule/accordion/src/styles/index.scss
+++ b/components/molecule/accordion/src/styles/index.scss
@@ -136,7 +136,7 @@ $base-class-item-panel: '#{$base-class-item}Panel';
min-height: $sz-empty-icon;
position: relative;
overflow: hidden;
- transform: rotate(180deg);
+ transform: rotate(-180deg);
&::before,
&::after {
position: absolute;
@@ -148,11 +148,11 @@ $base-class-item-panel: '#{$base-class-item}Panel';
box-sizing: border-box;
}
&::before {
- transform: rotate(-45deg);
+ transform: rotate(-135deg);
left: 33%;
}
&::after {
- transform: rotate(-135deg);
+ transform: rotate(-45deg);
right: 33%;
}
}
diff --git a/components/molecule/autosuggest/CHANGELOG.md b/components/molecule/autosuggest/CHANGELOG.md
index 036fc81316..c5ac8b9380 100644
--- a/components/molecule/autosuggest/CHANGELOG.md
+++ b/components/molecule/autosuggest/CHANGELOG.md
@@ -1,5 +1,14 @@
# CHANGELOG
+# 2.66.0 (2022-10-04)
+
+
+### Features
+
+* **components/molecule/autosuggest:** update the dropdownOption new prop name ([01facc9](https://github.com/SUI-Components/sui-components/commit/01facc9fb7058abda63dc9667fabee5cf44d8d36))
+
+
+
# 2.65.0 (2022-08-22)
diff --git a/components/molecule/autosuggest/demo/Icons/index.js b/components/molecule/autosuggest/demo/Icons/index.js
index 0bc30a8341..83d665d084 100644
--- a/components/molecule/autosuggest/demo/Icons/index.js
+++ b/components/molecule/autosuggest/demo/Icons/index.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types'
-import AtomIcon, {atomIconColors, atomIconSizes} from '@s-ui/react-atom-icon'
import {AntDesignIcon} from '@s-ui/documentation-library'
+import AtomIcon, {atomIconColors, atomIconSizes} from '@s-ui/react-atom-icon'
const alert = (
diff --git a/components/molecule/autosuggest/demo/config.js b/components/molecule/autosuggest/demo/config.js
index 47b27aa17f..865f65d3cc 100644
--- a/components/molecule/autosuggest/demo/config.js
+++ b/components/molecule/autosuggest/demo/config.js
@@ -1,6 +1,7 @@
import {withStateValue, withStateValueTags} from '@s-ui/hoc'
import MoleculeAutosuggestField from '@s-ui/react-molecule-autosuggest-field'
import MoleculeAutosuggestOption from '@s-ui/react-molecule-dropdown-option'
+
import MoleculeAutosuggest from '../src/index.js'
import withDynamicOptions from './hoc/withDynamicOptions.js'
import {getAsyncCountriesFromQuery} from './services/index.js'
diff --git a/components/molecule/autosuggest/demo/index.js b/components/molecule/autosuggest/demo/index.js
index 7da6f5a582..3bf122450b 100644
--- a/components/molecule/autosuggest/demo/index.js
+++ b/components/molecule/autosuggest/demo/index.js
@@ -9,19 +9,18 @@ import MoleculeAutosuggestOption from '@s-ui/react-molecule-dropdown-option'
import ComboCountries from './components/ComboCountries.js'
import {
- iconClose,
- iconSearch,
iconAlert,
+ iconClose,
+ iconError,
iconInfo,
- iconError
+ iconSearch
} from './Icons/index.js'
-
import {
CLASS_DEMO_SECTION,
- options,
MoleculeAutosuggestWithState,
MoleculeAutosuggestWithStateTags,
- MoleculeAutosuggestWithStateTagsLabels
+ MoleculeAutosuggestWithStateTagsLabels,
+ options
} from './config.js'
import './index.scss'
diff --git a/components/molecule/autosuggest/demo/package.json b/components/molecule/autosuggest/demo/package.json
index 8e41c8acb2..cf9206a5b1 100644
--- a/components/molecule/autosuggest/demo/package.json
+++ b/components/molecule/autosuggest/demo/package.json
@@ -15,7 +15,7 @@
"@s-ui/react-atom-button": "1",
"@s-ui/react-atom-icon": "1",
"@s-ui/react-molecule-autosuggest-field": "2",
- "@s-ui/react-molecule-dropdown-option": "1",
+ "@s-ui/react-molecule-dropdown-option": "2",
"@s-ui/react-molecule-input-tags": "2",
"@s-ui/react-molecule-select": "1",
"axios": "0.21.4"
diff --git a/components/molecule/autosuggest/package.json b/components/molecule/autosuggest/package.json
index 050c823c40..e74bba9fd6 100644
--- a/components/molecule/autosuggest/package.json
+++ b/components/molecule/autosuggest/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-autosuggest",
- "version": "2.65.0",
+ "version": "2.66.0",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -12,7 +12,7 @@
"@s-ui/js": "2",
"@s-ui/react-atom-input": "5",
"@s-ui/react-hooks": "1",
- "@s-ui/react-molecule-dropdown-list": "1",
+ "@s-ui/react-molecule-dropdown-list": "2",
"@s-ui/react-molecule-input-tags": "2",
"@s-ui/react-primitive-injector": "1",
"lodash.isequal": "4.5"
diff --git a/components/molecule/autosuggest/src/components/InputWithClearUI/index.js b/components/molecule/autosuggest/src/components/InputWithClearUI/index.js
index 70c8849133..10ee6c5a90 100644
--- a/components/molecule/autosuggest/src/components/InputWithClearUI/index.js
+++ b/components/molecule/autosuggest/src/components/InputWithClearUI/index.js
@@ -8,7 +8,7 @@ const InputWithClearUI = ({
onClickClear,
isVisibleClear,
iconClear,
- rightIcon =
,
+ rightIcon,
children,
...props
}) => {
diff --git a/components/molecule/autosuggest/src/index.js b/components/molecule/autosuggest/src/index.js
index 083de1d291..f47e016072 100644
--- a/components/molecule/autosuggest/src/index.js
+++ b/components/molecule/autosuggest/src/index.js
@@ -81,7 +81,7 @@ const MoleculeAutosuggest = ({
refsMoleculeAutosuggestOptions.current[index] = createRef()
return cloneElement(child, {
innerRef: refsMoleculeAutosuggestOptions.current[index],
- onSelectKey: keysSelection
+ selectKey: keysSelection
})
})
@@ -117,7 +117,6 @@ const MoleculeAutosuggest = ({
ev.persist()
const {current: domInnerInput} = refMoleculeAutosuggestInput
const {current: optionsFromRef} = refsMoleculeAutosuggestOptions
- const {current: innerRefInput} = innerRefMoleculeAutosuggestInput
const {key} = ev
const options = optionsFromRef.map(getTarget)
@@ -137,7 +136,7 @@ const MoleculeAutosuggest = ({
else if (isSomeOptionFocused) handleFocusIn(ev)
if (key === 'Enter') {
typeof onEnter === 'function' && onEnter(ev)
- innerRefInput && (!isControlled || autoClose) && innerRefInput.focus()
+ handleFocusInput()
}
}
}
@@ -180,8 +179,22 @@ const MoleculeAutosuggest = ({
}
const handleClick = () => {
+ handleFocusInput()
+ }
+
+ const handleFocusInput = () => {
const {current: innerRefInput} = innerRefMoleculeAutosuggestInput
- innerRefInput && (!isControlled || autoClose) && innerRefInput.focus()
+ if (innerRefInput && (!isControlled || autoClose)) {
+ innerRefInput.focus()
+ }
+ }
+
+ const handleClear = ev => {
+ ev.stopPropagation()
+ handleFocusInput()
+ if (onClear) {
+ onClear(ev)
+ }
}
const autosuggestSelectionProps = {
@@ -196,7 +209,7 @@ const MoleculeAutosuggest = ({
keysSelection,
onBlur,
onChange,
- onClear,
+ onClear: handleClear,
onEnter,
onFocus,
onInputKeyDown: handleInputKeyDown,
diff --git a/components/molecule/autosuggestField/CHANGELOG.md b/components/molecule/autosuggestField/CHANGELOG.md
index 90b5ff5ce1..5d5bde86d2 100644
--- a/components/molecule/autosuggestField/CHANGELOG.md
+++ b/components/molecule/autosuggestField/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 2.11.0 (2022-10-06)
+
+
+
# 2.10.0 (2022-06-22)
diff --git a/components/molecule/autosuggestField/demo/package.json b/components/molecule/autosuggestField/demo/package.json
index 8d1ed9e8ca..9bb12b8aec 100644
--- a/components/molecule/autosuggestField/demo/package.json
+++ b/components/molecule/autosuggestField/demo/package.json
@@ -13,7 +13,7 @@
"dependencies": {
"@s-ui/hoc": "1",
"@s-ui/react-molecule-autosuggest": "1",
- "@s-ui/react-molecule-dropdown-option": "1",
+ "@s-ui/react-molecule-dropdown-option": "2",
"@s-ui/react-molecule-field": "1"
}
}
diff --git a/components/molecule/autosuggestField/package.json b/components/molecule/autosuggestField/package.json
index 268957c004..8fa02421af 100644
--- a/components/molecule/autosuggestField/package.json
+++ b/components/molecule/autosuggestField/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-autosuggest-field",
- "version": "2.10.0",
+ "version": "2.11.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/avatar/CHANGELOG.md b/components/molecule/avatar/CHANGELOG.md
index 6b5ced7b33..731142dab3 100644
--- a/components/molecule/avatar/CHANGELOG.md
+++ b/components/molecule/avatar/CHANGELOG.md
@@ -1,5 +1,27 @@
# CHANGELOG
+# 1.16.0 (2022-10-06)
+
+
+
+# 1.15.0 (2022-10-03)
+
+
+### Features
+
+* **components/molecule/avatar:** Add primitive injector dependency ([014c3c1](https://github.com/SUI-Components/sui-components/commit/014c3c19eb8e5f4039c02e7180ed4b6459f9d2d9))
+
+
+
+# 1.14.0 (2022-09-29)
+
+
+### Features
+
+* **components/molecule/avatar:** handle background color for avatar name fallback ([d25b405](https://github.com/SUI-Components/sui-components/commit/d25b4059dadc602e6bcc97649c551bb91d8e847a))
+
+
+
# 1.13.0 (2022-08-12)
diff --git a/components/molecule/avatar/demo/ArticleImage.js b/components/molecule/avatar/demo/ArticleImage.js
index cc0e1a7824..2592fc9ed0 100644
--- a/components/molecule/avatar/demo/ArticleImage.js
+++ b/components/molecule/avatar/demo/ArticleImage.js
@@ -20,6 +20,8 @@ const ArticleImage = ({className}) => {
const [src, setSrc] = useState(
'https://randomuser.me/api/portraits/men/1.jpg'
)
+ const [brokenSrc, setBrokenSrc] = useState('https://brokenimagesrc')
+ const [name, setName] = useState('John Doe')
const [fallbackIcon, setFallbackIcon] = useState()
return (
@@ -98,6 +100,46 @@ const ArticleImage = ({className}) => {
) : undefined
}
/>
+ Fallback Name
+
+ If the provided image fails on loading and the name
{' '}
+ property is passed, the avatar will display the name initials with a
+ colored background.
+
+ {
+ setBrokenSrc(event.target.value)
+ }}
+ placeholder="image"
+ fullWidth
+ />
+
+
+ {
+ setName(event.target.value)
+ }}
+ placeholder="image"
+ fullWidth
+ />
+
+
+
+
+
+ ) : undefined
+ }
+ />
)
}
diff --git a/components/molecule/avatar/package.json b/components/molecule/avatar/package.json
index 0fc0bbeea3..8348db7971 100644
--- a/components/molecule/avatar/package.json
+++ b/components/molecule/avatar/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-avatar",
- "version": "1.13.0",
+ "version": "1.16.0",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -10,7 +10,8 @@
},
"dependencies": {
"@s-ui/react-atom-image": "2",
- "@s-ui/react-atom-skeleton": "1"
+ "@s-ui/react-atom-skeleton": "1",
+ "@s-ui/react-primitive-injector": "1"
},
"peerDependencies": {
"@s-ui/component-dependencies": "1"
diff --git a/components/molecule/avatar/src/AvatarFallback/index.js b/components/molecule/avatar/src/AvatarFallback/index.js
index 61b34f915a..aabcf79d03 100644
--- a/components/molecule/avatar/src/AvatarFallback/index.js
+++ b/components/molecule/avatar/src/AvatarFallback/index.js
@@ -1,8 +1,8 @@
-import {cloneElement} from 'react'
-
import cx from 'classnames'
import PropTypes from 'prop-types'
+import Injector from '@s-ui/react-primitive-injector'
+
import AvatarFallbackIcon from '../AvatarFallbackIcon/index.js'
import {BASE_CLASS_NAME as FALLBACK_ICON_CLASS_NAME} from '../AvatarFallbackIcon/settings.js'
import AvatarFallbackName from '../AvatarFallbackName/index.js'
@@ -14,11 +14,15 @@ const MoleculeAvatarFallback = ({
...others
}) => {
const className = cx(classNameProp, FALLBACK_ICON_CLASS_NAME)
- return name ? (
-
- ) : (
- cloneElement(icon, {...others, className, role: 'img'})
- )
+
+ const [Component, providedProps] = name
+ ? [AvatarFallbackName, {name, ...others}]
+ : [
+ props =>
{icon} ,
+ {...others, className, role: 'img'}
+ ]
+
+ return
}
MoleculeAvatarFallback.displayName = 'MoleculeAvatarFallback'
diff --git a/components/molecule/avatar/src/AvatarFallbackName/index.js b/components/molecule/avatar/src/AvatarFallbackName/index.js
index 348e51e387..9394745b5f 100644
--- a/components/molecule/avatar/src/AvatarFallbackName/index.js
+++ b/components/molecule/avatar/src/AvatarFallbackName/index.js
@@ -1,6 +1,7 @@
import cx from 'classnames'
import PropTypes from 'prop-types'
+import useConvertStringToHex from '../useConvertStringToHex.js'
import {BASE_CLASS_NAME} from './settings.js'
const MoleculeAvatarFallbackName = ({
@@ -20,9 +21,16 @@ const MoleculeAvatarFallbackName = ({
? `${firstName.charAt(0)}${lastName.charAt(0)}`
: firstName.charAt(0)
+ const backgroundColor = useConvertStringToHex(nameProp)
+
return (
-
- {name.toUpperCase()}
+
+ {name}
)
}
diff --git a/components/molecule/avatar/src/AvatarFallbackName/index.scss b/components/molecule/avatar/src/AvatarFallbackName/index.scss
index d9b862461d..2311b9dc37 100644
--- a/components/molecule/avatar/src/AvatarFallbackName/index.scss
+++ b/components/molecule/avatar/src/AvatarFallbackName/index.scss
@@ -1,5 +1,11 @@
-$base-class-fallback-name: '#{$base-class}FallbackName';
+$base-class-fallback-name: #{$base-class}FallbackName;
#{$base-class-fallback-name} {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
color: $c-avatar-fallback-name;
+ text-transform: uppercase;
}
diff --git a/components/molecule/avatar/src/index.js b/components/molecule/avatar/src/index.js
index cae0d9d884..d583abd129 100644
--- a/components/molecule/avatar/src/index.js
+++ b/components/molecule/avatar/src/index.js
@@ -1,10 +1,4 @@
-import {
- Children,
- cloneElement,
- forwardRef,
- isValidElement,
- useCallback
-} from 'react'
+import {forwardRef, useCallback} from 'react'
import cx from 'classnames'
import PropTypes from 'prop-types'
@@ -14,6 +8,7 @@ import AtomSkeleton, {
ATOM_SKELETON_ANIMATIONS,
ATOM_SKELETON_VARIANTS
} from '@s-ui/react-atom-skeleton'
+import Injector from '@s-ui/react-primitive-injector'
import AvatarBadge, {
AVATAR_BADGE_PLACEMENTS,
@@ -22,7 +17,6 @@ import AvatarBadge, {
} from './AvatarBadge/index.js'
import AvatarFallback from './AvatarFallback/index.js'
import {AVATAR_SIZES, baseClassName} from './settings.js'
-import useConvertStringToHex from './useConvertStringToHex.js'
const MoleculeAvatar = forwardRef(
(
@@ -43,16 +37,12 @@ const MoleculeAvatar = forwardRef(
style,
isLoading,
imageProps = {},
- children: childrenProp,
+ children,
...others
},
forwardedRef
) => {
const className = cx(baseClassName, `${baseClassName}--${size}`)
- const backgroundColor = useConvertStringToHex(name)
- const children = Children.toArray(childrenProp)
- .filter(child => isValidElement(child))
- .map(child => cloneElement(child, {size}))
const renderContent = useCallback(() => {
if (isLoading) {
@@ -75,7 +65,7 @@ const MoleculeAvatar = forwardRef(
) : (
fallback
)}
- {!isLoading && children}
+ {!isLoading &&
{children} }
>
)
}, [
@@ -90,15 +80,7 @@ const MoleculeAvatar = forwardRef(
])
return (
-
+
{renderContent()}
)
diff --git a/components/molecule/avatar/src/styles/index.scss b/components/molecule/avatar/src/styles/index.scss
index d22d7141d6..c5526badef 100644
--- a/components/molecule/avatar/src/styles/index.scss
+++ b/components/molecule/avatar/src/styles/index.scss
@@ -31,3 +31,5 @@ $base-class: '.sui-MoleculeAvatar';
}
}
}
+
+@import '../AvatarFallback/index.scss';
diff --git a/components/molecule/avatar/test/index.test.js b/components/molecule/avatar/test/index.test.js
index a1bb6b638d..1955955a0b 100644
--- a/components/molecule/avatar/test/index.test.js
+++ b/components/molecule/avatar/test/index.test.js
@@ -192,7 +192,7 @@ describe(json.name, () => {
const {getByText} = setup(props)
// Then
- expect(getByText('JS')).to.be.visible
+ expect(getByText('js')).to.be.visible
})
describe('forwardRef', () => {
diff --git a/components/molecule/breadcrumb/CHANGELOG.md b/components/molecule/breadcrumb/CHANGELOG.md
index 0ebd69d8e1..62085b4bdf 100644
--- a/components/molecule/breadcrumb/CHANGELOG.md
+++ b/components/molecule/breadcrumb/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 1.27.0 (2022-10-06)
+
+
+
# 1.26.0 (2022-06-22)
diff --git a/components/molecule/breadcrumb/package.json b/components/molecule/breadcrumb/package.json
index 15bb8a6014..8e7eb41577 100644
--- a/components/molecule/breadcrumb/package.json
+++ b/components/molecule/breadcrumb/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-breadcrumb",
- "version": "1.26.0",
+ "version": "1.27.0",
"description": "SUI Breadcrumb Basic",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/buttonGroup/CHANGELOG.md b/components/molecule/buttonGroup/CHANGELOG.md
index e4e0a6e28f..c4336c95f7 100644
--- a/components/molecule/buttonGroup/CHANGELOG.md
+++ b/components/molecule/buttonGroup/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 2.10.0 (2022-10-06)
+
+
+
# 2.9.0 (2022-06-22)
diff --git a/components/molecule/buttonGroup/package.json b/components/molecule/buttonGroup/package.json
index 51688c899c..2aa80ea4bd 100644
--- a/components/molecule/buttonGroup/package.json
+++ b/components/molecule/buttonGroup/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-button-group",
- "version": "2.9.0",
+ "version": "2.10.0",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -11,7 +11,8 @@
"dependencies": {
"@s-ui/component-dependencies": "1",
"@s-ui/react-atom-button": "1",
- "@s-ui/react-primitive-polymorphic-element": "1"
+ "@s-ui/react-primitive-polymorphic-element": "1",
+ "@s-ui/react-primitive-injector": "1"
},
"keywords": [],
"author": "",
diff --git a/components/molecule/buttonGroup/src/index.js b/components/molecule/buttonGroup/src/index.js
index 67682c36b5..762b5e9e23 100644
--- a/components/molecule/buttonGroup/src/index.js
+++ b/components/molecule/buttonGroup/src/index.js
@@ -1,12 +1,13 @@
-import {Children, cloneElement} from 'react'
+import {Children} from 'react'
import cx from 'classnames'
import PropTypes from 'prop-types'
import {atomButtonDesigns, atomButtonSizes} from '@s-ui/react-atom-button'
+import Injector from '@s-ui/react-primitive-injector'
import Poly from '@s-ui/react-primitive-polymorphic-element'
-import {BASE_CLASS, combineProps, isFunction} from './settings.js'
+import {BASE_CLASS} from './settings.js'
const getGroupPosition =
({groupPositions, numChildren}) =>
@@ -20,9 +21,9 @@ const MoleculeButtonGroup = ({
as = 'div',
children,
fullWidth,
- size: sizeProp,
- design: designProp,
- negative: negativeProp,
+ size,
+ design,
+ negative,
groupPositions,
onClick,
...props
@@ -35,26 +36,21 @@ const MoleculeButtonGroup = ({
const extendedChildren = Children.toArray(children)
.filter(Boolean)
.map((child, index) => {
- const {
- size: sizeChild,
- design: designChild,
- negative: negativeChild,
- onClick: onClickChild
- } = child.props
const groupPosition = getGroupPositionByIndex(index)
- const clickHandler = (event, ...args) => {
- isFunction(onClickChild) && onClickChild(event, ...args)
- isFunction(onClick) && onClick(event, ...args)
- }
- return cloneElement(child, {
- ...props,
- negative: combineProps(negativeChild, negativeProp),
- size: combineProps(sizeChild, sizeProp),
- design: combineProps(designChild, designProp),
- groupPosition,
- fullWidth,
- onClick: clickHandler
- })
+
+ return (
+
+ {child}
+
+ )
})
return (
diff --git a/components/molecule/buttonGroup/src/settings.js b/components/molecule/buttonGroup/src/settings.js
index 3d3293baf1..c5c2ae5da7 100644
--- a/components/molecule/buttonGroup/src/settings.js
+++ b/components/molecule/buttonGroup/src/settings.js
@@ -1,6 +1 @@
export const BASE_CLASS = 'sui-MoleculeButtonGroup'
-
-export const isFunction = fn => typeof fn === 'function'
-
-export const combineProps = (childProp, wrapperProp) =>
- childProp === undefined ? wrapperProp : childProp
diff --git a/components/molecule/buttonGroupField/CHANGELOG.md b/components/molecule/buttonGroupField/CHANGELOG.md
index 6ccce7b5de..b17a7556c9 100644
--- a/components/molecule/buttonGroupField/CHANGELOG.md
+++ b/components/molecule/buttonGroupField/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+# 1.9.0 (2022-10-06)
+
+
+
# 1.8.0 (2022-06-22)
diff --git a/components/molecule/buttonGroupField/package.json b/components/molecule/buttonGroupField/package.json
index 264b663169..392f478c1a 100644
--- a/components/molecule/buttonGroupField/package.json
+++ b/components/molecule/buttonGroupField/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-button-group-field",
- "version": "1.8.0",
+ "version": "1.9.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/checkboxField/CHANGELOG.md b/components/molecule/checkboxField/CHANGELOG.md
index c528035bf4..d14ea7e0d4 100644
--- a/components/molecule/checkboxField/CHANGELOG.md
+++ b/components/molecule/checkboxField/CHANGELOG.md
@@ -1,5 +1,14 @@
# CHANGELOG
+# 5.1.0 (2022-10-06)
+
+
+### Features
+
+* **components/organism/nestedCheckboxes:** remove unnecesary lines ([6339679](https://github.com/SUI-Components/sui-components/commit/633967945b38296dd61597aa8c748a0950540b0a))
+
+
+
# 5.0.0 (2022-07-18)
diff --git a/components/molecule/checkboxField/package.json b/components/molecule/checkboxField/package.json
index 74be695463..190008c691 100644
--- a/components/molecule/checkboxField/package.json
+++ b/components/molecule/checkboxField/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-checkbox-field",
- "version": "5.0.0",
+ "version": "5.1.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/drawer/CHANGELOG.md b/components/molecule/drawer/CHANGELOG.md
index 0f595e2bea..1e514c97cc 100644
--- a/components/molecule/drawer/CHANGELOG.md
+++ b/components/molecule/drawer/CHANGELOG.md
@@ -1,5 +1,14 @@
# CHANGELOG
+# 4.6.0 (2022-09-22)
+
+
+### Bug Fixes
+
+* **components/molecule/drawer:** avoid add a listener for keydown that prevents the default behaviou ([2f3158a](https://github.com/SUI-Components/sui-components/commit/2f3158affa430b3c1f0d73288ebc82c6091ccb88))
+
+
+
# 4.5.0 (2022-06-23)
diff --git a/components/molecule/drawer/package.json b/components/molecule/drawer/package.json
index db03b4559a..e4862ba94a 100644
--- a/components/molecule/drawer/package.json
+++ b/components/molecule/drawer/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-drawer",
- "version": "4.5.0",
+ "version": "4.6.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/drawer/src/index.js b/components/molecule/drawer/src/index.js
index 3c06e837dc..f16c9aca4a 100644
--- a/components/molecule/drawer/src/index.js
+++ b/components/molecule/drawer/src/index.js
@@ -39,7 +39,6 @@ const MoleculeDrawer = forwardRef(
useEventListener('keydown', event => {
if (isOpen === false) return
- event.preventDefault()
if (event.key === 'Escape') {
onClose(event, {isOpen: false})
}
diff --git a/components/molecule/dropdownList/CHANGELOG.md b/components/molecule/dropdownList/CHANGELOG.md
index 209f0eb3cf..d8598b0ad5 100644
--- a/components/molecule/dropdownList/CHANGELOG.md
+++ b/components/molecule/dropdownList/CHANGELOG.md
@@ -1,5 +1,24 @@
# CHANGELOG
+# 2.1.0 (2022-10-04)
+
+
+### Features
+
+* **components/molecule/dropdownList:** upgrade dropdownOption version ([6d1788c](https://github.com/SUI-Components/sui-components/commit/6d1788c8b2df523ab806dd88069a380292b48162))
+
+
+
+# 1.33.0 (2022-10-03)
+
+
+### Features
+
+* **components/molecule/dropdownList:** remove unnecesary code ([01d811e](https://github.com/SUI-Components/sui-components/commit/01d811ea44dbda9bd37c2a7edfc4a8016cc546a3))
+* **components/molecule/dropdownList:** replace cloneElement by Injector ([1b461d7](https://github.com/SUI-Components/sui-components/commit/1b461d7b8499e14c27327b9466918e3a055f972b)), closes [#2331](https://github.com/SUI-Components/sui-components/issues/2331)
+
+
+
# 1.32.0 (2022-07-26)
diff --git a/components/molecule/dropdownList/demo/package.json b/components/molecule/dropdownList/demo/package.json
index e2c1c085ae..fc3995f62c 100644
--- a/components/molecule/dropdownList/demo/package.json
+++ b/components/molecule/dropdownList/demo/package.json
@@ -11,6 +11,6 @@
"author": "",
"license": "ISC",
"dependencies": {
- "@s-ui/react-molecule-dropdown-option": "1"
+ "@s-ui/react-molecule-dropdown-option": "2"
}
}
diff --git a/components/molecule/dropdownList/package.json b/components/molecule/dropdownList/package.json
index 2094664c37..4a7f5e8273 100644
--- a/components/molecule/dropdownList/package.json
+++ b/components/molecule/dropdownList/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-dropdown-list",
- "version": "1.32.0",
+ "version": "2.1.0",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -11,7 +11,8 @@
"dependencies": {
"@s-ui/react-atom-input": "5",
"@s-ui/react-hooks": "1",
- "@s-ui/react-molecule-dropdown-option": "1",
+ "@s-ui/react-molecule-dropdown-option": "2",
+ "@s-ui/react-primitive-injector": "1",
"lodash.isequal": "4.5"
},
"peerDependencies": {
diff --git a/components/molecule/dropdownList/src/ExtendedChildren.js b/components/molecule/dropdownList/src/ExtendedChildren.js
index b0c2f7aabb..9ca263b6f5 100644
--- a/components/molecule/dropdownList/src/ExtendedChildren.js
+++ b/components/molecule/dropdownList/src/ExtendedChildren.js
@@ -1,42 +1,36 @@
-import {cloneElement} from 'react'
-
import isEqual from 'lodash.isequal'
import PropTypes from 'prop-types'
-const ExtendedChildren = ({
- value,
- children,
- onSelect: onSelectListHandler,
- checkbox,
- ...props
-}) => {
- const {
- value: valueChild,
- onSelect: onSelectOptionHandler,
- selected: selectedChild,
- checkbox: checkboxChild
- } = children.props
+import Injector from '@s-ui/react-primitive-injector'
+
+const ExtendedChildren = ({value, children, onSelect, checkbox, ...props}) => {
+ const {value: valueChild} = children.props
const selected = Array.isArray(value)
? value.some(innerValue => isEqual(valueChild, innerValue))
: isEqual(value, valueChild)
- const onSelectHandler = (...args) => {
- typeof onSelectOptionHandler === 'function' &&
- onSelectOptionHandler(...args)
- typeof onSelectListHandler === 'function' && onSelectListHandler(...args)
- }
- return cloneElement(children, {
- ...props,
- selected: selectedChild === undefined ? selected : selectedChild,
- onSelect: onSelectHandler,
- checkbox: checkboxChild === undefined ? checkbox : checkboxChild
- })
+ return (
+
+ {children}
+
+ )
}
ExtendedChildren.propTypes = {
/** selected value */
value: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
+ /** checkbox contained in all DropdownOption **/
+ checkbox: PropTypes.bool,
/** each single node to be included in the list (MoleculeDropdownOption) */
- children: PropTypes.node
+ children: PropTypes.node,
+ /** callback on select option **/
+ onSelect: PropTypes.func
}
export default ExtendedChildren
diff --git a/components/molecule/dropdownOption/CHANGELOG.md b/components/molecule/dropdownOption/CHANGELOG.md
index eb92ab45ca..82c2aba37b 100644
--- a/components/molecule/dropdownOption/CHANGELOG.md
+++ b/components/molecule/dropdownOption/CHANGELOG.md
@@ -1,5 +1,23 @@
# CHANGELOG
+# 2.2.0 (2022-10-10)
+
+
+### Features
+
+* **components/molecule/dropdownOption:** Fixed grammar error ([10ff698](https://github.com/SUI-Components/sui-components/commit/10ff698453177b950592d33e981cf964c69b05e4)), closes [#2371](https://github.com/SUI-Components/sui-components/issues/2371)
+
+
+
+# 2.1.0 (2022-10-04)
+
+
+### Features
+
+* **components/molecule/dropdownOption:** change prop naming following conventions ([c6e900e](https://github.com/SUI-Components/sui-components/commit/c6e900e197cccbf7a85e55e7b794333e9da3e997))
+
+
+
# 1.45.0 (2022-07-22)
diff --git a/components/molecule/dropdownOption/package.json b/components/molecule/dropdownOption/package.json
index 52ccd33a12..3947e7cc52 100644
--- a/components/molecule/dropdownOption/package.json
+++ b/components/molecule/dropdownOption/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-dropdown-option",
- "version": "1.45.0",
+ "version": "2.2.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/dropdownOption/src/handlersFactory/index.js b/components/molecule/dropdownOption/src/handlersFactory/index.js
index 4de11bdb91..6037722ea5 100644
--- a/components/molecule/dropdownOption/src/handlersFactory/index.js
+++ b/components/molecule/dropdownOption/src/handlersFactory/index.js
@@ -1,7 +1,7 @@
const handlersFactory = ({
disabled = false,
onSelect,
- onSelectKey = 'Enter',
+ selectKey = 'Enter',
selected,
setInnerSelected,
value
@@ -14,11 +14,11 @@ const handlersFactory = ({
}
const handleKeyDown = ev => {
const {key} = ev
- const isStringOnSelectKey = typeof onSelectKey === 'string'
- const isPressedOnSelectKey = isStringOnSelectKey
- ? key === onSelectKey
- : onSelectKey.includes(key)
- if (isPressedOnSelectKey && !disabled) {
+ const isStringSelectKey = typeof selectKey === 'string'
+ const isPressedSelectKey = isStringSelectKey
+ ? key === selectKey
+ : selectKey.includes(key)
+ if (isPressedSelectKey && !disabled) {
ev.preventDefault()
onSelect(ev, {value, selected: !selected})
setInnerSelected(!selected)
diff --git a/components/molecule/dropdownOption/src/index.js b/components/molecule/dropdownOption/src/index.js
index 2e30941887..52682b4962 100644
--- a/components/molecule/dropdownOption/src/index.js
+++ b/components/molecule/dropdownOption/src/index.js
@@ -35,7 +35,7 @@ const MoleculeDropdownOption = forwardRef(
highlightQuery,
highlightValue,
innerRef,
- onSelectKey,
+ selectKey,
onSelect,
selected,
defaultSelected,
@@ -72,7 +72,7 @@ const MoleculeDropdownOption = forwardRef(
])
const {handleClick, handleKeyDown, handleFocus} = handlersFactory({
disabled,
- onSelectKey,
+ selectKey,
onSelect,
selected: innerSelected,
setInnerSelected,
@@ -164,7 +164,7 @@ MoleculeDropdownOption.propTypes = {
children: PropTypes.node,
/** Contains checkbox */
checkbox: PropTypes.bool,
- /** Addtional props to set up the checkbox */
+ /** Additional props to set up the checkbox */
checkboxProps: PropTypes.object,
/** Is disabled */
disabled: PropTypes.bool,
@@ -179,7 +179,10 @@ MoleculeDropdownOption.propTypes = {
/** Text to be display if used with highlight query with custom content */
highlightValue: PropTypes.string,
/* key to provoke the onClick callback. Valid any value defined here → https://www.w3.org/TR/uievents-key/#named-key-attribute-values */
- onSelectKey: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
+ selectKey: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.arrayOf(PropTypes.string)
+ ]),
/** Custom ref handler that will be assigned to the "target" element */
innerRef: PropTypes.object,
/** Text with css clamp = 2 */
@@ -193,7 +196,7 @@ MoleculeDropdownOption.defaultProps = {
disabled: false,
onSelect: () => {},
defaultSelected: false,
- onSelectKey: 'Enter',
+ selectKey: 'Enter',
innerRef: createRef()
}
export default MoleculeDropdownOption
diff --git a/components/molecule/field/CHANGELOG.md b/components/molecule/field/CHANGELOG.md
index 105767084a..940a3a788e 100644
--- a/components/molecule/field/CHANGELOG.md
+++ b/components/molecule/field/CHANGELOG.md
@@ -1,5 +1,32 @@
# CHANGELOG
+# 1.37.0 (2022-10-06)
+
+
+### Features
+
+* **components/molecule/field:** admit react nodes in error alert success and help text ([a946f54](https://github.com/SUI-Components/sui-components/commit/a946f54bae2d472c25efab4a5d9709c021c92834))
+
+
+
+# 1.36.0 (2022-10-04)
+
+
+### Bug Fixes
+
+* **components/molecule/field:** fix lint error ([9f56f8b](https://github.com/SUI-Components/sui-components/commit/9f56f8bfee58813850bc68492b8696d97098f4c4))
+
+
+
+# 1.35.0 (2022-10-04)
+
+
+### Features
+
+* **components/molecule/field:** refactor Label's conditional in field ([605fc5a](https://github.com/SUI-Components/sui-components/commit/605fc5a33e79f3280980ff8f913a73299f086598)), closes [#2334](https://github.com/SUI-Components/sui-components/issues/2334)
+
+
+
# 1.34.0 (2022-06-23)
diff --git a/components/molecule/field/package.json b/components/molecule/field/package.json
index b2203fffc7..d8914ce888 100644
--- a/components/molecule/field/package.json
+++ b/components/molecule/field/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-field",
- "version": "1.34.0",
+ "version": "1.37.0",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -11,7 +11,8 @@
"dependencies": {
"@s-ui/react-atom-help-text": "1",
"@s-ui/react-atom-label": "1",
- "@s-ui/react-atom-validation-text": "1"
+ "@s-ui/react-atom-validation-text": "1",
+ "@s-ui/react-primitive-injector": "1"
},
"peerDependencies": {
"@s-ui/component-dependencies": "1"
diff --git a/components/molecule/field/src/Label.js b/components/molecule/field/src/Label.js
index c1ee638a32..6b65128cb6 100644
--- a/components/molecule/field/src/Label.js
+++ b/components/molecule/field/src/Label.js
@@ -1,41 +1,18 @@
-import {cloneElement} from 'react'
import {isElement} from 'react-is'
import PropTypes from 'prop-types'
-import AtomLabel, {AtomLabelTypes} from '@s-ui/react-atom-label'
+import AtomLabel from '@s-ui/react-atom-label'
+import Injector from '@s-ui/react-primitive-injector'
import {CLASS_NODE_LABEL_CONTAINER} from './config.js'
-const MoleculeLabel = ({
- label,
- nodeLabel,
- type: typeValidationLabel,
- name,
- onClick
-}) => {
+const MoleculeLabel = ({label, nodeLabel, ...props}) => {
const innerLabel = () => {
- if (label) {
- return isElement(label) ? (
- cloneElement(label, {
- type: typeValidationLabel,
- name,
- onClick
- })
- ) : (
-
- )
- } else if (nodeLabel) {
- return cloneElement(nodeLabel, {
- type: typeValidationLabel,
- name,
- onClick
- })
+ if ((label && isElement(label)) || (!label && nodeLabel)) {
+ return {!label ? nodeLabel : label}
+ } else if (label) {
+ return
}
return null
}
@@ -44,10 +21,7 @@ const MoleculeLabel = ({
MoleculeLabel.propTypes = {
label: PropTypes.string,
- nodeLabel: PropTypes.element,
- type: PropTypes.oneOf(Object.values(AtomLabelTypes)),
- name: PropTypes.string,
- onClick: PropTypes.func
+ nodeLabel: PropTypes.element
}
export default MoleculeLabel
diff --git a/components/molecule/field/src/index.js b/components/molecule/field/src/index.js
index ab11d8a920..e27892a0dd 100644
--- a/components/molecule/field/src/index.js
+++ b/components/molecule/field/src/index.js
@@ -140,16 +140,32 @@ MoleculeField.propTypes = {
name: PropTypes.string.isRequired,
/** Success message to display when success state */
- successText: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]),
+ successText: PropTypes.oneOfType([
+ PropTypes.element,
+ PropTypes.bool,
+ PropTypes.node
+ ]),
/** Error message to display when error state */
- errorText: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]),
+ errorText: PropTypes.oneOfType([
+ PropTypes.element,
+ PropTypes.bool,
+ PropTypes.node
+ ]),
/** Error message to display when alert state */
- alertText: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]),
+ alertText: PropTypes.oneOfType([
+ PropTypes.element,
+ PropTypes.bool,
+ PropTypes.node
+ ]),
/** Help Text to display */
- helpText: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]),
+ helpText: PropTypes.oneOfType([
+ PropTypes.element,
+ PropTypes.bool,
+ PropTypes.node
+ ]),
/** Boolean to decide if elements should be set inline */
inline: PropTypes.bool,
diff --git a/components/molecule/imageEditor/CHANGELOG.md b/components/molecule/imageEditor/CHANGELOG.md
index 408ded1e65..d5c2d27aef 100644
--- a/components/molecule/imageEditor/CHANGELOG.md
+++ b/components/molecule/imageEditor/CHANGELOG.md
@@ -1,5 +1,14 @@
# CHANGELOG
+# 1.10.0 (2022-09-20)
+
+
+### Features
+
+* **components/molecule/imageEditor:** Add a SCSS token to customize imageEditor labels color ([714c393](https://github.com/SUI-Components/sui-components/commit/714c393e87c94deb5fe2cb2f8f968deb7ce1224f))
+
+
+
# 1.9.0 (2022-09-05)
diff --git a/components/molecule/imageEditor/package.json b/components/molecule/imageEditor/package.json
index 5c0b5dbb00..5430f3b573 100644
--- a/components/molecule/imageEditor/package.json
+++ b/components/molecule/imageEditor/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-image-editor",
- "version": "1.9.0",
+ "version": "1.10.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/imageEditor/src/styles/index.scss b/components/molecule/imageEditor/src/styles/index.scss
index 2a118fb847..5d95678039 100644
--- a/components/molecule/imageEditor/src/styles/index.scss
+++ b/components/molecule/imageEditor/src/styles/index.scss
@@ -19,7 +19,7 @@ $base-class: '.sui-MoleculeImageEditor';
&-label {
align-items: center;
- color: $c-gray;
+ color: $c-molecule-image-editor-label;
display: flex;
margin-right: $m-l;
diff --git a/components/molecule/imageEditor/src/styles/settings.scss b/components/molecule/imageEditor/src/styles/settings.scss
index 2704749c75..b9552c9a4d 100644
--- a/components/molecule/imageEditor/src/styles/settings.scss
+++ b/components/molecule/imageEditor/src/styles/settings.scss
@@ -1,3 +1,4 @@
+$c-molecule-image-editor-label: $c-gray !default;
$h-molecule-image-editor: 300px !default;
$mb-molecule-image-editor-crop: $m-xxl !default;
$mt-molecule-image-editor-slider: $m-xl !default;
diff --git a/components/molecule/inputTags/src/config.js b/components/molecule/inputTags/src/config.js
index 3e08958bd6..4e1ee64da9 100644
--- a/components/molecule/inputTags/src/config.js
+++ b/components/molecule/inputTags/src/config.js
@@ -1,3 +1,6 @@
+import {inputSizes} from '@s-ui/react-atom-input'
+import {atomTagSizes} from '@s-ui/react-atom-tag'
+
export const BASE_CLASS = 'sui-AtomInput'
export const CLASS_TAGS = `${BASE_CLASS}--withTags`
export const CLASS_TAGS_FOCUS = `${CLASS_TAGS}--focus`
@@ -12,4 +15,15 @@ export const isDuplicate = (values, newValue) => {
return upperTags.includes(newValue.toUpperCase())
}
+export const getInputToTagSize = inputSize => {
+ const conversor = {
+ [inputSizes.XSMALL]: atomTagSizes.XSMALL,
+ [inputSizes.SMALL]: atomTagSizes.SMALL,
+ [inputSizes.MEDIUM]: atomTagSizes.MEDIUM,
+ [inputSizes.LARGE]: atomTagSizes.LARGE,
+ [inputSizes.XLARGE]: atomTagSizes.XLARGE
+ }
+ return conversor[inputSize]
+}
+
export const isFunction = fn => typeof fn === 'function'
diff --git a/components/molecule/inputTags/src/index.js b/components/molecule/inputTags/src/index.js
index 823c82910d..79da8ff01b 100644
--- a/components/molecule/inputTags/src/index.js
+++ b/components/molecule/inputTags/src/index.js
@@ -14,6 +14,7 @@ import {
CLASS_TAGS_ERROR,
CLASS_TAGS_FOCUS,
CLASS_TAGS_SUCCESS,
+ getInputToTagSize,
isDuplicate,
isFunction
} from './config.js'
@@ -136,10 +137,11 @@ const MoleculeInputTags = forwardRef(
label
})}
label={label}
- size={atomTagSizes.SMALL}
+ size={getInputToTagSize(size)}
responsive
readOnly={readOnly}
disabled={disabled}
+ isFitted
/>
)
})}
@@ -156,6 +158,7 @@ const MoleculeInputTags = forwardRef(
noBorder
readOnly={readOnly}
disabled={disabled}
+ size={size}
placeholder={isEmpty ? placeholder : undefined}
/>
)}
diff --git a/components/molecule/inputTags/src/styles/index.scss b/components/molecule/inputTags/src/styles/index.scss
index e92b1804b2..f499e479bb 100644
--- a/components/molecule/inputTags/src/styles/index.scss
+++ b/components/molecule/inputTags/src/styles/index.scss
@@ -10,6 +10,7 @@ $class-input: '#{$base-class}-input';
display: flex;
flex-wrap: wrap;
padding: 0 0 0 $p-m;
+ gap: $p-base;
&--focus {
@include sui-atom-input-input-focus;
@@ -22,6 +23,9 @@ $class-input: '#{$base-class}-input';
background-color: transparent;
}
}
+ &[aria-readonly='true'] {
+ background-color: $bgc-input-tag-read-only;
+ }
& #{$class-input} {
flex: 1;
diff --git a/components/molecule/inputTags/src/styles/settings.scss b/components/molecule/inputTags/src/styles/settings.scss
index 8fff321a6d..6c637513b9 100644
--- a/components/molecule/inputTags/src/styles/settings.scss
+++ b/components/molecule/inputTags/src/styles/settings.scss
@@ -1,3 +1,4 @@
$sizes-atom-input-paddings: m $p-m, s $p-s !default;
-$bg-input-tag-disable: $c-gray-light-4 !default;
+$bg-input-tag-disable: $bgc-atom-input-disabled;
+$bgc-input-tag-read-only: $bgc-atom-input-read-only;
$bdrs-molecule-input-tags: 0 !default;
diff --git a/components/molecule/inputTags/test/index.test.js b/components/molecule/inputTags/test/index.test.js
index 4078321014..8d9b8ff67d 100644
--- a/components/molecule/inputTags/test/index.test.js
+++ b/components/molecule/inputTags/test/index.test.js
@@ -127,7 +127,7 @@ describe(json.name, () => {
sinon.match({
tags: [],
name: props.name,
- value: value
+ value
})
)
})
@@ -161,7 +161,7 @@ describe(json.name, () => {
sinon.match({
tags: props.tags,
name: props.name,
- value: value
+ value
})
)
})
diff --git a/components/molecule/notification/CHANGELOG.md b/components/molecule/notification/CHANGELOG.md
index 92fa1df83c..9f672b78ff 100644
--- a/components/molecule/notification/CHANGELOG.md
+++ b/components/molecule/notification/CHANGELOG.md
@@ -1,5 +1,26 @@
# CHANGELOG
+# 1.34.0 (2022-10-01)
+
+
+### Features
+
+* **components/molecule/notification:** Remove -system ([b84c52c](https://github.com/SUI-Components/sui-components/commit/b84c52c956db4b709039dc6739f60c48b5427a79))
+
+
+
+# 1.33.0 (2022-09-19)
+
+
+### Features
+
+* **components/molecule/notification:** create new variable to define background positive variation ([b77ec9b](https://github.com/SUI-Components/sui-components/commit/b77ec9ba9fd3eb965df744311d09bec895184490))
+* **components/molecule/notification:** refactor to use background colors set at theme to create pos ([70bd3b0](https://github.com/SUI-Components/sui-components/commit/70bd3b07365967e52164b10a9a2a00e43240a209))
+* **Root:** Delete undefined dependencies ([c145905](https://github.com/SUI-Components/sui-components/commit/c145905350328925ba6fda2a462d7f8b508c8ea0))
+* **Root:** Merge commit ([d3735d0](https://github.com/SUI-Components/sui-components/commit/d3735d0644332e674d5a5b6291680697f0d6f7c4))
+
+
+
# 1.32.0 (2022-06-23)
diff --git a/components/molecule/notification/package.json b/components/molecule/notification/package.json
index e491defd02..472d434e86 100644
--- a/components/molecule/notification/package.json
+++ b/components/molecule/notification/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-notification",
- "version": "1.32.0",
+ "version": "1.34.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/notification/src/_settings.scss b/components/molecule/notification/src/_settings.scss
index b2365b1e3b..5f341033b8 100644
--- a/components/molecule/notification/src/_settings.scss
+++ b/components/molecule/notification/src/_settings.scss
@@ -1,3 +1,5 @@
+@use 'sass:map';
+
$w-notification: 100% !default;
$z-notification: 1000 !default;
$mh-notification: 500px !default;
@@ -30,7 +32,35 @@ $notification-type-colors: (
success: $c-success,
warning: $c-alert,
error: $c-error,
- system: $c-system
+ system: $c-black
+) !default;
+
+$notification-type-positive-colors: (
+ info:
+ color-variation(
+ map.get($notification-type-colors, 'info'),
+ $c-light-step * 2
+ ),
+ success:
+ color-variation(
+ map.get($notification-type-colors, 'success'),
+ $c-light-step * 2
+ ),
+ warning:
+ color-variation(
+ map.get($notification-type-colors, 'warning'),
+ $c-light-step * 2
+ ),
+ error:
+ color-variation(
+ map.get($notification-type-colors, 'error'),
+ $c-light-step * 2
+ ),
+ system:
+ color-variation(
+ map.get($notification-type-colors, 'system'),
+ $c-light-step * 2
+ )
) !default;
$notification-type-font-colors: (
@@ -47,7 +77,7 @@ $notification-type-positive-text-colors: (
success: $c-success,
warning: $c-alert,
error: $c-error,
- system: $c-system
+ system: $c-black
) !default;
// Positive Icon color
@@ -56,7 +86,7 @@ $notification-type-positive-icon-colors: (
success: $c-success,
warning: $c-alert,
error: $c-error,
- system: $c-system
+ system: $c-black
) !default;
// Effects
diff --git a/components/molecule/notification/src/styles/index.scss b/components/molecule/notification/src/styles/index.scss
index 128a6e6acb..c377eba752 100644
--- a/components/molecule/notification/src/styles/index.scss
+++ b/components/molecule/notification/src/styles/index.scss
@@ -85,9 +85,9 @@ $base-class: '.sui-MoleculeNotification';
}
// Type variations
- @each $key, $value in $notification-type-colors {
+ @each $key, $value in $notification-type-positive-colors {
{$base-class}--#{$key} {
- background: color-variation($value, $c-light-step * 2);
+ background: #{$value};
}
}
}
diff --git a/components/molecule/photoUploader/demo/package.json b/components/molecule/photoUploader/demo/package.json
index 3347b27be7..9a78a21592 100644
--- a/components/molecule/photoUploader/demo/package.json
+++ b/components/molecule/photoUploader/demo/package.json
@@ -12,7 +12,7 @@
"license": "ISC",
"dependencies": {
"@s-ui/react-atom-button": "1",
- "@s-ui/react-molecule-dropdown-option": "1",
+ "@s-ui/react-molecule-dropdown-option": "2",
"@s-ui/react-molecule-select": "1"
}
}
diff --git a/components/molecule/rating/CHANGELOG.md b/components/molecule/rating/CHANGELOG.md
index 4b041efc8a..096cc33ff1 100644
--- a/components/molecule/rating/CHANGELOG.md
+++ b/components/molecule/rating/CHANGELOG.md
@@ -1,5 +1,14 @@
# CHANGELOG
+# 1.21.0 (2022-10-01)
+
+
+### Features
+
+* **components/molecule/rating:** Remove -system ([dc7bd06](https://github.com/SUI-Components/sui-components/commit/dc7bd06a57c74e6112589ec6a97b738f090632cc))
+
+
+
# 1.20.0 (2022-06-23)
diff --git a/components/molecule/rating/package.json b/components/molecule/rating/package.json
index 6a0fc59052..15a9f5ed3e 100644
--- a/components/molecule/rating/package.json
+++ b/components/molecule/rating/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-rating",
- "version": "1.20.0",
+ "version": "1.21.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/rating/src/styles/settings.scss b/components/molecule/rating/src/styles/settings.scss
index 55e823696e..068bc9b402 100644
--- a/components/molecule/rating/src/styles/settings.scss
+++ b/components/molecule/rating/src/styles/settings.scss
@@ -21,5 +21,5 @@ $m-l-molecule-small-rating-stars: $m-l-molecule-rating-stars !default;
$p-molecule-rating-label: $p-m !default;
$p-molecule-rating-stars: 0 !default;
-$c-molecule-rating-svg: $c-system !default;
+$c-molecule-rating-svg: $c-black !default;
$c-molecule-rating-svg-hover: $c-primary !default;
diff --git a/components/molecule/select/CHANGELOG.md b/components/molecule/select/CHANGELOG.md
index 1c9e1a45d7..b8246404aa 100644
--- a/components/molecule/select/CHANGELOG.md
+++ b/components/molecule/select/CHANGELOG.md
@@ -1,5 +1,24 @@
# CHANGELOG
+# 1.57.0 (2022-10-11)
+
+
+### Bug Fixes
+
+* **components/molecule/select:** accept onblur prop ([ad3f8fb](https://github.com/SUI-Components/sui-components/commit/ad3f8fb08be2260ffba01fce160c4d3df3814754)), closes [#2282](https://github.com/SUI-Components/sui-components/issues/2282)
+
+
+
+# 1.56.0 (2022-10-04)
+
+
+### Features
+
+* **components/molecule/select:** set new prop name following conventions ([484a999](https://github.com/SUI-Components/sui-components/commit/484a9999fa2eace0fcaf27f73d37872b3d1ca208))
+* **components/molecule/select:** upgrade dropdownOption version ([e05859e](https://github.com/SUI-Components/sui-components/commit/e05859e6135cf0400b616705dce25c0f00a89c2f))
+
+
+
# 1.55.0 (2022-07-29)
diff --git a/components/molecule/select/demo/package.json b/components/molecule/select/demo/package.json
index 0ba8ff5989..b562f0365e 100644
--- a/components/molecule/select/demo/package.json
+++ b/components/molecule/select/demo/package.json
@@ -12,6 +12,6 @@
"license": "ISC",
"dependencies": {
"@s-ui/hoc": "1",
- "@s-ui/react-molecule-dropdown-option": "1"
+ "@s-ui/react-molecule-dropdown-option": "2"
}
}
diff --git a/components/molecule/select/package.json b/components/molecule/select/package.json
index c9887d8beb..9a2b056e30 100644
--- a/components/molecule/select/package.json
+++ b/components/molecule/select/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-select",
- "version": "1.55.0",
+ "version": "1.57.0",
"description": "",
"main": "lib/index.js",
"scripts": {
@@ -12,7 +12,7 @@
"@s-ui/js": "2",
"@s-ui/react-atom-input": "5",
"@s-ui/react-hooks": "1",
- "@s-ui/react-molecule-dropdown-list": "1",
+ "@s-ui/react-molecule-dropdown-list": "2",
"@s-ui/react-molecule-input-tags": "2",
"@s-ui/react-primitive-injector": "1"
},
diff --git a/components/molecule/select/src/components/MoleculeInputSelect.js b/components/molecule/select/src/components/MoleculeInputSelect.js
index a4ac2f9d48..624e007a9e 100644
--- a/components/molecule/select/src/components/MoleculeInputSelect.js
+++ b/components/molecule/select/src/components/MoleculeInputSelect.js
@@ -20,8 +20,12 @@ const MoleculeInputSelect = props => {
return (
- {children}
- {iconArrow}
+ {iconArrow}}
+ {...props}
+ >
+ {children}
+
)
}
diff --git a/components/molecule/select/src/components/MultipleSelection.js b/components/molecule/select/src/components/MultipleSelection.js
index 17a718a43a..3d24d7e315 100644
--- a/components/molecule/select/src/components/MultipleSelection.js
+++ b/components/molecule/select/src/components/MultipleSelection.js
@@ -26,6 +26,7 @@ const MoleculeSelectFieldMultiSelection = props => {
} = props
const tags = values.map(value => optionsData[value])
+ const isFull = () => maxTags && tags?.length >= maxTags
const handleMultiSelection = (ev, {value: valueOptionSelected}) => {
const handleToggle = ev => {
@@ -42,8 +43,6 @@ const MoleculeSelectFieldMultiSelection = props => {
const addToValues = () => [...values, valueOptionSelected]
- const isFull = () => maxTags && tags?.length >= maxTags
-
if (isValueSelectedAlreadySelected()) {
onChange(ev, {value: removeFromValues()})
} else if (!isFull()) {
@@ -82,7 +81,7 @@ const MoleculeSelectFieldMultiSelection = props => {
diff --git a/components/molecule/select/src/components/SingleSelection.js b/components/molecule/select/src/components/SingleSelection.js
index 3cd9c56e94..34fc386db7 100644
--- a/components/molecule/select/src/components/SingleSelection.js
+++ b/components/molecule/select/src/components/SingleSelection.js
@@ -48,7 +48,7 @@ const MoleculeSelectSingleSelection = props => {
size={selectSize}
tabIndex={tabIndex}
>
-
+
{
const {
+ onBlur,
isOpen,
onToggle,
children,
@@ -39,6 +40,7 @@ const MoleculeSelect = forwardRef((props, forwardedRef) => {
refMoleculeSelect: refMoleculeSelectFromProps,
'aria-label': ariaLabel
} = props
+
const refMoleculeSelect = useRef(refMoleculeSelectFromProps)
const refsMoleculeSelectOptions = useRef([])
const ref = useMergeRefs(forwardedRef, refMoleculeSelect)
@@ -57,7 +59,7 @@ const MoleculeSelect = forwardRef((props, forwardedRef) => {
refsMoleculeSelectOptions.current[index] = createRef()
return cloneElement(child, {
innerRef: refsMoleculeSelectOptions.current[index],
- onSelectKey: keysSelection
+ selectKey: keysSelection
})
})
@@ -125,7 +127,10 @@ const MoleculeSelect = forwardRef((props, forwardedRef) => {
}
}
- const handleFocusOut = () => setFocus(false)
+ const handleFocusOut = event => {
+ onBlur(event)
+ setFocus(false)
+ }
const handleFocusIn = () => !disabled && setFocus(true)
@@ -185,6 +190,9 @@ MoleculeSelect.propTypes = {
/** if list of options is displayed or not */
isOpen: PropTypes.bool,
+ /** callback onBlur to be triggered when focused outside of the input */
+ onBlur: PropTypes.func,
+
/** callback when arrow up/down is clicked → to show/hide list of options */
onToggle: PropTypes.func,
@@ -232,6 +240,7 @@ MoleculeSelect.propTypes = {
}
MoleculeSelect.defaultProps = {
+ onBlur: () => {},
disabled: false,
keysSelection: SELECTION_KEYS,
onChange: () => {},
diff --git a/components/molecule/select/src/styles/index.scss b/components/molecule/select/src/styles/index.scss
index 3318f7ac1a..f051f800eb 100644
--- a/components/molecule/select/src/styles/index.scss
+++ b/components/molecule/select/src/styles/index.scss
@@ -13,7 +13,7 @@ $class-select-atom-input-tags: '#{$class-select-atom-input}--withTags';
z-index: $z-select-list;
}
- &-inputSelect {
+ #{$class-input} {
&-container {
align-items: center;
border: $bd-select;
@@ -23,19 +23,13 @@ $class-select-atom-input-tags: '#{$class-select-atom-input}--withTags';
#{$class-select-atom-input-input} {
caret-color: transparent;
- background: $bgc-atom-input;
- color: $c-atom-input;
}
- .is-disabled & {
+ #{$class-select-atom-input}--is-disabled {
cursor: default;
#{$class-select-atom-input-input} {
-webkit-text-fill-color: $c-molecule-select-disabled;
-
- background: $bg-molecule-select-disabled;
- border: $bd-molecule-select-disabled;
- color: $c-molecule-select-disabled;
}
#{$class-input}-arrow {
@@ -49,18 +43,9 @@ $class-select-atom-input-tags: '#{$class-select-atom-input}--withTags';
opacity: 1;
-webkit-appearance: none;
}
-
- #{$class-select-atom-input-input}:first-child,
- #{$class-select-atom-input-tags} {
- padding-right: $pr-select-atom-input-tags;
- }
}
&-arrow {
- height: $h-select-list-arrow;
- margin-left: $mr-select-list-arrow;
- width: $w-select-list-arrow;
-
&--down {
transform: rotate(0deg);
}
diff --git a/components/molecule/select/test/index.test.js b/components/molecule/select/test/index.test.js
index e1ec6bb9fc..d39dd6633c 100644
--- a/components/molecule/select/test/index.test.js
+++ b/components/molecule/select/test/index.test.js
@@ -9,6 +9,9 @@ import ReactDOM from 'react-dom'
import chai, {expect} from 'chai'
import chaiDOM from 'chai-dom'
+import sinon from 'sinon'
+
+import userEvents from '@testing-library/user-event'
import json from '../package.json'
import * as pkg from '../src/index.js'
@@ -85,6 +88,24 @@ describe(json.name, () => {
// Then
expect(findClassName(container.innerHTML)).to.be.null
})
+
+ it('should call onBlur callback', () => {
+ const spy = sinon.spy()
+
+ const props = {
+ onBlur: spy
+ }
+
+ // When
+ const {getByRole} = setup(props)
+ const textBox = getByRole('textbox')
+
+ userEvents.click(textBox)
+ userEvents.tab()
+
+ // Then
+ sinon.assert.calledOnce(spy)
+ })
})
describe('moleculeSelectDropdownListSizes', () => {
diff --git a/components/molecule/selectField/demo/package.json b/components/molecule/selectField/demo/package.json
index 6aaac19f57..f66d073fa0 100644
--- a/components/molecule/selectField/demo/package.json
+++ b/components/molecule/selectField/demo/package.json
@@ -12,7 +12,7 @@
"license": "ISC",
"dependencies": {
"@s-ui/hoc": "1",
- "@s-ui/react-molecule-dropdown-option": "1",
+ "@s-ui/react-molecule-dropdown-option": "2",
"@s-ui/react-molecule-field": "1",
"@s-ui/react-molecule-select": "1"
}
diff --git a/components/molecule/selectPopover/demo/package.json b/components/molecule/selectPopover/demo/package.json
index fcdfd82e15..c12143910c 100644
--- a/components/molecule/selectPopover/demo/package.json
+++ b/components/molecule/selectPopover/demo/package.json
@@ -12,7 +12,7 @@
"license": "ISC",
"dependencies": {
"@s-ui/react-icons": "1",
- "@s-ui/react-molecule-dropdown-option": "1",
+ "@s-ui/react-molecule-dropdown-option": "2",
"@s-ui/react-molecule-modal": "1",
"@s-ui/react-molecule-select": "1"
}
diff --git a/components/molecule/tabs/CHANGELOG.md b/components/molecule/tabs/CHANGELOG.md
index bd792b53b1..8d9f1081b2 100644
--- a/components/molecule/tabs/CHANGELOG.md
+++ b/components/molecule/tabs/CHANGELOG.md
@@ -1,5 +1,29 @@
# CHANGELOG
+# 2.37.0 (2022-10-13)
+
+
+### Features
+
+* **components/molecule/tabs:** add id prop to make tabs uniques ([b90231d](https://github.com/SUI-Components/sui-components/commit/b90231dc07db9ef4dcc7943fafe2c634b38a1070))
+* **components/molecule/tabs:** add pull request feedback ([208e0be](https://github.com/SUI-Components/sui-components/commit/208e0bed5aa055ae796fc934d79c334b17acc1b4))
+* **components/molecule/tabs:** pull request feedback ([f32e971](https://github.com/SUI-Components/sui-components/commit/f32e9718a114586ba6e9139406c0db8f330100fd))
+
+
+
+# 2.36.0 (2022-09-22)
+
+
+### Features
+
+* **components/molecule/tabs:** add orientation aria attribute ([71296a3](https://github.com/SUI-Components/sui-components/commit/71296a319365c6109c7e9aaa2077933ceb80d09e))
+* **components/molecule/tabs:** Change tabs to be able to modify current active tabs by updating pro ([3f6a23e](https://github.com/SUI-Components/sui-components/commit/3f6a23e3538970054c289b4607c806baa72c6922))
+* **components/molecule/tabs:** control/uncontroll active tabs ([7945c33](https://github.com/SUI-Components/sui-components/commit/7945c339e5a145a2d593b2f68d4344aea2100f7b))
+* **components/molecule/tabs:** make tabs accesibles ([b4ebaf3](https://github.com/SUI-Components/sui-components/commit/b4ebaf3f60efa0bb51422059bf631f9e1e076666))
+* **components/molecule/tabs:** remove unnecesary prop injected ([4b67d13](https://github.com/SUI-Components/sui-components/commit/4b67d1304388ec589112eb3bd4d24767c8733367))
+
+
+
# 2.35.0 (2022-06-23)
diff --git a/components/molecule/tabs/demo/Articles/ArticleActiveTabs.js b/components/molecule/tabs/demo/Articles/ArticleActiveTabs.js
new file mode 100644
index 0000000000..4effa6569a
--- /dev/null
+++ b/components/molecule/tabs/demo/Articles/ArticleActiveTabs.js
@@ -0,0 +1,111 @@
+import {useState} from 'react'
+
+import MoleculeTabs, {MoleculeTab} from 'components/molecule/tabs/src/index.js'
+import PropTypes from 'prop-types'
+
+import {
+ Article,
+ Code,
+ H2,
+ H3,
+ Paragraph,
+ RadioButton,
+ RadioButtonGroup
+} from '@s-ui/documentation-library'
+
+import Content from '../components/Content.js'
+import {CLASS_DEMO_CONTENT_TAB} from '../config.js'
+
+const tabsNumber = 5
+
+const ArticleActiveTabs = ({className}) => {
+ const [activeTabIndex, setActiveTabIndex] = useState(3)
+ return (
+
+ Controlled and uncontrolled active tabs
+
+ Under activeTabIndex
(number, default 1) developer can
+ control the active tab. Use the defaultActiveTabIndex
for
+ defining the initial tab uncontrolled.
+
+ Uncontrolled
+
+ {Array(tabsNumber)
+ .fill(true)
+ .map((v, index) => (
+ Label {index + 1} }
+ numTab={index + 1}
+ disabled={index + 1 === 4}
+ >
+
+
+ ))}
+
+
Controlled
+
{
+ setActiveTabIndex(value)
+ }}
+ >
+ {Array(tabsNumber)
+ .fill(true)
+ .map((v, index) => (
+ {`tab ${index + 1}`}
+ ))}
+
+
{
+ setActiveTabIndex(numTab)
+ }}
+ >
+ {Array(tabsNumber)
+ .fill(true)
+ .map((v, index) => (
+ Label {index + 1}}
+ numTab={index + 1}
+ disabled={index + 1 === 4}
+ >
+
+
+ ))}
+
+
+ )
+}
+
+ArticleActiveTabs.displayName = 'ArticleActiveTabs'
+
+ArticleActiveTabs.propTypes = {
+ className: PropTypes.string
+}
+
+export default ArticleActiveTabs
diff --git a/components/molecule/tabs/demo/index.js b/components/molecule/tabs/demo/index.js
index 2ad6efb130..9315dffb17 100644
--- a/components/molecule/tabs/demo/index.js
+++ b/components/molecule/tabs/demo/index.js
@@ -1,5 +1,6 @@
import {H1, Paragraph} from '@s-ui/documentation-library'
+import ArticleActiveTabs from './Articles/ArticleActiveTabs.js'
import ArticleDefault from './Articles/ArticleDefault.js'
import ArticleIconsCounters from './Articles/ArticleIconsCounters.js'
import ArticleType from './Articles/ArticleType.js'
@@ -18,6 +19,8 @@ const Demo = () => {
+
+
diff --git a/components/molecule/tabs/package.json b/components/molecule/tabs/package.json
index 98db3ad4ad..1eb73a36c8 100644
--- a/components/molecule/tabs/package.json
+++ b/components/molecule/tabs/package.json
@@ -1,6 +1,6 @@
{
"name": "@s-ui/react-molecule-tabs",
- "version": "2.35.0",
+ "version": "2.37.0",
"description": "",
"main": "lib/index.js",
"scripts": {
diff --git a/components/molecule/tabs/src/components/MoleculeTab.js b/components/molecule/tabs/src/components/MoleculeTab.js
index 52636797f5..bd256c93dc 100644
--- a/components/molecule/tabs/src/components/MoleculeTab.js
+++ b/components/molecule/tabs/src/components/MoleculeTab.js
@@ -21,6 +21,7 @@ const MoleculeTab = forwardRef(
count,
disabled,
icon,
+ id = 'molecule-tab-content',
isIntersecting,
label,
numTab,
@@ -54,6 +55,9 @@ const MoleculeTab = forwardRef(
className={className}
onClick={handleChange}
ref={useMergeRefs(innerRef, forwardedRef)}
+ role="tab"
+ aria-selected={active}
+ aria-controls={`${id}-${numTab}`}
>
{icon &&
{icon} }
{!isNaN(count) &&
{count} }
@@ -73,6 +77,9 @@ MoleculeTab.propTypes = {
/** icon (React component) */
icon: PropTypes.node,
+ /** id used to make tabs unique per page */
+ id: PropTypes.string,
+
/** count to display */
count: PropTypes.string,
diff --git a/components/molecule/tabs/src/components/MoleculeTabs.js b/components/molecule/tabs/src/components/MoleculeTabs.js
index 754f1ef41e..c82d5d1da2 100644
--- a/components/molecule/tabs/src/components/MoleculeTabs.js
+++ b/components/molecule/tabs/src/components/MoleculeTabs.js
@@ -16,6 +16,7 @@ import {
const MoleculeTabs = ({
autoScrollIntoView = true,
children,
+ id = 'molecule-tab-content',
onChange,
type,
variant
@@ -25,6 +26,7 @@ const MoleculeTabs = ({
[`${BASE_CLASS}--${type}`]: type
})
const childrenArray = Children.toArray(children)
+ const isVerticalOrientation = type === TYPES.VERTICAL
const [isIntersecting, outerRef] = useOnScreen()
@@ -36,26 +38,39 @@ const MoleculeTabs = ({
autoScrollIntoView,
isIntersecting,
numTab,
+ id,
onChange
})
})
const activeTabContent = childrenArray.reduce((activeContent, child) => {
if (child) {
- const {children: childrenChild, active} = child.props
- return active ? childrenChild : activeContent
+ const {children: childrenChild, active, numTab} = child.props
+
+ if (active) {
+ return (
+
+ {childrenChild}
+
+ )
+ }
}
return activeContent
}, null)
return (
-
+
- {activeTabContent ? (
- {activeTabContent}
- ) : null}
+ {activeTabContent}
)
}
@@ -69,6 +84,9 @@ MoleculeTabs.propTypes = {
/** children */
children: PropTypes.any,
+ /** id used to make tabs unique */
+ id: PropTypes.string,
+
/** onChange */
onChange: PropTypes.func,
diff --git a/components/molecule/tabs/src/index.js b/components/molecule/tabs/src/index.js
index 436bb17b80..0b8d360e73 100644
--- a/components/molecule/tabs/src/index.js
+++ b/components/molecule/tabs/src/index.js
@@ -1,47 +1,49 @@
-import {Children, cloneElement, useEffect, useState} from 'react'
+import {Children, cloneElement} from 'react'
import PropTypes from 'prop-types'
+import useControlledState from '@s-ui/react-hooks/lib/useControlledState'
+
import MoleculeTab from './components/MoleculeTab.js'
import MoleculeTabs from './components/MoleculeTabs.js'
import {TYPES, VARIANTS} from './config.js'
-const MoleculeTabsWithStateActive = ({children, onChange, ...props}) => {
- const [activeTab, setActiveTab] = useState(null)
-
- useEffect(() => {
- Children.forEach(children, (child, index) => {
- if (child) {
- const {active} = child.props
- if (active) setActiveTab(index + 1)
- }
- })
- }, []) // eslint-disable-line
-
- const extendedChildren = () => {
- return Children.toArray(children)
- .filter(Boolean)
- .map((child, index) => {
- const numTab = index + 1
- const active = activeTab === numTab
- return cloneElement(child, {active})
- })
- }
+const MoleculeTabsWithStateActive = ({
+ children,
+ activeTabIndex: activeTabIndexProp,
+ defaultActiveTabIndex: defaultActiveTabIndexProp = 1,
+ onChange,
+ ...props
+}) => {
+ const [activeTab, setActiveTab] = useControlledState(
+ activeTabIndexProp,
+ defaultActiveTabIndexProp
+ )
- const handleChange = (e, {numTab}) => {
- setActiveTab(numTab)
- typeof onChange === 'function' && onChange(e, {numTab})
+ const handleChange = (e, {numTab: tabIndex}) => {
+ setActiveTab(tabIndex)
+ typeof onChange === 'function' && onChange(e, {numTab: tabIndex})
}
return (
- {extendedChildren()}
+ {Children.toArray(children)
+ .filter(Boolean)
+ .map((child, index) =>
+ cloneElement(child, {active: activeTab === index + 1})
+ )}
)
}
MoleculeTabsWithStateActive.displayName = 'MoleculeTabsWithStateActive'
MoleculeTabsWithStateActive.propTypes = {
+ /** defines the active tab */
+ activeTabIndex: PropTypes.number,
+
+ /** defines the initial active tab */
+ defaultActiveTabIndex: PropTypes.number,
+
/** children of the component */
children: PropTypes.element,
diff --git a/components/molecule/tabs/test/index.test.js b/components/molecule/tabs/test/index.test.js
index 36633d62dd..0128f895b0 100644
--- a/components/molecule/tabs/test/index.test.js
+++ b/components/molecule/tabs/test/index.test.js
@@ -10,6 +10,8 @@ import ReactDOM from 'react-dom'
import chai, {expect} from 'chai'
import chaiDOM from 'chai-dom'
+import {fireEvent} from '@testing-library/react'
+
import json from '../package.json'
import * as pkg from '../src/index.js'
@@ -148,6 +150,42 @@ describe(json.name, () => {
count[2].toString()
)
})
+
+ it('should switch content when tab 2 is clicked', () => {
+ // Given
+ const library = pkg
+ const {MoleculeTab} = library
+ const expectedContent1 = 'Content 1'
+ const expectedContent2 = 'Content 2'
+ const props = {
+ children: [
+
+ {expectedContent1}
+ ,
+
+ {expectedContent2}
+
+ ]
+ }
+
+ // When
+ const {getByRole} = setup(props)
+ const tab1 = getByRole('tab', {name: 'Tab 1'})
+ expect(tab1).to.have.attribute('aria-selected', 'true')
+
+ const content1 = getByRole('tabpanel')
+ expect(content1.innerHTML).to.equal(expectedContent1)
+
+ // Click on second tab
+ const tab2 = getByRole('tab', {name: 'Tab 2'})
+ expect(tab2).to.have.attribute('aria-selected', 'false')
+ fireEvent.click(tab2)
+ const content2 = getByRole('tabpanel')
+
+ // Then
+ expect(tab2).to.have.attribute('aria-selected', 'true')
+ expect(content2.innerHTML).to.equal(expectedContent2)
+ })
})
describe('moleculeTabsTypes', () => {