From e139a8b6587956f1333804769ac59b2a748df1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Matias=CC=8Cko?= Date: Wed, 15 May 2024 14:28:03 +0200 Subject: [PATCH] FormGenerator - expandable groups --- src/components/Atomic/Modal/Modal.styles.ts | 1 + .../Atomic/TimeoutControl/TimeoutControl.tsx | 2 + .../TimeoutControl/TimeoutControl.types.ts | 1 + .../Atomic/Tooltip/TooltipUtils.tsx | 6 +- src/components/Layout/LeftPanel/LeftPanel.tsx | 10 +-- .../DevicesResourcesModal.styles.ts | 15 ++++ .../DevicesResourcesModal.tsx | 18 ++-- .../FormGenerator/FormGenerator.tsx | 83 ++++++++++++++---- .../components/FormGeneratorLine.styles.ts | 52 +++++++++++ .../components/FormGeneratorLine.tsx | 32 +++++++ .../components/FormGeneratorLine.types.ts | 7 ++ .../components/SubHeadline.styles.ts | 60 +++++++++++++ .../FormGenerator/components/SubHeadline.tsx | 36 ++++++++ .../components/SubHeadline.types.ts | 6 ++ ...undPage-default-1-Google-Chrome-darwin.png | Bin 0 -> 16061 bytes ...NotFoundPage-default-1-chromium-darwin.png | Bin 0 -> 16061 bytes 16 files changed, 289 insertions(+), 40 deletions(-) create mode 100644 src/components/Organisms/DevicesResourcesModal/DevicesResourcesModal.styles.ts create mode 100644 src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.styles.ts create mode 100644 src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.tsx create mode 100644 src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.types.ts create mode 100644 src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.styles.ts create mode 100644 src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.tsx create mode 100644 src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.types.ts create mode 100644 tests/components.spec.ts-snapshots/Pages-NotFoundPage-default-1-Google-Chrome-darwin.png create mode 100644 tests/components.spec.ts-snapshots/Pages-NotFoundPage-default-1-chromium-darwin.png diff --git a/src/components/Atomic/Modal/Modal.styles.ts b/src/components/Atomic/Modal/Modal.styles.ts index 01d05377..d531a359 100644 --- a/src/components/Atomic/Modal/Modal.styles.ts +++ b/src/components/Atomic/Modal/Modal.styles.ts @@ -81,6 +81,7 @@ export const content = (theme: ThemeType) => css` export const contentPadding = css` padding-top: 24px; ` + export const footer = (theme: ThemeType) => css` padding: 24px 24px 0 24px; background: ${getThemeColor(theme, `Modal.footer.background`)}; diff --git a/src/components/Atomic/TimeoutControl/TimeoutControl.tsx b/src/components/Atomic/TimeoutControl/TimeoutControl.tsx index 03bf2ced..a2b8b573 100644 --- a/src/components/Atomic/TimeoutControl/TimeoutControl.tsx +++ b/src/components/Atomic/TimeoutControl/TimeoutControl.tsx @@ -33,6 +33,7 @@ export const TimeoutControlCore: FC = (props) => { size, smallMode, unitClassName, + unitMenuPortalTarget, watchUnitChange, } = props const closestUnit = useMemo(() => findClosestUnit(defaultValue), [defaultValue]) @@ -165,6 +166,7 @@ export const TimeoutControlCore: FC = (props) => { defaultValue={units.filter((option) => option.value === unit)} disabled={disabled} inlineStyle={inlineStyle} + menuPortalTarget={unitMenuPortalTarget} name='unit' onChange={(e) => { handleOnUnitChange(e) diff --git a/src/components/Atomic/TimeoutControl/TimeoutControl.types.ts b/src/components/Atomic/TimeoutControl/TimeoutControl.types.ts index 66b1966d..f2fcf6c1 100644 --- a/src/components/Atomic/TimeoutControl/TimeoutControl.types.ts +++ b/src/components/Atomic/TimeoutControl/TimeoutControl.types.ts @@ -25,5 +25,6 @@ export type Props = { smallMode?: boolean ttlHasError?: boolean unitClassName?: string + unitMenuPortalTarget?: HTMLElement watchUnitChange?: boolean } & Pick diff --git a/src/components/Atomic/Tooltip/TooltipUtils.tsx b/src/components/Atomic/Tooltip/TooltipUtils.tsx index b4c0f3d8..8aebd565 100644 --- a/src/components/Atomic/Tooltip/TooltipUtils.tsx +++ b/src/components/Atomic/Tooltip/TooltipUtils.tsx @@ -137,7 +137,7 @@ export const TooltipContent = forwardRef(function TooltipContent( arrowElement.current.style[staticSide] = '-4px' } - const { portalTarget, error, maxWidth, ...rest } = props + const { portalTarget, error, maxWidth, zIndex, ...rest } = props return ( {c}}> @@ -153,8 +153,8 @@ export const TooltipContent = forwardRef(function TooltipContent( position: state.strategy, top: state.y ?? 0, left: state.x ?? 0, - maxWidth: maxWidth, - zIndex: props.zIndex, + maxWidth, + zIndex, ...rest.style, }} transition={ diff --git a/src/components/Layout/LeftPanel/LeftPanel.tsx b/src/components/Layout/LeftPanel/LeftPanel.tsx index d6a11c85..869c78e7 100644 --- a/src/components/Layout/LeftPanel/LeftPanel.tsx +++ b/src/components/Layout/LeftPanel/LeftPanel.tsx @@ -222,15 +222,7 @@ const LeftPanel: FC = (props) => { , document.getElementById(headerIconCollapsePortalTargetId!) as Element )} - {logo && ( -
- {logo} - {/* {logo &&*/} - {/* cloneElement(logo as ReactElement, {*/} - {/* css: [styles.logoSvg, collapsed && styles.logoSvgCollapsed],*/} - {/* })}*/} -
- )} + {logo &&
{logo}
}
    {menu?.map( diff --git a/src/components/Organisms/DevicesResourcesModal/DevicesResourcesModal.styles.ts b/src/components/Organisms/DevicesResourcesModal/DevicesResourcesModal.styles.ts new file mode 100644 index 00000000..1207420b --- /dev/null +++ b/src/components/Organisms/DevicesResourcesModal/DevicesResourcesModal.styles.ts @@ -0,0 +1,15 @@ +import { css } from '@emotion/react' +import { getThemeColor, ThemeType } from '../../Atomic/_theme' + +export const flexLine = css` + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; +` + +export const contentHeadline = (theme: ThemeType) => css` + background: ${getThemeColor(theme, `Modal.content.background`)}; + position: relative; + z-index: 2; +` diff --git a/src/components/Organisms/DevicesResourcesModal/DevicesResourcesModal.tsx b/src/components/Organisms/DevicesResourcesModal/DevicesResourcesModal.tsx index f0d369c8..9bdc5a3d 100644 --- a/src/components/Organisms/DevicesResourcesModal/DevicesResourcesModal.tsx +++ b/src/components/Organisms/DevicesResourcesModal/DevicesResourcesModal.tsx @@ -17,6 +17,8 @@ import GeneratedResourceForm from '../GeneratedResourceForm' import Spacer from '../../Atomic/Spacer' import Headline from '../../Atomic/Headline' import Loadable from '../../Atomic/Loadable' +import * as styles from './DevicesResourcesModal.styles' +import { knownResourceHref } from '../GeneratedResourceForm/constants' const { UPDATE_RESOURCE } = resourceModalTypes @@ -179,6 +181,7 @@ const DevicesResourcesModal: FC = (props) => { = (props) => { <> - - {i18n.content} + + + {i18n.content} + + {hasGeneratedForm && setAdvancedView(!advancedView)} />} - {hasGeneratedForm && ( - - setAdvancedView(!advancedView)} /> - - )} - @@ -236,7 +236,7 @@ const DevicesResourcesModal: FC = (props) => { resetFormKey={reset} setFormError={setFormError} setIsEditable={setIsEditable} - values={resourceData?.data?.content} + values={href === knownResourceHref.WELL_KNOW_WOT ? resourceData?.data?.content : resourceData?.data?.content?.properties} /> ) : (
    diff --git a/src/components/Organisms/GeneratedResourceForm/FormGenerator/FormGenerator.tsx b/src/components/Organisms/GeneratedResourceForm/FormGenerator/FormGenerator.tsx index b2650919..3fdb0817 100644 --- a/src/components/Organisms/GeneratedResourceForm/FormGenerator/FormGenerator.tsx +++ b/src/components/Organisms/GeneratedResourceForm/FormGenerator/FormGenerator.tsx @@ -5,18 +5,19 @@ import get from 'lodash/get' import isObject from 'lodash/isObject' import isFunction from 'lodash/isFunction' import set from 'lodash/set' +import { AnimatePresence, motion } from 'framer-motion' import { PropertiesType, Property } from '../GeneratedResourceForm.types' import FormInput from '../../../Atomic/FormInput' import IconNumbers from '../../../Atomic/Icon/components/IconNumbers' import Switch from '../../../Atomic/Switch' import Spacer from '../../../Atomic/Spacer' -import Headline from '../../../Atomic/Headline' -import { ModalStrippedLine } from '../../../Atomic/Modal' import FormGroup from '../../../Atomic/FormGroup' import { Props } from './FormGenerator.types' import { knownResourceHref } from '../constants' +import FormGeneratorLine from './components/FormGeneratorLine' import Editor from '../../../Atomic/Editor' +import SubHeadline from './components/SubHeadline' export const sortProperties = (properties: PropertiesType) => properties @@ -36,7 +37,7 @@ export const sortProperties = (properties: PropertiesType) => ) : [] -export const getHref = (parentHref: string, href: string) => `${parentHref !== '' ? parentHref + '/' : parentHref}${href}` +export const getHref = (parentHref: string, href: string) => `${parentHref !== '' && !parentHref.startsWith('/') ? parentHref + '/' : parentHref}${href}` const FormGenerator: FC = (props) => { const { href: topHref, properties, resetFormKey, schema, values, onChange, setFormError } = props @@ -46,7 +47,9 @@ const FormGenerator: FC = (props) => { const isSingleValueMode = useMemo(() => !isObject(values), [values]) const formDefaultValues = useMemo(() => (isSingleValueMode ? values : { [topHref]: values }), [isSingleValueMode, topHref, values]) const [hasError, setHasError] = useState(false) + const [firstRender, setFirstRender] = useState(true) const [editorErrors, setEditorErrors] = useState([]) + const [expandedGroups, setExpandedGroups] = useState([]) const { control, @@ -59,7 +62,10 @@ const FormGenerator: FC = (props) => { }, [reset, resetFormKey]) const getDefaultValue = useCallback( - (href: string) => (isSingleValueMode ? values : get(values, href.replace(topHref, '').substring(1).replace('/', '.'), '')), + (href: string) => { + const valuesBase = href === knownResourceHref.WELL_KNOW_WOT ? values.properties : values + return isSingleValueMode ? values : get(valuesBase, href.replace(topHref, '').substring(1).replace('/', '.'), '') + }, [isSingleValueMode, topHref, values] ) @@ -104,12 +110,14 @@ const FormGenerator: FC = (props) => { }, [editorErrors, hasError, isValid, setFormError]) useEffect(() => { + let firstGroup = true const buildProperties: any = (properties: PropertiesType, parentHref = '', readOnly = false, depth = 1) => sortProperties(properties).map((property: Property & { href: string }, k) => { const href = getHref(parentHref, property.href) const key = `${href}-${k}-${depth}-${property.title}` const readOnlyP = property.readOnly || readOnly const defaultValue = getDefaultValue(href) + const isLast = k === Object.keys(properties).length - 1 if (property.href === knownResourceHref.WELL_KNOW_WOT) { return buildProperties(property.properties, href, readOnlyP, depth) @@ -117,7 +125,7 @@ const FormGenerator: FC = (props) => { if (['string', 'integer', 'number'].includes(property.type)) { const isNumber = ['integer', 'number'].includes(property.type) - const formatValue = (value?: string) => (isNumber && value ? parseInt(value, 10) : value) + const formatValue = (value?: string) => (isNumber && value ? parseFloat(value) : value) return ( = (props) => { key={key} name={href} render={({ field }) => ( - = (props) => { /> } + isLast={isLast} label={property.title || property.href} /> )} @@ -165,8 +173,7 @@ const FormGenerator: FC = (props) => { key={key} name={href} render={({ field }) => ( - = (props) => { />
    } + isLast={isLast} label={property.title || property.href} /> )} @@ -187,14 +195,51 @@ const FormGenerator: FC = (props) => { ) } else if (property.type === 'object') { if (property.properties) { + const show = expandedGroups.includes(key) + + if (firstGroup && expandedGroups.length === 0 && firstRender) { + firstGroup = false + setExpandedGroups([...expandedGroups, key]) + } + return ( - - - - {property.title || property.href} - - - {buildProperties(property.properties, href, readOnlyP, depth + 1)} + + + { + if (expandedGroups.includes(key)) { + setExpandedGroups(expandedGroups.filter((group) => group !== key)) + } else { + setExpandedGroups([...expandedGroups, key]) + } + }} + /> + + {show && ( + + {buildProperties(property.properties, href, readOnlyP, depth + 1)} + + )} + + + } + isLast={isLast} + /> ) } else { @@ -205,8 +250,7 @@ const FormGenerator: FC = (props) => { key={key} name={href} render={({ field }) => ( - = (props) => { if (properties) { setComponents(buildProperties(properties)) + setFirstRender(false) } - }, [control, errors, getDefaultValue, handleEditorChange, handleValueChange, properties]) + }, [control, errors, expandedGroups, firstRender, getDefaultValue, handleEditorChange, handleValueChange, properties]) return <>{components} } diff --git a/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.styles.ts b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.styles.ts new file mode 100644 index 00000000..df864516 --- /dev/null +++ b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.styles.ts @@ -0,0 +1,52 @@ +import { css } from '@emotion/react' + +export const wrapper = css` + position: relative; +` + +export const line = css` + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 0; +` + +export const lineImg = css` + position: absolute; + bottom: -15px; + left: -20px; + background: #f2f3f5; + height: calc(100% + 30px); + width: 2px; + + &:after { + content: ''; + position: absolute; + width: 14px; + height: 10px; + bottom: 50%; + left: 0; + border-left: 2px solid #f2f3f5; + border-bottom: 2px solid #f2f3f5; + border-bottom-left-radius: 20px; + } +` + +export const isLast = css` + height: calc(50% + 20px) !important; + bottom: calc(50% + 8px) !important; + + &:after { + bottom: -8px !important; + } +` + +export const noBefore = css` + &:after { + display: none; + } +` + +export const lastGroup = css` + height: 0 !important; +` diff --git a/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.tsx b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.tsx new file mode 100644 index 00000000..62c2fe9e --- /dev/null +++ b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.tsx @@ -0,0 +1,32 @@ +import React, { FC } from 'react' + +import Row from '../../../../Atomic/Grid/Row' +import Column from '../../../../Atomic/Grid/Column' +import Spacer from '../../../../Atomic/Spacer' +import * as ModalStrippedLineStyles from '../../../../Atomic/Modal/ModalStrippedLine/ModalStrippedLine.styles' +import * as styles from './FormGeneratorLine.styles' +import { Props } from './FormGeneratorLine.types' + +const FormGeneratorLine: FC = (props) => ( + +
    +
    + {props.label ? ( + + + {props.label} + + + {props.component} + + + ) : ( + props.component + )} +
    +
    +) + +FormGeneratorLine.displayName = 'FormGeneratorLine' + +export default FormGeneratorLine diff --git a/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.types.ts b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.types.ts new file mode 100644 index 00000000..e9afdd2e --- /dev/null +++ b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/FormGeneratorLine.types.ts @@ -0,0 +1,7 @@ +import { ReactNode } from 'react' + +export type Props = { + component: ReactNode + isLast?: boolean + label?: string +} diff --git a/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.styles.ts b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.styles.ts new file mode 100644 index 00000000..bf50fdf8 --- /dev/null +++ b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.styles.ts @@ -0,0 +1,60 @@ +import { css } from '@emotion/react' +import { getTheme, getThemeColor, ThemeType } from '../../../../Atomic/_theme' + +export const wrapper = css` + position: relative; +` + +export const headline = (theme: ThemeType) => css` + text-transform: capitalize; + background: ${getThemeColor(theme, `Modal.content.background`)}; + position: relative; + z-index: 2; +` + +export const headlineLine = css` + display: inline-flex; + align-items: center; + gap: 12px; + + &:hover { + text-decoration: none !important; + } +` + +export const line = css` + position: absolute; + bottom: calc(50% + 8px) !important; + left: -20px; + background: #f2f3f5; + height: calc(100% + 20px); + width: 2px; + z-index: 1; + + &:after { + content: ''; + position: absolute; + width: 14px; + height: 10px; + bottom: -8px; + left: 0; + border-left: 2px solid #f2f3f5; + border-bottom: 2px solid #f2f3f5; + border-bottom-left-radius: 20px; + } +` + +export const icon = (theme: ThemeType) => css` + transform: rotate(180deg); + transition: all 0.3s; + display: block; + color: ${getTheme(theme, `Global.iconColor`)}; + + &:hover { + color: ${getTheme(theme, `colorPalette.primary`)}; + } +` + +export const iconExpanded = css` + transform: rotate(0deg); +` diff --git a/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.tsx b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.tsx new file mode 100644 index 00000000..39f7d1ec --- /dev/null +++ b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.tsx @@ -0,0 +1,36 @@ +import React, { FC } from 'react' +import isFunction from 'lodash/isFunction' + +import Spacer from '../../../../Atomic/Spacer' +import Headline from '../../../../Atomic/Headline' +import { Props } from './SubHeadline.types' +import * as styles from './SubHeadline.styles' +import IconArrowDown from '../../../../Atomic/Icon/components/IconArrowDown' +import { convertSize } from '../../../../Atomic/Icon' + +const SubHeadline: FC = (props) => ( + + {props.hasLine &&
    } + { + e.preventDefault() + isFunction(props.onToggle) && props.onToggle() + }} + > + + {props.headline} + + {isFunction(props.onToggle) && ( + + + + )} + +
    +) + +SubHeadline.displayName = 'SubHeadline' + +export default SubHeadline diff --git a/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.types.ts b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.types.ts new file mode 100644 index 00000000..c72a3a6f --- /dev/null +++ b/src/components/Organisms/GeneratedResourceForm/FormGenerator/components/SubHeadline.types.ts @@ -0,0 +1,6 @@ +export type Props = { + expanded?: boolean + headline: string + hasLine?: boolean + onToggle?: () => void +} diff --git a/tests/components.spec.ts-snapshots/Pages-NotFoundPage-default-1-Google-Chrome-darwin.png b/tests/components.spec.ts-snapshots/Pages-NotFoundPage-default-1-Google-Chrome-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..b89490c8235833a99df7f4c496e88575e1f8ff23 GIT binary patch literal 16061 zcmeHuc~nzbvv1T^+g9XuJJ5)L1B!~k2MEY)w~d%aKt*N(DnevNAPHfL-L}$-fCd4X zRT=~W34exyKuhKJdF2CdI zLtRk66Ha9jqaARzy2Ztx3ci2%{--NP4s*Nn*qZ4AMm+rZ(&6kQdKlqfwi{Pv>TSglq=KhdUtPg%|I?y9*4E%QrWl1IH898+<*; zUE|kfWoGu7dJcYmeyA)V+0ECta5YxsNGp*0szD%q&GV05ogg=U5AkU%Dd9A|iMWBv z`bCW^;%a~Q9Rxzo2-kuftG+ciz}Nd@cZ@#pIMg1<=4XF}QG>MwfQn|rxFL|UlVuG| z*ydvswZJWqXCvlnUnPSOE-+1gnpT2VRLBOZQm-Nt#!bV)l z&}wwuNmG`mtigg?YMFNBs3)EcL$q+)dT1*hX38s_AIDC2>}@+>;iZzZ^lAL@&z7H!3*nt9q<~Hb z(lO{7GwS9VGgy?Pe9IpO$9dP@{IqyD+d2xFHFUXb@|8WILjIFup;;q2l-+zB84F>U zF9yqYo7biqFL{t>2Xt_l7N3v6GmXSY(|rb4U0w5_IxlV>9{EL;T{^;wWd@`5msOh9bLN}G*&1fE53J45WBz6{a-Rl%WwI~g z`zxZR^dE8|eZv?2DKj%v%Z+%WFSLJ>ml+`mEbvLW;) zYN(e@8B`iQF;-2b;JqNO*WTfWy3%b7-)wB+bzeVJ=_8y^rss|%m;O~EG!k618$lD$}-LqvZDLnXIYq*bo z)PBY^e#?FY>LdhGjRl1gbOO&REN%`GI)BL_ou5;Opb%W@Jbf+ENz6(`cn zmL7*!RKsg7Y;GaK0^Qn1`;Yph?~J}m{gSlb7;!kZc^ zIyJlTK_g@n={*uLSWV89UP=qvc@6@(%Xl@=0{1`c>K34>GeDjgw9WDvnP%{2ErgUf z$B?;W4aD#6a?3lDdvyLXmhkC6#Un1bU)dq?ER5TDoO!OU20v}f9x9vsi5SKqAJJtN z!BIg!kFJ?TUvnx>t%IRbjy9OMXY9Y5KO!XDMEv@tch@sUrn&jRm30R3*mb*rrfXRu z=CHP1nn$J@XQi7*TkF8*8qY}cvjQU6sdkz5lOq~tG8PNHexH2s>^~>BNcJ{xmNul5 zcWuk;g@f($%e*9RZB?~i;YdImGX^DtvAaFpvr3MPh)D^x2?|d94N0bKM%Q6?Bf42S z$+n7Id{UBE!>rlmPAD$$;;eNrG-op!3%E~t64RMKP4&8-Kj3&1eSPZs7uHU zTty?HFvk(3$A_@tymZBgMRG27&j(XZ)sHDq?CbsX>1C9t*C8tQ*15tXuLV`7CE@)m z2iO3$JfnfQ+Ce-uIabHp+yr_(bglXbjLxk->Kx{MM>GRa3>@%V{8MhlQ%Dsey$4}C zy`}CH!flQF_%rU<)Pbv&WdmDH)E`5MC0E(|=vVFt&JPMdzW$vBT$h6xw!0)l#j-jw%G2%|_&xW_GDT-L}qLqwqjj62m&=H$S}s zpTevI>8*BWhQ3Q>=a1?n?F#Oed!3p7GPkNa*q8UwPt6FCn09cDVLcLc*;#MgKQPg< z*;<=P*P)IFLw!O*8nTS|ybNFgj$17^N@x=Y?@F}YJz8TxMZdBxY`~#drWFPbwvn?A z++$D*WpF^s8z~SEvxmA?Q2Lh&3kbXffQCojC{{x6(Rmf$e`Jz-3*rScxhr9b;Eqx?+(_tEE27kt0@<$1?o!>xi{88j5P zq$yNUh3G_xDiV$tJy4#j(m}XJ7gdBNul0AY5 z#7?#Of1Ea&H-g`heC8A3akuzbavo`UK-ylKnHg;%F9{Eze5w%;;EdO07xfD2&v=D@ z%1hX8I<4!x5gpUx6yAIq6JHMJoW^%O?DG1-(W~z$v_`~nXt>QNK8cmCJuGOL%Pz>a zBpN70F|;$LX@XDZ&73*;! zfs9`?OWgQc8_iS!>u?K0P)AQ$@YpjoZdG?;)2({j28W_*7~6>`L1#&J9zmU>k1FI zz=y*D32@>GSnjoe;ZRlXGBIcW(+s{$y{FqNpb{==Mu*wg*17GGAN#0R8L-auujP1K zAI&zWCP3C_lXW*SQ`M+V3dh_taE`q$qmcYUPwkWTq-oFyB~-y#N!X`5kA(R+!LU7& z{pi>$_PU~8?$i4zA3J>4D*0pXZ!D7^sc(=DT2wjNC%@aF#?YgAc)KZ`W}^mU%f|hk zpGv0#HywgNDw18#91ey%{xm||cWc@+!$9GBjS;*==55Y%2|+Vr*}dO?HlLqlAs=Lc zpP?FUs zBZfAcO_z)fjl5W;-&PG?o<8&jN4`b4h_aH@3IrKZd_jh(a!BV45tex`%$;C9(LN9O zw_#{v8qy}bpU^R>UsvH(BYjq6dRsi9Nn7nuGYJ%n1&T!Rur9FoY6D>Vux%n;;rn;w zAkpX46`sef8-9`()%Z!DR#i&k)5O(}u)f+L6)a6I{~4 zxVGG^TcS<+D#NvQ+by<0&Y5!g4|eP7ZUiND%$M$ruuFf1^iK&za75Fc&oLQX*8t5h zv}>&euW_DB+!=9f(X&4ZhZv?CdPU4^ji5s>WGZhAlM4W%bb)uzg=9pO7o9B88APJ| z)#pA(4P+oH@I*|#d29h}DXC)BDAS7^rZ@%qp_&@kR*XEylI60m~Fyq9^s@l{bI+*(Cns zwjuJ&WNtqLGEZ+k$xQ=OrYEvwAEl8FOopfZ(bF*1KlLUqc6!zzMa+7Wp;&%H<2Z=B z@(O_8HWuDMqc%i7=zPJ?-YYcDov8Ak? zBgBV|-MU2fWFw`a%indQ#PaNsH(0S%lK4Sxq=&Jf%r*f!rj}8oK@dL-aC>4NS<`i+7 z>w_=0mGG7 zPWWP*g1bucB-aU-d@pA`Rog3m8)iRHq^HWfJax~@n3L1a1t?C)ZO)pSx5}EzRi@9Z z!M(^`yS=C#E=FAEtf{^mDdL$ZtH_Tm+g0k5pI72=*+K`jb1&Z`;-zZW+>v~ruA1@_kX16#dO#1$WR*Q}IS`Zgq+ zMA>+-&ld%t zF>#G^3~>eNx)(?unxZz-T)}&>sj!lbA;@oZA5QzI&-R=z6l_+@77?6>`MkLi1E;Wyd zRw7TDW}k8@_zO4kjy;x-R^oqBv=TivUcQiRT1{P)eS#i{s<(?B-oYKuy% zyxdPrO%Ua|%Z?6aFcTR=Gu21(Wfm@FMMXR8$Txq&f~l6qmYk?QCGIo_9?O{u&6-|a52?zIg37BN?mpId%6n%$|tc^%^krJMRP)^QnOps>1HLLHtJ1T9HHKS zVm`(={TUF{-8|JOSwI5(W;9(tlwj{NNjYk&{MNMsYV_L}sa3W9U$x z29B`>m0x$GbsJD(LLkwNnNUYKqr0(>x#tWrY1AhRmTtNOf@UszygKc=A2QJV-CbZS zD9@f=ux5v}kbnDMMJTZsxoO*rOud$1ec0Vikh}bUwjMeM{luX1wUNF$=>M*5-^Vt` zp-?-bTjGGSnw+cG0y#GD=~Lb@`>c}c>gq;&G!sW4(11y=;Z6#I5>NyCY(57*>V!eh zPvH2!RpJJl4uRL7xyv5E<{(kPEr5jD20Q=t_3Crr3BcEX*X{o``#A()DG22E|0<%7 zL%{0#?oUAd4UGR|+5hc!$g^*%`~Ms^6_m!E?)#jqjPz~lzkJviMi7h~J-;m+Tlrvj zM_BmJ89u94jc=^6{wWUPkvdG*`N6{O3hhGss4G+BG|kMnTO{CdP10$vexcUL z&C81Tm4t9U9}BvaPrvz35XzG%iX_)%6xIFrFXGXYnjMtz5&R(cRBm9JRlcu6Tre+8 z+C5^m#UwDMZ8Fo?#GkEy#Q9hd|ol9a7d3;dDXn1|?07%b>eq256t(1M3vgsYJCq+EWeiX1$Mu9d}~a_UA~D_aS#W$FcYuT3W1>fq#73?=9Vhm`viQQ)+d*(+JEPDHXl zX$wCYEgQynIT!`4zt~NHRYxohT#8$mvpgd!J7a7NA1{5YY8n|~GD~6w(Q6E8&5Kui zgeTLLyGzu<`@*OnN;sBl>qh9={@2S3Q9BJ|-@kaQXc&QF@s4vC46dsrdC>S{PD3AHSDVs z!XlmU&exO`s=9_kz6JTw%|;?ePSR!Tow0kCttZDTYT>TKfyjAnc7B?}=<+_nT(PaaVZ_WNu1h6v?XBf%cas!Y z(NNT|mA(oH(W{V(l7t-7)G{*)U|cvXhWSIgqjY`yTBn;+A_g#RKDZ&r?FB>lebX9A ziN}<LWeL+P(QF!jaQVLds5*&9DRjbmi;DKt02$;lC|=x}FMh9r83shjwcYvBO6eqd5VvX6J~?yhNf9;Mi=Rh)x2#y4G3A7#oM;40^sfMN5HWl$ zkHvv6r(vVR6T~+AOk|9=KXbrew>@82hZFYL%j@5HhBb1ZHZ8pvT<#KJPBk{)_#~7N z5+I>jV^%MSU0uzB=ivzVNkMp%X;h)aM;W(m zn3C3;lRL(b{U?C=_u*Xs{xAN#cT{zfYNkvyYOTbjj<1TUJ))KwR3``QC5$wCcPq71 zuJc0|$I^ldTQ|L){@}5yL1_SUL`8O-`aF^m#Pprc@lsNMvQ)H~8Cb?$mlNV^f zs#ZviLHs^;f-lqueRBYAP?X7+d^Hd6DJnM{7vk8i5G#50X zE`)i>^A6kZB3V!nDZp+a+*gR2t)H!wtqYRnA{rF?;R9zpcIJ(@}!%44;HX%5;@KMXSgd=W8ST#*p2n`go;^-Q)0f@AYYAc&)<$ zA)uKaiOmvk_xYCP#C1u|G$EdoV8$;BcOq;Qh`U0SIW1}VzRWc$waHk(44ppqw7x=g@W^cO@N70HXMf9(6P6XQnH+p$R*Nx#L-< zvu@xkg(hw!XSEL41z4w(7R>eB6nud(GqL^g&(C}l70#-Z=@PMos?pW|+B+}Mh*Qx| z231XdXFjrdu@`Wq_eO+{hj5>#wEQUl#zo*fh@_=zar3gCg@PJ6B35J+`YigIMHH%g z9bb!CnDZ8oSp=ne)R+2SeW(_WDGiW`dd&@Ub;GxcGGQM$$?clsH((^$^7Q_{L7Fkp z9M^81k2?-sE2u{t=bs^yWg=5nE?jPf$q=C1Lm#-bQnk=dxr>W)aG#4)L}l08>(6|4}@U30G;D7o6uOP1&Ri z!RssSA_6g_0*CARXA81&#Cm2V6V*ptoeeCEb-J)?m5rgB?jPPBpPGLn1xSv zg?M=r5Q#_TbqmWzSVa2g^eB%1=MpvifR)2AnRtw~O*Ui?u-j;U)V!Y)<1`iVWr){X zH={Q>dT{w#W5Up1b7?ltwN31TvAQw%yP?(~{^TElPWb)NBA{XR3dZtOMh)={V-=ItxwM4!%m+np-|_TaK$I<>x97mu^%95O;j>!Tpj;wQgQZ8_}0AkLDaBo4@xHEc z)!F|_yv>UE9B3>dDTy?~24CqxImkW)>YhouZHRGni%zP)>8<4yw>b^h_Wk#QXySz? z6(eGgwIWg8mNWg*D|-ACzm9QL?Nv_#eo~L-L`!(NvAlSgw}qh<7>3V3I5h`%YnH5( z50}0SU!4KzsFtQ%ij+8FZIiQhC;%bvA_mM=A^22ZSv4}gg{yC4R`fvW67~}J&^Qjr zF8wa-Do1Xi2qs3*(L>`ouJ;+ziC$#;Dv-(mEbOZE&}5F9NQqeZ#aMF2#F+7&M{``I zxZMVc>j};bujjp8UMLO0T>Ula?R6<=rEd z{iov{>Oc;5up%*6FY1Y@xwx)nj(#^3E^FdECpnClOb?sr8W7|%n}Oj^!bE;T43ZKx zvPvi;5=VQH@e{?2nYR1(SS@{BPi(k!R-|(ltc$PnTsQXL1*1&<#3~TWqP}>z-NL=x zBII%fy$+~P#J_^W^srjm>Ivt--IQ|$aWTj>#cTs1rgD!B1>=C4R7e-nB3WtjC!iAm zIXXWlLD?pTgsdDN`U}XOr`|YGEPUl00(P3|AKqTi=#vFxcQ27R-w#VxH>Ncf?1BH_nq^^pWob($F{c` zS1LXLT-%z7$_-QNa1e77RGS&l1)tee2t*?o>;;&k-k@eUeh~(#qi4M$`65gfkda)( zjz_n*f>TFsNc*JRmmbGKEJB7nio-Xp|FMOAtv0^jNs&iOT%7?Tvlco=e4665Yrask zKvt+@Ig@$MT%$3(+ckGa>YP^UfnvATj@`$Ai725^_y?VwM!&OQ$0~Rj+9+c!MKmsk zOH1F1<8fh~dr;;1; z%+Izfp}@QBB3q6tnQ`vLF%FsniD&*#a({6}=S&?MwbREl4@i`bOF?%Z3grF<87{Kp zeX6u_J(Cf<-P$COmbX|f8?9smDZzN`s!A=5KX#1)s!2R%^IE&hYnBOIjanRIKiSl! zeQ(%r#=wmG&-o~^XhACk(kv|G~B)ONZAhz=boZg~R}m)=#@HMeP4 zjZ(|4xy|D@39CjUFW9kSnUiDp%yDY){TZA2s%9Yr$QA#{rC1sXKB!d|f=RbdCGIF; zC9&5UeH9FI1APIno;?C`pLC2jDi#@cJ`^IZqa_>ypNo`eCN74Fxf#Btum)*PXmDAu zvpp<#W;j*>CP0bHlTIl2nG6+;ToF(4VLp;pz?#xG9gp&P>I7f!>5 zo}2Q{mLHg}EHCalfJ;Y?FOrgkc!ec_%)>^dbxM?nivtuK&Jm-+7!zfijp+SN^(Xv@ zqn3VlVXTwPM7Mw?tUvnJhdj%bS?55Y9$UY1&nN(w!RQChpn!;Kv(v{rkJZer72iz> zdiTK%2efw>6~vf0YbKb}tf_~Jl9W5^pWds5Dl(E@Iym%XoA^2Uc-NmjnzTE;b3E!k`eNfMn^^d=?yMwO+cjhWpo3RfFi-aiJ&> zeY1C&9t!56reRbUQx~wo2BPzN>-Fs%efMW5O_>cC>D|ce%zGxiE^ITCJwy%SfDD}V z0%%HcyZ$ygdAYeuffXng9^~u?-n<07f3ZM`{}n6@xWofs_53*lnE19yywhlAL}j1| zuh*Is;+nq;+!SO8x%nJ8o~YJf!oUxZKJ<5Y!SVmG^EUScluFepjo8_jr(xtbWN$aO ztfk5J*KPzKrl%V`$H4DGLA>ze0!6}y#WIiCXHM}O1-)xy;f0B^4a8g>s0a7up@;kL z3S!zV3~#*qYaU~@N_U%iq=R>#SW9=ZHuDOtbI~Ku zzS67IffmHhmn{&-!q8Js?a0zmP)8MLz|)^=*=e9}?bq{uet)M5X9Ql@ zJKZS448C4y9W1KHxIrrHa;ukRQKkNlXD9yhMvnNyJXOF|rfYk@yW1SQ`a7GFFh~k# zhmhw=%+^2OGm4z*umnaZR>ddgu+iLNvqfpHX@$nYuE!m6p52-J zFg>ZMh|z19!p1N7Y2v~#OKmF4WljmFCO@Qf{k3CHBqtjV9?-UWQl!)RGu=kCZdG{R zQ{YDbu~1UaeH9;fCM9O+OJ2;EhpOh$x3?)Bc-E?HW9ekM^c!~Su~Baaf&t4?3#&hz ze%v7l#Xp*6Y3TggvB$*?mNDpPp$m=VR+0i}R-*0)YGKcJ>^VM#wbz4Q*$c&je+8v4 zZ`b#z(Td|Yz{7wYx|AdOU)h>X{I$n0Y`lJfs*sC$;h4sEs0b#4F@1N-?hYD8zI-X~ ztbv7~DN3(-Wk4zyQEBfV?lFp(f0iL^Gg|o_~P{mWsLjdgJv~nzx;g^Xaai#n0NpA2fI#wNLBaBLkxMeg*EbA zwN7r^eb9Zc?Ugg8rYhm+F0V%q9z6K+$=OM_*K)c02-E;AoZ8Jb1DDWhGZ_nUj+czF z^}r>xPVxb{fpx!}*W9>VM@-hI)c}_1q-X)8Stpdu{IkE56w|4eDwiOVIK3XmV|@Iqt-xS7(JCN0WiO zZjRLW(|Oy~qc2zYn2hahJGJdD;TjikVVIRX*;o2SXWLy86X|sYSZXF8<=RRGtmWU8 zxlc(+sV$4LQVc>S&1&rga`;Bl{L)Spz0(H{9C!raz4AHWmw<*h7*ro-Vz1fEUd(!{ zrYpH}_RH7T8&!BO?SM^=Sh-9B2ZX$YZJJOD?=WaTm@cA-npG`hBCu1^Wg3m{=9>@l z(BNw)@H5P6?T_sm9RPX_1G=BjlTpoFn7BVJ@tIbGgx{F1#qh->gf*`YX_X;QCPrkJsOU)(nKg zWO$IEhy1zSKi`ex)w%WBD5QB9x!6q5v>f?vhxV=Y#RbNn&?{a>-|!J zAM-?z906Lo(IY-J;exePNSC2lz)1dY|J>?Pb^VuZyMBJ+6#r$<$n|?l<`r;T?o3Z^ zmKOcGArv_7OxFS`VO#>+$wn4U9FOeELFnw1pJMoCc>2an+(*`}3D}B#!Si$+L#F@( z(A7ubah`F~qm&kODe z!FS(NwtmhAwk=*GQS<%MtW2PhLmqG!lCq|?B^$8HGC*Gb=?*4P?0BMtN9P^2OTC0W z2-so-ITo6(C1Rp{@sy4ET?fxb)CH-Ugt)Itw`;^)U-hme)S81N5wz%X2e1l!VYs@C zKyU)id5th~={zw>BldO%4YuR50C4A~87l!a)9Gx@@sO&w+X8Rj?wIW_3O>GAzxZya z(araNTS^yO8@@c!iR?W2dI|_KplNGGthkv!cj|Ry0tS8;3K-lcm}Lx@tc83%KX6mM zVQv^Xu%@YQya~N5%w$Bnn zJs{7;FW%Gau4DM*t^ydY3qlX(vYs72|6nTESKJ6kNwqI!o`nnrwX z$xGarGvij&8lw2)Al}eGXsrQuNQfRAUHLbXcQCEKpC||E{LV_h9U;09Bn9)Myp}(< zB=6L3sscG2;Ar4Az@sk!GwXu9q16Ub6g2(#J|N1JX<&GD3|Er&*KlLG*s?|4hx_-@ z)Y9yjq7#pfK$r3b@vl#0(k@#90?jvo_X9R4BMXcf-p*QO4T)nC*}NOo6NpS;!gO}N zw5WXM_p2b?x4p7W2IHBkQNUgRVijQ)KoAC=uAjJ+>{7nU$qmOh2qx2PC>O6vxxR`Z zH#eXq<59K|9N<^L(O#0n0DQFpzI+W>90;5{+YTokyy`5Ou~CTUDKmLdjy*(B8$gKG z_POKbMhOOhau)%E_5bvJ#ybEZhVb6J$Lba)fbV(KN8A8Yr;?JAONG`};jx3cHMc%u zSGWv)?ZWuT5{KMOAY_%qN&%ULedm?^0e0(JUz!{&YR82iYKWd206{QE$GKfd(|{R0 zw8NfuuR3IV<&7F4%oea(db=jZ65J&5Pk{K37{PnHU;J`!0LZfFc*N3|HuU1#?M5NP zRmd5iJpr_W{MQAsr;0A5lq0(;pPPpJ07)bzq>)D)iJ44s3mzL4{@c0%#XmsYZUM`y z8r=L1hy(im1OGr96mm(_?8_t$fd2q6`QYoN8Fw^-4f3U{=gHS!LKj!*nj8|a-(*fv-Zb~*Xw`&Cm?Dg A7XSbN literal 0 HcmV?d00001 diff --git a/tests/components.spec.ts-snapshots/Pages-NotFoundPage-default-1-chromium-darwin.png b/tests/components.spec.ts-snapshots/Pages-NotFoundPage-default-1-chromium-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..b89490c8235833a99df7f4c496e88575e1f8ff23 GIT binary patch literal 16061 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 A7XSbN literal 0 HcmV?d00001