@lifesg/react-design-system 3.5.0 → 3.6.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/breadcrumb/breadcrumb.js +1 -1
- package/breadcrumb/breadcrumb.js.map +1 -1
- package/breadcrumb/breadcrumb.style.d.ts +1 -6
- package/breadcrumb/breadcrumb.style.js +27 -43
- package/breadcrumb/breadcrumb.style.js.map +1 -1
- package/breadcrumb/types.d.ts +2 -5
- package/cjs/breadcrumb/breadcrumb.js +1 -1
- package/cjs/breadcrumb/breadcrumb.js.map +1 -1
- package/cjs/breadcrumb/breadcrumb.style.js +16 -32
- package/cjs/breadcrumb/breadcrumb.style.js.map +1 -1
- package/cjs/drawer/drawer.js +1 -1
- package/cjs/drawer/drawer.js.map +1 -1
- package/cjs/drawer/drawer.styles.js +48 -31
- package/cjs/drawer/drawer.styles.js.map +1 -1
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js +1 -1
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js +30 -16
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js.map +1 -1
- package/cjs/local-nav/local-nav-menu/local-nav-menu.js +1 -1
- package/cjs/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
- package/cjs/local-nav/local-nav-menu/local-nav-menu.styles.js +25 -11
- package/cjs/local-nav/local-nav-menu/local-nav-menu.styles.js.map +1 -1
- package/cjs/menu/menu-content.js +1 -1
- package/cjs/menu/menu-content.js.map +1 -1
- package/cjs/menu/menu-content.styles.js +4 -1
- package/cjs/menu/menu-content.styles.js.map +1 -1
- package/cjs/menu/menu-item.styles.js +1 -1
- package/cjs/menu/menu-item.styles.js.map +1 -1
- package/cjs/menu/menu-link.styles.js +1 -1
- package/cjs/menu/menu-link.styles.js.map +1 -1
- package/cjs/menu/menu-section.js +1 -1
- package/cjs/menu/menu-section.js.map +1 -1
- package/cjs/menu/menu-section.styles.js +23 -9
- package/cjs/menu/menu-section.styles.js.map +1 -1
- package/cjs/navbar/navbar-items.js +1 -1
- package/cjs/navbar/navbar-items.js.map +1 -1
- package/cjs/pagination/pagination.js +1 -1
- package/cjs/pagination/pagination.js.map +1 -1
- package/cjs/shared/dropdown-list/dropdown-label.js +1 -1
- package/cjs/shared/dropdown-list/dropdown-label.js.map +1 -1
- package/cjs/shared/fade-wrapper/fade-wrapper.js +1 -1
- package/cjs/shared/fade-wrapper/fade-wrapper.js.map +1 -1
- package/drawer/drawer.d.ts +1 -1
- package/drawer/drawer.js +1 -1
- package/drawer/drawer.js.map +1 -1
- package/drawer/drawer.styles.d.ts +8 -1
- package/drawer/drawer.styles.js +46 -29
- package/drawer/drawer.styles.js.map +1 -1
- package/drawer/types.d.ts +7 -0
- package/input-group/types.d.ts +1 -1
- package/input-select/types.d.ts +1 -1
- package/local-nav/local-nav-dropdown/local-nav-dropdown.js +1 -1
- package/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
- package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.d.ts +3 -0
- package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js +42 -28
- package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js.map +1 -1
- package/local-nav/local-nav-menu/local-nav-menu.js +1 -1
- package/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
- package/local-nav/local-nav-menu/local-nav-menu.styles.d.ts +3 -0
- package/local-nav/local-nav-menu/local-nav-menu.styles.js +25 -11
- package/local-nav/local-nav-menu/local-nav-menu.styles.js.map +1 -1
- package/local-nav/types.d.ts +17 -0
- package/menu/menu-content.js +1 -1
- package/menu/menu-content.js.map +1 -1
- package/menu/menu-content.styles.d.ts +1 -0
- package/menu/menu-content.styles.js +17 -14
- package/menu/menu-content.styles.js.map +1 -1
- package/menu/menu-item.styles.js +1 -1
- package/menu/menu-item.styles.js.map +1 -1
- package/menu/menu-link.styles.js +1 -1
- package/menu/menu-link.styles.js.map +1 -1
- package/menu/menu-section.d.ts +1 -1
- package/menu/menu-section.js +1 -1
- package/menu/menu-section.js.map +1 -1
- package/menu/menu-section.styles.d.ts +9 -2
- package/menu/menu-section.styles.js +22 -8
- package/menu/menu-section.styles.js.map +1 -1
- package/menu/menu.d.ts +1 -1
- package/menu/types.d.ts +2 -2
- package/navbar/navbar-items.js +1 -1
- package/navbar/navbar-items.js.map +1 -1
- package/navbar/types.d.ts +1 -0
- package/package.json +1 -1
- package/pagination/pagination.js +1 -1
- package/pagination/pagination.js.map +1 -1
- package/pagination/types.d.ts +1 -0
- package/select-histogram/types.d.ts +1 -1
- package/shared/dropdown-list/dropdown-label.d.ts +2 -2
- package/shared/dropdown-list/dropdown-label.js +1 -1
- package/shared/dropdown-list/dropdown-label.js.map +1 -1
- package/shared/dropdown-list/types.d.ts +2 -2
- package/shared/fade-wrapper/fade-wrapper.js +1 -1
- package/shared/fade-wrapper/fade-wrapper.js.map +1 -1
- package/shared/fade-wrapper/types.d.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer.styles.js","sources":["../../../src/drawer/drawer.styles.tsx"],"sourcesContent":["import styled, { css } from \"styled-components\";\nimport { ClickableIcon } from \"../shared/clickable-icon\";\nimport {\n Border,\n Colour,\n Font,\n MediaQuery,\n Motion,\n Radius,\n Shadow,\n Spacing,\n} from \"../theme\";\nimport { Typography } from \"../typography\";\n\n// =============================================================================\n// STYLE INTERFACE, transient props are denoted with $\n// See more https://styled-components.com/docs/api#transient-props\n// =============================================================================\ninterface StyleProps {\n $show?: boolean | undefined;\n}\n\n// =============================================================================\n// STYLING HELPERS\n// =============================================================================\n// FloatingUI transition styles\nconst FLOATING_TRANSITION_STYLES = css`\n transition-property: right, visibility;\n\n &[data-status=\"initial\"] {\n right: -100%;\n visibility: hidden;\n }\n\n &[data-status=\"open\"] {\n transition-duration: ${Motion[\"duration-800\"]};\n transition-timing-function: ${Motion[\"ease-entrance\"]};\n right: 0;\n visibility: visible;\n }\n\n &[data-status=\"close\"] {\n transition-duration: ${Motion[\"duration-800\"]};\n transition-timing-function: ${Motion[\"ease-exit\"]};\n right: -100%;\n visibility: hidden;\n }\n`;\n\n// =============================================================================\n// STYLING\n// =============================================================================\nexport const Container = styled.div<StyleProps>`\n position: fixed;\n top: 0;\n\n display: flex;\n flex-direction: column;\n height: 100%;\n\n background-color: ${Colour.bg};\n box-shadow: ${Shadow[\"lg-subtle\"]};\n\n ${FLOATING_TRANSITION_STYLES}\n\n width: 40%;\n border-top-left-radius: ${Radius[\"md\"]};\n border-bottom-left-radius: ${Radius[\"md\"]};\n overflow: hidden;\n\n ${MediaQuery.MaxWidth.xl} {\n width: 50%;\n min-width: 700px;\n }\n\n ${MediaQuery.MaxWidth.lg} {\n width: 100%;\n min-width: unset;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n`;\n\nexport const Header = styled.div
|
|
1
|
+
{"version":3,"file":"drawer.styles.js","sources":["../../../src/drawer/drawer.styles.tsx"],"sourcesContent":["import styled, { css } from \"styled-components\";\nimport { ClickableIcon } from \"../shared/clickable-icon\";\nimport {\n Border,\n Colour,\n Font,\n MediaQuery,\n Motion,\n Radius,\n Shadow,\n Spacing,\n} from \"../theme\";\nimport { Typography } from \"../typography\";\n\n// =============================================================================\n// STYLE INTERFACE, transient props are denoted with $\n// See more https://styled-components.com/docs/api#transient-props\n// =============================================================================\ninterface StyleProps {\n $show?: boolean | undefined;\n}\n\ninterface HeaderStyleProps {\n $stacked?: boolean | undefined;\n}\n\ninterface CallToActionStyleProps {\n $stacked?: boolean | undefined;\n}\n\n// =============================================================================\n// STYLING HELPERS\n// =============================================================================\n// FloatingUI transition styles\nconst FLOATING_TRANSITION_STYLES = css`\n transition-property: right, visibility;\n\n &[data-status=\"initial\"] {\n right: -100%;\n visibility: hidden;\n }\n\n &[data-status=\"open\"] {\n transition-duration: ${Motion[\"duration-800\"]};\n transition-timing-function: ${Motion[\"ease-entrance\"]};\n right: 0;\n visibility: visible;\n }\n\n &[data-status=\"close\"] {\n transition-duration: ${Motion[\"duration-800\"]};\n transition-timing-function: ${Motion[\"ease-exit\"]};\n right: -100%;\n visibility: hidden;\n }\n`;\n\n// =============================================================================\n// STYLING\n// =============================================================================\nexport const Container = styled.div<StyleProps>`\n position: fixed;\n top: 0;\n\n display: flex;\n flex-direction: column;\n height: 100%;\n\n background-color: ${Colour.bg};\n box-shadow: ${Shadow[\"lg-subtle\"]};\n\n ${FLOATING_TRANSITION_STYLES}\n\n width: 40%;\n border-top-left-radius: ${Radius[\"md\"]};\n border-bottom-left-radius: ${Radius[\"md\"]};\n overflow: hidden;\n\n ${MediaQuery.MaxWidth.xl} {\n width: 50%;\n min-width: 700px;\n }\n\n ${MediaQuery.MaxWidth.lg} {\n width: 100%;\n min-width: unset;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n`;\n\nexport const Header = styled.div<HeaderStyleProps>`\n top: 0;\n display: flex;\n align-items: center;\n gap: ${Spacing[\"spacing-16\"]};\n padding: ${Spacing[\"spacing-32\"]} ${Spacing[\"spacing-16\"]}\n ${Spacing[\"spacing-16\"]}\n calc(${Font.Spec[\"heading-lh-md\"]} + ${Spacing[\"spacing-32\"]});\n background-color: ${Colour.bg};\n border-bottom: ${Border[\"width-010\"]} ${Border.solid} ${Colour.border};\n\n ${(props) =>\n props.$stacked &&\n css`\n /* Stack the call-to-action below the heading when the drawer is too\n narrow to fit both on one line. */\n flex-direction: column;\n align-items: stretch;\n gap: ${Spacing[\"spacing-16\"]};\n `}\n\n ${MediaQuery.MaxWidth.lg} {\n padding: ${Spacing[\"spacing-32\"]} ${Spacing[\"spacing-20\"]}\n ${Spacing[\"spacing-16\"]}\n calc(${Font.Spec[\"heading-lh-md\"]} + ${Spacing[\"spacing-24\"]});\n }\n`;\n\nexport const CallToAction = styled.div<CallToActionStyleProps>`\n display: flex;\n /* Flush right, beside the heading. */\n margin-left: auto;\n\n ${(props) =>\n props.$stacked &&\n css`\n /* When stacked, flush left so the buttons line up with the heading\n (the header's left padding already clears the close icon). */\n margin-left: 0;\n `}\n`;\n\nexport const CloseButton = styled(ClickableIcon)`\n color: ${Colour.icon};\n padding: 0;\n position: absolute;\n top: ${Spacing[\"spacing-32\"]};\n left: ${Spacing[\"spacing-16\"]};\n &:active,\n &:focus {\n color: ${Colour[\"icon-hover\"]};\n }\n\n svg {\n height: ${Font.Spec[\"heading-lh-md\"]};\n width: ${Font.Spec[\"heading-lh-md\"]};\n }\n`;\n\nexport const Heading = styled(Typography.HeadingMD)`\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n`;\n\nexport const Content = styled.div`\n flex: 1;\n overflow-y: auto;\n`;\n"],"names":["FLOATING_TRANSITION_STYLES","css","Motion","Container","styled","div","Colour","bg","Shadow","Radius","MediaQuery","MaxWidth","xl","lg","Header","Spacing","Font","Spec","Border","solid","border","props","$stacked","CallToAction","CloseButton","ClickableIcon","icon","Heading","Typography","HeadingMD","Content"],"mappings":"mQAkCA,MAAMA,EAA6BC,EAAAA,GAAG;;;;;;;;;+BASPC,EAAAA,OAAO;sCACAA,EAAAA,OAAO;;;;;;+BAMdA,EAAAA,OAAO;sCACAA,EAAAA,OAAO;;;;EAShCC,EAAYC,EAAAA,QAAOC,GAAe;;;;;;;;wBAQvBC,EAAAA,OAAOC;kBACbC,EAAAA,OAAO;;MAEnBR;;;8BAGwBS,EAAAA,OAAW;iCACRA,EAAAA,OAAW;;;MAGtCC,EAAAA,WAAWC,SAASC;;;;;MAKpBF,EAAAA,WAAWC,SAASE;;;;;;EAQbC,EAASV,EAAAA,QAAOC,GAAqB;;;;WAIvCU,EAAAA,QAAQ;eACJA,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;UACtCA,EAAAA,QAAQ;eACHC,EAAAA,KAAKC,KAAK,sBAAsBF,EAAAA,QAAQ;wBAC/BT,EAAAA,OAAOC;qBACVW,EAAAA,OAAO,gBAAgBA,EAAAA,OAAOC,SAASb,EAAAA,OAAOc;;MAE5DC,GACCA,EAAMC,UACNrB,KAAG;;;;;mBAKQc,EAAAA,QAAQ;;;MAGrBL,EAAAA,WAAWC,SAASE;mBACPE,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;cACtCA,EAAAA,QAAQ;mBACHC,EAAAA,KAAKC,KAAK,sBAAsBF,EAAAA,QAAQ;;EAI9CQ,EAAenB,EAAAA,QAAOC,GAA2B;;;;;MAKvDgB,GACCA,EAAMC,UACNrB,KAAG;;;;;EAOEuB,EAAcpB,EAAAA,QAAOqB,EAAAA,cAAc;aACnCnB,EAAAA,OAAOoB;;;WAGTX,EAAAA,QAAQ;YACPA,EAAAA,QAAQ;;;iBAGHT,EAAAA,OAAO;;;;kBAINU,EAAAA,KAAKC,KAAK;iBACXD,EAAAA,KAAKC,KAAK;;EAIdU,EAAUvB,EAAAA,QAAOwB,aAAWC,UAAU;;;;EAMtCC,EAAU1B,EAAAA,QAAOC,GAAG;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react/jsx-runtime"),t=require("react"),n=require("../../typography/typography.js");require("../../util/calendar-helper.js"),require("../../util/date-helper.js"),require("../../util/date-input-helper.js");var r=require("../../util/simple-id-generator.js");require("../../util/string-helper.js"),require("@react-aria/live-announcer");var i=require("./local-nav-dropdown.styles.js");function s(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}const
|
|
1
|
+
"use strict";var e=require("react/jsx-runtime"),t=require("react"),n=require("../../typography/typography.js");require("../../util/calendar-helper.js"),require("../../util/date-helper.js"),require("../../util/date-input-helper.js");var r=require("../../util/simple-id-generator.js");require("../../util/string-helper.js"),require("@react-aria/live-announcer");var i=require("./local-nav-dropdown.styles.js");function s(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}const d=s(t).default.forwardRef((({defaultLabel:s,stickyOffset:d=0,onNavItemSelect:a,items:c,selectedItemIndex:u,id:f,"data-testid":p,className:h,renderItem:m},v)=>{const w=t.useRef(null),x=t.useRef(null),y=t.useRef(null),g=t.useRef([]),[j,b]=t.useState(!1),[E,I]=t.useState(!1),[k,L]=t.useState(0),[S,D]=t.useState(0),[$,N]=t.useState(0),[q,C]=t.useState(0),A=p||"local-nav-dropdown",R=r.useId();t.useImperativeHandle(v,(()=>y.current));const B="number"==typeof u&&u>=0&&j?c[u].title:s;t.useEffect((()=>{if(x.current){const e=x.current.getBoundingClientRect().height;D(e)}}),[]),t.useEffect((()=>(T(),()=>{H("remove")})),[]),t.useEffect((()=>{H(E&&j?"add":"remove")}),[E,j]),t.useEffect((()=>{L(window.innerHeight);const e=()=>{L(window.innerHeight)};return window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)}),[]),t.useEffect((()=>{const e=new IntersectionObserver((e=>{const[t]=e;b(!t.isIntersecting)}),{threshold:1,rootMargin:`-${d}px 0px 0px 0px`});return w.current&&e.observe(w.current),()=>e.disconnect()}),[d]),t.useEffect((()=>{const e=()=>{const e=null==y?void 0:y.current;if(e){const t=e.getBoundingClientRect(),n=document.body.clientWidth-t.right,r=t.left,i=Math.max(n,r);N(i)}};return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[]),t.useEffect((()=>{var e;E&&(null===(e=g.current[q])||void 0===e||e.focus())}),[E,q]);const T=()=>{if(!document.getElementById(o)){const e=document.createElement("style");e.id=o;const t=document.documentElement.clientWidth,n=window.innerWidth-t;e.innerHTML=`\n\t\t\t\t.${l} {\n\t\t\t\t\toverflow: hidden;\n\t\t\t\t\tpadding-right: ${n}px !important;\n\t\t\t\t\t-ms-overflow-style: none;\n\t\t\t\t\tscrollbar-width: none;\n\t\t\t\t}\n\n\t\t\t\t.${l}::-webkit-scrollbar {\n\t\t\t\t\tdisplay: none;\n\t\t\t\t}\n\t\t\t`,document.body.appendChild(e)}},H=e=>{const t=document.body.classList.contains(l);"add"!==e||t?"remove"===e&&t&&document.body.classList.remove(l):document.body.classList.add(l)},z=(e,t)=>{const{key:n}=e;"Enter"!==n&&" "!==n||(e.preventDefault(),t(e))};return e.jsxs(e.Fragment,{children:[e.jsx("span",{ref:w,"data-testid":"sticky-ref"}),e.jsxs(i.NavWrapper,{$isStickied:j,$sideMargin:$,$stickyOffset:d,ref:y,id:f,"data-testid":A,className:h,children:[e.jsxs(i.NavSelect,{ref:x,role:"button",onClick:()=>{I((e=>!e))},onKeyDown:e=>{const{key:t}=e;"ArrowDown"===t?(e.preventDefault(),E||I(!0),C(0)):"ArrowUp"===t?(e.preventDefault(),E||I(!0),C(c.length-1)):"Enter"===t||" "===t?(e.preventDefault(),I(!0),C(0)):("Tab"===t||"Escape"===t)&&I(!1)},"data-testid":`${A}-label`,$isDropdownExpanded:E,"aria-haspopup":"true","aria-expanded":E,"aria-controls":R,tabIndex:0,children:[e.jsx(n.Typography.BodyBL,{weight:"semibold",children:B}),e.jsx(i.NavSelectIcon,{$isDropdownExpanded:E})]}),E&&e.jsx(i.NavItemList,{id:R,role:"menu",onKeyDown:e=>{var t;const{key:n}=e;if("ArrowDown"===n){e.preventDefault();const t=(q+1)%c.length;C(t)}else if("ArrowUp"===n){e.preventDefault();const t=q>0?q-1:c.length-1;C(t)}else"Tab"===n?I(!1):"Escape"===n&&(I(!1),null===(t=x.current)||void 0===t||t.focus())},"data-testid":`${A}-dropdown-list`,$viewportHeight:k-S-d,children:c.map(((t,n)=>(({handleClick:t,isSelected:n,item:r,renderItem:s,index:d})=>{const{id:o,title:l,titleAddon:a}=r;return s?e.jsx("li",{id:o,role:"menuitem",onClick:t,onKeyDown:e=>z(e,t),"aria-current":!!n||void 0,tabIndex:-1,ref:e=>{g.current[d]=e},children:s(r,{selected:n,stickied:j})},d):e.jsxs(i.NavItem,{id:o,role:"menuitem",$isSelected:n&&j,onClick:t,onKeyDown:e=>z(e,t),"aria-current":!!n||void 0,tabIndex:-1,ref:e=>{g.current[d]=e},children:[n&&e.jsx(i.LeftAddon,{children:e.jsx(i.StyledTickIcon,{})}),a?e.jsxs(i.TitleContainer,{children:[a.left&&e.jsx(i.LeftAddon,{children:a.left}),e.jsx(i.NavItemLabel,{$isSelected:n,children:l}),a.right&&e.jsx(i.RightAddon,{children:a.right})]}):e.jsx(i.NavItemLabel,{$isSelected:n,children:l})]},d)})({handleClick:e=>((e,t,n)=>{a&&a(e,t,n),I(!1)})(e,t,n),isSelected:n===u,item:t,renderItem:m,index:n})))}),E&&j&&e.jsx(i.Backdrop,{onClick:()=>{I(!1)}})]})]})})),o="lifesg-ds-local-nav-dropdown-stylesheet",l="lifesg-ds-local-nav-dropdown-open";exports.LocalNavDropdown=d;
|
|
2
2
|
//# sourceMappingURL=local-nav-dropdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-nav-dropdown.js","sources":["../../../../src/local-nav/local-nav-dropdown/local-nav-dropdown.tsx"],"sourcesContent":["import React, { useEffect, useImperativeHandle, useRef, useState } from \"react\";\nimport { Typography } from \"../../typography\";\nimport { useId } from \"../../util\";\nimport { LocalNavDropdownItemComponentProps } from \"../internal-types\";\nimport { LocalNavDropdownProps, LocalNavItemProps } from \"../types\";\nimport {\n Backdrop,\n NavItem,\n NavItemLabel,\n NavItemList,\n NavSelect,\n NavSelectIcon,\n NavWrapper,\n StyledTickIcon,\n} from \"./local-nav-dropdown.styles\";\n\nconst Component = (\n {\n defaultLabel,\n stickyOffset = 0,\n onNavItemSelect,\n items,\n selectedItemIndex,\n id,\n \"data-testid\": testId,\n className,\n renderItem,\n }: LocalNavDropdownProps,\n ref: React.Ref<HTMLElement>\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const detectStickyRef = useRef<HTMLSpanElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const navWrapperRef = useRef<HTMLElement>(null);\n const listItemRefs = useRef<(HTMLLIElement | null)[]>([]);\n const [isStickied, setIsStickied] = useState<boolean>(false);\n const [isDropdownExpanded, setIsDropdownExpanded] =\n useState<boolean>(false);\n const [viewportHeight, setViewportHeight] = useState(0);\n const [dropdowntHeight, setDropdownHeight] = useState(0);\n const [dynamicMargin, setDynamicMargin] = useState(0);\n const [focusedIndex, setFocusedIndex] = useState(0);\n const navTestId = testId || \"local-nav-dropdown\";\n const dropdownListId = useId();\n\n useImperativeHandle(ref, () => navWrapperRef.current!);\n\n const labelText =\n typeof selectedItemIndex === \"number\" &&\n selectedItemIndex >= 0 &&\n isStickied\n ? items[selectedItemIndex].title\n : defaultLabel;\n\n // =============================================================================\n // EFFECTS, EVENT LISTENERS\n // ============================================================================\n\n useEffect(() => {\n if (dropdownRef.current) {\n const dropdownHeight =\n dropdownRef.current.getBoundingClientRect().height;\n setDropdownHeight(dropdownHeight);\n }\n }, []);\n\n useEffect(() => {\n addStylesheetForDocumentBody();\n return () => {\n applyBodyStyleClass(\"remove\");\n };\n }, []);\n\n useEffect(() => {\n if (isDropdownExpanded && isStickied) {\n applyBodyStyleClass(\"add\");\n } else {\n applyBodyStyleClass(\"remove\");\n }\n }, [isDropdownExpanded, isStickied]);\n\n useEffect(() => {\n setViewportHeight(window.innerHeight);\n const handleResize = () => {\n setViewportHeight(window.innerHeight);\n };\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n const callback = (entries: IntersectionObserverEntry[]) => {\n const [entry] = entries;\n setIsStickied(!entry.isIntersecting);\n };\n\n const observer = new IntersectionObserver(callback, {\n threshold: 1,\n rootMargin: `-${stickyOffset}px 0px 0px 0px`,\n });\n\n if (detectStickyRef.current) {\n observer.observe(detectStickyRef.current);\n }\n\n return () => observer.disconnect();\n }, [stickyOffset]);\n\n useEffect(() => {\n const adjustPadding = () => {\n const dropdown = navWrapperRef?.current;\n if (dropdown) {\n const dropdownRect = dropdown.getBoundingClientRect();\n const spaceToRight =\n document.body.clientWidth - dropdownRect.right;\n const spaceToLeft = dropdownRect.left;\n // Calculate the padding needed to balance the dropdown in the viewport\n const sidePadding = Math.max(spaceToRight, spaceToLeft);\n setDynamicMargin(sidePadding);\n }\n };\n adjustPadding();\n\n window.addEventListener(\"resize\", adjustPadding);\n\n return () => {\n window.removeEventListener(\"resize\", adjustPadding);\n };\n }, []);\n\n useEffect(() => {\n if (isDropdownExpanded) {\n listItemRefs.current[focusedIndex]?.focus();\n }\n }, [isDropdownExpanded, focusedIndex]);\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n\n const addStylesheetForDocumentBody = () => {\n /**\n * This stylesheet is to manipulate the <body>. We only add once\n */\n if (!document.getElementById(STYLESHEET_ID)) {\n const overlayStyleSheet = document.createElement(\"style\");\n overlayStyleSheet.id = STYLESHEET_ID;\n\n const documentWidth = document.documentElement.clientWidth;\n const windowWidth = window.innerWidth;\n const scrollBarWidth = windowWidth - documentWidth;\n\n overlayStyleSheet.innerHTML = `\n\t\t\t\t.${DROPDOWN_OPEN_CLASSNAME} {\n\t\t\t\t\toverflow: hidden;\n\t\t\t\t\tpadding-right: ${scrollBarWidth}px !important;\n\t\t\t\t\t-ms-overflow-style: none;\n\t\t\t\t\tscrollbar-width: none;\n\t\t\t\t}\n\n\t\t\t\t.${DROPDOWN_OPEN_CLASSNAME}::-webkit-scrollbar {\n\t\t\t\t\tdisplay: none;\n\t\t\t\t}\n\t\t\t`;\n\n document.body.appendChild(overlayStyleSheet);\n }\n };\n\n const applyBodyStyleClass = (action: \"add\" | \"remove\") => {\n const isOverlayStyleClassApplied = document.body.classList.contains(\n DROPDOWN_OPEN_CLASSNAME\n );\n\n if (action === \"add\" && !isOverlayStyleClassApplied) {\n document.body.classList.add(DROPDOWN_OPEN_CLASSNAME);\n } else if (action === \"remove\" && isOverlayStyleClassApplied) {\n document.body.classList.remove(DROPDOWN_OPEN_CLASSNAME);\n }\n };\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n\n const handleToggleDropdown = () => {\n setIsDropdownExpanded((prev) => !prev);\n };\n\n const handleDismissBackdrop = () => {\n setIsDropdownExpanded(false);\n };\n\n const handleNavItemClick = (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n item: LocalNavItemProps,\n index: number\n ) => {\n if (onNavItemSelect) {\n onNavItemSelect(e, item, index);\n }\n setIsDropdownExpanded(false);\n };\n\n const handleNavItemKeyDown = (\n e: React.KeyboardEvent<HTMLElement>,\n handleClick: (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>\n ) => void\n ) => {\n const { key } = e;\n\n if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n handleClick(e);\n }\n };\n\n const handleNavSelectKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const { key } = e;\n\n if (key === \"ArrowDown\") {\n e.preventDefault();\n if (!isDropdownExpanded) {\n setIsDropdownExpanded(true);\n }\n setFocusedIndex(0);\n } else if (key === \"ArrowUp\") {\n e.preventDefault();\n if (!isDropdownExpanded) {\n setIsDropdownExpanded(true);\n }\n setFocusedIndex(items.length - 1);\n } else if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n setIsDropdownExpanded(true);\n setFocusedIndex(0);\n } else if (key === \"Tab\") {\n setIsDropdownExpanded(false);\n } else if (key === \"Escape\") {\n setIsDropdownExpanded(false);\n }\n };\n\n const handleNavItemListKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const { key } = e;\n\n if (key === \"ArrowDown\") {\n e.preventDefault();\n const nextIndex = (focusedIndex + 1) % items.length;\n setFocusedIndex(nextIndex);\n } else if (key === \"ArrowUp\") {\n e.preventDefault();\n const prevIndex =\n focusedIndex > 0 ? focusedIndex - 1 : items.length - 1;\n setFocusedIndex(prevIndex);\n } else if (key === \"Tab\") {\n setIsDropdownExpanded(false);\n } else if (key === \"Escape\") {\n setIsDropdownExpanded(false);\n dropdownRef.current?.focus();\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const renderDropdownNavItem = ({\n handleClick,\n isSelected,\n item,\n renderItem,\n index,\n }: LocalNavDropdownItemComponentProps) => {\n const { id, title } = item;\n\n if (renderItem) {\n return (\n <li\n id={id}\n key={index}\n role=\"menuitem\"\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n aria-current={isSelected ? true : undefined}\n tabIndex={-1}\n ref={(el) => {\n listItemRefs.current[index] = el;\n }}\n >\n {renderItem(item, {\n selected: isSelected,\n stickied: isStickied,\n })}\n </li>\n );\n }\n\n return (\n <NavItem\n id={id}\n key={index}\n role=\"menuitem\"\n $isSelected={isSelected && isStickied}\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n aria-current={isSelected ? true : undefined}\n tabIndex={-1}\n ref={(el) => {\n listItemRefs.current[index] = el as HTMLLIElement;\n }}\n >\n {isSelected && <StyledTickIcon />}\n <NavItemLabel $isSelected={isSelected}>{title}</NavItemLabel>\n </NavItem>\n );\n };\n\n return (\n <>\n <span ref={detectStickyRef} data-testid={\"sticky-ref\"} />\n <NavWrapper\n $isStickied={isStickied}\n $sideMargin={dynamicMargin}\n $stickyOffset={stickyOffset}\n ref={navWrapperRef}\n id={id}\n data-testid={navTestId}\n className={className}\n >\n <NavSelect\n ref={dropdownRef}\n role=\"button\"\n onClick={handleToggleDropdown}\n onKeyDown={handleNavSelectKeyDown}\n data-testid={`${navTestId}-label`}\n $isDropdownExpanded={isDropdownExpanded}\n aria-haspopup=\"true\"\n aria-expanded={isDropdownExpanded}\n aria-controls={dropdownListId}\n tabIndex={0}\n >\n <Typography.BodyBL weight=\"semibold\">\n {labelText}\n </Typography.BodyBL>\n <NavSelectIcon $isDropdownExpanded={isDropdownExpanded} />\n </NavSelect>\n {isDropdownExpanded && (\n <NavItemList\n id={dropdownListId}\n role=\"menu\"\n onKeyDown={handleNavItemListKeyDown}\n data-testid={`${navTestId}-dropdown-list`}\n $viewportHeight={\n viewportHeight - dropdowntHeight - stickyOffset\n }\n >\n {items.map((item, i) =>\n renderDropdownNavItem({\n handleClick: (e) =>\n handleNavItemClick(e, item, i),\n isSelected: i === selectedItemIndex,\n item,\n renderItem,\n index: i,\n })\n )}\n </NavItemList>\n )}\n {isDropdownExpanded && isStickied && (\n <Backdrop onClick={handleDismissBackdrop} />\n )}\n </NavWrapper>\n </>\n );\n};\n\nexport const LocalNavDropdown = React.forwardRef(Component);\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\nconst STYLESHEET_ID = \"lifesg-ds-local-nav-dropdown-stylesheet\";\nconst DROPDOWN_OPEN_CLASSNAME = \"lifesg-ds-local-nav-dropdown-open\";\n"],"names":["LocalNavDropdown","React","forwardRef","defaultLabel","stickyOffset","onNavItemSelect","items","selectedItemIndex","id","testId","className","renderItem","ref","detectStickyRef","useRef","dropdownRef","navWrapperRef","listItemRefs","isStickied","setIsStickied","useState","isDropdownExpanded","setIsDropdownExpanded","viewportHeight","setViewportHeight","dropdowntHeight","setDropdownHeight","dynamicMargin","setDynamicMargin","focusedIndex","setFocusedIndex","navTestId","dropdownListId","useId","useImperativeHandle","current","labelText","title","useEffect","dropdownHeight","getBoundingClientRect","height","addStylesheetForDocumentBody","applyBodyStyleClass","window","innerHeight","handleResize","addEventListener","removeEventListener","observer","IntersectionObserver","entries","entry","isIntersecting","threshold","rootMargin","observe","disconnect","adjustPadding","dropdown","dropdownRect","spaceToRight","document","body","clientWidth","right","spaceToLeft","left","sidePadding","Math","max","_a","focus","getElementById","STYLESHEET_ID","overlayStyleSheet","createElement","documentWidth","documentElement","scrollBarWidth","innerWidth","innerHTML","DROPDOWN_OPEN_CLASSNAME","appendChild","action","isOverlayStyleClassApplied","classList","contains","remove","add","handleNavItemKeyDown","e","handleClick","key","preventDefault","_jsxs","_Fragment","children","_jsx","NavWrapper","$isStickied","$sideMargin","$stickyOffset","NavSelect","role","onClick","prev","onKeyDown","length","$isDropdownExpanded","tabIndex","Typography","BodyBL","weight","NavSelectIcon","NavItemList","nextIndex","prevIndex","$viewportHeight","map","item","i","isSelected","index","undefined","el","selected","stickied","NavItem","$isSelected","StyledTickIcon","NavItemLabel","renderDropdownNavItem","handleNavItemClick","Backdrop"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"local-nav-dropdown.js","sources":["../../../../src/local-nav/local-nav-dropdown/local-nav-dropdown.tsx"],"sourcesContent":["import React, { useEffect, useImperativeHandle, useRef, useState } from \"react\";\nimport { Typography } from \"../../typography\";\nimport { useId } from \"../../util\";\nimport { LocalNavDropdownItemComponentProps } from \"../internal-types\";\nimport { LocalNavDropdownProps, LocalNavItemProps } from \"../types\";\nimport {\n Backdrop,\n LeftAddon,\n NavItem,\n NavItemLabel,\n NavItemList,\n NavSelect,\n NavSelectIcon,\n NavWrapper,\n RightAddon,\n StyledTickIcon,\n TitleContainer,\n} from \"./local-nav-dropdown.styles\";\n\nconst Component = (\n {\n defaultLabel,\n stickyOffset = 0,\n onNavItemSelect,\n items,\n selectedItemIndex,\n id,\n \"data-testid\": testId,\n className,\n renderItem,\n }: LocalNavDropdownProps,\n ref: React.Ref<HTMLElement>\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const detectStickyRef = useRef<HTMLSpanElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const navWrapperRef = useRef<HTMLElement>(null);\n const listItemRefs = useRef<(HTMLLIElement | null)[]>([]);\n const [isStickied, setIsStickied] = useState<boolean>(false);\n const [isDropdownExpanded, setIsDropdownExpanded] =\n useState<boolean>(false);\n const [viewportHeight, setViewportHeight] = useState(0);\n const [dropdowntHeight, setDropdownHeight] = useState(0);\n const [dynamicMargin, setDynamicMargin] = useState(0);\n const [focusedIndex, setFocusedIndex] = useState(0);\n const navTestId = testId || \"local-nav-dropdown\";\n const dropdownListId = useId();\n\n useImperativeHandle(ref, () => navWrapperRef.current!);\n\n const labelText =\n typeof selectedItemIndex === \"number\" &&\n selectedItemIndex >= 0 &&\n isStickied\n ? items[selectedItemIndex].title\n : defaultLabel;\n\n // =============================================================================\n // EFFECTS, EVENT LISTENERS\n // ============================================================================\n\n useEffect(() => {\n if (dropdownRef.current) {\n const dropdownHeight =\n dropdownRef.current.getBoundingClientRect().height;\n setDropdownHeight(dropdownHeight);\n }\n }, []);\n\n useEffect(() => {\n addStylesheetForDocumentBody();\n return () => {\n applyBodyStyleClass(\"remove\");\n };\n }, []);\n\n useEffect(() => {\n if (isDropdownExpanded && isStickied) {\n applyBodyStyleClass(\"add\");\n } else {\n applyBodyStyleClass(\"remove\");\n }\n }, [isDropdownExpanded, isStickied]);\n\n useEffect(() => {\n setViewportHeight(window.innerHeight);\n const handleResize = () => {\n setViewportHeight(window.innerHeight);\n };\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n const callback = (entries: IntersectionObserverEntry[]) => {\n const [entry] = entries;\n setIsStickied(!entry.isIntersecting);\n };\n\n const observer = new IntersectionObserver(callback, {\n threshold: 1,\n rootMargin: `-${stickyOffset}px 0px 0px 0px`,\n });\n\n if (detectStickyRef.current) {\n observer.observe(detectStickyRef.current);\n }\n\n return () => observer.disconnect();\n }, [stickyOffset]);\n\n useEffect(() => {\n const adjustPadding = () => {\n const dropdown = navWrapperRef?.current;\n if (dropdown) {\n const dropdownRect = dropdown.getBoundingClientRect();\n const spaceToRight =\n document.body.clientWidth - dropdownRect.right;\n const spaceToLeft = dropdownRect.left;\n // Calculate the padding needed to balance the dropdown in the viewport\n const sidePadding = Math.max(spaceToRight, spaceToLeft);\n setDynamicMargin(sidePadding);\n }\n };\n adjustPadding();\n\n window.addEventListener(\"resize\", adjustPadding);\n\n return () => {\n window.removeEventListener(\"resize\", adjustPadding);\n };\n }, []);\n\n useEffect(() => {\n if (isDropdownExpanded) {\n listItemRefs.current[focusedIndex]?.focus();\n }\n }, [isDropdownExpanded, focusedIndex]);\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n\n const addStylesheetForDocumentBody = () => {\n /**\n * This stylesheet is to manipulate the <body>. We only add once\n */\n if (!document.getElementById(STYLESHEET_ID)) {\n const overlayStyleSheet = document.createElement(\"style\");\n overlayStyleSheet.id = STYLESHEET_ID;\n\n const documentWidth = document.documentElement.clientWidth;\n const windowWidth = window.innerWidth;\n const scrollBarWidth = windowWidth - documentWidth;\n\n overlayStyleSheet.innerHTML = `\n\t\t\t\t.${DROPDOWN_OPEN_CLASSNAME} {\n\t\t\t\t\toverflow: hidden;\n\t\t\t\t\tpadding-right: ${scrollBarWidth}px !important;\n\t\t\t\t\t-ms-overflow-style: none;\n\t\t\t\t\tscrollbar-width: none;\n\t\t\t\t}\n\n\t\t\t\t.${DROPDOWN_OPEN_CLASSNAME}::-webkit-scrollbar {\n\t\t\t\t\tdisplay: none;\n\t\t\t\t}\n\t\t\t`;\n\n document.body.appendChild(overlayStyleSheet);\n }\n };\n\n const applyBodyStyleClass = (action: \"add\" | \"remove\") => {\n const isOverlayStyleClassApplied = document.body.classList.contains(\n DROPDOWN_OPEN_CLASSNAME\n );\n\n if (action === \"add\" && !isOverlayStyleClassApplied) {\n document.body.classList.add(DROPDOWN_OPEN_CLASSNAME);\n } else if (action === \"remove\" && isOverlayStyleClassApplied) {\n document.body.classList.remove(DROPDOWN_OPEN_CLASSNAME);\n }\n };\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n\n const handleToggleDropdown = () => {\n setIsDropdownExpanded((prev) => !prev);\n };\n\n const handleDismissBackdrop = () => {\n setIsDropdownExpanded(false);\n };\n\n const handleNavItemClick = (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n item: LocalNavItemProps,\n index: number\n ) => {\n if (onNavItemSelect) {\n onNavItemSelect(e, item, index);\n }\n setIsDropdownExpanded(false);\n };\n\n const handleNavItemKeyDown = (\n e: React.KeyboardEvent<HTMLElement>,\n handleClick: (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>\n ) => void\n ) => {\n const { key } = e;\n\n if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n handleClick(e);\n }\n };\n\n const handleNavSelectKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const { key } = e;\n\n if (key === \"ArrowDown\") {\n e.preventDefault();\n if (!isDropdownExpanded) {\n setIsDropdownExpanded(true);\n }\n setFocusedIndex(0);\n } else if (key === \"ArrowUp\") {\n e.preventDefault();\n if (!isDropdownExpanded) {\n setIsDropdownExpanded(true);\n }\n setFocusedIndex(items.length - 1);\n } else if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n setIsDropdownExpanded(true);\n setFocusedIndex(0);\n } else if (key === \"Tab\") {\n setIsDropdownExpanded(false);\n } else if (key === \"Escape\") {\n setIsDropdownExpanded(false);\n }\n };\n\n const handleNavItemListKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const { key } = e;\n\n if (key === \"ArrowDown\") {\n e.preventDefault();\n const nextIndex = (focusedIndex + 1) % items.length;\n setFocusedIndex(nextIndex);\n } else if (key === \"ArrowUp\") {\n e.preventDefault();\n const prevIndex =\n focusedIndex > 0 ? focusedIndex - 1 : items.length - 1;\n setFocusedIndex(prevIndex);\n } else if (key === \"Tab\") {\n setIsDropdownExpanded(false);\n } else if (key === \"Escape\") {\n setIsDropdownExpanded(false);\n dropdownRef.current?.focus();\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const renderDropdownNavItem = ({\n handleClick,\n isSelected,\n item,\n renderItem,\n index,\n }: LocalNavDropdownItemComponentProps) => {\n const { id, title, titleAddon } = item;\n\n if (renderItem) {\n return (\n <li\n id={id}\n key={index}\n role=\"menuitem\"\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n aria-current={isSelected ? true : undefined}\n tabIndex={-1}\n ref={(el) => {\n listItemRefs.current[index] = el;\n }}\n >\n {renderItem(item, {\n selected: isSelected,\n stickied: isStickied,\n })}\n </li>\n );\n }\n\n return (\n <NavItem\n id={id}\n key={index}\n role=\"menuitem\"\n $isSelected={isSelected && isStickied}\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n aria-current={isSelected ? true : undefined}\n tabIndex={-1}\n ref={(el) => {\n listItemRefs.current[index] = el as HTMLLIElement;\n }}\n >\n {isSelected && (\n <LeftAddon>\n <StyledTickIcon />\n </LeftAddon>\n )}\n {titleAddon ? (\n <TitleContainer>\n {titleAddon.left && (\n <LeftAddon>{titleAddon.left}</LeftAddon>\n )}\n <NavItemLabel $isSelected={isSelected}>\n {title}\n </NavItemLabel>\n {titleAddon.right && (\n <RightAddon>{titleAddon.right}</RightAddon>\n )}\n </TitleContainer>\n ) : (\n <NavItemLabel $isSelected={isSelected}>\n {title}\n </NavItemLabel>\n )}\n </NavItem>\n );\n };\n\n return (\n <>\n <span ref={detectStickyRef} data-testid={\"sticky-ref\"} />\n <NavWrapper\n $isStickied={isStickied}\n $sideMargin={dynamicMargin}\n $stickyOffset={stickyOffset}\n ref={navWrapperRef}\n id={id}\n data-testid={navTestId}\n className={className}\n >\n <NavSelect\n ref={dropdownRef}\n role=\"button\"\n onClick={handleToggleDropdown}\n onKeyDown={handleNavSelectKeyDown}\n data-testid={`${navTestId}-label`}\n $isDropdownExpanded={isDropdownExpanded}\n aria-haspopup=\"true\"\n aria-expanded={isDropdownExpanded}\n aria-controls={dropdownListId}\n tabIndex={0}\n >\n <Typography.BodyBL weight=\"semibold\">\n {labelText}\n </Typography.BodyBL>\n <NavSelectIcon $isDropdownExpanded={isDropdownExpanded} />\n </NavSelect>\n {isDropdownExpanded && (\n <NavItemList\n id={dropdownListId}\n role=\"menu\"\n onKeyDown={handleNavItemListKeyDown}\n data-testid={`${navTestId}-dropdown-list`}\n $viewportHeight={\n viewportHeight - dropdowntHeight - stickyOffset\n }\n >\n {items.map((item, i) =>\n renderDropdownNavItem({\n handleClick: (e) =>\n handleNavItemClick(e, item, i),\n isSelected: i === selectedItemIndex,\n item,\n renderItem,\n index: i,\n })\n )}\n </NavItemList>\n )}\n {isDropdownExpanded && isStickied && (\n <Backdrop onClick={handleDismissBackdrop} />\n )}\n </NavWrapper>\n </>\n );\n};\n\nexport const LocalNavDropdown = React.forwardRef(Component);\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\nconst STYLESHEET_ID = \"lifesg-ds-local-nav-dropdown-stylesheet\";\nconst DROPDOWN_OPEN_CLASSNAME = \"lifesg-ds-local-nav-dropdown-open\";\n"],"names":["LocalNavDropdown","React","forwardRef","defaultLabel","stickyOffset","onNavItemSelect","items","selectedItemIndex","id","testId","className","renderItem","ref","detectStickyRef","useRef","dropdownRef","navWrapperRef","listItemRefs","isStickied","setIsStickied","useState","isDropdownExpanded","setIsDropdownExpanded","viewportHeight","setViewportHeight","dropdowntHeight","setDropdownHeight","dynamicMargin","setDynamicMargin","focusedIndex","setFocusedIndex","navTestId","dropdownListId","useId","useImperativeHandle","current","labelText","title","useEffect","dropdownHeight","getBoundingClientRect","height","addStylesheetForDocumentBody","applyBodyStyleClass","window","innerHeight","handleResize","addEventListener","removeEventListener","observer","IntersectionObserver","entries","entry","isIntersecting","threshold","rootMargin","observe","disconnect","adjustPadding","dropdown","dropdownRect","spaceToRight","document","body","clientWidth","right","spaceToLeft","left","sidePadding","Math","max","_a","focus","getElementById","STYLESHEET_ID","overlayStyleSheet","createElement","documentWidth","documentElement","scrollBarWidth","innerWidth","innerHTML","DROPDOWN_OPEN_CLASSNAME","appendChild","action","isOverlayStyleClassApplied","classList","contains","remove","add","handleNavItemKeyDown","e","handleClick","key","preventDefault","_jsxs","_Fragment","children","_jsx","NavWrapper","$isStickied","$sideMargin","$stickyOffset","NavSelect","role","onClick","prev","onKeyDown","length","$isDropdownExpanded","tabIndex","Typography","BodyBL","weight","NavSelectIcon","NavItemList","nextIndex","prevIndex","$viewportHeight","map","item","i","isSelected","index","titleAddon","undefined","el","selected","stickied","NavItem","$isSelected","LeftAddon","StyledTickIcon","TitleContainer","NavItemLabel","RightAddon","renderDropdownNavItem","handleNavItemClick","Backdrop"],"mappings":"geAmBA,MAgYaA,OAAmBC,QAAMC,YAhYpB,EAEVC,eACAC,eAAe,EACfC,kBACAC,QACAC,oBACAC,KACA,cAAeC,EACfC,YACAC,cAEJC,KAKA,MAAMC,EAAkBC,EAAAA,OAAwB,MAC1CC,EAAcD,EAAAA,OAAuB,MACrCE,EAAgBF,EAAAA,OAAoB,MACpCG,EAAeH,EAAAA,OAAiC,KAC/CI,EAAYC,GAAiBC,EAAAA,UAAkB,IAC/CC,EAAoBC,GACvBF,EAAAA,UAAkB,IACfG,EAAgBC,GAAqBJ,EAAAA,SAAS,IAC9CK,EAAiBC,GAAqBN,EAAAA,SAAS,IAC/CO,EAAeC,GAAoBR,EAAAA,SAAS,IAC5CS,EAAcC,GAAmBV,EAAAA,SAAS,GAC3CW,EAAYtB,GAAU,qBACtBuB,EAAiBC,EAAAA,QAEvBC,EAAAA,oBAAoBtB,GAAK,IAAMI,EAAcmB,UAE7C,MAAMC,EAC2B,iBAAtB7B,GACPA,GAAqB,GACrBW,EACMZ,EAAMC,GAAmB8B,MACzBlC,EAMVmC,EAAAA,WAAU,KACN,GAAIvB,EAAYoB,QAAS,CACrB,MAAMI,EACFxB,EAAYoB,QAAQK,wBAAwBC,OAChDf,EAAkBa,EACtB,IACD,IAEHD,EAAAA,WAAU,KACNI,IACO,KACHC,EAAoB,SAAS,IAElC,IAEHL,EAAAA,WAAU,KAEFK,EADAtB,GAAsBH,EACF,MAEA,SACxB,GACD,CAACG,EAAoBH,IAExBoB,EAAAA,WAAU,KACNd,EAAkBoB,OAAOC,aACzB,MAAMC,EAAe,KACjBtB,EAAkBoB,OAAOC,YAAY,EAGzC,OADAD,OAAOG,iBAAiB,SAAUD,GAC3B,IAAMF,OAAOI,oBAAoB,SAAUF,EAAa,GAChE,IAEHR,EAAAA,WAAU,KACN,MAKMW,EAAW,IAAIC,sBALHC,IACd,MAAOC,GAASD,EAChBhC,GAAeiC,EAAMC,eAAe,GAGY,CAChDC,UAAW,EACXC,WAAY,IAAInD,oBAOpB,OAJIS,EAAgBsB,SAChBc,EAASO,QAAQ3C,EAAgBsB,SAG9B,IAAMc,EAASQ,YAAY,GACnC,CAACrD,IAEJkC,EAAAA,WAAU,KACN,MAAMoB,EAAgB,KAClB,MAAMC,EAAW3C,aAAa,EAAbA,EAAemB,QAChC,GAAIwB,EAAU,CACV,MAAMC,EAAeD,EAASnB,wBACxBqB,EACFC,SAASC,KAAKC,YAAcJ,EAAaK,MACvCC,EAAcN,EAAaO,KAE3BC,EAAcC,KAAKC,IAAIT,EAAcK,GAC3CtC,EAAiBwC,EACrB,GAMJ,OAJAV,IAEAd,OAAOG,iBAAiB,SAAUW,GAE3B,KACHd,OAAOI,oBAAoB,SAAUU,EAAc,CACtD,GACF,IAEHpB,EAAAA,WAAU,WACFjB,IACkC,QAAlCkD,EAAAtD,EAAakB,QAAQN,UAAa,IAAA0C,GAAAA,EAAEC,QACxC,GACD,CAACnD,EAAoBQ,IAMxB,MAAMa,EAA+B,KAIjC,IAAKoB,SAASW,eAAeC,GAAgB,CACzC,MAAMC,EAAoBb,SAASc,cAAc,SACjDD,EAAkBnE,GAAKkE,EAEvB,MAAMG,EAAgBf,SAASgB,gBAAgBd,YAEzCe,EADcnC,OAAOoC,WACUH,EAErCF,EAAkBM,UAAY,cACnCC,8DAEeH,iHAKfG,sEAKKpB,SAASC,KAAKoB,YAAYR,EAC9B,GAGEhC,EAAuByC,IACzB,MAAMC,EAA6BvB,SAASC,KAAKuB,UAAUC,SACvDL,GAGW,QAAXE,GAAqBC,EAEH,WAAXD,GAAuBC,GAC9BvB,SAASC,KAAKuB,UAAUE,OAAON,GAF/BpB,SAASC,KAAKuB,UAAUG,IAAIP,EAGhC,EA0BEQ,EAAuB,CACzBC,EACAC,KAIA,MAAMC,IAAEA,GAAQF,EAEJ,UAARE,GAA2B,MAARA,IACnBF,EAAEG,iBACFF,EAAYD,GAChB,EA4HJ,OACII,OAAAC,EAAAA,SAAA,CAAAC,SAAA,CACIC,EAAAA,IAAA,OAAA,CAAMtF,IAAKC,EAAe,cAAe,eACzCkF,EAAAA,KAACI,EAAAA,WAAU,CAAAC,YACMlF,EAAUmF,YACV1E,EAAa2E,cACXlG,EACfQ,IAAKI,EACLR,GAAIA,EAAE,cACOuB,EACbrB,UAAWA,EAASuF,SAAA,CAEpBF,EAAAA,KAACQ,YAAS,CACN3F,IAAKG,EACLyF,KAAK,SACLC,QAzKa,KACzBnF,GAAuBoF,IAAUA,GAAK,EAyK1BC,UAzIgBhB,IAC5B,MAAME,IAAEA,GAAQF,EAEJ,cAARE,GACAF,EAAEG,iBACGzE,GACDC,GAAsB,GAE1BQ,EAAgB,IACD,YAAR+D,GACPF,EAAEG,iBACGzE,GACDC,GAAsB,GAE1BQ,EAAgBxB,EAAMsG,OAAS,IAChB,UAARf,GAA2B,MAARA,GAC1BF,EAAEG,iBACFxE,GAAsB,GACtBQ,EAAgB,KACD,QAAR+D,GAEQ,WAARA,IADPvE,GAAsB,EAG1B,EAkH6C,cACpB,GAAGS,UAAiB8E,oBACZxF,EAAkB,gBACzB,OAAM,gBACLA,EAAkB,gBAClBW,EACf8E,SAAU,EAACb,SAAA,CAEXC,EAAAA,IAACa,EAAAA,WAAWC,OAAM,CAACC,OAAO,WAAUhB,SAC/B7D,IAEL8D,EAAAA,IAACgB,gBAAa,CAAAL,oBAAsBxF,OAEvCA,GACG6E,EAAAA,IAACiB,cAAW,CACR3G,GAAIwB,EACJwE,KAAK,OACLG,UAhIchB,UAC9B,MAAME,IAAEA,GAAQF,EAEhB,GAAY,cAARE,EAAqB,CACrBF,EAAEG,iBACF,MAAMsB,GAAavF,EAAe,GAAKvB,EAAMsG,OAC7C9E,EAAgBsF,EACpB,MAAO,GAAY,YAARvB,EAAmB,CAC1BF,EAAEG,iBACF,MAAMuB,EACFxF,EAAe,EAAIA,EAAe,EAAIvB,EAAMsG,OAAS,EACzD9E,EAAgBuF,EACpB,KAAmB,QAARxB,EACPvE,GAAsB,GACP,WAARuE,IACPvE,GAAsB,GACH,QAAnBiD,EAAAxD,EAAYoB,eAAO,IAAAoC,GAAAA,EAAEC,QACzB,EA+GmD,cACtB,GAAGzC,kBAAyBuF,gBAErC/F,EAAiBE,EAAkBrB,EAAY6F,SAGlD3F,EAAMiH,KAAI,CAACC,EAAMC,IA9GR,GAC1B7B,cACA8B,aACAF,OACA7G,aACAgH,YAEA,MAAMnH,GAAEA,EAAE6B,MAAEA,EAAKuF,WAAEA,GAAeJ,EAElC,OAAI7G,EAEIuF,YACI1F,GAAIA,EAEJgG,KAAK,WACLC,QAASb,EACTe,UAAYhB,GAAMD,EAAqBC,EAAGC,oBAC5B8B,QAAoBG,EAClCf,UAAU,EACVlG,IAAMkH,IACF7G,EAAakB,QAAQwF,GAASG,CAAE,EACnC7B,SAEAtF,EAAW6G,EAAM,CACdO,SAAUL,EACVM,SAAU9G,KAZTyG,GAmBb5B,EAAAA,KAACkC,EAAAA,QAAO,CACJzH,GAAIA,EAEJgG,KAAK,WAAU0B,YACFR,GAAcxG,EAC3BuF,QAASb,EACTe,UAAYhB,GAAMD,EAAqBC,EAAGC,GAAY,iBACxC8B,QAAoBG,EAClCf,UAAU,EACVlG,IAAMkH,IACF7G,EAAakB,QAAQwF,GAASG,CAAmB,EACpD7B,SAAA,CAEAyB,GACGxB,EAAAA,IAACiC,EAAAA,UAAS,CAAAlC,SACNC,EAAAA,IAACkC,EAAAA,qBAGRR,EACG7B,EAAAA,KAACsC,EAAAA,eAAc,CAAApC,SAAA,CACV2B,EAAWzD,MACR+B,EAAAA,IAACiC,EAAAA,UAAS,CAAAlC,SAAE2B,EAAWzD,OAE3B+B,EAAAA,IAACoC,EAAAA,aAAY,CAAAJ,YAAcR,EAAUzB,SAChC5D,IAEJuF,EAAW3D,OACRiC,EAAAA,IAACqC,EAAAA,WAAU,CAAAtC,SAAE2B,EAAW3D,WAIhCiC,MAACoC,EAAAA,aAAY,CAAAJ,YAAcR,EAAUzB,SAChC5D,MA9BJsF,EAiCC,EA4CMa,CAAsB,CAClB5C,YAAcD,GA3Lf,EACvBA,EACA6B,EACAG,KAEItH,GACAA,EAAgBsF,EAAG6B,EAAMG,GAE7BrG,GAAsB,EAAM,EAoLAmH,CAAmB9C,EAAG6B,EAAMC,GAChCC,WAAYD,IAAMlH,EAClBiH,OACA7G,aACAgH,MAAOF,QAKtBpG,GAAsBH,GACnBgF,EAAAA,IAACwC,EAAAA,SAAQ,CAACjC,QA1MI,KAC1BnF,GAAsB,EAAM,SA4MzB,IASLoD,EAAgB,0CAChBQ,EAA0B"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var e=require("@lifesg/react-icons/chevron-down"),i=require("@lifesg/react-icons/tick"),o=require("styled-components"),t=require("../../theme/index.js");function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var a=r(o);const n=a.default(e.ChevronDownIcon)`
|
|
2
2
|
color: ${t.Colour.icon};
|
|
3
3
|
transition: transform ${t.Motion["duration-250"]} ${t.Motion["ease-default"]};
|
|
4
|
-
transform: rotate(${
|
|
5
|
-
`,
|
|
4
|
+
transform: rotate(${e=>e.$isDropdownExpanded?180:0}deg);
|
|
5
|
+
`,s=a.default.div`
|
|
6
6
|
cursor: pointer;
|
|
7
7
|
background: ${t.Colour.bg};
|
|
8
8
|
padding: ${t.Spacing["spacing-12"]} ${t.Spacing["spacing-16"]};
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
box-shadow: 0 0 ${t.Border["width-010"]} ${t.Border["width-010"]}
|
|
11
11
|
${t.Colour.border};
|
|
12
12
|
border-radius: ${t.Radius.sm};
|
|
13
|
-
${
|
|
13
|
+
${e=>e.$isDropdownExpanded&&o.css`
|
|
14
14
|
border-bottom-left-radius: ${t.Radius.none};
|
|
15
15
|
border-bottom-right-radius: ${t.Radius.none};
|
|
16
16
|
`}
|
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
border-radius: ${t.Radius.sm};
|
|
27
27
|
}
|
|
28
28
|
`,d=a.default.li`
|
|
29
|
-
padding: ${
|
|
29
|
+
padding: ${e=>e.$isSelected?o.css`
|
|
30
30
|
${t.Spacing["spacing-12"]} ${t.Spacing["spacing-8"]}
|
|
31
31
|
${t.Spacing["spacing-12"]} 0
|
|
32
|
-
`:
|
|
32
|
+
`:o.css`
|
|
33
33
|
${t.Spacing["spacing-12"]} ${t.Spacing["spacing-8"]}
|
|
34
34
|
${t.Spacing["spacing-12"]} ${t.Spacing["spacing-32"]}
|
|
35
35
|
`};
|
|
36
|
-
background: ${
|
|
36
|
+
background: ${e=>e.$isSelected?t.Colour["bg-primary-subtlest"]:t.Colour.bg};
|
|
37
37
|
/* Ensures that the tick mark is positioned relative to the selected item */
|
|
38
38
|
position: relative;
|
|
39
39
|
display: flex;
|
|
@@ -60,14 +60,28 @@
|
|
|
60
60
|
/* Enables vertical scrolling */
|
|
61
61
|
overflow-y: auto;
|
|
62
62
|
/* Set a max height for the dropdown list */
|
|
63
|
-
max-height: ${
|
|
63
|
+
max-height: ${e=>e.$viewportHeight}px;
|
|
64
64
|
`,c=a.default.div`
|
|
65
65
|
${t.Font["body-baseline-regular"]}
|
|
66
|
-
color: ${
|
|
67
|
-
`,
|
|
66
|
+
color: ${e=>e.$isSelected?t.Colour["text-selected"]:t.Colour.text};
|
|
67
|
+
`,p=a.default.span`
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
gap: ${t.Spacing["spacing-8"]};
|
|
71
|
+
flex: 1;
|
|
72
|
+
`,u=a.default.span`
|
|
73
|
+
display: inline-flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
align-self: flex-start;
|
|
76
|
+
min-height: ${t.Font.Spec["body-lh-baseline"]};
|
|
77
|
+
`,g=a.default.span`
|
|
78
|
+
display: inline-flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
margin-left: auto;
|
|
81
|
+
`,$=a.default(i.TickIcon)`
|
|
68
82
|
color: ${t.Colour["icon-selected"]};
|
|
69
83
|
margin: 0 ${t.Spacing["spacing-8"]};
|
|
70
|
-
`,
|
|
84
|
+
`,f=a.default.div`
|
|
71
85
|
position: fixed;
|
|
72
86
|
top: 0;
|
|
73
87
|
right: 0;
|
|
@@ -75,15 +89,15 @@
|
|
|
75
89
|
bottom: 0;
|
|
76
90
|
background-color: ${t.Colour["overlay-strong"]};
|
|
77
91
|
z-index: -1;
|
|
78
|
-
|
|
92
|
+
`,b=a.default.nav`
|
|
79
93
|
display: block;
|
|
80
94
|
position: sticky;
|
|
81
|
-
top: ${
|
|
95
|
+
top: ${e=>e.$stickyOffset}px;
|
|
82
96
|
width: 100%;
|
|
83
97
|
z-index: 10;
|
|
84
98
|
|
|
85
|
-
${({$isStickied:
|
|
86
|
-
${
|
|
99
|
+
${({$isStickied:e,$sideMargin:i})=>e&&o.css`
|
|
100
|
+
${s} {
|
|
87
101
|
${i&&`margin: 0 -${i}px;`}
|
|
88
102
|
padding: ${t.Spacing["spacing-12"]} ${t.Spacing["spacing-16"]};
|
|
89
103
|
border-radius: ${t.Radius.none};
|
|
@@ -96,5 +110,5 @@
|
|
|
96
110
|
border-radius-bottom-right: ${t.Radius.sm};
|
|
97
111
|
}
|
|
98
112
|
`}
|
|
99
|
-
`;exports.Backdrop=
|
|
113
|
+
`;exports.Backdrop=f,exports.LeftAddon=u,exports.NavItem=d,exports.NavItemLabel=c,exports.NavItemList=l,exports.NavSelect=s,exports.NavSelectIcon=n,exports.NavWrapper=b,exports.RightAddon=g,exports.StyledTickIcon=$,exports.TitleContainer=p;
|
|
100
114
|
//# sourceMappingURL=local-nav-dropdown.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-nav-dropdown.styles.js","sources":["../../../../src/local-nav/local-nav-dropdown/local-nav-dropdown.styles.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@lifesg/react-icons/chevron-down\";\nimport { TickIcon } from \"@lifesg/react-icons/tick\";\nimport styled, { css } from \"styled-components\";\nimport { Border, Colour, Font, Motion, Radius, Spacing } from \"../../theme\";\n\n// =============================================================================\n// STYLE INTERFACES, transient props are denoted with $\n// See more https://styled-components.com/docs/api#transient-props\n// =============================================================================\ninterface DropdownNavStyleProps {\n $isStickied?: boolean;\n $stickyOffset: number;\n $sideMargin?: number;\n}\n\ninterface NavItemListStyleProps {\n $viewportHeight?: number;\n}\n\ninterface NavItemStyleProps {\n $isSelected?: boolean;\n}\ninterface DropdownExpandedProps {\n $isDropdownExpanded: boolean;\n}\n\ninterface NavIconStyleProps extends DropdownExpandedProps {}\ninterface NavLabelStyleProps extends DropdownExpandedProps {}\n\n// =============================================================================\n// STYLING\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// NAV SELECT\n// -----------------------------------------------------------------------------\n\nexport const NavSelectIcon = styled(ChevronDownIcon)<NavIconStyleProps>`\n color: ${Colour[\"icon\"]};\n transition: transform ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transform: rotate(${(props) => (props.$isDropdownExpanded ? 180 : 0)}deg);\n`;\n\nexport const NavSelect = styled.div<NavLabelStyleProps>`\n cursor: pointer;\n background: ${Colour[\"bg\"]};\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n overflow: hidden;\n box-shadow: 0 0 ${Border[\"width-010\"]} ${Border[\"width-010\"]}\n ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n ${(props) =>\n props.$isDropdownExpanded &&\n css`\n border-bottom-left-radius: ${Radius[\"none\"]};\n border-bottom-right-radius: ${Radius[\"none\"]};\n `}\n display: flex;\n justify-content: space-between;\n align-items: center;\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transition-property: background, border-radius, box-shadow, transform;\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 2px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n\n// -----------------------------------------------------------------------------\n// NAV ITEMS\n// -----------------------------------------------------------------------------\n\nexport const NavItem = styled.li<NavItemStyleProps>`\n padding: ${(props) =>\n props.$isSelected\n ? css`\n ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]} \n ${Spacing[\"spacing-12\"]} 0\n `\n : css`\n ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]}\n ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-32\"]}\n `};\n background: ${(props) =>\n props.$isSelected ? Colour[\"bg-primary-subtlest\"] : Colour[\"bg\"]};\n /* Ensures that the tick mark is positioned relative to the selected item */\n position: relative;\n display: flex;\n /* Vertically align text and tick */\n align-items: center;\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 0px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n\nexport const NavItemList = styled.ul<NavItemListStyleProps>`\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transform-origin: top;\n list-style-type: none;\n padding: 0 ${Spacing[\"spacing-8\"]};\n margin: 0;\n background: ${Colour[\"bg\"]};\n cursor: pointer;\n box-shadow: 0 0 ${Border[\"width-010\"]} ${Border[\"width-010\"]}\n ${Colour[\"border\"]};\n border-bottom-right-radius: ${Radius[\"sm\"]};\n border-bottom-left-radius: ${Radius[\"sm\"]};\n /* Enables vertical scrolling */\n overflow-y: auto;\n /* Set a max height for the dropdown list */\n max-height: ${(props) => props.$viewportHeight}px;\n`;\n\nexport const NavItemLabel = styled.div<NavItemStyleProps>`\n ${Font[\"body-baseline-regular\"]}\n color: ${(props) =>\n props.$isSelected ? Colour[\"text-selected\"] : Colour[\"text\"]};\n`;\n\nexport const StyledTickIcon = styled(TickIcon)`\n color: ${Colour[\"icon-selected\"]};\n margin: 0 ${Spacing[\"spacing-8\"]};\n`;\n\n// -----------------------------------------------------------------------------\n// MAIN\n// -----------------------------------------------------------------------------\n\nexport const Backdrop = styled.div`\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n bottom: 0;\n background-color: ${Colour[\"overlay-strong\"]};\n z-index: -1;\n`;\n\nexport const NavWrapper = styled.nav<DropdownNavStyleProps>`\n display: block;\n position: sticky;\n top: ${(props) => props.$stickyOffset}px;\n width: 100%;\n z-index: 10;\n\n ${({ $isStickied, $sideMargin }) =>\n $isStickied &&\n css`\n ${NavSelect} {\n ${$sideMargin && `margin: 0 -${$sideMargin}px;`}\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n border-radius: ${Radius[\"none\"]};\n }\n\n ${NavItemList} {\n ${$sideMargin && `margin-left: -${$sideMargin}px;`}\n ${$sideMargin && `margin-right: -${$sideMargin}px;`}\n border-radius-bottom-left: ${Radius.sm};\n border-radius-bottom-right: ${Radius.sm};\n }\n `}\n`;\n"],"names":["NavSelectIcon","styled","ChevronDownIcon","Colour","Motion","props","$isDropdownExpanded","NavSelect","div","Spacing","Border","Radius","css","NavItem","li","$isSelected","NavItemList","ul","$viewportHeight","NavItemLabel","Font","StyledTickIcon","TickIcon","Backdrop","NavWrapper","nav","$stickyOffset","$isStickied","$sideMargin","sm"],"mappings":"+PAqCaA,EAAgBC,EAAAA,QAAOC,EAAAA,gBAAmC;aAC1DC,EAAAA,OAAa;4BACEC,EAAAA,OAAO,mBAAmBA,EAAAA,OAAO;wBACpCC,GAAWA,EAAMC,oBAAsB,IAAM;EAGzDC,EAAYN,EAAAA,QAAOO,GAAuB;;kBAErCL,EAAAA,OAAW;eACdM,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;;sBAE1BC,EAAAA,OAAO,gBAAgBA,EAAAA,OAAO;UAC1CP,EAAAA,OAAe;qBACJQ,EAAAA,OAAW;MACzBN,GACCA,EAAMC,qBACNM,KAAG;yCAC8BD,EAAAA,OAAa;0CACZA,EAAAA,OAAa;;;;;sBAKjCP,EAAAA,OAAO,mBAAmBA,EAAAA,OAAO;;;;6BAI1BD,EAAAA,OAAO;;yBAEXQ,EAAAA,OAAW;;EAQvBE,EAAUZ,EAAAA,QAAOa,EAAqB;eACnCT,GACRA,EAAMU,YACAH,KAAG;oBACGH,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;oBACjCA,EAAAA,QAAQ;gBAEdG,KAAG;oBACGH,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;oBACjCA,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;;kBAElCJ,GACXA,EAAMU,YAAcZ,EAAAA,OAAO,uBAAyBA,SAAW;;;;;;;;6BAQ1CA,EAAAA,OAAO;;yBAEXQ,EAAAA,OAAW;;EAIvBK,EAAcf,EAAAA,QAAOgB,EAAyB;sBACrCb,EAAAA,OAAO,mBAAmBA,EAAAA,OAAO;;;iBAGtCK,EAAAA,QAAQ;;kBAEPN,EAAAA,OAAW;;sBAEPO,EAAAA,OAAO,gBAAgBA,EAAAA,OAAO;UAC1CP,EAAAA,OAAe;kCACSQ,EAAAA,OAAW;iCACZA,EAAAA,OAAW;;;;kBAIzBN,GAAUA,EAAMa;EAGtBC,EAAelB,EAAAA,QAAOO,GAAsB;MACnDY,EAAAA,KAAK;aACGf,GACNA,EAAMU,YAAcZ,EAAAA,OAAO,iBAAmBA,SAAa;EAGtDkB,EAAiBpB,EAAAA,QAAOqB,EAAAA,SAAS;
|
|
1
|
+
{"version":3,"file":"local-nav-dropdown.styles.js","sources":["../../../../src/local-nav/local-nav-dropdown/local-nav-dropdown.styles.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@lifesg/react-icons/chevron-down\";\nimport { TickIcon } from \"@lifesg/react-icons/tick\";\nimport styled, { css } from \"styled-components\";\nimport { Border, Colour, Font, Motion, Radius, Spacing } from \"../../theme\";\n\n// =============================================================================\n// STYLE INTERFACES, transient props are denoted with $\n// See more https://styled-components.com/docs/api#transient-props\n// =============================================================================\ninterface DropdownNavStyleProps {\n $isStickied?: boolean;\n $stickyOffset: number;\n $sideMargin?: number;\n}\n\ninterface NavItemListStyleProps {\n $viewportHeight?: number;\n}\n\ninterface NavItemStyleProps {\n $isSelected?: boolean;\n}\ninterface DropdownExpandedProps {\n $isDropdownExpanded: boolean;\n}\n\ninterface NavIconStyleProps extends DropdownExpandedProps {}\ninterface NavLabelStyleProps extends DropdownExpandedProps {}\n\n// =============================================================================\n// STYLING\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// NAV SELECT\n// -----------------------------------------------------------------------------\n\nexport const NavSelectIcon = styled(ChevronDownIcon)<NavIconStyleProps>`\n color: ${Colour[\"icon\"]};\n transition: transform ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transform: rotate(${(props) => (props.$isDropdownExpanded ? 180 : 0)}deg);\n`;\n\nexport const NavSelect = styled.div<NavLabelStyleProps>`\n cursor: pointer;\n background: ${Colour[\"bg\"]};\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n overflow: hidden;\n box-shadow: 0 0 ${Border[\"width-010\"]} ${Border[\"width-010\"]}\n ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n ${(props) =>\n props.$isDropdownExpanded &&\n css`\n border-bottom-left-radius: ${Radius[\"none\"]};\n border-bottom-right-radius: ${Radius[\"none\"]};\n `}\n display: flex;\n justify-content: space-between;\n align-items: center;\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transition-property: background, border-radius, box-shadow, transform;\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 2px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n\n// -----------------------------------------------------------------------------\n// NAV ITEMS\n// -----------------------------------------------------------------------------\n\nexport const NavItem = styled.li<NavItemStyleProps>`\n padding: ${(props) =>\n props.$isSelected\n ? css`\n ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]} \n ${Spacing[\"spacing-12\"]} 0\n `\n : css`\n ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]}\n ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-32\"]}\n `};\n background: ${(props) =>\n props.$isSelected ? Colour[\"bg-primary-subtlest\"] : Colour[\"bg\"]};\n /* Ensures that the tick mark is positioned relative to the selected item */\n position: relative;\n display: flex;\n /* Vertically align text and tick */\n align-items: center;\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 0px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n\nexport const NavItemList = styled.ul<NavItemListStyleProps>`\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transform-origin: top;\n list-style-type: none;\n padding: 0 ${Spacing[\"spacing-8\"]};\n margin: 0;\n background: ${Colour[\"bg\"]};\n cursor: pointer;\n box-shadow: 0 0 ${Border[\"width-010\"]} ${Border[\"width-010\"]}\n ${Colour[\"border\"]};\n border-bottom-right-radius: ${Radius[\"sm\"]};\n border-bottom-left-radius: ${Radius[\"sm\"]};\n /* Enables vertical scrolling */\n overflow-y: auto;\n /* Set a max height for the dropdown list */\n max-height: ${(props) => props.$viewportHeight}px;\n`;\n\nexport const NavItemLabel = styled.div<NavItemStyleProps>`\n ${Font[\"body-baseline-regular\"]}\n color: ${(props) =>\n props.$isSelected ? Colour[\"text-selected\"] : Colour[\"text\"]};\n`;\n\nexport const TitleContainer = styled.span`\n display: flex;\n align-items: center;\n gap: ${Spacing[\"spacing-8\"]};\n flex: 1;\n`;\n\n/* Keeps the left addon aligned with the first line when the title wraps. */\nexport const LeftAddon = styled.span`\n display: inline-flex;\n align-items: center;\n align-self: flex-start;\n min-height: ${Font.Spec[\"body-lh-baseline\"]};\n`;\n\n/* Flushed right; stays vertically centred against the (possibly wrapped) title. */\nexport const RightAddon = styled.span`\n display: inline-flex;\n align-items: center;\n margin-left: auto;\n`;\n\nexport const StyledTickIcon = styled(TickIcon)`\n color: ${Colour[\"icon-selected\"]};\n margin: 0 ${Spacing[\"spacing-8\"]};\n`;\n\n// -----------------------------------------------------------------------------\n// MAIN\n// -----------------------------------------------------------------------------\n\nexport const Backdrop = styled.div`\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n bottom: 0;\n background-color: ${Colour[\"overlay-strong\"]};\n z-index: -1;\n`;\n\nexport const NavWrapper = styled.nav<DropdownNavStyleProps>`\n display: block;\n position: sticky;\n top: ${(props) => props.$stickyOffset}px;\n width: 100%;\n z-index: 10;\n\n ${({ $isStickied, $sideMargin }) =>\n $isStickied &&\n css`\n ${NavSelect} {\n ${$sideMargin && `margin: 0 -${$sideMargin}px;`}\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n border-radius: ${Radius[\"none\"]};\n }\n\n ${NavItemList} {\n ${$sideMargin && `margin-left: -${$sideMargin}px;`}\n ${$sideMargin && `margin-right: -${$sideMargin}px;`}\n border-radius-bottom-left: ${Radius.sm};\n border-radius-bottom-right: ${Radius.sm};\n }\n `}\n`;\n"],"names":["NavSelectIcon","styled","ChevronDownIcon","Colour","Motion","props","$isDropdownExpanded","NavSelect","div","Spacing","Border","Radius","css","NavItem","li","$isSelected","NavItemList","ul","$viewportHeight","NavItemLabel","Font","TitleContainer","span","LeftAddon","Spec","RightAddon","StyledTickIcon","TickIcon","Backdrop","NavWrapper","nav","$stickyOffset","$isStickied","$sideMargin","sm"],"mappings":"+PAqCaA,EAAgBC,EAAAA,QAAOC,EAAAA,gBAAmC;aAC1DC,EAAAA,OAAa;4BACEC,EAAAA,OAAO,mBAAmBA,EAAAA,OAAO;wBACpCC,GAAWA,EAAMC,oBAAsB,IAAM;EAGzDC,EAAYN,EAAAA,QAAOO,GAAuB;;kBAErCL,EAAAA,OAAW;eACdM,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;;sBAE1BC,EAAAA,OAAO,gBAAgBA,EAAAA,OAAO;UAC1CP,EAAAA,OAAe;qBACJQ,EAAAA,OAAW;MACzBN,GACCA,EAAMC,qBACNM,KAAG;yCAC8BD,EAAAA,OAAa;0CACZA,EAAAA,OAAa;;;;;sBAKjCP,EAAAA,OAAO,mBAAmBA,EAAAA,OAAO;;;;6BAI1BD,EAAAA,OAAO;;yBAEXQ,EAAAA,OAAW;;EAQvBE,EAAUZ,EAAAA,QAAOa,EAAqB;eACnCT,GACRA,EAAMU,YACAH,KAAG;oBACGH,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;oBACjCA,EAAAA,QAAQ;gBAEdG,KAAG;oBACGH,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;oBACjCA,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;;kBAElCJ,GACXA,EAAMU,YAAcZ,EAAAA,OAAO,uBAAyBA,SAAW;;;;;;;;6BAQ1CA,EAAAA,OAAO;;yBAEXQ,EAAAA,OAAW;;EAIvBK,EAAcf,EAAAA,QAAOgB,EAAyB;sBACrCb,EAAAA,OAAO,mBAAmBA,EAAAA,OAAO;;;iBAGtCK,EAAAA,QAAQ;;kBAEPN,EAAAA,OAAW;;sBAEPO,EAAAA,OAAO,gBAAgBA,EAAAA,OAAO;UAC1CP,EAAAA,OAAe;kCACSQ,EAAAA,OAAW;iCACZA,EAAAA,OAAW;;;;kBAIzBN,GAAUA,EAAMa;EAGtBC,EAAelB,EAAAA,QAAOO,GAAsB;MACnDY,EAAAA,KAAK;aACGf,GACNA,EAAMU,YAAcZ,EAAAA,OAAO,iBAAmBA,SAAa;EAGtDkB,EAAiBpB,EAAAA,QAAOqB,IAAI;;;WAG9Bb,EAAAA,QAAQ;;EAKNc,EAAYtB,EAAAA,QAAOqB,IAAI;;;;kBAIlBF,EAAAA,KAAKI,KAAK;EAIfC,EAAaxB,EAAAA,QAAOqB,IAAI;;;;EAMxBI,EAAiBzB,EAAAA,QAAO0B,EAAAA,SAAS;aACjCxB,EAAAA,OAAO;gBACJM,EAAAA,QAAQ;EAOXmB,EAAW3B,EAAAA,QAAOO,GAAG;;;;;;wBAMVL,EAAAA,OAAO;;EAIlB0B,EAAa5B,EAAAA,QAAO6B,GAA0B;;;WAG/CzB,GAAUA,EAAM0B;;;;MAItB,EAAGC,cAAaC,iBACdD,GACApB,KAAG;cACGL;kBACI0B,GAAe,cAAcA;2BACpBxB,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;iCAC3BE,EAAAA,OAAa;;;cAGhCK;kBACIiB,GAAe,iBAAiBA;kBAChCA,GAAe,kBAAkBA;6CACNtB,EAAAA,OAAOuB;8CACNvB,EAAAA,OAAOuB;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react/jsx-runtime"),t=require("react"),n=require("./local-nav-menu.styles.js");function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}const
|
|
1
|
+
"use strict";var e=require("react/jsx-runtime"),t=require("react"),n=require("./local-nav-menu.styles.js");function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}const i=r(t).default.forwardRef((({onNavItemSelect:t,items:r,selectedItemIndex:i,id:d,"data-testid":l,className:a,renderItem:s},c)=>{const o=l||"local-nav-menu";return e.jsx(n.Nav,{ref:c,id:d,className:a,"data-testid":o,children:r.map(((r,d)=>(({handleClick:t,isSelected:r,item:i,renderItem:d,index:l})=>{const{id:a,title:s,titleAddon:c}=i;return e.jsx(n.NavItem,{id:a,$isSelected:r,children:e.jsx(n.NavItemContent,{role:"link",onClick:t,onKeyDown:e=>((e,t)=>{const{key:n}=e;"Enter"!==n&&" "!==n||(e.preventDefault(),t(e))})(e,t),tabIndex:0,"aria-current":!!r||void 0,children:(()=>{if(d)return d(i,{selected:r});const t=e.jsx(n.TextLabel,{weight:r?"semibold":"regular",children:s});return c?e.jsxs(n.TitleContainer,{children:[c.left&&e.jsx(n.LeftAddon,{children:c.left}),t,c.right&&e.jsx(n.RightAddon,{children:c.right})]}):t})()})},l)})({handleClick:e=>t(e,r,d),isSelected:d===i,item:r,renderItem:s,index:d})))})}));exports.LocalNavMenu=i;
|
|
2
2
|
//# sourceMappingURL=local-nav-menu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-nav-menu.js","sources":["../../../../src/local-nav/local-nav-menu/local-nav-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport { LocalNavMenuItemComponentProps } from \"../internal-types\";\nimport { LocalNavMenuProps } from \"../types\";\nimport {\n Nav,\n NavItem,\n NavItemContent,\n TextLabel,\n} from \"./local-nav-menu.styles\";\n\n/**\n * A sidebar navigation element. The currently visible section will be highlighted.\n *\n * This component should be placed inside a container that aligns it to the side.\n * The container can also have `position: sticky` in order to make it a sticky sidebar.\n */\nconst Component = (\n {\n onNavItemSelect,\n items,\n selectedItemIndex,\n id,\n \"data-testid\": dataTestId,\n className,\n renderItem,\n }: LocalNavMenuProps,\n ref: React.Ref<HTMLUListElement>\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const localNavMenuId = dataTestId || \"local-nav-menu\";\n\n // =============================================================================\n // EVENT HANDLERS\n // ============================================================================\n const handleNavItemKeyDown = (\n e: React.KeyboardEvent<HTMLElement>,\n handleClick: (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>\n ) => void\n ) => {\n const { key } = e;\n\n if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n handleClick(e);\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const renderLocalNavItem = ({\n handleClick,\n isSelected,\n item,\n renderItem,\n index,\n }: LocalNavMenuItemComponentProps) => {\n const { id, title } = item;\n\n const renderTitle = () => {\n if (renderItem) {\n return renderItem(item, { selected: isSelected });\n }\n
|
|
1
|
+
{"version":3,"file":"local-nav-menu.js","sources":["../../../../src/local-nav/local-nav-menu/local-nav-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport { LocalNavMenuItemComponentProps } from \"../internal-types\";\nimport { LocalNavMenuProps } from \"../types\";\nimport {\n LeftAddon,\n Nav,\n NavItem,\n NavItemContent,\n RightAddon,\n TextLabel,\n TitleContainer,\n} from \"./local-nav-menu.styles\";\n\n/**\n * A sidebar navigation element. The currently visible section will be highlighted.\n *\n * This component should be placed inside a container that aligns it to the side.\n * The container can also have `position: sticky` in order to make it a sticky sidebar.\n */\nconst Component = (\n {\n onNavItemSelect,\n items,\n selectedItemIndex,\n id,\n \"data-testid\": dataTestId,\n className,\n renderItem,\n }: LocalNavMenuProps,\n ref: React.Ref<HTMLUListElement>\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const localNavMenuId = dataTestId || \"local-nav-menu\";\n\n // =============================================================================\n // EVENT HANDLERS\n // ============================================================================\n const handleNavItemKeyDown = (\n e: React.KeyboardEvent<HTMLElement>,\n handleClick: (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>\n ) => void\n ) => {\n const { key } = e;\n\n if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n handleClick(e);\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const renderLocalNavItem = ({\n handleClick,\n isSelected,\n item,\n renderItem,\n index,\n }: LocalNavMenuItemComponentProps) => {\n const { id, title, titleAddon } = item;\n\n const renderTitle = () => {\n if (renderItem) {\n return renderItem(item, { selected: isSelected });\n }\n const label = (\n <TextLabel weight={isSelected ? \"semibold\" : \"regular\"}>\n {title}\n </TextLabel>\n );\n if (!titleAddon) {\n return label;\n }\n return (\n <TitleContainer>\n {titleAddon.left && (\n <LeftAddon>{titleAddon.left}</LeftAddon>\n )}\n {label}\n {titleAddon.right && (\n <RightAddon>{titleAddon.right}</RightAddon>\n )}\n </TitleContainer>\n );\n };\n\n return (\n <NavItem id={id} key={index} $isSelected={isSelected}>\n <NavItemContent\n role=\"link\"\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n tabIndex={0}\n aria-current={isSelected ? true : undefined}\n >\n {renderTitle()}\n </NavItemContent>\n </NavItem>\n );\n };\n return (\n <Nav\n ref={ref}\n id={id}\n className={className}\n data-testid={localNavMenuId}\n >\n {items.map((item, i) => {\n const isSelected = i === selectedItemIndex;\n return renderLocalNavItem({\n handleClick: (e) => onNavItemSelect(e, item, i),\n isSelected,\n item,\n renderItem,\n index: i,\n });\n })}\n </Nav>\n );\n};\n\nexport const LocalNavMenu = React.forwardRef(Component);\n"],"names":["LocalNavMenu","React","forwardRef","onNavItemSelect","items","selectedItemIndex","id","dataTestId","className","renderItem","ref","localNavMenuId","_jsx","Nav","children","map","item","i","handleClick","isSelected","index","title","titleAddon","NavItem","$isSelected","NavItemContent","role","onClick","onKeyDown","e","key","preventDefault","handleNavItemKeyDown","tabIndex","undefined","selected","label","TextLabel","weight","_jsxs","TitleContainer","left","LeftAddon","right","RightAddon","renderTitle","renderLocalNavItem"],"mappings":"mLAmBA,MA2GaA,OAAeC,QAAMC,YA3GhB,EAEVC,kBACAC,QACAC,oBACAC,KACA,cAAeC,EACfC,YACAC,cAEJC,KAKA,MAAMC,EAAiBJ,GAAc,iBAuErC,OACIK,EAAAA,IAACC,EAAAA,IAAG,CACAH,IAAKA,EACLJ,GAAIA,EACJE,UAAWA,EAAS,cACPG,EAAcG,SAE1BV,EAAMW,KAAI,CAACC,EAAMC,IAvDC,GACvBC,cACAC,aACAH,OACAP,aACAW,YAEA,MAAMd,GAAEA,EAAEe,MAAEA,EAAKC,WAAEA,GAAeN,EA2BlC,OACIJ,EAAAA,IAACW,EAAAA,QAAO,CAACjB,GAAIA,EAAEkB,YAA2BL,EAAUL,SAChDF,EAAAA,IAACa,EAAAA,eAAc,CACXC,KAAK,OACLC,QAAST,EACTU,UAAYC,GAzDC,EACzBA,EACAX,KAIA,MAAMY,IAAEA,GAAQD,EAEJ,UAARC,GAA2B,MAARA,IACnBD,EAAEE,iBACFb,EAAYW,GAChB,EA8C8BG,CAAqBH,EAAGX,GAC1Ce,SAAU,EAAC,iBACGd,QAAoBe,EAASpB,SAhCnC,MAChB,GAAIL,EACA,OAAOA,EAAWO,EAAM,CAAEmB,SAAUhB,IAExC,MAAMiB,EACFxB,EAAAA,IAACyB,EAAAA,UAAS,CAACC,OAAQnB,EAAa,WAAa,UAASL,SACjDO,IAGT,OAAKC,EAIDiB,OAACC,EAAAA,eAAc,CAAA1B,SAAA,CACVQ,EAAWmB,MACR7B,EAAAA,IAAC8B,EAAAA,UAAS,CAAA5B,SAAEQ,EAAWmB,OAE1BL,EACAd,EAAWqB,OACR/B,EAAAA,IAACgC,EAAAA,WAAU,CAAA9B,SAAEQ,EAAWqB,WATzBP,CAWU,EAaZS,MARazB,EAUZ,EAYC0B,CAAmB,CACtB5B,YAAcW,GAAM1B,EAAgB0B,EAAGb,EAAMC,GAC7CE,WAHeF,IAAMZ,EAIrBW,OACAP,aACAW,MAAOH,OAGb"}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
"use strict";var e=require("styled-components"),
|
|
1
|
+
"use strict";var e=require("styled-components"),t=require("../../theme/index.js"),i=require("../../typography/typography.js");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n=o(e);const a=n.default.ul`
|
|
2
2
|
list-style-type: none;
|
|
3
3
|
padding: 0;
|
|
4
4
|
margin-top: 0;
|
|
5
|
-
`,n
|
|
5
|
+
`,l=n.default(i.Typography.BodyBL)`
|
|
6
6
|
margin: 0;
|
|
7
|
-
`,
|
|
7
|
+
`,r=n.default.span`
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
gap: ${t.Spacing["spacing-8"]};
|
|
11
|
+
width: 100%;
|
|
12
|
+
`,s=n.default.span`
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
align-self: flex-start;
|
|
16
|
+
min-height: ${t.Font.Spec["body-lh-baseline"]};
|
|
17
|
+
`,p=n.default.span`
|
|
18
|
+
display: inline-flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
margin-left: auto;
|
|
21
|
+
`,d=n.default.li`
|
|
8
22
|
display: block;
|
|
9
23
|
position: relative;
|
|
10
24
|
margin: 0;
|
|
@@ -18,23 +32,23 @@
|
|
|
18
32
|
width: 4px;
|
|
19
33
|
height: 100%;
|
|
20
34
|
top: 0;
|
|
21
|
-
background-color: ${e=>e.$isSelected?
|
|
35
|
+
background-color: ${e=>e.$isSelected?t.Colour["bg-primary"]:t.Colour["bg-primary-subtler"]};
|
|
22
36
|
transition: all 250ms linear;
|
|
23
37
|
}
|
|
24
38
|
|
|
25
39
|
&:hover,
|
|
26
40
|
&:focus-within {
|
|
27
|
-
background-color: ${
|
|
41
|
+
background-color: ${t.Colour["bg-hover-subtle"]};
|
|
28
42
|
}
|
|
29
|
-
`,
|
|
43
|
+
`,u=n.default.div`
|
|
30
44
|
display: block;
|
|
31
|
-
padding: ${
|
|
32
|
-
padding-left: ${
|
|
45
|
+
padding: ${t.Spacing["spacing-16"]};
|
|
46
|
+
padding-left: ${t.Spacing["spacing-20"]};
|
|
33
47
|
|
|
34
48
|
&:focus-visible {
|
|
35
|
-
outline: 2px solid ${
|
|
49
|
+
outline: 2px solid ${t.Colour["focus-ring"]};
|
|
36
50
|
outline-offset: 2px;
|
|
37
|
-
border-radius: ${
|
|
51
|
+
border-radius: ${t.Radius.sm};
|
|
38
52
|
}
|
|
39
|
-
`;exports.Nav=a,exports.NavItem=
|
|
53
|
+
`;exports.LeftAddon=s,exports.Nav=a,exports.NavItem=d,exports.NavItemContent=u,exports.RightAddon=p,exports.TextLabel=l,exports.TitleContainer=r;
|
|
40
54
|
//# sourceMappingURL=local-nav-menu.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-nav-menu.styles.js","sources":["../../../../src/local-nav/local-nav-menu/local-nav-menu.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { Colour, Radius, Spacing } from \"../../theme\";\nimport { Typography } from \"../../typography\";\n\n// =============================================================================\n// STYLE INTERFACES, transient props are denoted with $\n// See more https://styled-components.com/docs/api#transient-props\n// =============================================================================\ninterface NavItemStyleProps {\n $isSelected?: boolean;\n}\n\n// =============================================================================\n// STYLING\n// =============================================================================\n\nexport const Nav = styled.ul`\n list-style-type: none;\n padding: 0;\n margin-top: 0;\n`;\n\nexport const TextLabel = styled(Typography.BodyBL)<NavItemStyleProps>`\n margin: 0;\n`;\n\nexport const NavItem = styled.li<NavItemStyleProps>`\n display: block;\n position: relative;\n margin: 0;\n padding: 0;\n cursor: pointer;\n\n &::before {\n content: \"\";\n position: absolute;\n left: 0;\n width: 4px;\n height: 100%;\n top: 0;\n background-color: ${(props) =>\n props.$isSelected\n ? Colour[\"bg-primary\"]\n : Colour[\"bg-primary-subtler\"]};\n transition: all 250ms linear;\n }\n\n &:hover,\n &:focus-within {\n background-color: ${Colour[\"bg-hover-subtle\"]};\n }\n`;\n\nexport const NavItemContent = styled.div`\n display: block;\n padding: ${Spacing[\"spacing-16\"]};\n padding-left: ${Spacing[\"spacing-20\"]};\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 2px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n"],"names":["Nav","styled","ul","TextLabel","Typography","BodyBL","NavItem","li","props","$isSelected","Colour","NavItemContent","div","
|
|
1
|
+
{"version":3,"file":"local-nav-menu.styles.js","sources":["../../../../src/local-nav/local-nav-menu/local-nav-menu.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { Colour, Font, Radius, Spacing } from \"../../theme\";\nimport { Typography } from \"../../typography\";\n\n// =============================================================================\n// STYLE INTERFACES, transient props are denoted with $\n// See more https://styled-components.com/docs/api#transient-props\n// =============================================================================\ninterface NavItemStyleProps {\n $isSelected?: boolean;\n}\n\n// =============================================================================\n// STYLING\n// =============================================================================\n\nexport const Nav = styled.ul`\n list-style-type: none;\n padding: 0;\n margin-top: 0;\n`;\n\nexport const TextLabel = styled(Typography.BodyBL)<NavItemStyleProps>`\n margin: 0;\n`;\n\nexport const TitleContainer = styled.span`\n display: flex;\n align-items: center;\n gap: ${Spacing[\"spacing-8\"]};\n width: 100%;\n`;\n\n/* Keeps the left addon aligned with the first line when the title wraps. */\nexport const LeftAddon = styled.span`\n display: inline-flex;\n align-items: center;\n align-self: flex-start;\n min-height: ${Font.Spec[\"body-lh-baseline\"]};\n`;\n\n/* Flushed right; stays vertically centred against the (possibly wrapped) title. */\nexport const RightAddon = styled.span`\n display: inline-flex;\n align-items: center;\n margin-left: auto;\n`;\n\nexport const NavItem = styled.li<NavItemStyleProps>`\n display: block;\n position: relative;\n margin: 0;\n padding: 0;\n cursor: pointer;\n\n &::before {\n content: \"\";\n position: absolute;\n left: 0;\n width: 4px;\n height: 100%;\n top: 0;\n background-color: ${(props) =>\n props.$isSelected\n ? Colour[\"bg-primary\"]\n : Colour[\"bg-primary-subtler\"]};\n transition: all 250ms linear;\n }\n\n &:hover,\n &:focus-within {\n background-color: ${Colour[\"bg-hover-subtle\"]};\n }\n`;\n\nexport const NavItemContent = styled.div`\n display: block;\n padding: ${Spacing[\"spacing-16\"]};\n padding-left: ${Spacing[\"spacing-20\"]};\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 2px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n"],"names":["Nav","styled","ul","TextLabel","Typography","BodyBL","TitleContainer","span","Spacing","LeftAddon","Font","Spec","RightAddon","NavItem","li","props","$isSelected","Colour","NavItemContent","div","Radius"],"mappings":"iNAgBO,MAAMA,EAAMC,EAAAA,QAAOC,EAAE;;;;EAMfC,EAAYF,EAAAA,QAAOG,aAAWC,OAA0B;;EAIxDC,EAAiBL,EAAAA,QAAOM,IAAI;;;WAG9BC,EAAAA,QAAQ;;EAKNC,EAAYR,EAAAA,QAAOM,IAAI;;;;kBAIlBG,EAAAA,KAAKC,KAAK;EAIfC,EAAaX,EAAAA,QAAOM,IAAI;;;;EAMxBM,EAAUZ,EAAAA,QAAOa,EAAqB;;;;;;;;;;;;;;4BActBC,GACjBA,EAAMC,YACAC,EAAAA,OAAO,cACPA,EAAAA,OAAO;;;;;;4BAMGA,EAAAA,OAAO;;EAItBC,EAAiBjB,EAAAA,QAAOkB,GAAG;;eAEzBX,EAAAA,QAAQ;oBACHA,EAAAA,QAAQ;;;6BAGCS,EAAAA,OAAO;;yBAEXG,EAAAA,OAAW;;"}
|
package/cjs/menu/menu-content.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("../_virtual/_tslib.js"),t=require("react/jsx-runtime"),r=require("./menu-content.styles.js");const
|
|
1
|
+
"use strict";var e=require("../_virtual/_tslib.js"),t=require("react/jsx-runtime"),r=require("react"),n=require("./menu-content.styles.js"),o=require("./menu-section.styles.js");function i(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var a=i(r);const s=i=>{var{children:s,"data-testid":l="menu-content",overflow:u,maxHeight:d}=i,c=e.__rest(i,["children","data-testid","overflow","maxHeight"]);const f=r.useMemo((()=>{const e=r.Children.toArray(s).filter((e=>a.default.isValidElement(e)&&!!e.props.columns)).reduce(((e,t)=>{var r;return Math.max(e,null!==(r=t.props.columns)&&void 0!==r?r:0)}),0);if(e)return e*o.GRID_COLUMN_WIDTH_PX+(e-1)*o.GRID_COLUMN_GAP_PX+2}),[s]);return t.jsx(n.MenuPanel,Object.assign({$overflow:u,$maxHeight:d,$maxWidth:f,"data-testid":l,tabIndex:-1,onKeyDown:e=>{var t;const r="ArrowDown"===e.key||"ArrowRight"===e.key,n="ArrowUp"===e.key||"ArrowLeft"===e.key;if(!r&&!n)return;const o=(e=>Array.from(e.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter((e=>!e.hasAttribute("disabled"))))(e.currentTarget);if(!o.length)return;const i=document.activeElement,a=i?o.indexOf(i):-1;e.preventDefault();const s=r?1:-1;null===(t=o[-1===a?r?0:o.length-1:(a+s+o.length)%o.length])||void 0===t||t.focus()}},c,{children:s}))};s.displayName="Menu.Content",exports.MenuContent=s;
|
|
2
2
|
//# sourceMappingURL=menu-content.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-content.js","sources":["../../../src/menu/menu-content.tsx"],"sourcesContent":["import React from \"react\";\nimport { MenuPanel } from \"./menu-content.styles\";\nimport { MenuContentProps } from \"./types\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\nconst getFocusables = (container: HTMLElement) => {\n return Array.from(\n container.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n )\n ).filter((el) => !el.hasAttribute(\"disabled\"));\n};\n\nexport const MenuContent = ({\n children,\n \"data-testid\": testId = \"menu-content\",\n overflow,\n maxHeight,\n ...otherProps\n}: MenuContentProps): JSX.Element => {\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const isNextKey = e.key === \"ArrowDown\" || e.key === \"ArrowRight\";\n const isPrevKey = e.key === \"ArrowUp\" || e.key === \"ArrowLeft\";\n\n if (!isNextKey && !isPrevKey) return;\n\n const container = e.currentTarget as HTMLElement;\n const focusables = getFocusables(container);\n if (!focusables.length) return;\n\n const active = document.activeElement as HTMLElement | null;\n const idx = active ? focusables.indexOf(active) : -1;\n\n e.preventDefault();\n\n const delta = isNextKey ? 1 : -1;\n\n const nextIndex =\n idx === -1\n ? isNextKey\n ? 0\n : focusables.length - 1\n : (idx + delta + focusables.length) % focusables.length;\n\n focusables[nextIndex]?.focus();\n };\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n return (\n <MenuPanel\n $overflow={overflow}\n $maxHeight={maxHeight}\n data-testid={testId}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n {...otherProps}\n >\n {children}\n </MenuPanel>\n );\n};\n\nMenuContent.displayName = \"Menu.Content\";\n"],"names":["MenuContent","_a","children","testId","overflow","maxHeight","otherProps","__rest","_jsx","MenuPanel","Object","assign","$overflow","tabIndex","onKeyDown","e","isNextKey","key","isPrevKey","focusables","container","Array","from","querySelectorAll","
|
|
1
|
+
{"version":3,"file":"menu-content.js","sources":["../../../src/menu/menu-content.tsx"],"sourcesContent":["import React, { Children, useMemo } from \"react\";\nimport { MenuPanel } from \"./menu-content.styles\";\nimport {\n GRID_COLUMN_GAP_PX,\n GRID_COLUMN_WIDTH_PX,\n} from \"./menu-section.styles\";\nimport { MenuContentProps, MenuSectionProps } from \"./types\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\nconst getFocusables = (container: HTMLElement) => {\n return Array.from(\n container.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n )\n ).filter((el) => !el.hasAttribute(\"disabled\"));\n};\n\nexport const MenuContent = ({\n children,\n \"data-testid\": testId = \"menu-content\",\n overflow,\n maxHeight,\n ...otherProps\n}: MenuContentProps): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n // caps the panel width so it fits the widest Menu.Section's grid columns, falling back to the default 24rem\n const gridMaxWidth = useMemo(() => {\n const maxColumns = Children.toArray(children)\n .filter(\n (child): child is React.ReactElement<MenuSectionProps> =>\n React.isValidElement(child) &&\n !!(child.props as MenuSectionProps).columns\n )\n .reduce((max, child) => Math.max(max, child.props.columns ?? 0), 0);\n\n if (!maxColumns) return undefined;\n\n return (\n maxColumns * GRID_COLUMN_WIDTH_PX +\n (maxColumns - 1) * GRID_COLUMN_GAP_PX +\n 2 // 1px border × 2 sides\n );\n }, [children]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const isNextKey = e.key === \"ArrowDown\" || e.key === \"ArrowRight\";\n const isPrevKey = e.key === \"ArrowUp\" || e.key === \"ArrowLeft\";\n\n if (!isNextKey && !isPrevKey) return;\n\n const container = e.currentTarget as HTMLElement;\n const focusables = getFocusables(container);\n if (!focusables.length) return;\n\n const active = document.activeElement as HTMLElement | null;\n const idx = active ? focusables.indexOf(active) : -1;\n\n e.preventDefault();\n\n const delta = isNextKey ? 1 : -1;\n\n const nextIndex =\n idx === -1\n ? isNextKey\n ? 0\n : focusables.length - 1\n : (idx + delta + focusables.length) % focusables.length;\n\n focusables[nextIndex]?.focus();\n };\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n return (\n <MenuPanel\n $overflow={overflow}\n $maxHeight={maxHeight}\n $maxWidth={gridMaxWidth}\n data-testid={testId}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n {...otherProps}\n >\n {children}\n </MenuPanel>\n );\n};\n\nMenuContent.displayName = \"Menu.Content\";\n"],"names":["MenuContent","_a","children","testId","overflow","maxHeight","otherProps","__rest","gridMaxWidth","useMemo","maxColumns","Children","toArray","filter","child","React","isValidElement","props","columns","reduce","max","Math","GRID_COLUMN_WIDTH_PX","GRID_COLUMN_GAP_PX","_jsx","MenuPanel","Object","assign","$overflow","$maxHeight","$maxWidth","tabIndex","onKeyDown","e","isNextKey","key","isPrevKey","focusables","container","Array","from","querySelectorAll","el","hasAttribute","getFocusables","currentTarget","length","active","document","activeElement","idx","indexOf","preventDefault","delta","focus","displayName"],"mappings":"qQAWA,MAQaA,EAAeC,IAAA,IAAAC,SACxBA,EACA,cAAeC,EAAS,eAAcC,SACtCA,EAAQC,UACRA,GAASJ,EACNK,EAAUC,EAAAA,OAAAN,EALW,mDAWxB,MAAMO,EAAeC,EAAAA,SAAQ,KACzB,MAAMC,EAAaC,WAASC,QAAQV,GAC/BW,QACIC,GACGC,UAAMC,eAAeF,MAClBA,EAAMG,MAA2BC,UAE3CC,QAAO,CAACC,EAAKN,KAAS,IAAAb,EAAC,OAAAoB,KAAKD,IAAIA,EAAwB,QAAnBnB,EAAAa,EAAMG,MAAMC,eAAO,IAAAjB,EAAAA,EAAI,EAAE,GAAE,GAErE,GAAKS,EAEL,OACIA,EAAaY,EAAAA,sBACZZ,EAAa,GAAKa,EAAAA,mBACnB,IAEL,CAACrB,IAkCJ,OACIsB,EAAAA,IAACC,YAASC,OAAAC,OAAA,CAAAC,UACKxB,EAAQyB,WACPxB,EAASyB,UACVtB,EAAY,cACVL,EACb4B,UAAU,EACVC,UApCeC,UACnB,MAAMC,EAAsB,cAAVD,EAAEE,KAAiC,eAAVF,EAAEE,IACvCC,EAAsB,YAAVH,EAAEE,KAA+B,cAAVF,EAAEE,IAE3C,IAAKD,IAAcE,EAAW,OAE9B,MACMC,EA/CQ,CAACC,GACZC,MAAMC,KACTF,EAAUG,iBACN,qEAEN5B,QAAQ6B,IAAQA,EAAGC,aAAa,cA0CXC,CADDX,EAAEY,eAEpB,IAAKR,EAAWS,OAAQ,OAExB,MAAMC,EAASC,SAASC,cAClBC,EAAMH,EAASV,EAAWc,QAAQJ,IAAU,EAElDd,EAAEmB,iBAEF,MAAMC,EAAQnB,EAAY,GAAI,EAST,QAArBjC,EAAAoC,GANY,IAARa,EACMhB,EACI,EACAG,EAAWS,OAAS,GACvBI,EAAMG,EAAQhB,EAAWS,QAAUT,EAAWS,eAEpC,IAAA7C,GAAAA,EAAEqD,OAAO,GAatBhD,EAAU,CAAAJ,SAEbA,IACO,EAIpBF,EAAYuD,YAAc"}
|
|
@@ -20,7 +20,10 @@
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
min-width: min(15rem, var(--available-width));
|
|
23
|
-
max-width: min(
|
|
23
|
+
max-width: min(
|
|
24
|
+
${({$maxWidth:r})=>r?`${r}px`:"24rem"},
|
|
25
|
+
var(--available-width)
|
|
26
|
+
);
|
|
24
27
|
|
|
25
28
|
${({$maxHeight:r})=>void 0!==r&&`\n max-height: ${r}px;\n `}
|
|
26
29
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-content.styles.js","sources":["../../../src/menu/menu-content.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { PopoverOverflowType } from \"../popover-v2/types\";\nimport {\n Border,\n Breakpoint,\n Colour,\n MediaQuery,\n Radius,\n Shadow,\n} from \"../theme\";\n\n// =============================================================================\n// STYLES INTERFACE\n// =============================================================================\ninterface MenuPanelStylesProps {\n $overflow?: PopoverOverflowType | undefined;\n $maxHeight?: number | undefined;\n}\n\n// =============================================================================\n// MENU CONTENT STYLES\n// =============================================================================\nexport const MenuPanel = styled.div<MenuPanelStylesProps>`\n border-radius: ${Radius[\"md\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n background: ${Colour[\"bg\"]};\n box-shadow: ${Shadow[\"md-subtle\"]};\n\n --x-spacing: 0px;\n --available-width: calc(100vw - var(--x-spacing) * 2);\n\n ${MediaQuery.MaxWidth.sm} {\n --x-spacing: ${Breakpoint[\"sm-margin\"]}px;\n }\n\n ${MediaQuery.MaxWidth.xs} {\n --x-spacing: ${Breakpoint[\"xs-margin\"]}px;\n }\n\n ${MediaQuery.MaxWidth.xxs} {\n --x-spacing: ${Breakpoint[\"xxs-margin\"]}px;\n }\n\n min-width: min(15rem, var(--available-width));\n max-width: min(24rem
|
|
1
|
+
{"version":3,"file":"menu-content.styles.js","sources":["../../../src/menu/menu-content.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { PopoverOverflowType } from \"../popover-v2/types\";\nimport {\n Border,\n Breakpoint,\n Colour,\n MediaQuery,\n Radius,\n Shadow,\n} from \"../theme\";\n\n// =============================================================================\n// STYLES INTERFACE\n// =============================================================================\ninterface MenuPanelStylesProps {\n $overflow?: PopoverOverflowType | undefined;\n $maxHeight?: number | undefined;\n $maxWidth?: number | undefined;\n}\n\n// =============================================================================\n// MENU CONTENT STYLES\n// =============================================================================\nexport const MenuPanel = styled.div<MenuPanelStylesProps>`\n border-radius: ${Radius[\"md\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n background: ${Colour[\"bg\"]};\n box-shadow: ${Shadow[\"md-subtle\"]};\n\n --x-spacing: 0px;\n --available-width: calc(100vw - var(--x-spacing) * 2);\n\n ${MediaQuery.MaxWidth.sm} {\n --x-spacing: ${Breakpoint[\"sm-margin\"]}px;\n }\n\n ${MediaQuery.MaxWidth.xs} {\n --x-spacing: ${Breakpoint[\"xs-margin\"]}px;\n }\n\n ${MediaQuery.MaxWidth.xxs} {\n --x-spacing: ${Breakpoint[\"xxs-margin\"]}px;\n }\n\n min-width: min(15rem, var(--available-width));\n max-width: min(\n ${({ $maxWidth }) => ($maxWidth ? `${$maxWidth}px` : \"24rem\")},\n var(--available-width)\n );\n\n ${({ $maxHeight }) =>\n $maxHeight !== undefined &&\n `\n max-height: ${$maxHeight}px;\n `}\n\n ${({ $overflow }) =>\n $overflow &&\n `\n overflow-y: ${$overflow};\n `}\n\n &:focus {\n outline: none;\n }\n\n &::-webkit-scrollbar {\n width: 14px;\n }\n\n &::-webkit-scrollbar-track {\n background: transparent;\n }\n\n &::-webkit-scrollbar-thumb {\n background: ${Colour[\"bg-inverse-subtlest\"]};\n border: 5px solid transparent;\n border-radius: ${Radius[\"full\"]};\n background-clip: padding-box;\n }\n`;\n"],"names":["MenuPanel","styled","div","Radius","Border","Colour","Shadow","MediaQuery","MaxWidth","sm","Breakpoint","xs","xxs","$maxWidth","$maxHeight","undefined","$overflow"],"mappings":"uJAuBO,MAAMA,OAAYC,QAAOC,GAAyB;qBACpCC,EAAAA,OAAW;cAClBC,EAAAA,OAAO,gBAAgBA,EAAAA,OAAc,SAAKC,SAAe;kBACrDA,EAAAA,OAAW;kBACXC,EAAAA,OAAO;;;;;MAKnBC,EAAAA,WAAWC,SAASC;uBACHC,EAAAA,WAAW;;;MAG5BH,EAAAA,WAAWC,SAASG;uBACHD,EAAAA,WAAW;;;MAG5BH,EAAAA,WAAWC,SAASI;uBACHF,EAAAA,WAAW;;;;;UAKxB,EAAGG,eAAiBA,EAAY,GAAGA,MAAgB;;;;MAIvD,EAAGC,qBACcC,IAAfD,GACA,yBACcA;;MAGhB,EAAGE,eACDA,GACA,yBACcA;;;;;;;;;;;;;;;sBAgBAX,EAAAA,OAAO;;yBAEJF,EAAAA,OAAa;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";var e=require("styled-components"),t=require("../theme/index.js"),r=require("../typography/typography.js");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var i=o(e);const a=i.default.li`
|
|
2
2
|
display: flex;
|
|
3
3
|
flex-direction: column;
|
|
4
|
-
padding: ${t.Spacing["spacing-
|
|
4
|
+
padding: ${t.Spacing["spacing-12"]} ${t.Spacing["spacing-16"]};
|
|
5
5
|
`,n=i.default(r.Typography.BodySM)`
|
|
6
6
|
color: ${t.Colour["text-subtler"]};
|
|
7
7
|
`;exports.MenuItemDiv=a,exports.SubLabel=n;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-item.styles.js","sources":["../../../src/menu/menu-item.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { Colour, Spacing } from \"../theme\";\nimport { Typography } from \"../typography\";\n\n// =============================================================================\n// MENU ITEM STYLES\n// =============================================================================\nexport const MenuItemDiv = styled.li`\n display: flex;\n flex-direction: column;\n padding: ${Spacing[\"spacing-
|
|
1
|
+
{"version":3,"file":"menu-item.styles.js","sources":["../../../src/menu/menu-item.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { Colour, Spacing } from \"../theme\";\nimport { Typography } from \"../typography\";\n\n// =============================================================================\n// MENU ITEM STYLES\n// =============================================================================\nexport const MenuItemDiv = styled.li`\n display: flex;\n flex-direction: column;\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n`;\n\nexport const SubLabel = styled(Typography.BodySM)`\n color: ${Colour[\"text-subtler\"]};\n`;\n"],"names":["MenuItemDiv","styled","li","Spacing","SubLabel","Typography","BodySM","Colour"],"mappings":"2MAOO,MAAMA,EAAcC,EAAAA,QAAOC,EAAE;;;eAGrBC,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;EAGnCC,EAAWH,EAAAA,QAAOI,aAAWC,OAAO;aACpCC,EAAAA,OAAO;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-link.styles.js","sources":["../../../src/menu/menu-link.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { lineClampCss } from \"../shared/styles\";\nimport { Border, Colour, Radius, Spacing } from \"../theme\";\nimport { Typography } from \"../typography\";\n\n// =============================================================================\n// MENU LINK STYLES\n// =============================================================================\nexport const MenuLinkDiv = styled.li`\n display: flex;\n flex-direction: column;\n`;\n\nexport const Link = styled(Typography.LinkMD)`\n color: ${Colour[\"text\"]};\n\n margin: 0 ${Spacing[\"spacing-8\"]};\n\n border: ${Border[\"solid\"]} transparent;\n border-width: ${Spacing[\"spacing-
|
|
1
|
+
{"version":3,"file":"menu-link.styles.js","sources":["../../../src/menu/menu-link.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { lineClampCss } from \"../shared/styles\";\nimport { Border, Colour, Radius, Spacing } from \"../theme\";\nimport { Typography } from \"../typography\";\n\n// =============================================================================\n// MENU LINK STYLES\n// =============================================================================\nexport const MenuLinkDiv = styled.li`\n display: flex;\n flex-direction: column;\n`;\n\nexport const Link = styled(Typography.LinkMD)`\n color: ${Colour[\"text\"]};\n\n margin: 0 ${Spacing[\"spacing-8\"]};\n\n border: ${Border[\"solid\"]} transparent;\n border-width: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]};\n\n border-radius: ${Radius[\"md\"]};\n\n ${lineClampCss(2)}\n white-space: pre-wrap;\n\n &:hover,\n &:active,\n &:focus {\n background-color: ${Colour[\"bg-hover\"]};\n color: ${Colour[\"text\"]};\n }\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 0;\n }\n`;\n"],"names":["MenuLinkDiv","styled","li","Link","Typography","LinkMD","Colour","Spacing","Border","Radius","lineClampCss"],"mappings":"kPAQO,MAAMA,EAAcC,EAAAA,QAAOC,EAAE;;;EAKvBC,EAAOF,EAAAA,QAAOG,aAAWC,OAAO;aAChCC,EAAAA,OAAa;;gBAEVC,EAAAA,QAAQ;;cAEVC,EAAAA,OAAc;oBACRD,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;;qBAEhCE,EAAAA,OAAW;;MAE1BC,EAAAA,aAAa;;;;;;4BAMSJ,EAAAA,OAAO;iBAClBA,EAAAA,OAAa;;;;6BAIDA,EAAAA,OAAO;;;"}
|
package/cjs/menu/menu-section.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("../_virtual/_tslib.js"),r=require("react/jsx-runtime");require("../util/calendar-helper.js"),require("../util/date-helper.js"),require("../util/date-input-helper.js")
|
|
1
|
+
"use strict";var e=require("../_virtual/_tslib.js"),r=require("react/jsx-runtime"),i=require("react");require("../util/calendar-helper.js"),require("../util/date-helper.js"),require("../util/date-input-helper.js");var s=require("../util/simple-id-generator.js");require("../util/string-helper.js"),require("@react-aria/live-announcer");var t=require("./menu-section.styles.js");const a=a=>{var{children:l,label:n,showDivider:u=!0,columns:c,className:d,"data-testid":o="menu-section"}=a,h=e.__rest(a,["children","label","showDivider","columns","className","data-testid"]);const m=s.useId(),j=i.useMemo((()=>void 0!==c?Math.ceil(i.Children.count(l)/Math.max(1,c)):void 0),[c,l]);return r.jsxs(t.SectionWrapper,{$showDivider:u,className:d,children:[n&&r.jsx(t.Label,{weight:"semibold",id:m,children:n}),r.jsx(t.List,Object.assign({$columns:c,$gridRows:j,"data-testid":o,"aria-labelledby":m},h,{children:l}))]})};a.displayName="Menu.Section",exports.MenuSection=a;
|
|
2
2
|
//# sourceMappingURL=menu-section.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-section.js","sources":["../../../src/menu/menu-section.tsx"],"sourcesContent":["import { useId } from \"../util\";\nimport { Label,
|
|
1
|
+
{"version":3,"file":"menu-section.js","sources":["../../../src/menu/menu-section.tsx"],"sourcesContent":["import { Children, useMemo } from \"react\";\nimport { useId } from \"../util\";\nimport { Label, List, SectionWrapper } from \"./menu-section.styles\";\nimport { MenuSectionProps } from \"./types\";\n\nexport const MenuSection = ({\n children,\n label,\n showDivider = true,\n columns,\n className,\n \"data-testid\": testId = \"menu-section\",\n ...otherProps\n}: MenuSectionProps): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const internalId = useId();\n // clamp to 1 column so a non-positive `columns` never yields a negative grid-template-rows count\n const gridRows = useMemo(\n () =>\n columns !== undefined\n ? Math.ceil(Children.count(children) / Math.max(1, columns))\n : undefined,\n [columns, children]\n );\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n return (\n <SectionWrapper $showDivider={showDivider} className={className}>\n {label && (\n <Label weight=\"semibold\" id={internalId}>\n {label}\n </Label>\n )}\n <List\n $columns={columns}\n $gridRows={gridRows}\n data-testid={testId}\n aria-labelledby={internalId}\n {...otherProps}\n >\n {children}\n </List>\n </SectionWrapper>\n );\n};\n\nMenuSection.displayName = \"Menu.Section\";\n"],"names":["MenuSection","_a","children","label","showDivider","columns","className","testId","otherProps","__rest","internalId","useId","gridRows","useMemo","undefined","Math","ceil","Children","count","max","_jsxs","SectionWrapper","$showDivider","_jsx","Label","weight","id","List","Object","assign","$columns","$gridRows","displayName"],"mappings":"0XAKO,MAAMA,EAAeC,QAAAC,SACxBA,EAAQC,MACRA,EAAKC,YACLA,GAAc,EAAIC,QAClBA,EAAOC,UACPA,EACA,cAAeC,EAAS,kBACrBC,EAAUC,EAAAA,OAAAR,EAPW,CAAA,WAAA,QAAA,cAAA,UAAA,YAAA,gBAYxB,MAAMS,EAAaC,EAAAA,QAEbC,EAAWC,WACb,SACgBC,IAAZT,EACMU,KAAKC,KAAKC,EAAAA,SAASC,MAAMhB,GAAYa,KAAKI,IAAI,EAAGd,SACjDS,GACV,CAACT,EAASH,IAMd,OACIkB,EAAAA,KAACC,EAAAA,eAAc,CAAAC,aAAelB,EAAaE,UAAWA,EAASJ,SAAA,CAC1DC,GACGoB,EAAAA,IAACC,EAAAA,MAAK,CAACC,OAAO,WAAWC,GAAIhB,EAAUR,SAClCC,IAGToB,EAAAA,IAACI,EAAAA,KAAIC,OAAAC,OAAA,CAAAC,SACSzB,EAAO0B,UACNnB,gBACEL,EAAM,kBACFG,GACbF,YAEHN,OAEQ,EAIzBF,EAAYgC,YAAc"}
|