UNPKG

@plurid/plurid-ui-components-react

Version:

Plurid User Interface Components for React

1,784 lines (1,598 loc) 140 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var React = require("react"); var themes = require("@plurid/plurid-themes"); var styled = require("styled-components"); var pluridIconsReact = require("@plurid/plurid-icons-react"); var pluridFunctionsReact = require("@plurid/plurid-functions-react"); var pluridFunctions = require("@plurid/plurid-functions"); var reactRedux = require("react-redux"); var pluridUiStateReact = require("@plurid/plurid-ui-state-react"); function _interopDefault(e) { return e && e.__esModule ? e : { default: e }; } var React__default = _interopDefault(React); var themes__default = _interopDefault(themes); var styled__default = _interopDefault(styled); const StyledSpinner = styled__default.default.div` position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); `; const StyledLoader = styled__default.default.div` display: inline-block; position: relative; width: ${props => { switch (props.size) { case "small": return "1rem"; case "normal": return "1.8rem"; case "large": return "2.4rem"; default: return "1.8rem"; } }}; height: ${props => { switch (props.size) { case "small": return "1rem"; case "normal": return "1.8rem"; case "large": return "2.4rem"; default: return "1.8rem"; } }}; div { width: ${props => { switch (props.size) { case "small": return "1rem"; case "normal": return "1.8rem"; case "large": return "2.4rem"; default: return "1.8rem"; } }}; height: ${props => { switch (props.size) { case "small": return "1rem"; case "normal": return "1.8rem"; case "large": return "2.4rem"; default: return "1.8rem"; } }}; margin: ${props => { switch (props.size) { case "small": return "0.1rem"; case "normal": return "0.2rem"; case "large": return "0.3rem"; default: return "0.2rem"; } }}; border: ${props => { switch (props.size) { case "small": return "0.1rem solid " + props.theme.colorPrimary; case "normal": return "0.2rem solid " + props.theme.colorPrimary; case "large": return "0.3rem solid " + props.theme.colorPrimary; default: return "0.2rem solid " + props.theme.colorPrimary; } }}; border-color: ${props => props.theme.colorPrimary} transparent transparent transparent; box-sizing: border-box; display: block; position: absolute; border-radius: 50%; animation: spinner-rotate 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; } div:nth-child(1) { animation-delay: -0.45s; } div:nth-child(2) { animation-delay: -0.3s; } div:nth-child(3) { animation-delay: -0.15s; } @keyframes spinner-rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `; const Spinner$1 = properties => { const {theme: theme, size: size, style: style, className: className} = properties; const themeValue = theme || themes.plurid; const sizeValue = size || "normal"; return React__default.default.createElement(StyledSpinner, { style: { ...style }, className: className }, React__default.default.createElement(StyledLoader, { theme: themeValue, size: sizeValue }, React__default.default.createElement("div", null), React__default.default.createElement("div", null), React__default.default.createElement("div", null), React__default.default.createElement("div", null))); }; const StyledPureButton = styled__default.default.button` color: ${({theme: theme}) => theme.colorPrimary}; background-color: ${({theme: theme, level: level, isDisabled: isDisabled}) => { if (isDisabled) { return theme.backgroundColorPrimaryAlpha; } switch (level) { case 0: return theme.backgroundColorPrimary; case 1: return theme.backgroundColorSecondary; case 2: return theme.backgroundColorTertiary; case 3: return theme.backgroundColorQuaternary; default: return theme.backgroundColorPrimary; } }}; box-shadow: 0px 8px 8px 0px ${({theme: theme}) => theme.boxShadowUmbraColor}; box-sizing: border-box; display: block; width: 100%; min-width: ${({size: size}) => { switch (size) { case "small": return "8rem"; case "normal": return "10rem"; case "large": return "12rem"; default: return "10rem"; } }}; border-radius: ${({size: size}) => { switch (size) { case "small": return "1rem"; case "normal": return "1.2rem"; case "large": return "1.4rem"; default: return "1.2rem"; } }}; padding: ${({size: size}) => { switch (size) { case "small": return "0 1.2rem"; case "normal": return "0 1.4rem"; case "large": return "0 1.6rem"; default: return "0 1.4rem"; } }}; font-family: ${({theme: theme}) => theme.fontFamilySansSerif}; font-size: ${({size: size}) => { switch (size) { case "small": return "0.8rem"; case "normal": return "0.9rem"; case "large": return "1rem"; default: return "0.9rem"; } }}; height: ${({size: size}) => { switch (size) { case "small": return "2rem"; case "normal": return "2.4rem"; case "large": return "2.8rem"; default: return "2.4rem"; } }}; cursor: ${({isDisabled: isDisabled}) => { if (isDisabled) { return "default"; } return "pointer"; }}; border: none; outline: none; user-select: none; display: grid; place-content: center; line-height: 1.2; font-weight: bold; transition: box-shadow 200ms linear, background-color 200ms linear; position: relative; min-height: 40px; min-width: 160px; @media (hover: hover) { :hover { background-color: ${({theme: theme, level: level, isDisabled: isDisabled}) => { if (isDisabled) { return theme.backgroundColorPrimaryAlpha; } switch (level) { case 0: return theme.backgroundColorSecondary; case 1: return theme.backgroundColorTertiary; case 2: return theme.backgroundColorQuaternary; case 3: return theme.backgroundColorPrimary; default: return theme.backgroundColorSecondary; } }}; } } :active { box-shadow: ${({theme: theme, isDisabled: isDisabled}) => { if (isDisabled) { return "0px 8px 8px 0px " + theme.boxShadowUmbraColor; } return "0px 3px 3px 0px " + theme.boxShadowUmbraColor; }}; } `; const StyledPureButtonDiv = styled__default.default(StyledPureButton).attrs({ as: "div" })` background-color: ${({theme: theme, level: level, isDisabled: isDisabled}) => { if (isDisabled) { return ""; } switch (level) { case 0: return theme.backgroundColorSecondary; case 1: return theme.backgroundColorTertiary; case 2: return theme.backgroundColorQuaternary; case 3: return theme.backgroundColorPrimary; default: return theme.backgroundColorSecondary; } }}; box-shadow: 0px 3px 3px 0px ${({theme: theme}) => theme.boxShadowUmbraColor}; `; const PureButton$1 = properties => { const {text: text, atClick: atClick, theme: themeProperty, level: levelProperty, size: sizeProperty, disabled: disabled, loading: loading, style: style, className: className} = properties; const theme = themeProperty || themes.plurid; const level = levelProperty ?? 0; const size = sizeProperty || "normal"; if (loading) { return React__default.default.createElement(StyledPureButtonDiv, { style: { ...style }, className: className, theme: theme, level: level, size: size, isDisabled: disabled }, React__default.default.createElement(Spinner$1, { theme: theme, size: "small" })); } return React__default.default.createElement(StyledPureButton, { onClick: event => disabled ? null : atClick(event), style: { ...style }, className: className, theme: theme, level: level, size: size, isDisabled: disabled }, text); }; const StyledLinkButton = styled__default.default.button` font-family: ${({theme: theme}) => theme.fontFamilySansSerif}; color: ${({theme: theme, level: level, isDisabled: isDisabled}) => { if (isDisabled) { return theme.backgroundColorPrimaryAlpha; } switch (level) { case 0: return theme.colorPrimary; case 1: return theme.colorSecondary; case 2: return theme.colorTertiary; default: return theme.colorPrimary; } }}; margin: ${({inline: inline}) => { if (inline) { return "0"; } return "0 1rem"; }}; padding: ${({inline: inline}) => { if (inline) { return "0"; } return "initial"; }}; font-size: ${({inline: inline}) => { if (inline) { return "inherit"; } return "0.9rem"; }}; display: ${({inline: inline}) => { if (inline) { return "inline"; } return "grid"; }}; cursor: ${({isDisabled: isDisabled}) => { if (isDisabled) { return "inherit"; } return "pointer"; }}; border: none; border-bottom: 1px solid ${({isActive: isActive, theme: theme}) => { if (isActive) { return theme.colorPrimary; } return "transparent"; }}; font-weight: bold; background: transparent; place-content: center; user-select: none; outline: none; `; const StyledLinkButtonLoading = styled__default.default.div` position: relative; min-height: 1rem; height: 100%; width: 100%; `; const DEFAULT_LEVEL$1 = 0; const LinkButton$1 = properties => { const {text: text, atClick: atClick, theme: themeProperty, level: levelProperty, inline: inline, disabled: disabled, loading: loading, active: active, style: style, className: className} = properties; const theme = themeProperty || themes.plurid; const level = levelProperty ?? DEFAULT_LEVEL$1; if (loading) { return React__default.default.createElement(StyledLinkButtonLoading, null, React__default.default.createElement(Spinner$1, { size: "small", theme: theme })); } return React__default.default.createElement(StyledLinkButton, { onClick: event => disabled ? null : atClick(event), style: { ...style }, className: className, theme: theme, level: level, inline: inline, isDisabled: disabled, isActive: active }, text); }; const StyledRefreshButton = styled__default.default.div` `; const RefreshButton$1 = properties => { const {atClick: atClick, theme: themeProperty, text: textProperty, disabled: disabled, hideAtClick: hideAtClickProperty, hideTime: hideTimeProperty} = properties; const theme = themeProperty || themes.plurid; const text = textProperty || ""; const hideAtClick = hideAtClickProperty ?? true; const hideTime = hideTimeProperty || 1300; const isMounted = React.useRef(true); const [showIconReset, setShowIconReset] = React.useState(true); const atClickHandler = event => { if (disabled) { return; } if (hideAtClick) { setShowIconReset(false); } atClick(event); if (hideAtClick) { setTimeout((() => { if (!isMounted.current) { return; } setShowIconReset(true); }), hideTime); } }; React.useEffect((() => () => { isMounted.current = false; }), []); return React__default.default.createElement(StyledRefreshButton, { theme: theme }, showIconReset && React__default.default.createElement(pluridIconsReact.PluridIconReset, { theme: theme, title: text, inactive: disabled, opacity: disabled ? .5 : 1, atClick: atClickHandler })); }; const buttons = { PureButton: PureButton$1, LinkButton: LinkButton$1, RefreshButton: RefreshButton$1 }; const StyledFormbutton = styled__default.default.div` display: grid; grid-template-columns: 20px 1fr; grid-gap: 0.5rem; align-items: center; min-height: 2rem; user-select: none; text-decoration: none; padding: 0.3rem 0.7rem; margin: ${props => { if (props.devisible) { return "0"; } return "initial"; }}; cursor: ${props => { if (props.inactive) { return "default"; } return "pointer"; }}; color: ${props => props.theme.colorPrimary}; :hover { background-color: ${props => { if (!props.hoverEffect) { return "initial"; } if (props.inactive || props.devisible) { return "initial"; } return props.theme.backgroundColorSecondary; }}; } `; const StyledFormbuttonIcon = styled__default.default.div` justify-self: ${props => props.position}; display: grid; place-content: center; `; const StyledFormbuttonText = styled__default.default.div` `; const Formbutton$1 = properties => { const {text: text, Icon: Icon, atClick: atClick, link: link, target: target, theme: theme, devisible: devisible, level: level, iconPosition: iconPosition, inactive: inactive, hoverEffect: hoverEffectProperty, style: style, className: className} = properties; const _theme = theme || themes.plurid; const _level = level ?? 0; const _devisible = devisible ?? false; const _iconPosition = iconPosition || "left"; const _inactive = inactive ?? false; const hoverEffect = hoverEffectProperty ?? true; const render = () => React__default.default.createElement(React__default.default.Fragment, null, React__default.default.createElement(StyledFormbuttonIcon, { position: _iconPosition }, React__default.default.createElement(Icon, { theme: _theme })), React__default.default.createElement(StyledFormbuttonText, null, text)); const renderProperties = { style: { ...style }, className: className, theme: _theme, level: _level, inactive: _inactive, devisible: _devisible, hoverEffect: hoverEffect }; if (link) { return React__default.default.createElement(StyledFormbutton, { onClick: event => !_inactive ? atClick(event) : null, as: "a", href: link, target: target, ...renderProperties }, render()); } return React__default.default.createElement(StyledFormbutton, { onClick: event => !_inactive ? atClick(event) : null, ...renderProperties }, render()); }; const StyledFormitem = styled__default.default.div` display: grid; align-items: center; min-height: 2rem; padding: 0.3rem 0.7rem; user-select: none; `; const Formitem$1 = properties => { const {theme: theme, level: level, style: style, className: className, children: children} = properties; const _theme = theme || themes.plurid; const _level = level ?? 0; return React__default.default.createElement(StyledFormitem, { style: { ...style }, className: className, theme: _theme, level: _level }, children); }; const StyledFormLeftRight = styled__default.default.div` display: flex; align-items: center; justify-content: space-between; `; const FormLeftRight$1 = properties => { const {theme: theme, style: style, className: className, children: children} = properties; const _theme = theme || themes.plurid; return React__default.default.createElement(StyledFormLeftRight, { style: { ...style }, className: className, theme: _theme }, children); }; const StyledFormline = styled__default.default.div` display: grid; grid-template-columns: 1fr 1fr; align-items: center; min-height: 2rem; padding: 0.3rem 0.7rem; color: ${props => props.theme.colorPrimary}; @media (max-width: 800px) { grid-template-columns: ${props => { if (props.responsive) { return "1fr"; } return "1fr 1fr"; }}; min-height: ${props => { if (props.responsive) { return "2.4rem"; } return "2rem"; }}; justify-items: ${props => { if (props.responsive) { return "center"; } return "auto"; }}; justify-content: ${props => { if (props.responsive) { return "center"; } return "auto"; }}; } `; const StyledFormlineText = styled__default.default.div` user-select: none; `; const StyledFormlineElement = styled__default.default.div` justify-self: right; @media (max-width: 800px) { justify-self: ${props => { if (props.responsive) { return "center"; } return "right"; }}; } `; const Formline$1 = properties => { const {text: text, Element: Element, theme: theme, level: level, responsive: responsive, style: style, className: className, children: children} = properties; const _theme = theme || themes.plurid; const _level = level === undefined ? 0 : level; const _responsive = responsive === undefined ? false : responsive; return React__default.default.createElement(StyledFormline, { style: { ...style }, className: className, theme: _theme, level: _level, responsive: _responsive }, React__default.default.createElement(StyledFormlineText, null, text), React__default.default.createElement(StyledFormlineElement, { responsive: _responsive }, Element ? React__default.default.createElement(Element, null) : React__default.default.createElement(React__default.default.Fragment, null, children))); }; const StyledFormObliterate = styled__default.default.div` color: ${properties => properties.theme.colorPrimary}; font-family: ${properties => properties.theme.fontFamilySansSerif}; font-size: 0.8rem; user-select: none; `; const StyledObliterateContainer = styled__default.default.div` text-align: center; display: grid; grid-template-columns: 1fr; grid-template-rows: 30px 45px 60px; align-items: center; max-width: 200px; margin: 1rem auto; `; const FormObliterate$1 = properties => { const {atObliterate: atObliterate, item: item, theme: theme, devisible: devisible, level: level, style: style, className: className} = properties; const _theme = theme || themes.plurid; const _level = level ?? 0; const _devisible = devisible ?? false; const [showObliterate, setShowObliterate] = React.useState(false); const handleObliterate = event => { setShowObliterate(false); atObliterate(event); }; return React__default.default.createElement(StyledFormObliterate, { theme: _theme, level: _level, devisible: _devisible, style: { ...style }, className: className }, !showObliterate && React__default.default.createElement(Formbutton$1, { theme: _theme, text: item ? `obliterate ${item}` : "obliterate", Icon: pluridIconsReact.PluridIconObliterate, atClick: () => setShowObliterate(true), devisible: true }), showObliterate && React__default.default.createElement(StyledObliterateContainer, null, React__default.default.createElement("div", null, "remove forever?"), React__default.default.createElement(LinkButton$1, { theme: _theme, text: "cancel", atClick: () => setShowObliterate(false) }), React__default.default.createElement(PureButton$1, { theme: _theme, text: "Obliterate", atClick: event => handleObliterate(event) }))); }; const form = { Formbutton: Formbutton$1, Formitem: Formitem$1, FormLeftRight: FormLeftRight$1, Formline: Formline$1, FormObliterate: FormObliterate$1 }; const GlobalStyles$1 = styled.createGlobalStyle` *, *::after, *::before { box-sizing: border-box; } html { height: 100%; min-height: 100vh; } body { font-family: ${({theme: theme}) => theme.fontFamilySansSerif}; height: 100%; margin: 0; padding: 0; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: ${({theme: theme}) => { if (theme.type === "dark") { return theme.backgroundColorBright; } return theme.colorPrimary; }}; background: ${({theme: theme}) => { if (theme.type === "dark") { return theme.backgroundColorDark; } return theme.backgroundColorPrimary; }}; } `; const general = { GlobalStyles: GlobalStyles$1 }; const setNativeValue = (element, value) => { const valueSetter = Object.getOwnPropertyDescriptor(element, "value").set; const prototype = Object.getPrototypeOf(element); const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, "value").set; if (valueSetter && valueSetter !== prototypeValueSetter) { prototypeValueSetter.call(element, value); } else { valueSetter.call(element, value); } }; const StyledTextline = styled__default.default.div` position: relative; display: inline-block; width: 100%; input { box-sizing: border-box; border: none; outline: none; font-size: 0.8rem; padding: ${props => { if (props.devisible) { return "0"; } return "0.6rem 1rem"; }}; padding-top: ${props => { if (props.devisible) { return "0"; } return "0.7rem"; }}; min-height: ${props => { if (props.devisible) { return "initial"; } return "36px"; }}; background-color: ${props => { if (props.devisible) { return "transparent"; } switch (props.level) { case 0: return props.theme.backgroundColorPrimary; case 1: return props.theme.backgroundColorSecondary; case 2: return props.theme.backgroundColorTertiary; case 3: return props.theme.backgroundColorQuaternary; default: return props.theme.backgroundColorPrimary; } }}; color: ${props => props.theme.colorPrimary}; box-shadow: inset 0px 4px 4px ${props => { if (props.devisible) { return "transparent"; } return props.theme.boxShadowUmbraColor; }}; border-radius: ${props => { if (props.devisible) { return "0"; } if (props.round) { return "1000px"; } return "0px"; }}; width: ${props => { if (!props.width) { return "100%"; } if (typeof props.width === "number") { return props.width + "px"; } return props.width; }}; text-align: ${props => { if (props.center) { return "center"; } return "left"; }}; ::placeholder { color: ${props => props.theme.colorSecondary}; } } `; const StyledEnterIcon = styled__default.default.div` position: absolute; top: 50%; transform: translateY(-50%); height: 20px; width: 20px; border-radius: 100px; display: flex; align-items: center; justify-content: center; font-size: 0.9rem; user-select: none; cursor: pointer; border: 1px solid transparent; right: ${props => { if (props.left) { return "auto"; } return "0.6rem"; }}; left: ${props => { if (props.left) { return "0.6rem"; } return "auto"; }}; color: ${props => props.theme.colorPrimary}; :hover { border: 1px solid ${props => props.theme.colorPrimary}; } `; const StyledErrorLine = styled__default.default.div` position: absolute; background-color: #FF0000; bottom: -2px; height: ${props => { if (props.devisible) { return "2px"; } return "4px"; }}; left: ${props => { if (props.devisible) { return "0"; } if (!props.round) { return "0"; } return "14px"; }}; right: ${props => { if (props.devisible) { return "0"; } if (!props.round) { return "0"; } return "14px"; }}; border-radius: ${props => { if (props.devisible) { return "0"; } if (props.round) { return "10px"; } return "0px"; }}; box-shadow: 0px 1px 3px 0px ${props => { if (props.devisible) { return "initial"; } return props.theme.boxShadowUmbraColor; }}; `; const Textline$1 = React.forwardRef(((properties, reference) => { const {text: text, atChange: atChange, atKeyDown: atKeyDown, atFocus: atFocus, atBlur: atBlur, type: type, placeholder: placeholder, autoCapitalize: autoCapitalize, autoComplete: autoComplete, autoCorrect: autoCorrect, spellCheck: spellCheck, style: style, className: className, theme: theme, level: level, devisible: devisible, center: center, round: round, width: width, error: error, enterIconLeft: enterIconLeft, enterEmpty: enterEmpty, enterAtClick: enterAtClick, escapeClear: escapeClear, ariaLabel: ariaLabel} = properties; const _type = type || "text"; const _theme = theme || themes.plurid; const _level = level ?? 0; const _round = round ?? true; const inputElement = React.useRef(); const handleKeyDown = event => { if (!inputElement.current) { return; } if (atKeyDown) { atKeyDown(event); } if (enterAtClick && event.key === "Enter") { enterAtClick(); } if (escapeClear && event.key === "Escape" && inputElement.current) { setNativeValue(inputElement.current, ""); const _event = new Event("input", { bubbles: true }); inputElement.current.dispatchEvent(_event); } }; const showEnterIcon = enterAtClick && (text.length > 0 || enterEmpty); return React__default.default.createElement(StyledTextline, { theme: _theme, level: _level, devisible: devisible, center: center, round: _round, width: width, className: className }, React__default.default.createElement("input", { type: _type, value: text, onChange: event => { atChange(event, event.target.value); }, onKeyDown: handleKeyDown, onFocus: atFocus, onBlur: atBlur, placeholder: placeholder, autoCapitalize: autoCapitalize, autoComplete: autoComplete, autoCorrect: autoCorrect, spellCheck: spellCheck, "aria-label": ariaLabel, style: { ...style, paddingRight: showEnterIcon ? "35px" : undefined }, ref: pluridFunctionsReact.mergeReferences(inputElement, reference) }), error && React__default.default.createElement(StyledErrorLine, { theme: _theme, devisible: devisible, round: _round }), showEnterIcon && React__default.default.createElement(StyledEnterIcon, { theme: _theme, onClick: () => enterAtClick(), left: enterIconLeft }, "➔")); })); const StyledDropdown = styled__default.default.div` color: ${props => props.theme.colorPrimary}; text-align: ${props => { if (props.left) { return "left"; } return "right"; }}; font-size: 1rem; position: relative; `; const StyledDropdownSelected = styled__default.default.div` cursor: pointer; user-select: none; color: ${props => { if (props.selectedColor) { return props.selectedColor; } return props.theme.colorPrimary; }}; `; const StyledDropdownList = styled__default.default.div` font-size: 0.85rem; background: ${props => { switch (props.level) { case 0: return props.theme.backgroundColorPrimary; case 1: return props.theme.backgroundColorSecondary; case 2: return props.theme.backgroundColorTertiary; case 3: return props.theme.backgroundColorQuaternary; default: return props.theme.backgroundColorPrimary; } }}; color: ${props => props.theme.colorPrimary}; position: absolute; left: ${props => { if (props.left) { return "0px"; } return "auto"; }}; right: ${props => { if (props.left) { return "auto"; } return "0px"; }}; top: ${props => { if (props.listTop) { return props.listTop; } return "25px"; }}; height: ${props => { if (props.heightItems) { const value = props.heightItems * 2 + "rem"; if (props.heightBeyond) { return `calc(${value} + 1rem)`; } return value; } return "initial"; }}; overflow: ${props => { if (props.heightItems) { return "scroll"; } return "initial"; }}; /* Hide Scrollbar */ scrollbar-width: none; /* Firefox 64 */ -ms-overflow-style: none; /* Internet Explorer 11 */ ::-webkit-scrollbar { /** WebKit */ display: none; } width: ${props => { if (props.width) { if (typeof props.width === "number") { return props.width + "px"; } if (typeof props.width === "string") { return props.width; } } return "initial"; }}; border-radius: 10px; min-width: 60px; z-index: 9998; box-shadow: 0px 3px 5px 1px hsla(327, 94%, 10%, 0.7); ul { margin: 0; padding: 0; list-style: none; } ul li { box-sizing: border-box; padding: 0.3rem 0.6rem; user-select: none; cursor: pointer; min-height: 2rem; display: grid; align-items: center; word-break: break-all; justify-content: ${props => { if (props.left) { return "left"; } return "right"; }}; } ul li:hover { background: ${props => { if (props.level === 2) { return props.theme.backgroundColorSecondary; } return props.theme.backgroundColorTertiary; }}; } ul li:first-child { border-top-right-radius: 10px; border-top-left-radius: 10px; } ul li:last-child { border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; } `; const StyledFilterable = styled__default.default.div` position: relative; input { text-align: ${props => { if (props.left) { return "left !important"; } return "right !important"; }}; } `; const StyledFilterUpdate = styled__default.default.div` position: absolute; z-index: 9999; top: 0; left: ${props => { if (props.left) { return "auto"; } return "0"; }}; right: ${props => { if (props.left) { return "0"; } return "auto"; }}; `; const Dropdown$1 = properties => { const {selected: selected, selectables: selectables, atSelect: atSelect, left: left, kind: kind, listTop: listTop, dropdownToggled: dropdownToggled, dropdownSign: dropdownSign, hideAtSelect: hideAtSelect, selectAtHover: selectAtHover, selectedColor: selectedColor, filterable: filterable, style: style, className: className, theme: themeProperty, generalTheme: generalThemeProperty, interactionTheme: interactionThemeProperty, level: level, heightItems: heightItems, width: width, setDropdownToggled: setDropdownToggled, filterUpdate: filterUpdate} = properties; const _generalTheme = generalThemeProperty === undefined ? themeProperty === undefined ? themes.plurid : themeProperty : generalThemeProperty; const _interactionTheme = interactionThemeProperty === undefined ? themeProperty === undefined ? themes.plurid : themeProperty : interactionThemeProperty; const _level = level ?? 0; const _hideAtSelect = hideAtSelect ?? true; const _selectAtHover = selectAtHover ?? false; const _dropdownSign = typeof dropdownSign === "string" ? dropdownSign : !dropdownSign ? "" : "▼"; const isMounted = React.useRef(true); const filterInput = React.useRef(null); const [generalTheme, setGeneralTheme] = React.useState(_generalTheme); const [interactionTheme, setInteractionTheme] = React.useState(_interactionTheme); const [showList, setShowList] = React.useState(false); const [selectedBackgroundColor, setSelectedBackgroundColor] = React.useState(interactionTheme.backgroundColorTertiary); const [filterValue, setFilterValue] = React.useState(""); const [filteredSelectables, setFilteredSelectables] = React.useState([ ...selectables ]); const [showFilterUpdate, setShowFilterUpdate] = React.useState(!!filterUpdate); const [arrowIndex, setArrowIndex] = React.useState(-1); const select = selected => { kind ? atSelect(selected, kind) : atSelect(selected); }; const handleSelect = selected => { select(selected); if (_hideAtSelect) { setShowList(false); } }; const handleHover = selected => { if (_selectAtHover) { select(selected); } }; const handleFiltering = event => { const {value: value} = event.target; const filterValue = value.toLowerCase(); const filteredSelectables = selectables.filter((selectable => { if (typeof selectable === "string") { const filterSelectable = selectable.toLowerCase(); if (selectable.toLowerCase().startsWith(filterValue)) { return true; } const split = filterSelectable.split(" "); for (const element of split) { if (element.startsWith(filterValue)) { return true; } } return false; } const filterSelectable = selectable.value.toLowerCase(); if (filterSelectable.startsWith(filterValue)) { return true; } const split = filterSelectable.split(" "); for (const element of split) { if (element.startsWith(filterValue)) { return true; } } return false; })); setFilterValue(value); setFilteredSelectables(filteredSelectables); itemsReferences.current = filteredSelectables.reduce(((accumulator, _, index) => { accumulator[index] = React__default.default.createRef(); return accumulator; }), {}); }; const focusFilterInput = () => { setTimeout((() => { if (filterInput.current) { filterInput.current.focus(); } }), 100); }; const itemsReferences = React.useRef(filteredSelectables.reduce(((accumulator, _, index) => { accumulator[index] = React__default.default.createRef(); return accumulator; }), {})); React.useEffect((() => { if (!dropdownToggled) { setShowList(false); } }), [ dropdownToggled ]); React.useEffect((() => { if (_level === 2) { setSelectedBackgroundColor(interactionTheme.backgroundColorSecondary); } else { setSelectedBackgroundColor(interactionTheme.backgroundColorTertiary); } }), [ _level, interactionTheme ]); React.useEffect((() => { const generalTheme = generalThemeProperty === undefined ? themeProperty === undefined ? themes.plurid : themeProperty : generalThemeProperty; const interactionTheme = interactionThemeProperty === undefined ? themeProperty === undefined ? themes.plurid : themeProperty : interactionThemeProperty; setGeneralTheme(generalTheme); setInteractionTheme(interactionTheme); }), [ themeProperty, generalThemeProperty, interactionThemeProperty ]); React.useEffect((() => { const scrollTo = index => { if (itemsReferences.current[index].current) { itemsReferences.current[index].current.scrollIntoView({ behavior: "smooth", block: "start" }); } }; const handleArrows = event => { if (event.key === "ArrowUp") { const newIndex = arrowIndex - 1; if (newIndex >= 0) { setArrowIndex(newIndex); scrollTo(newIndex); } } if (event.key === "ArrowDown") { const newIndex = arrowIndex + 1; if (newIndex < filteredSelectables.length) { setArrowIndex(newIndex); scrollTo(newIndex); } } if (event.key === "Enter") { const selected = filteredSelectables[arrowIndex]; if (selected) { atSelect(selected); setArrowIndex(-1); if (_hideAtSelect) { setShowList(false); } } } }; const handleScroll = () => { setArrowIndex(-1); }; if (showList) { window.addEventListener("keydown", handleArrows); window.addEventListener("wheel", handleScroll); } else { setArrowIndex(-1); } return () => { if (showList) { window.removeEventListener("keydown", handleArrows); window.removeEventListener("wheel", handleScroll); } }; }), [ arrowIndex, showList ]); React.useEffect((() => () => { isMounted.current = false; }), []); React.useEffect((() => { setFilteredSelectables([ ...selectables ]); }), [ selectables.length ]); return React__default.default.createElement(StyledDropdown, { theme: interactionTheme, left: left, style: { ...style }, className: className }, React__default.default.createElement(StyledDropdownSelected, { onClick: () => { setShowList(!showList); if (setDropdownToggled) { setDropdownToggled(kind); } if (!showList && filterable) { focusFilterInput(); } }, theme: generalTheme, selectedColor: selectedColor }, typeof selected === "string" ? selected : selected.value, _dropdownSign && React__default.default.createElement(React__default.default.Fragment, null, " ", _dropdownSign)), showList && React__default.default.createElement(StyledDropdownList, { theme: interactionTheme, left: left, listTop: listTop, level: _level, heightItems: heightItems && filterable && filteredSelectables.length < heightItems ? filteredSelectables.length + 1 : heightItems, heightBeyond: filteredSelectables.length > (heightItems || 0), width: width }, React__default.default.createElement("ul", null, filterable && React__default.default.createElement("li", { style: { backgroundColor: interactionTheme.backgroundColorTertiary, boxShadow: interactionTheme.boxShadowPenumbraInset } }, React__default.default.createElement(StyledFilterable, { left: left }, filterUpdate && showFilterUpdate && React__default.default.createElement(StyledFilterUpdate, { left: left }, React__default.default.createElement(pluridIconsReact.PluridIconReset, { theme: interactionTheme, atClick: () => { setShowFilterUpdate(false); filterUpdate(); setTimeout((() => { if (!isMounted.current) { return; } setShowFilterUpdate(true); }), 5300); } })), React__default.default.createElement(Textline$1, { ref: filterInput, theme: interactionTheme, text: filterValue, atChange: handleFiltering, devisible: true, spellCheck: false, autoCapitalize: "false", autoComplete: "false", autoCorrect: "false", style: { padding: !!filterUpdate ? left ? "0 1.3rem 0 0" : "0 0 0 1.3rem" : "0" } }))), filteredSelectables.map(((selectable, index) => { let selectableID = typeof selectable === "string" ? selectable : selectable.id; let selectableValue = typeof selectable === "string" ? selectable : selectable.value; let isSelected = false; if (typeof selected === "string") { if (selected === selectableID) { isSelected = true; } } else { if (selected.id === selectableID) { isSelected = true; } } if (arrowIndex === index) { isSelected = true; } return React__default.default.createElement("li", { ref: itemsReferences.current[index], key: selectableID, onClick: () => handleSelect(selectable), onMouseEnter: () => handleHover(selectable), style: { backgroundColor: isSelected ? selectedBackgroundColor : "" } }, selectableValue); }))))); }; const StyledEntityPill = styled__default.default.div` background-color: ${({theme: theme}) => theme.backgroundColorTertiary}; box-shadow: ${({theme: theme}) => theme.boxShadowUmbra}; padding: 0.5rem 1rem; margin: 0.5rem; border-radius: 20px; display: flex; align-items: center; `; const EntityPill$1 = properties => { const {id: id, remove: remove, text: text, theme: theme, style: style} = properties; const textValue = text || id; return React__default.default.createElement(StyledEntityPill, { theme: theme || themes.plurid, style: { ...style } }, React__default.default.createElement("div", { style: { marginRight: "0.5rem" } }, textValue), React__default.default.createElement(pluridIconsReact.PluridIconDelete, { theme: theme, atClick: () => remove(id) })); }; const StyledEntityPillGroup = styled__default.default.div` display: flex; flex-flow: wrap; margin: 0 auto; justify-content: center; `; const EntityPillGroup$1 = properties => { const {entities: entities, remove: remove, keyFix: keyFix, theme: theme, style: style, pillStyle: pillStyle} = properties; return React__default.default.createElement(StyledEntityPillGroup, { theme: theme, style: { ...style } }, entities.map((entity => { const stringEntity = typeof entity === "string"; const id = stringEntity ? entity : entity.id; const text = stringEntity ? undefined : entity.text; return React__default.default.createElement(EntityPill$1, { key: `entity-pill-${id}${keyFix || ""}`, id: id, text: text, remove: remove, theme: theme || themes.plurid, style: pillStyle }); }))); }; const StyledInputDescriptor = styled__default.default.div` text-align: left; font-size: 0.9rem; line-height: 1; min-height: 1.1rem; margin-top: 1.3rem; margin-bottom: 0.4rem; margin-left: 0.9rem; font-family: ${({theme: theme}) => theme.fontFamilySansSerif}; color: ${({theme: theme}) => theme.colorPrimary}; `; const InputDescriptor$1 = properties => { const {name: name, show: show, theme: themeProperty, style: style, className: className} = properties; const theme = themeProperty || themes.plurid; return React__default.default.createElement(StyledInputDescriptor, { theme: theme, className: className, style: { ...style } }, show && React__default.default.createElement(React__default.default.Fragment, null, name)); }; const StyledInputBox = styled__default.default.div` textarea { box-sizing: border-box; width: 100%; min-height: 5rem; resize: vertical; outline: none; border: none; padding: 0.9rem; font-size: 0.8rem; border-radius: 0.9rem; line-height: 1.5; font-family: ${({theme: theme}) => theme.fontFamilySansSerif}; color: ${({theme: theme}) => theme.colorPrimary}; background-color: ${({theme: theme}) => theme.backgroundColorTertiary}; box-shadow: inset 0px 4px 4px ${({theme: theme}) => theme.boxShadowUmbraColor}; ::placeholder { color: ${({theme: theme}) => theme.colorSecondary}; } } `; const StyledTextBox = styled__default.default.div` `; const InputBox$1 = properties => { const {text: text, name: name, atChange: atChange, theme: themeProperty, style: style, className: className, atKeyDown: atKeyDown} = properties; const theme = themeProperty || themes.plurid; return React__default.default.createElement(StyledInputBox, { theme: theme, className: className, style: { ...style } }, React__default.default.createElement(InputDescriptor$1, { name: name, show: text !== "", theme: theme }), React__default.default.createElement(StyledTextBox, { theme: theme }, React__default.default.createElement("textarea", { value: text, placeholder: name, onChange: event => atChange(event), onKeyDown: event => atKeyDown ? atKeyDown(event) : null, spellCheck: false, autoCapitalize: "false", autoComplete: "false", autoCorrect: "false" }))); }; const StyledInputLine = styled__default.default.div` width: 350px; `; const InputLine$1 = properties => { const {name: name, text: text, atChange: atChange, theme: themeProperty, type: type, error: error, textline: textline, style: style, className: className, atKeyDown: atKeyDown} = properties; const theme = themeProperty || themes.plurid; return React__default.default.createElement(StyledInputLine, { theme: theme, style: { ...style }, className: className }, React__default.default.createElement(InputDescriptor$1, { name: name, show: text !== "", theme: theme }), React__default.default.createElement(Textline$1, { text: text, type: type, placeholder: name, theme: theme, level: 2, error: error, spellCheck: false, autoCapitalize: "false", autoComplete: "false", autoCorrect: "false", atChange: atChange, atKeyDown: atKeyDown, ...textline })); }; const StyledSwitch = styled__default.default.label` position: relative; display: inline-block; width: 60px; height: 34px; input { opacity: 0; width: 0; height: 0; } `; const levelBackgroundColor = props => { switch (props.level) { case 0: return props.theme.backgroundColorPrimary; case 1: return props.theme.backgroundColorSecondary; case 2: return props.theme.backgroundColorTertiary; case 3: return props.theme.backgroundColorQuaternary; default: return props.theme.backgroundColorPrimary; } }; const backgroundColor = props => { if (props.accent) { return props.accent; } if (props.exclusive && !props.checked) { switch (props.level) { case 0: return props.theme.backgroundColorPrimaryAlpha; case 1: return props.theme.backgroundColorSecondaryAlpha; case 2: return props.theme.backgroundColorTertiaryAlpha; case 3: return props.theme.backgroundColorQuaternaryAlpha; default: return props.theme.backgroundColorPrimaryAlpha; } } return levelBackgroundColor(props); }; const StyledSwitchSlider = styled__default.default.span` position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; transition: .4s ease-in-out; box-shadow: inset 0 2px 3px black; background-color: ${props => backgroundColor(props)}; border-radius: ${props => { if (props.round) { return "34px"; } return "0"; }}; :before { position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px; transition: .4s; background-color: ${props => props.theme.colorPrimary}; border-radius: ${props => { if (props.round) { return "50%"; } return "0"; }}; transform: ${props => { if (props.checked) { return "translateX(26px)"; } return "translateX(0px)"; }};