@ahrowe/ui 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/common/animatedText/animatedText.mjs +2 -0
- package/dist/esm/common/animatedText/animatedText.mjs.map +1 -0
- package/dist/esm/common/animatedText/animatedText.module.mjs +2 -0
- package/dist/esm/common/animatedText/animatedText.module.mjs.map +1 -0
- package/dist/esm/common/animatedText/animatedText.types.mjs +2 -0
- package/dist/esm/common/animatedText/animatedText.types.mjs.map +1 -0
- package/dist/esm/common/floatingMenu/floatingMenu.mjs +1 -1
- package/dist/esm/common/floatingMenu/floatingMenu.mjs.map +1 -1
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs +1 -1
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs.map +1 -1
- package/dist/esm/common/hooks/useSwipeDismiss.mjs +2 -0
- package/dist/esm/common/hooks/useSwipeDismiss.mjs.map +1 -0
- package/dist/esm/common/popover/popover.mjs +2 -0
- package/dist/esm/common/popover/popover.mjs.map +1 -0
- package/dist/esm/common/popover/popover.module.mjs +2 -0
- package/dist/esm/common/popover/popover.module.mjs.map +1 -0
- package/dist/esm/common/popover/popover.types.mjs +2 -0
- package/dist/esm/common/popover/popover.types.mjs.map +1 -0
- package/dist/esm/common/popover/usePopoverPosition.mjs +2 -0
- package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -0
- package/dist/esm/common/stepper/stepper.mjs +1 -1
- package/dist/esm/common/stepper/stepper.mjs.map +1 -1
- package/dist/esm/common/stepper/stepper.module.mjs +1 -1
- package/dist/esm/common/stepper/stepper.module.mjs.map +1 -1
- package/dist/esm/common/stepper/stepper.types.mjs +2 -0
- package/dist/esm/common/stepper/stepper.types.mjs.map +1 -0
- package/dist/esm/common/themeProvider/themeProvider.mjs +1 -1
- package/dist/esm/common/themeProvider/themeProvider.mjs.map +1 -1
- package/dist/esm/common/toast/toast.mjs +1 -1
- package/dist/esm/common/toast/toast.mjs.map +1 -1
- package/dist/esm/common/toast/toast.module.mjs.map +1 -1
- package/dist/esm/common/utils/scrollAncestors.mjs +2 -0
- package/dist/esm/common/utils/scrollAncestors.mjs.map +1 -0
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/logo.svg +4 -0
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/logo.svg +4 -0
- package/dist/style.css +1 -1
- package/dist/types/package/common/animatedText/animatedText.d.ts +4 -0
- package/dist/types/package/common/animatedText/animatedText.types.d.ts +59 -0
- package/dist/types/package/common/animatedText/index.d.ts +2 -0
- package/dist/types/package/common/hooks/useSwipeDismiss.d.ts +33 -0
- package/dist/types/package/common/popover/index.d.ts +2 -0
- package/dist/types/package/common/popover/popover.d.ts +3 -0
- package/dist/types/package/common/popover/popover.types.d.ts +58 -0
- package/dist/types/package/common/popover/usePopoverPosition.d.ts +23 -0
- package/dist/types/package/common/stepper/index.d.ts +1 -0
- package/dist/types/package/common/stepper/stepper.d.ts +1 -1
- package/dist/types/package/common/stepper/stepper.types.d.ts +61 -5
- package/dist/types/package/common/themeProvider/theme.types.d.ts +22 -0
- package/dist/types/package/common/utils/scrollAncestors.d.ts +2 -0
- package/dist/types/package/index.d.ts +4 -0
- package/docs/AnimatedText.md +94 -0
- package/docs/CLAUDE.md +2 -0
- package/docs/FloatingMenu.md +2 -0
- package/docs/Popover.md +61 -0
- package/docs/Stepper.md +101 -8
- package/docs/Toast.md +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{AnimatedTextUnit as e,AnimatedTextVariant as t}from"./animatedText.types.mjs";import n from"./animatedText.module.mjs";import{Fragment as r,useEffect as i,useMemo as a,useState as o}from"react";import s from"classnames";import{Fragment as c,jsx as l,jsxs as u}from"react/jsx-runtime";function d(){return typeof window<`u`&&typeof window.matchMedia==`function`?window.matchMedia(`(prefers-reduced-motion: reduce)`).matches:!1}var f={[t.RiseUp]:n.animatedTextVariantRiseUp,[t.BlurIn]:n.animatedTextVariantBlurIn,[t.Bounce]:n.animatedTextVariantBounce,[t.Glitch]:n.animatedTextVariantGlitch};function p(t,n){return n===e.Word?t.split(` `).filter(Boolean):Array.from(t)}function m({units:t,unit:a,staggerDelay:f,classNames:p,slotStyles:m}){let[h,g]=o(()=>t.length===0?0:d()?t.length:1);i(()=>{if(t.length<=1||d())return;let e=1,n=setInterval(()=>{e+=1,g(e),e>=t.length&&clearInterval(n)},f);return()=>clearInterval(n)},[t,f]);let _=h>=t.length;return u(c,{children:[t.slice(0,h).map((t,i)=>u(r,{children:[l(`span`,{className:s(n.animatedTextTypewriterLetter,p?.letter),style:m?.letter,children:t}),a===e.Word&&i<h-1?` `:null]},i)),l(`span`,{className:s(n.animatedTextCursor,_&&n.animatedTextCursorBlinking,p?.cursor),style:m?.cursor})]})}var h=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%&*`,g=35;function _(e){return Array.from({length:e},()=>h[Math.floor(Math.random()*69)]).join(``)}function v({units:t,unit:a,staggerDelay:f,classNames:p,slotStyles:m}){let[h]=o(d),[v,y]=o(0);i(()=>{if(t.length===0||h)return;let e=0,n=Math.ceil(t.length*f/g)+1,r=setInterval(()=>{e+=1,y(e),e>=n&&clearInterval(r)},g);return()=>clearInterval(r)},[t,f,h]);let b=Math.min(t.length,Math.floor(v*g/f));return l(c,{children:t.map((i,o)=>{let c=h||o<b;return u(r,{children:[l(`span`,{className:s(n.animatedTextScrambleLetter,p?.letter),style:m?.letter,children:i===` `?` `:c?i:_(i.length)}),a===e.Word&&o<t.length-1?` `:null]},o)})})}function y({text:i,variant:o=t.RiseUp,unit:c=e.Letter,staggerDelay:d=40,duration:h,className:g,style:_,classNames:y,styles:b,...x}){let S=a(()=>p(i,c),[i,c]),C=`${o} ${i} ${c} ${d} ${h??``}`;if(o===t.Shine)return u(`span`,{...x,className:s(n.animatedText,g),style:_,children:[l(`span`,{className:n.animatedTextVisuallyHidden,children:i}),l(`span`,{"aria-hidden":`true`,className:s(n.animatedTextShine,y?.letter),style:{animationDuration:`${h??2e3}ms`,...b?.letter},children:i},C)]});if(o===t.Highlight)return u(`span`,{...x,className:s(n.animatedText,g),style:_,children:[l(`span`,{className:n.animatedTextVisuallyHidden,children:i}),l(`span`,{"aria-hidden":`true`,className:s(n.animatedTextHighlight,y?.letter),style:{animationDuration:`${h??600}ms`,...b?.letter},children:i},C)]});if(o===t.Typewriter)return u(`span`,{...x,className:s(n.animatedText,g),style:_,children:[l(`span`,{className:n.animatedTextVisuallyHidden,children:i}),l(`span`,{"aria-hidden":`true`,children:l(m,{units:S,unit:c,staggerDelay:d,classNames:y,slotStyles:b})},C)]});if(o===t.Scramble)return u(`span`,{...x,className:s(n.animatedText,g),style:_,children:[l(`span`,{className:n.animatedTextVisuallyHidden,children:i}),l(`span`,{"aria-hidden":`true`,children:l(v,{units:S,unit:c,staggerDelay:d,classNames:y,slotStyles:b})},C)]});if(o===t.Wave)return u(`span`,{...x,className:s(n.animatedText,g),style:_,children:[l(`span`,{className:n.animatedTextVisuallyHidden,children:i}),l(`span`,{"aria-hidden":`true`,children:S.map((t,i)=>u(r,{children:[l(`span`,{className:s(n.animatedTextLetter,n.animatedTextVariantWave,y?.letter),style:{animationDelay:`-${i*d}ms`,animationDuration:`${h??1200}ms`,...b?.letter},children:t===` `?` `:t}),c===e.Word&&i<S.length-1?` `:null]},i))},C)]});let w=f[o]??n.animatedTextVariantRiseUp;return u(`span`,{...x,className:s(n.animatedText,g),style:_,children:[l(`span`,{className:n.animatedTextVisuallyHidden,children:i}),l(`span`,{"aria-hidden":`true`,children:S.map((t,i)=>u(r,{children:[l(`span`,{className:s(n.animatedTextLetter,w,y?.letter),style:{animationDelay:`${i*d}ms`,animationDuration:`${h??500}ms`,...b?.letter},children:t===` `?` `:t}),c===e.Word&&i<S.length-1?` `:null]},i))},C)]})}export{y as default};
|
|
2
|
+
//# sourceMappingURL=animatedText.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animatedText.mjs","names":[],"sources":["../../../../package/common/animatedText/animatedText.tsx"],"sourcesContent":["import { Fragment, useEffect, useMemo, useState, type ReactElement } from 'react';\nimport cx from 'classnames';\n\nimport { AnimatedTextVariant, AnimatedTextUnit } from './animatedText.types';\nimport type { AnimatedTextProps } from './animatedText.types';\nimport styles from './animatedText.module.pcss';\n\nfunction prefersReducedMotion(): boolean {\n return typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(prefers-reduced-motion: reduce)').matches\n : false;\n}\n\n// CSS-driven one-shot entrance variants: identical rendering, only the keyframe (via this class)\n// differs. RiseUp/BlurIn/Bounce/Glitch all animate opacity 0 -> 1 with `animation-fill-mode:\n// forwards`, staggered per unit via `animation-delay`.\nconst ENTRANCE_VARIANT_CLASS: Partial<Record<AnimatedTextVariant, string>> = {\n [AnimatedTextVariant.RiseUp]: styles.animatedTextVariantRiseUp,\n [AnimatedTextVariant.BlurIn]: styles.animatedTextVariantBlurIn,\n [AnimatedTextVariant.Bounce]: styles.animatedTextVariantBounce,\n [AnimatedTextVariant.Glitch]: styles.animatedTextVariantGlitch,\n};\n\nfunction splitUnits(text: string, unit: AnimatedTextUnit): string[] {\n return unit === AnimatedTextUnit.Word ? text.split(' ').filter(Boolean) : Array.from(text);\n}\n\ninterface TypewriterProps {\n units: string[];\n unit: AnimatedTextUnit;\n staggerDelay: number;\n classNames: AnimatedTextProps['classNames'];\n slotStyles: AnimatedTextProps['styles'];\n}\n\n// Split out so its wrapper (keyed by `replayKey`, see below) can be remounted on prop change to\n// reset this component's reveal state, the idiomatic React way to reset state on prop change.\n// It also keeps the reveal-count updates that happen over time (inside the interval callback) as\n// the only setState calls, none of them synchronous-in-effect.\nfunction Typewriter({ units, unit, staggerDelay, classNames, slotStyles }: TypewriterProps) {\n const [revealCount, setRevealCount] = useState(() => {\n if (units.length === 0) return 0;\n return prefersReducedMotion() ? units.length : 1;\n });\n\n useEffect(() => {\n if (units.length <= 1 || prefersReducedMotion()) return;\n let revealed = 1;\n const id = setInterval(() => {\n revealed += 1;\n setRevealCount(revealed);\n if (revealed >= units.length) clearInterval(id);\n }, staggerDelay);\n return () => clearInterval(id);\n }, [units, staggerDelay]);\n\n const isDone = revealCount >= units.length;\n\n return (\n <>\n {units.slice(0, revealCount).map((unitText, index) => (\n <Fragment key={index}>\n <span className={cx(styles.animatedTextTypewriterLetter, classNames?.letter)} style={slotStyles?.letter}>\n {unitText}\n </span>\n {unit === AnimatedTextUnit.Word && index < revealCount - 1 ? ' ' : null}\n </Fragment>\n ))}\n <span\n className={cx(styles.animatedTextCursor, isDone && styles.animatedTextCursorBlinking, classNames?.cursor)}\n style={slotStyles?.cursor}\n />\n </>\n );\n}\n\nconst SCRAMBLE_CHARSET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%&*';\nconst SCRAMBLE_TICK_MS = 35;\n\nfunction randomScrambleText(length: number): string {\n return Array.from({ length }, () => SCRAMBLE_CHARSET[Math.floor(Math.random() * SCRAMBLE_CHARSET.length)]).join('');\n}\n\ninterface ScrambleProps {\n units: string[];\n unit: AnimatedTextUnit;\n staggerDelay: number;\n classNames: AnimatedTextProps['classNames'];\n slotStyles: AnimatedTextProps['styles'];\n}\n\n// Same keyed-remount-on-prop-change approach as Typewriter. Every unit starts scrambled and\n// \"locks in\" left to right; the scramble refresh (SCRAMBLE_TICK_MS) is a separate, faster cadence\n// than the per-unit settle pacing (staggerDelay) so still-scrambling units keep visibly flickering.\nfunction Scramble({ units, unit, staggerDelay, classNames, slotStyles }: ScrambleProps) {\n const [reduceMotion] = useState(prefersReducedMotion);\n const [tick, setTick] = useState(0);\n\n useEffect(() => {\n if (units.length === 0 || reduceMotion) return;\n let t = 0;\n const totalTicks = Math.ceil((units.length * staggerDelay) / SCRAMBLE_TICK_MS) + 1;\n const id = setInterval(() => {\n t += 1;\n setTick(t);\n if (t >= totalTicks) clearInterval(id);\n }, SCRAMBLE_TICK_MS);\n return () => clearInterval(id);\n }, [units, staggerDelay, reduceMotion]);\n\n const settledCount = Math.min(units.length, Math.floor((tick * SCRAMBLE_TICK_MS) / staggerDelay));\n\n return (\n <>\n {units.map((unitText, index) => {\n const isSettled = reduceMotion || index < settledCount;\n return (\n <Fragment key={index}>\n <span className={cx(styles.animatedTextScrambleLetter, classNames?.letter)} style={slotStyles?.letter}>\n {unitText === ' ' ? ' ' : isSettled ? unitText : randomScrambleText(unitText.length)}\n </span>\n {unit === AnimatedTextUnit.Word && index < units.length - 1 ? ' ' : null}\n </Fragment>\n );\n })}\n </>\n );\n}\n\nfunction AnimatedText({\n text,\n variant = AnimatedTextVariant.RiseUp,\n unit = AnimatedTextUnit.Letter,\n staggerDelay = 40,\n duration,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: AnimatedTextProps): ReactElement {\n const units = useMemo(() => splitUnits(text, unit), [text, unit]);\n\n // Forces the animated subtree (not the whole component) to remount whenever anything that\n // affects the animation changes, most commonly `text`. Without this, CSS entrance variants\n // rely on `animation-fill-mode: forwards`, which just holds the prior end state instead of\n // replaying when the letters underneath it change; keying on these values makes every variant\n // (CSS-driven and JS-driven alike) replay consistently, matching what a component named\n // AnimatedText should do when the text it's animating actually changes.\n const replayKey = `${variant} ${text} ${unit} ${staggerDelay} ${duration ?? ''}`;\n\n if (variant === AnimatedTextVariant.Shine) {\n return (\n <span {...rest} className={cx(styles.animatedText, className)} style={style}>\n <span className={styles.animatedTextVisuallyHidden}>{text}</span>\n <span\n key={replayKey}\n aria-hidden=\"true\"\n className={cx(styles.animatedTextShine, classNames?.letter)}\n style={{ animationDuration: `${duration ?? 2000}ms`, ...slotStyles?.letter }}\n >\n {text}\n </span>\n </span>\n );\n }\n\n if (variant === AnimatedTextVariant.Highlight) {\n return (\n <span {...rest} className={cx(styles.animatedText, className)} style={style}>\n <span className={styles.animatedTextVisuallyHidden}>{text}</span>\n <span\n key={replayKey}\n aria-hidden=\"true\"\n className={cx(styles.animatedTextHighlight, classNames?.letter)}\n style={{ animationDuration: `${duration ?? 600}ms`, ...slotStyles?.letter }}\n >\n {text}\n </span>\n </span>\n );\n }\n\n if (variant === AnimatedTextVariant.Typewriter) {\n return (\n <span {...rest} className={cx(styles.animatedText, className)} style={style}>\n <span className={styles.animatedTextVisuallyHidden}>{text}</span>\n <span key={replayKey} aria-hidden=\"true\">\n <Typewriter\n units={units}\n unit={unit}\n staggerDelay={staggerDelay}\n classNames={classNames}\n slotStyles={slotStyles}\n />\n </span>\n </span>\n );\n }\n\n if (variant === AnimatedTextVariant.Scramble) {\n return (\n <span {...rest} className={cx(styles.animatedText, className)} style={style}>\n <span className={styles.animatedTextVisuallyHidden}>{text}</span>\n <span key={replayKey} aria-hidden=\"true\">\n <Scramble units={units} unit={unit} staggerDelay={staggerDelay} classNames={classNames} slotStyles={slotStyles} />\n </span>\n </span>\n );\n }\n\n if (variant === AnimatedTextVariant.Wave) {\n return (\n <span {...rest} className={cx(styles.animatedText, className)} style={style}>\n <span className={styles.animatedTextVisuallyHidden}>{text}</span>\n <span key={replayKey} aria-hidden=\"true\">\n {units.map((unitText, index) => (\n <Fragment key={index}>\n <span\n className={cx(styles.animatedTextLetter, styles.animatedTextVariantWave, classNames?.letter)}\n style={{\n // Negative delay starts the loop already mid-cycle, phase-shifted per unit.\n // That's what makes it read as a travelling wave from the very first frame,\n // instead of every unit bobbing in lockstep or staggering in once and then syncing.\n animationDelay: `-${index * staggerDelay}ms`,\n animationDuration: `${duration ?? 1200}ms`,\n ...slotStyles?.letter,\n }}\n >\n {unitText === ' ' ? ' ' : unitText}\n </span>\n {unit === AnimatedTextUnit.Word && index < units.length - 1 ? ' ' : null}\n </Fragment>\n ))}\n </span>\n </span>\n );\n }\n\n const entranceClass = ENTRANCE_VARIANT_CLASS[variant] ?? styles.animatedTextVariantRiseUp;\n\n return (\n <span {...rest} className={cx(styles.animatedText, className)} style={style}>\n <span className={styles.animatedTextVisuallyHidden}>{text}</span>\n <span key={replayKey} aria-hidden=\"true\">\n {units.map((unitText, index) => (\n <Fragment key={index}>\n <span\n className={cx(styles.animatedTextLetter, entranceClass, classNames?.letter)}\n style={{\n animationDelay: `${index * staggerDelay}ms`,\n animationDuration: `${duration ?? 500}ms`,\n ...slotStyles?.letter,\n }}\n >\n {unitText === ' ' ? ' ' : unitText}\n </span>\n {unit === AnimatedTextUnit.Word && index < units.length - 1 ? ' ' : null}\n </Fragment>\n ))}\n </span>\n </span>\n );\n}\n\nexport default AnimatedText;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={animatedText:`animatedText_xkLRE`,"animatedText-visually-hidden":`animatedText-visually-hidden_N-uxP`,animatedTextVisuallyHidden:`animatedText-visually-hidden_N-uxP`,"animatedText-letter":`animatedText-letter_HBpbr`,animatedTextLetter:`animatedText-letter_HBpbr`,"animatedText-variant-rise-up":`animatedText-variant-rise-up_iZl7w`,animatedTextVariantRiseUp:`animatedText-variant-rise-up_iZl7w`,animatedTextRiseUp:`animatedTextRiseUp_4tb02`,"animatedText-variant-blur-in":`animatedText-variant-blur-in_TaxXd`,animatedTextVariantBlurIn:`animatedText-variant-blur-in_TaxXd`,animatedTextBlurIn:`animatedTextBlurIn_OPXmX`,"animatedText-variant-bounce":`animatedText-variant-bounce_1EWqT`,animatedTextVariantBounce:`animatedText-variant-bounce_1EWqT`,animatedTextBounceIn:`animatedTextBounceIn_R8l6K`,"animatedText-variant-glitch":`animatedText-variant-glitch_A-F8k`,animatedTextVariantGlitch:`animatedText-variant-glitch_A-F8k`,animatedTextGlitch:`animatedTextGlitch_tM2K9`,"animatedText-variant-wave":`animatedText-variant-wave_Wiv27`,animatedTextVariantWave:`animatedText-variant-wave_Wiv27`,animatedTextWave:`animatedTextWave_ztd68`,"animatedText-typewriter-letter":`animatedText-typewriter-letter_gAdNb`,animatedTextTypewriterLetter:`animatedText-typewriter-letter_gAdNb`,"animatedText-scramble-letter":`animatedText-scramble-letter_18T2z`,animatedTextScrambleLetter:`animatedText-scramble-letter_18T2z`,"animatedText-cursor":`animatedText-cursor_ns0l7`,animatedTextCursor:`animatedText-cursor_ns0l7`,"animatedText-cursor-blinking":`animatedText-cursor-blinking_IdVo3`,animatedTextCursorBlinking:`animatedText-cursor-blinking_IdVo3`,animatedTextCursorBlink:`animatedTextCursorBlink_MTiee`,"animatedText-shine":`animatedText-shine_VmmS9`,animatedTextShine:`animatedText-shine_VmmS9`,animatedTextShineSweep:`animatedTextShineSweep_-A864`,"animatedText-highlight":`animatedText-highlight_Bu-rP`,animatedTextHighlight:`animatedText-highlight_Bu-rP`,animatedTextHighlightSweep:`animatedTextHighlightSweep_e4-hF`};export{e as default};
|
|
2
|
+
//# sourceMappingURL=animatedText.module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animatedText.module.mjs","names":[],"sources":["../../../../package/common/animatedText/animatedText.module.pcss"],"sourcesContent":[".animatedText {\n display: inline-block;\n position: relative;\n\n &-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n &-letter {\n display: inline-block;\n white-space: pre;\n opacity: 0;\n animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);\n animation-fill-mode: forwards;\n }\n\n &-variant {\n &-rise-up {\n animation-name: animatedTextRiseUp;\n }\n\n &-blur-in {\n animation-name: animatedTextBlurIn;\n }\n\n &-bounce {\n animation-name: animatedTextBounceIn;\n animation-timing-function: ease-out;\n }\n\n &-glitch {\n animation-name: animatedTextGlitch;\n animation-timing-function: steps(5, jump-none);\n }\n\n &-wave {\n /* Ambient/looping, not an entrance, so the letter stays visible throughout, overriding\n `.animatedText-letter`'s opacity:0 base (meant for one-shot entrance variants). */\n opacity: 1;\n animation-name: animatedTextWave;\n animation-iteration-count: infinite;\n animation-timing-function: ease-in-out;\n }\n }\n\n &-typewriter-letter {\n display: inline-block;\n white-space: pre;\n }\n\n &-scramble-letter {\n display: inline-block;\n white-space: pre;\n }\n\n &-cursor {\n display: inline-block;\n width: 0.08em;\n min-width: 1px;\n height: 0.85em;\n margin-left: 0.05em;\n background: var(--text-color);\n vertical-align: baseline;\n\n &-blinking {\n animation: animatedTextCursorBlink 1s step-end infinite;\n }\n }\n\n &-shine {\n display: inline-block;\n white-space: pre;\n /* currentColor can't be used here: it would resolve against this same rule's\n `color: transparent` below, making the whole gradient transparent. */\n background-image: linear-gradient(90deg, var(--text-color) 25%, var(--primary-lighter) 50%, var(--text-color) 75%);\n background-size: 200% 100%;\n background-clip: text;\n -webkit-background-clip: text;\n color: transparent;\n -webkit-text-fill-color: transparent;\n animation-name: animatedTextShineSweep;\n animation-timing-function: linear;\n animation-iteration-count: infinite;\n }\n\n &-highlight {\n display: inline-block;\n white-space: pre;\n background-image: linear-gradient(var(--primary-lighter), var(--primary-lighter));\n background-repeat: no-repeat;\n background-position: left center;\n background-size: 0% 100%;\n animation-name: animatedTextHighlightSweep;\n animation-timing-function: ease-out;\n animation-fill-mode: forwards;\n }\n\n @media (prefers-reduced-motion: reduce) {\n &-letter {\n animation: none;\n opacity: 1;\n }\n\n &-shine {\n animation: none;\n background-image: none;\n color: currentColor;\n -webkit-text-fill-color: currentColor;\n }\n\n &-highlight {\n animation: none;\n background-size: 100% 100%;\n }\n\n &-cursor-blinking {\n animation: none;\n opacity: 1;\n }\n }\n}\n\n@keyframes animatedTextRiseUp {\n from {\n opacity: 0;\n transform: translateY(0.6em);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes animatedTextBlurIn {\n from {\n opacity: 0;\n filter: blur(8px);\n }\n\n to {\n opacity: 1;\n filter: blur(0);\n }\n}\n\n@keyframes animatedTextBounceIn {\n 0% {\n opacity: 0;\n transform: translateY(-0.8em);\n }\n\n 60% {\n opacity: 1;\n transform: translateY(0.15em);\n }\n\n 80% {\n transform: translateY(-0.05em);\n }\n\n 100% {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes animatedTextGlitch {\n 0% {\n opacity: 0;\n transform: translate(0, 0);\n text-shadow: none;\n }\n\n 15% {\n opacity: 1;\n transform: translate(-0.05em, 0.03em);\n text-shadow: 0.06em 0 var(--error-color), -0.06em 0 var(--info-color);\n }\n\n 30% {\n transform: translate(0.05em, -0.03em);\n text-shadow: -0.06em 0 var(--error-color), 0.06em 0 var(--info-color);\n }\n\n 45% {\n transform: translate(-0.03em, 0);\n text-shadow: 0.03em 0 var(--error-color), -0.03em 0 var(--info-color);\n }\n\n 60%,\n 100% {\n opacity: 1;\n transform: translate(0, 0);\n text-shadow: none;\n }\n}\n\n@keyframes animatedTextWave {\n 0%,\n 100% {\n transform: translateY(0);\n }\n\n 50% {\n transform: translateY(-0.25em);\n }\n}\n\n@keyframes animatedTextShineSweep {\n 0% {\n background-position: 200% 0;\n }\n\n 100% {\n background-position: -200% 0;\n }\n}\n\n@keyframes animatedTextHighlightSweep {\n from {\n background-size: 0% 100%;\n }\n\n to {\n background-size: 100% 100%;\n }\n}\n\n@keyframes animatedTextCursorBlink {\n 0%,\n 50% {\n opacity: 1;\n }\n\n 50.01%,\n 100% {\n opacity: 0;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=function(e){return e.RiseUp=`rise-up`,e.BlurIn=`blur-in`,e.Bounce=`bounce`,e.Typewriter=`typewriter`,e.Scramble=`scramble`,e.Glitch=`glitch`,e.Wave=`wave`,e.Shine=`shine`,e.Highlight=`highlight`,e}({}),t=function(e){return e.Letter=`letter`,e.Word=`word`,e}({});export{t as AnimatedTextUnit,e as AnimatedTextVariant};
|
|
2
|
+
//# sourceMappingURL=animatedText.types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animatedText.types.mjs","names":[],"sources":["../../../../package/common/animatedText/animatedText.types.ts"],"sourcesContent":["import type { CSSProperties } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\n/** Which animation plays across the text. */\nexport enum AnimatedTextVariant {\n /** Each unit rises up from below its baseline, staggered left to right. */\n RiseUp = 'rise-up',\n /** Each unit fades in from a blur, staggered left to right. */\n BlurIn = 'blur-in',\n /** Each unit drops in from above with a spring overshoot, staggered left to right. */\n Bounce = 'bounce',\n /** Each unit pops in in order, like it's being typed, with a blinking cursor at the end. */\n Typewriter = 'typewriter',\n /** Each unit resolves from random characters to its real value, staggered left to right. */\n Scramble = 'scramble',\n /** Each unit briefly RGB-splits and jitters before settling, staggered left to right. */\n Glitch = 'glitch',\n /** Every unit continuously bobs up and down in a travelling wave, on a loop. */\n Wave = 'wave',\n /** A highlight sweeps across the text, left to right, on a loop. */\n Shine = 'shine',\n /** A marker-style highlight block wipes in behind the whole string, once, left to right. */\n Highlight = 'highlight',\n}\n\n/**\n * What gets staggered and animated as one entrance unit. Applies to every variant except\n * `Shine` and `Highlight`, which always animate the whole string as a single run.\n */\nexport enum AnimatedTextUnit {\n /** Every letter animates on its own. */\n Letter = 'letter',\n /** Every word animates as a whole block. */\n Word = 'word',\n}\n\nexport type AnimatedTextSlots = 'letter' | 'cursor';\n\nexport interface AnimatedTextProps extends HtmlProps {\n /** The text to animate. Split and animated one unit at a time for every variant but `Shine`/`Highlight`. */\n text: string;\n /** Which animation plays (default `RiseUp`). */\n variant?: AnimatedTextVariant;\n /** Whether entrance/loop variants stagger by letter or by word (default `Letter`). Ignored by `Shine`/`Highlight`. */\n unit?: AnimatedTextUnit;\n /**\n * Delay in ms between each unit's animation start. Applies to every variant except `Shine`\n * and `Highlight`, which animate as a single run (default `40`).\n */\n staggerDelay?: number;\n /**\n * Duration in ms of one animation cycle: a single unit's entrance for `RiseUp`/`BlurIn`/\n * `Bounce`/`Glitch` (default `500`), one bob cycle for `Wave` (default `1200`), one sweep of\n * the highlight for `Shine` (default `2000`), or the one-shot wipe-in for `Highlight` (default\n * `600`). Ignored by `Typewriter` and `Scramble`, since each unit resolves instantly; use\n * `staggerDelay` to control their pacing.\n */\n duration?: number;\n\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<AnimatedTextSlots>;\n styles?: SlotStyles<AnimatedTextSlots>;\n}\n"],"mappings":"AAIA,IAAY,EAAL,SAAA,EAAA,OAEL,GAAA,OAAA,UAEA,EAAA,OAAA,UAEA,EAAA,OAAA,SAEA,EAAA,WAAA,aAEA,EAAA,SAAA,WAEA,EAAA,OAAA,SAEA,EAAA,KAAA,OAEA,EAAA,MAAA,QAEA,EAAA,UAAA,aACF,EAAA,CAAA,CAAA,EAMY,EAAL,SAAA,EAAA,OAEL,GAAA,OAAA,SAEA,EAAA,KAAA,QACF,EAAA,CAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../bodyEnd/bodyEnd.mjs";import t from"./floatingMenu.module.mjs";import{useFloatingPosition as n}from"./useFloatingPosition.mjs";import{Align as r}from"./floatingMenu.types.mjs";import{useEffect as i,useRef as a,useState as o}from"react";import s from"classnames";import{jsx as c,jsxs as l}from"react/jsx-runtime";function u(e){return e.charAt(0).toUpperCase()+e.slice(1)}function d({align:d=r.Left,children:f=null,content:p=null,isOpen:m=!1,onOpenChange:h=()=>{},dontCloseOnChildClick:g=!1,className:_,style:v,classNames:y,styles:b,...x}){let S=a(null),C=a(null),w=a(null),T=a(h),[E,D]=o(10);i(()=>{T.current=h});function
|
|
1
|
+
import e from"../bodyEnd/bodyEnd.mjs";import t from"./floatingMenu.module.mjs";import{useFloatingPosition as n}from"./useFloatingPosition.mjs";import{Align as r}from"./floatingMenu.types.mjs";import{useEffect as i,useRef as a,useState as o}from"react";import s from"classnames";import{jsx as c,jsxs as l}from"react/jsx-runtime";function u(e){return e.charAt(0).toUpperCase()+e.slice(1)}function d({align:d=r.Left,children:f=null,content:p=null,isOpen:m=!1,onOpenChange:h=()=>{},dontCloseOnChildClick:g=!1,className:_,style:v,classNames:y,styles:b,...x}){let S=a(null),C=a(null),w=a(null),T=a(h),[E,D]=o(10),O=a(!1);function k(){O.current=!0}i(()=>{T.current=h});function A(){if(!m){let e=w.current?.getBoundingClientRect();D(e?.width??10),h(!0)}}return n({isOpen:m,triggerRef:w,anchorRef:C,panelRef:S,flipClassName:t.floatingMenuAnimFlip}),i(()=>{if(!m)return;function e(e){let t=S.current,n=w.current;if(!t||!n)return;let r=O.current;O.current=!1;let i=r||t===e.target||t.contains(e.target),a=g&&(n===e.target||n.contains(e.target));!i&&!a&&T.current(!1)}return window.addEventListener(`mouseup`,e),()=>window.removeEventListener(`mouseup`,e)},[m,g]),l(`div`,{...x,className:s(t.floatingMenu,_,y?.root),style:{...v,...b?.root},children:[c(`div`,{className:s(t.floatingMenuContent,y?.trigger),style:b?.trigger,ref:w,onClick:A,children:f}),m&&c(e,{children:l(`div`,{ref:C,className:s(t.floatingMenuAnim,y?.menu),style:{width:`${E}px`,...b?.menu},children:[c(`div`,{className:s(t.floatingMenuContainerFlag,t[`floatingMenuContainerFlagAlign${u(d)}`])}),c(`div`,{ref:S,className:s(t.floatingMenuContainer,t[`floatingMenuContainerAlign${u(d)}`],y?.menuContainer),style:b?.menuContainer,onMouseUpCapture:k,children:p})]})})]})}export{d as default};
|
|
2
2
|
//# sourceMappingURL=floatingMenu.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floatingMenu.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.tsx"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './floatingMenu.module.pcss';\nimport { useFloatingPosition } from './useFloatingPosition';\nimport { Align, FloatingMenuProps } from './floatingMenu.types';\n\nfunction capitalize(s: string) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\nfunction FloatingMenu({\n align = Align.Left,\n children = null,\n content = null,\n isOpen = false,\n onOpenChange = () => {},\n dontCloseOnChildClick = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: FloatingMenuProps) {\n const menuContainerRef = useRef<HTMLDivElement>(null);\n const menuAnimRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const onOpenChangeRef = useRef(onOpenChange);\n const [triggerWidth, setTriggerWidth] = useState(10);\n\n useEffect(() => { onOpenChangeRef.current = onOpenChange; });\n\n function handleTriggerClick() {\n if (!isOpen) {\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n onOpenChange(true);\n }\n }\n\n useFloatingPosition({\n isOpen,\n triggerRef,\n anchorRef: menuAnimRef,\n panelRef: menuContainerRef,\n flipClassName: styles.floatingMenuAnimFlip,\n });\n\n useEffect(() => {\n if (!isOpen) return;\n\n function onMouseUp(event: MouseEvent) {\n const menuElem = menuContainerRef.current;\n const triggerElem = triggerRef.current;\n if (!menuElem || !triggerElem) return;\n\n const
|
|
1
|
+
{"version":3,"file":"floatingMenu.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.tsx"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './floatingMenu.module.pcss';\nimport { useFloatingPosition } from './useFloatingPosition';\nimport { Align, FloatingMenuProps } from './floatingMenu.types';\n\nfunction capitalize(s: string) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\nfunction FloatingMenu({\n align = Align.Left,\n children = null,\n content = null,\n isOpen = false,\n onOpenChange = () => {},\n dontCloseOnChildClick = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: FloatingMenuProps) {\n const menuContainerRef = useRef<HTMLDivElement>(null);\n const menuAnimRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const onOpenChangeRef = useRef(onOpenChange);\n const [triggerWidth, setTriggerWidth] = useState(10);\n\n const contentInteractedRef = useRef(false);\n function handleContentMouseUp() {\n contentInteractedRef.current = true;\n }\n\n useEffect(() => { onOpenChangeRef.current = onOpenChange; });\n\n function handleTriggerClick() {\n if (!isOpen) {\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n onOpenChange(true);\n }\n }\n\n useFloatingPosition({\n isOpen,\n triggerRef,\n anchorRef: menuAnimRef,\n panelRef: menuContainerRef,\n flipClassName: styles.floatingMenuAnimFlip,\n });\n\n useEffect(() => {\n if (!isOpen) return;\n\n function onMouseUp(event: MouseEvent) {\n const menuElem = menuContainerRef.current;\n const triggerElem = triggerRef.current;\n if (!menuElem || !triggerElem) return;\n\n const contentInteracted = contentInteractedRef.current;\n contentInteractedRef.current = false;\n\n const menuClicked =\n contentInteracted || menuElem === event.target || menuElem.contains(event.target as Node);\n const triggerClicked = dontCloseOnChildClick &&\n (triggerElem === event.target || triggerElem.contains(event.target as Node));\n\n if (!menuClicked && !triggerClicked) {\n onOpenChangeRef.current(false);\n }\n }\n\n window.addEventListener('mouseup', onMouseUp);\n return () => window.removeEventListener('mouseup', onMouseUp);\n }, [isOpen, dontCloseOnChildClick]);\n\n return (\n <div {...rest} className={cx(styles.floatingMenu, className, classNames?.root)} style={{ ...style, ...slotStyles?.root }}>\n <div\n className={cx(styles.floatingMenuContent, classNames?.trigger)}\n style={slotStyles?.trigger}\n ref={triggerRef}\n onClick={handleTriggerClick}\n >\n {children}\n </div>\n {isOpen && (\n <BodyEnd>\n <div\n ref={menuAnimRef}\n className={cx(styles.floatingMenuAnim, classNames?.menu)}\n style={{\n width: `${triggerWidth}px`,\n ...slotStyles?.menu,\n }}\n >\n <div className={cx(\n styles.floatingMenuContainerFlag,\n styles[`floatingMenuContainerFlagAlign${capitalize(align)}`],\n )} />\n <div\n ref={menuContainerRef}\n className={cx(\n styles.floatingMenuContainer,\n styles[`floatingMenuContainerAlign${capitalize(align)}`],\n classNames?.menuContainer,\n )}\n style={slotStyles?.menuContainer}\n onMouseUpCapture={handleContentMouseUp}\n >\n {content}\n </div>\n </div>\n </BodyEnd>\n )}\n </div>\n );\n}\n\nexport default FloatingMenu;\n"],"mappings":"wUAQA,SAAS,EAAW,EAAW,CAC7B,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,EAAI,EAAE,MAAM,CAAC,CAC9C,CAEA,SAAS,EAAa,CACpB,QAAQ,EAAM,KACd,WAAW,KACX,UAAU,KACV,SAAS,GACT,mBAAqB,CAAC,EACtB,wBAAwB,GACxB,YACA,QACA,aACA,OAAQ,EACR,GAAG,GACiB,CACpB,IAAM,EAAmB,EAAuB,IAAI,EAC9C,EAAc,EAAuB,IAAI,EACzC,EAAa,EAAuB,IAAI,EACxC,EAAkB,EAAO,CAAY,EACrC,CAAC,EAAc,GAAmB,EAAS,EAAE,EAE7C,EAAuB,EAAO,EAAK,EACzC,SAAS,GAAuB,CAC9B,EAAqB,QAAU,EACjC,CAEA,MAAgB,CAAE,EAAgB,QAAU,CAAc,CAAC,EAE3D,SAAS,GAAqB,CAC5B,GAAI,CAAC,EAAQ,CACX,IAAM,EAAO,EAAW,SAAS,sBAAsB,EACvD,EAAgB,GAAM,OAAS,EAAE,EACjC,EAAa,EAAI,CACnB,CACF,CAmCA,OAjCA,EAAoB,CAClB,SACA,aACA,UAAW,EACX,SAAU,EACV,cAAe,EAAO,oBACxB,CAAC,EAED,MAAgB,CACd,GAAI,CAAC,EAAQ,OAEb,SAAS,EAAU,EAAmB,CACpC,IAAM,EAAW,EAAiB,QAC5B,EAAc,EAAW,QAC/B,GAAI,CAAC,GAAY,CAAC,EAAa,OAE/B,IAAM,EAAoB,EAAqB,QAC/C,EAAqB,QAAU,GAE/B,IAAM,EACJ,GAAqB,IAAa,EAAM,QAAU,EAAS,SAAS,EAAM,MAAc,EACpF,EAAiB,IACpB,IAAgB,EAAM,QAAU,EAAY,SAAS,EAAM,MAAc,GAExE,CAAC,GAAe,CAAC,GACnB,EAAgB,QAAQ,EAAK,CAEjC,CAGA,OADA,OAAO,iBAAiB,UAAW,CAAS,MAC/B,OAAO,oBAAoB,UAAW,CAAS,CAC9D,EAAG,CAAC,EAAQ,CAAqB,CAAC,EAGhC,EAAC,MAAD,CAAK,GAAI,EAAM,UAAW,EAAG,EAAO,aAAc,EAAW,GAAY,IAAI,EAAG,MAAO,CAAE,GAAG,EAAO,GAAG,GAAY,IAAK,WAAvH,CACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,oBAAqB,GAAY,OAAO,EAC7D,MAAO,GAAY,QACnB,IAAK,EACL,QAAS,EAER,UACE,CAAA,EACJ,GACC,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EAAG,EAAO,iBAAkB,GAAY,IAAI,EACvD,MAAO,CACL,MAAO,GAAG,EAAa,IACvB,GAAG,GAAY,IACjB,WANF,CAQE,EAAC,MAAD,CAAK,UAAW,EACd,EAAO,0BACP,EAAO,iCAAiC,EAAW,CAAK,IAC1D,CAAI,CAAA,EACJ,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EACT,EAAO,sBACP,EAAO,6BAA6B,EAAW,CAAK,KACpD,GAAY,aACd,EACA,MAAO,GAAY,cACnB,iBAAkB,WAEjB,CACE,CAAA,CACF,GACE,CAAA,CAER,GAET"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{getScrollableAncestors as e,isHiddenByAnyAncestor as t}from"../utils/scrollAncestors.mjs";import{useLayoutEffect as n}from"react";function r({isOpen:r,triggerRef:i,anchorRef:a,panelRef:o,flipClassName:s,placement:c=`bottom`}){n(()=>{if(!r)return;let n,l;function u(){let r=i.current,d=a.current;if(!r||!d){n=requestAnimationFrame(u);return}let f=e(r);function p(){let e=r.getBoundingClientRect(),n=o.current?.offsetHeight??0,i=window.innerHeight-e.bottom,a=e.top,l=c===`top`?a:i,u=l<n&&(c===`top`?i:a)>l,p=c===`top`?!u:u;d.classList.toggle(s,u),d.style.top=`${p?e.top-d.offsetHeight:e.bottom}px`,d.style.left=`${e.left}px`,d.style.visibility=t(e,f)?`hidden`:``}p();let m=[window,...f];m.forEach(e=>e.addEventListener(`scroll`,p,{passive:!0})),window.addEventListener(`resize`,p),l=()=>{m.forEach(e=>e.removeEventListener(`scroll`,p)),window.removeEventListener(`resize`,p)}}return u(),()=>{n!==void 0&&cancelAnimationFrame(n),l?.()}},[r,i,a,o,s,c])}export{r as useFloatingPosition};
|
|
2
2
|
//# sourceMappingURL=useFloatingPosition.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { useLayoutEffect, type RefObject } from 'react';\
|
|
1
|
+
{"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { useLayoutEffect, type RefObject } from 'react';\nimport { getScrollableAncestors, isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\n\nexport interface UseFloatingPositionArgs {\n isOpen: boolean;\n /** The element the popup is anchored to. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */\n anchorRef: RefObject<HTMLElement | null>;\n /** The visible panel whose height decides whether there's room to render on the preferred side. */\n panelRef: RefObject<HTMLElement | null>;\n /** Class toggled on `anchorRef` when flipped to the non-preferred side. */\n flipClassName: string;\n /** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */\n placement?: 'top' | 'bottom';\n}\n\n/**\n * Keeps a portaled, `position: fixed` popup anchored to a trigger element: tracks the\n * trigger across scroll/resize on every real scrolling ancestor, flips above the trigger\n * when there's no room below, and hides (not closes) the popup when the trigger itself\n * scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.\n *\n * Position/visibility are written straight to the DOM via refs, not through React state:\n * going through setState -> re-render -> commit adds a round-trip that lags behind the\n * browser's own scroll painting by at least a frame.\n */\nexport function useFloatingPosition({ isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement = 'bottom' }: UseFloatingPositionArgs) {\n useLayoutEffect(() => {\n if (!isOpen) return;\n\n let rafId: number | undefined;\n let teardown: (() => void) | undefined;\n\n // The anchor/trigger may not be mounted yet on the very first invocation of this\n // effect: a portal target (e.g. BodyEnd's `#bodyEnd` div) can still be missing on\n // the initial render, in which case the portaled content — and this ref — commits\n // one render later. Since refs never change identity, that later commit doesn't\n // re-trigger this effect on its own, so retry on the next frame until it's there.\n function trySetup() {\n const trigger = triggerRef.current;\n const anchor = anchorRef.current;\n if (!trigger || !anchor) {\n rafId = requestAnimationFrame(trySetup);\n return;\n }\n const ancestors = getScrollableAncestors(trigger);\n\n function updatePos() {\n const rect = trigger!.getBoundingClientRect();\n const panelHeight = panelRef.current?.offsetHeight ?? 0;\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceAbove = rect.top;\n const preferredSpace = placement === 'top' ? spaceAbove : spaceBelow;\n const alternateSpace = placement === 'top' ? spaceBelow : spaceAbove;\n const flip = preferredSpace < panelHeight && alternateSpace > preferredSpace;\n const renderAbove = placement === 'top' ? !flip : flip;\n anchor!.classList.toggle(flipClassName, flip);\n // Shift up by the anchor's own height when rendering above, so this works whether\n // the anchor is a zero-height decorative wrapper (FloatingMenu, whose real panel\n // hangs off it via absolute-positioned CSS) or the visible panel itself\n // (Dropdown) — for the former the shift is a no-op (height 0).\n anchor!.style.top = `${renderAbove ? rect.top - anchor!.offsetHeight : rect.bottom}px`;\n anchor!.style.left = `${rect.left}px`;\n anchor!.style.visibility = isHiddenByAnyAncestor(rect, ancestors) ? 'hidden' : '';\n }\n\n updatePos();\n\n const scrollTargets: (Window | HTMLElement)[] = [window, ...ancestors];\n scrollTargets.forEach((t) => t.addEventListener('scroll', updatePos, { passive: true }));\n window.addEventListener('resize', updatePos);\n teardown = () => {\n scrollTargets.forEach((t) => t.removeEventListener('scroll', updatePos));\n window.removeEventListener('resize', updatePos);\n };\n }\n\n trySetup();\n\n return () => {\n if (rafId !== undefined) cancelAnimationFrame(rafId);\n teardown?.();\n };\n }, [isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement]);\n}"],"mappings":"yIA2BA,SAAgB,EAAoB,CAAE,SAAQ,aAAY,YAAW,WAAU,gBAAe,YAAY,UAAqC,CAC7I,MAAsB,CACpB,GAAI,CAAC,EAAQ,OAEb,IAAI,EACA,EAOJ,SAAS,GAAW,CAClB,IAAM,EAAU,EAAW,QACrB,EAAS,EAAU,QACzB,GAAI,CAAC,GAAW,CAAC,EAAQ,CACvB,EAAQ,sBAAsB,CAAQ,EACtC,MACF,CACA,IAAM,EAAY,EAAuB,CAAO,EAEhD,SAAS,GAAY,CACnB,IAAM,EAAO,EAAS,sBAAsB,EACtC,EAAc,EAAS,SAAS,cAAgB,EAChD,EAAa,OAAO,YAAc,EAAK,OACvC,EAAa,EAAK,IAClB,EAAiB,IAAc,MAAQ,EAAa,EAEpD,EAAO,EAAiB,IADP,IAAc,MAAQ,EAAa,GACI,EACxD,EAAc,IAAc,MAAQ,CAAC,EAAO,EAClD,EAAQ,UAAU,OAAO,EAAe,CAAI,EAK5C,EAAQ,MAAM,IAAM,GAAG,EAAc,EAAK,IAAM,EAAQ,aAAe,EAAK,OAAO,IACnF,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAK,IAClC,EAAQ,MAAM,WAAa,EAAsB,EAAM,CAAS,EAAI,SAAW,EACjF,CAEA,EAAU,EAEV,IAAM,EAA0C,CAAC,OAAQ,GAAG,CAAS,EACrE,EAAc,QAAS,GAAM,EAAE,iBAAiB,SAAU,EAAW,CAAE,QAAS,EAAK,CAAC,CAAC,EACvF,OAAO,iBAAiB,SAAU,CAAS,EAC3C,MAAiB,CACf,EAAc,QAAS,GAAM,EAAE,oBAAoB,SAAU,CAAS,CAAC,EACvE,OAAO,oBAAoB,SAAU,CAAS,CAChD,CACF,CAIA,OAFA,EAAS,MAEI,CACP,IAAU,IAAA,IAAW,qBAAqB,CAAK,EACnD,IAAW,CACb,CACF,EAAG,CAAC,EAAQ,EAAY,EAAW,EAAU,EAAe,CAAS,CAAC,CACxE"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useEffect as e,useRef as t,useState as n}from"react";var r=180,i=10;function a({onDismiss:a,axis:o=`x`,distanceThreshold:s=80,velocityThreshold:c=.5,disabled:l=!1,mobileOnly:u=!0}){let d=t(null),[f,p]=n(!1),[m,h]=n(()=>typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(pointer: coarse)`).matches);e(()=>{if(typeof window.matchMedia!=`function`)return;let e=window.matchMedia(`(pointer: coarse)`),t=e=>h(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let g=l||u&&!m,_=t(null),v=t(a);return e(()=>{v.current=a}),e(()=>{let e=d.current;if(!e||g)return;function t(t,n){if(!e)return;n!==`none`&&e.offsetHeight;let r=o===`x`?`translateX(${t}px)`:`translateY(${t}px)`;e.style.transition=n,e.style.transform=r;let i=Math.max(0,1-Math.abs(t)/(s*2.5));e.style.opacity=String(i)}function n(e){let n=_.current;if(!n||e.pointerId!==n.pointerId)return;let r=e.clientX-n.startX,a=e.clientY-n.startY;if(!n.axisLocked){let e=o===`x`?r:a,t=o===`x`?a:r;if(Math.abs(e)<i&&Math.abs(t)<i)return;if(Math.abs(t)>Math.abs(e)){n.active=!1;return}n.axisLocked=!0,p(!0)}n.active&&(e.preventDefault(),n.offset=o===`x`?r:a,t(n.offset,`none`))}function a(){let i=_.current;if(_.current=null,window.removeEventListener(`pointermove`,n),window.removeEventListener(`pointerup`,a),window.removeEventListener(`pointercancel`,a),!i||!i.active||!i.axisLocked){p(!1);return}let o=Math.max(1,Date.now()-i.startTime),l=i.offset/o;if(Math.abs(i.offset)>=s||Math.abs(l)>=c){let n=e?.getBoundingClientRect().width??0;t(Math.sign(i.offset||1)*(n+40),`transform ${r}ms ease-out, opacity ${r}ms ease-out`),setTimeout(()=>v.current(),r)}else t(0,`transform ${r}ms ease-out, opacity ${r}ms ease-out`);p(!1)}function l(t){_.current||!e||(e.style.animation=`none`,_.current={pointerId:t.pointerId,startX:t.clientX,startY:t.clientY,startTime:Date.now(),offset:0,axisLocked:!1,active:!0},window.addEventListener(`pointermove`,n,{passive:!1}),window.addEventListener(`pointerup`,a),window.addEventListener(`pointercancel`,a))}return e.addEventListener(`pointerdown`,l),()=>{e.removeEventListener(`pointerdown`,l),window.removeEventListener(`pointermove`,n),window.removeEventListener(`pointerup`,a),window.removeEventListener(`pointercancel`,a)}},[o,s,c,g]),{ref:d,isDragging:f}}export{a as useSwipeDismiss};
|
|
2
|
+
//# sourceMappingURL=useSwipeDismiss.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSwipeDismiss.mjs","names":[],"sources":["../../../../package/common/hooks/useSwipeDismiss.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\n\nexport interface UseSwipeDismissOptions {\n /** Called once the swipe commits (past the threshold) — after the exit transition finishes,\n * not the instant the pointer is released. */\n onDismiss: () => void;\n /** Which axis the drag tracks (default `'x'`, the natural direction for a toast/notification). */\n axis?: 'x' | 'y';\n /** Distance in px past which releasing counts as a commit, regardless of speed (default `80`). */\n distanceThreshold?: number;\n /** Speed in px/ms past which releasing counts as a commit, regardless of distance (default `0.5`) —\n * lets a fast flick dismiss even if the pointer didn't travel very far. */\n velocityThreshold?: number;\n /** Disables the gesture entirely — no listeners are attached. */\n disabled?: boolean;\n /** Restricts the gesture to coarse (touch) pointers, auto-detected via `matchMedia`. On a\n * mouse/trackpad device a drag is more likely to be a text selection than an intentional\n * dismiss, and other affordances (a close button, auto-dismiss) typically already cover that\n * case. Default `true`; set `false` to allow the gesture on any pointer type. */\n mobileOnly?: boolean;\n}\n\nexport interface UseSwipeDismissResult<T extends HTMLElement> {\n /** Attach to the element that should become draggable. The hook wires up its own pointer\n * listeners on this node directly (no handlers to spread), so this is the only thing to attach. */\n ref: React.RefObject<T | null>;\n /** True for the duration of an active drag — e.g. use it to pause an auto-dismiss timer. */\n isDragging: boolean;\n}\n\nconst EXIT_TRANSITION_MS = 180;\n// Below this many px of movement, direction intent isn't decided yet — lets a vertical scroll\n// gesture that merely starts on the element pass through instead of being hijacked as a swipe.\nconst AXIS_LOCK_THRESHOLD = 10;\n\n/**\n * Drag-to-dismiss on any pointer type (touch, mouse, pen) via the Pointer Events API. Applies the\n * drag offset and a fading opacity directly to the DOM node (bypassing React state) so the visual\n * tracks the pointer at native speed, then either springs back or animates fully off-screen and\n * calls `onDismiss` once that exit transition completes.\n */\nexport function useSwipeDismiss<T extends HTMLElement>({\n onDismiss,\n axis = 'x',\n distanceThreshold = 80,\n velocityThreshold = 0.5,\n disabled = false,\n mobileOnly = true,\n}: UseSwipeDismissOptions): UseSwipeDismissResult<T> {\n const ref = useRef<T>(null);\n const [isDragging, setIsDragging] = useState(false);\n\n const [isCoarsePointer, setIsCoarsePointer] = useState(\n () => typeof window !== 'undefined' && typeof window.matchMedia === 'function' && window.matchMedia('(pointer: coarse)').matches\n );\n useEffect(() => {\n if (typeof window.matchMedia !== 'function') return;\n const mql = window.matchMedia('(pointer: coarse)');\n const onChange = (event: MediaQueryListEvent) => setIsCoarsePointer(event.matches);\n mql.addEventListener('change', onChange);\n return () => mql.removeEventListener('change', onChange);\n }, []);\n\n const effectiveDisabled = disabled || (mobileOnly && !isCoarsePointer);\n\n // Mutable across the life of one drag; doesn't need to trigger re-renders.\n const dragRef = useRef<{\n pointerId: number;\n startX: number;\n startY: number;\n startTime: number;\n offset: number;\n axisLocked: boolean;\n active: boolean;\n } | null>(null);\n\n const onDismissRef = useRef(onDismiss);\n useEffect(() => {\n onDismissRef.current = onDismiss;\n });\n\n useEffect(() => {\n const el = ref.current;\n if (!el || effectiveDisabled) return;\n\n function applyTransform(offset: number, transition: string) {\n if (!el) return;\n if (transition !== 'none') {\n // Switching straight from the live drag's `transition: none` to an animated one, in the\n // same tick as the transform change, can get coalesced into a single frame with no\n // animation in between — the element just jumps to its end state instead of sliding\n // there. Forcing a layout read first commits the current (pre-transition) position as\n // its own frame, so the transition below actually has something to animate from.\n void el.offsetHeight;\n }\n const translate = axis === 'x' ? `translateX(${offset}px)` : `translateY(${offset}px)`;\n el.style.transition = transition;\n el.style.transform = translate;\n const fade = Math.max(0, 1 - Math.abs(offset) / (distanceThreshold * 2.5));\n el.style.opacity = String(fade);\n }\n\n function onPointerMove(event: PointerEvent) {\n const drag = dragRef.current;\n if (!drag || event.pointerId !== drag.pointerId) return;\n\n const deltaX = event.clientX - drag.startX;\n const deltaY = event.clientY - drag.startY;\n\n if (!drag.axisLocked) {\n const primary = axis === 'x' ? deltaX : deltaY;\n const cross = axis === 'x' ? deltaY : deltaX;\n if (Math.abs(primary) < AXIS_LOCK_THRESHOLD && Math.abs(cross) < AXIS_LOCK_THRESHOLD) return;\n if (Math.abs(cross) > Math.abs(primary)) {\n // The gesture is mostly along the other axis (e.g. a page scroll) — hand it back.\n drag.active = false;\n return;\n }\n drag.axisLocked = true;\n setIsDragging(true);\n }\n\n if (!drag.active) return;\n event.preventDefault();\n drag.offset = axis === 'x' ? deltaX : deltaY;\n applyTransform(drag.offset, 'none');\n }\n\n function finishDrag() {\n const drag = dragRef.current;\n dragRef.current = null;\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', finishDrag);\n window.removeEventListener('pointercancel', finishDrag);\n if (!drag || !drag.active || !drag.axisLocked) {\n setIsDragging(false);\n return;\n }\n\n const elapsed = Math.max(1, Date.now() - drag.startTime);\n const velocity = drag.offset / elapsed;\n const committed =\n Math.abs(drag.offset) >= distanceThreshold || Math.abs(velocity) >= velocityThreshold;\n\n if (committed) {\n const width = el?.getBoundingClientRect().width ?? 0;\n const exitOffset = Math.sign(drag.offset || 1) * (width + 40);\n applyTransform(exitOffset, `transform ${EXIT_TRANSITION_MS}ms ease-out, opacity ${EXIT_TRANSITION_MS}ms ease-out`);\n setTimeout(() => onDismissRef.current(), EXIT_TRANSITION_MS);\n } else {\n applyTransform(0, `transform ${EXIT_TRANSITION_MS}ms ease-out, opacity ${EXIT_TRANSITION_MS}ms ease-out`);\n }\n setIsDragging(false);\n }\n\n function onPointerDown(event: PointerEvent) {\n if (dragRef.current || !el) return;\n // A still-\"forwards\"-filling CSS animation (e.g. the toast's entrance slide) wins the\n // cascade over an inline style.transform, so the drag offset below would silently never\n // show up on screen unless the animation is cleared first.\n el.style.animation = 'none';\n dragRef.current = {\n pointerId: event.pointerId,\n startX: event.clientX,\n startY: event.clientY,\n startTime: Date.now(),\n offset: 0,\n axisLocked: false,\n active: true,\n };\n window.addEventListener('pointermove', onPointerMove, { passive: false });\n window.addEventListener('pointerup', finishDrag);\n window.addEventListener('pointercancel', finishDrag);\n }\n\n el.addEventListener('pointerdown', onPointerDown);\n return () => {\n el.removeEventListener('pointerdown', onPointerDown);\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', finishDrag);\n window.removeEventListener('pointercancel', finishDrag);\n };\n }, [axis, distanceThreshold, velocityThreshold, effectiveDisabled]);\n\n return { ref, isDragging };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"../bodyEnd/bodyEnd.mjs";import t from"./popover.module.mjs";import{PopoverAlign as n,PopoverPlacement as r,PopoverTrigger as i}from"./popover.types.mjs";import{usePopoverPosition as a}from"./usePopoverPosition.mjs";import{useCallback as o,useEffect as s,useRef as c,useState as l}from"react";import u from"classnames";import{jsx as d,jsxs as f}from"react/jsx-runtime";var p=[`a[href]`,`area[href]`,`button:not([disabled])`,`input:not([disabled])`,`select:not([disabled])`,`textarea:not([disabled])`,`[tabindex]:not([tabindex="-1"])`,`[contenteditable="true"]`].join(`,`);function m(e){return e?Array.from(e.querySelectorAll(p)):[]}function h({children:p=null,content:h=null,placement:g=r.Bottom,align:_=n.Center,trigger:v=i.Click,isOpen:y,defaultOpen:b=!1,onOpenChange:x=()=>{},offset:S=10,withArrow:C=!0,closeOnOutsideClick:w=!0,closeOnEscape:T=!0,openDelay:E=100,closeDelay:D=120,disabled:O=!1,className:k,style:A,classNames:j,styles:M,...N}){let P=c(null),F=c(null),I=c(null),L=c(null),R=c(void 0),z=y!==void 0,[B,V]=l(b),H=z?y:B,U=c(x);s(()=>{U.current=x});let W=o(e=>{O&&e||(z||V(e),U.current(e))},[O,z]);a({isOpen:!!H,placement:g,align:_,offset:S,triggerRef:P,floatingRef:F,panelRef:I,arrowRef:C?L:{current:null}});function G(){return m(P.current)[0]??P.current}function K(){G()?.focus()}function q(){let e=m(document.body).filter(e=>!F.current?.contains(e)),t=G(),n=t?e.indexOf(t):-1;n>=0&&e[n+1]?.focus()}s(()=>{if(!H||v!==i.Click)return;let e=m(I.current);e.length!==0&&(F.current?.setAttribute(`role`,`dialog`),e[0].focus())},[H,v]);function J(e){if(e.key!==`Tab`||v!==i.Click)return;let t=m(I.current);if(t.length===0)return;let n=document.activeElement;!e.shiftKey&&n===t[t.length-1]?(e.preventDefault(),q(),W(!1)):e.shiftKey&&n===t[0]&&(e.preventDefault(),K(),W(!1))}s(()=>{if(!H)return;function e(e){let t=e.target,n=F.current?.contains(t),r=P.current?.contains(t);!n&&!r&&W(!1)}function t(e){e.key===`Escape`&&(F.current?.contains(document.activeElement)&&(m(P.current)[0]??P.current)?.focus(),W(!1))}function n(e){let t=e.target,n=F.current?.contains(t),r=P.current?.contains(t);!n&&!r&&W(!1)}return w&&v!==i.Hover&&(window.addEventListener(`mouseup`,e),document.addEventListener(`focusin`,n)),T&&window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`mouseup`,e),document.removeEventListener(`focusin`,n),window.removeEventListener(`keydown`,t)}},[H,w,T,v,W]),s(()=>()=>clearTimeout(R.current),[]);function Y(e){clearTimeout(R.current),R.current=setTimeout(()=>W(e),e?E:D)}let X=v===i.Click?{onClick:()=>W(!H)}:v===i.Hover?{onMouseEnter:()=>Y(!0),onMouseLeave:()=>Y(!1)}:{onFocus:()=>W(!0),onBlur:()=>W(!1)},Z=v===i.Hover?{onMouseEnter:()=>Y(!0),onMouseLeave:()=>Y(!1)}:{};return f(`div`,{...N,className:u(t.popover,k,j?.root),style:{...A,...M?.root},children:[d(`div`,{ref:P,className:u(t.popoverTrigger,j?.trigger),style:M?.trigger,...X,children:p}),H&&d(e,{children:f(`div`,{ref:F,className:u(t.popoverFloating,j?.floating),style:M?.floating,"data-placement":g,onKeyDown:J,...Z,children:[d(`div`,{ref:I,className:u(t.popoverPanel,j?.panel),style:M?.panel,children:h}),C&&d(`div`,{ref:L,className:u(t.popoverArrow,j?.arrow),style:M?.arrow})]})})]})}export{h as default};
|
|
2
|
+
//# sourceMappingURL=popover.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.mjs","names":[],"sources":["../../../../package/common/popover/popover.tsx"],"sourcesContent":["import { useRef, useEffect, useState, useCallback } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './popover.module.pcss';\nimport { usePopoverPosition } from './usePopoverPosition';\nimport { PopoverPlacement, PopoverAlign, PopoverTrigger, type PopoverProps } from './popover.types';\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n].join(',');\n\n/** Tabbable descendants of `root`, in DOM order. */\nfunction tabbablesIn(root: ParentNode | null): HTMLElement[] {\n if (!root) return [];\n return Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));\n}\n\nfunction Popover({\n children = null,\n content = null,\n placement = PopoverPlacement.Bottom,\n align = PopoverAlign.Center,\n trigger = PopoverTrigger.Click,\n isOpen,\n defaultOpen = false,\n onOpenChange = () => {},\n offset = 10,\n withArrow = true,\n closeOnOutsideClick = true,\n closeOnEscape = true,\n openDelay = 100,\n closeDelay = 120,\n disabled = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: PopoverProps) {\n const triggerRef = useRef<HTMLDivElement>(null);\n const floatingRef = useRef<HTMLDivElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const arrowRef = useRef<HTMLDivElement>(null);\n const hoverTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const isControlled = isOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const open = isControlled ? isOpen : internalOpen;\n\n // Keep the outside-click/Escape listeners pointed at the latest setter without re-subscribing.\n const onOpenChangeRef = useRef(onOpenChange);\n useEffect(() => { onOpenChangeRef.current = onOpenChange; });\n\n const setOpen = useCallback((next: boolean) => {\n if (disabled && next) return;\n if (!isControlled) setInternalOpen(next);\n onOpenChangeRef.current(next);\n }, [disabled, isControlled]);\n\n usePopoverPosition({\n isOpen: !!open,\n placement,\n align,\n offset,\n triggerRef,\n floatingRef,\n panelRef,\n arrowRef: withArrow ? arrowRef : { current: null },\n });\n\n function firstTriggerFocusable(): HTMLElement | null {\n return tabbablesIn(triggerRef.current)[0] ?? triggerRef.current;\n }\n\n // Hand focus back to the trigger — used on Escape and on Shift+Tab out of the panel top.\n function restoreFocusToTrigger() {\n firstTriggerFocusable()?.focus();\n }\n\n // Move focus to the tabbable element that follows the trigger in the document, skipping the\n // portaled panel — the \"natural next\" stop when Tab exits the bottom of the panel.\n function focusAfterTrigger() {\n const all = tabbablesIn(document.body).filter((el) => !floatingRef.current?.contains(el));\n const trig = firstTriggerFocusable();\n const idx = trig ? all.indexOf(trig) : -1;\n if (idx >= 0) all[idx + 1]?.focus();\n }\n\n // The panel is portaled to the end of the DOM, so Tab never flows into it naturally. When we\n // manage focus (click trigger + focusable content), move focus in on open and, on Tab out of\n // either end, close and continue focus as if the panel sat right after the trigger.\n useEffect(() => {\n if (!open || trigger !== PopoverTrigger.Click) return;\n const focusables = tabbablesIn(panelRef.current);\n if (focusables.length === 0) return;\n // Only claim the dialog role when we're actually managing focus for real content.\n floatingRef.current?.setAttribute('role', 'dialog');\n focusables[0].focus();\n }, [open, trigger]);\n\n function handleFloatingKeyDown(event: React.KeyboardEvent) {\n if (event.key !== 'Tab' || trigger !== PopoverTrigger.Click) return;\n const focusables = tabbablesIn(panelRef.current);\n if (focusables.length === 0) return;\n const active = document.activeElement;\n if (!event.shiftKey && active === focusables[focusables.length - 1]) {\n event.preventDefault();\n focusAfterTrigger();\n setOpen(false);\n } else if (event.shiftKey && active === focusables[0]) {\n event.preventDefault();\n restoreFocusToTrigger();\n setOpen(false);\n }\n }\n\n // Outside click + Escape. Registered only while open and only for the relevant trigger mode.\n useEffect(() => {\n if (!open) return;\n\n function onMouseUp(event: MouseEvent) {\n const target = event.target as Node;\n const inPanel = floatingRef.current?.contains(target);\n const inTrigger = triggerRef.current?.contains(target);\n if (!inPanel && !inTrigger) setOpen(false);\n }\n function onKeyDown(event: KeyboardEvent) {\n if (event.key !== 'Escape') return;\n // Hand focus back to the trigger when it currently sits inside the panel.\n if (floatingRef.current?.contains(document.activeElement)) {\n (tabbablesIn(triggerRef.current)[0] ?? triggerRef.current)?.focus();\n }\n setOpen(false);\n }\n // Keyboard counterpart to the outside click: once focus leaves both the trigger\n // and the (portaled) panel — e.g. tabbing on to the next element — close.\n function onFocusIn(event: FocusEvent) {\n const target = event.target as Node;\n const inPanel = floatingRef.current?.contains(target);\n const inTrigger = triggerRef.current?.contains(target);\n if (!inPanel && !inTrigger) setOpen(false);\n }\n\n if (closeOnOutsideClick && trigger !== PopoverTrigger.Hover) {\n window.addEventListener('mouseup', onMouseUp);\n document.addEventListener('focusin', onFocusIn);\n }\n if (closeOnEscape) window.addEventListener('keydown', onKeyDown);\n return () => {\n window.removeEventListener('mouseup', onMouseUp);\n document.removeEventListener('focusin', onFocusIn);\n window.removeEventListener('keydown', onKeyDown);\n };\n }, [open, closeOnOutsideClick, closeOnEscape, trigger, setOpen]);\n\n useEffect(() => () => clearTimeout(hoverTimer.current), []);\n\n function scheduleHover(next: boolean) {\n clearTimeout(hoverTimer.current);\n hoverTimer.current = setTimeout(() => setOpen(next), next ? openDelay : closeDelay);\n }\n\n const triggerHandlers =\n trigger === PopoverTrigger.Click\n ? { onClick: () => setOpen(!open) }\n : trigger === PopoverTrigger.Hover\n ? { onMouseEnter: () => scheduleHover(true), onMouseLeave: () => scheduleHover(false) }\n : { onFocus: () => setOpen(true), onBlur: () => setOpen(false) };\n\n const floatingHoverHandlers =\n trigger === PopoverTrigger.Hover\n ? { onMouseEnter: () => scheduleHover(true), onMouseLeave: () => scheduleHover(false) }\n : {};\n\n return (\n <div\n {...rest}\n className={cx(styles.popover, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <div\n ref={triggerRef}\n className={cx(styles.popoverTrigger, classNames?.trigger)}\n style={slotStyles?.trigger}\n {...triggerHandlers}\n >\n {children}\n </div>\n {open && (\n <BodyEnd>\n <div\n ref={floatingRef}\n className={cx(styles.popoverFloating, classNames?.floating)}\n style={slotStyles?.floating}\n data-placement={placement}\n onKeyDown={handleFloatingKeyDown}\n {...floatingHoverHandlers}\n >\n <div\n ref={panelRef}\n className={cx(styles.popoverPanel, classNames?.panel)}\n style={slotStyles?.panel}\n >\n {content}\n </div>\n {withArrow && (\n <div\n ref={arrowRef}\n className={cx(styles.popoverArrow, classNames?.arrow)}\n style={slotStyles?.arrow}\n />\n )}\n </div>\n </BodyEnd>\n )}\n </div>\n );\n}\n\nexport default Popover;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={popover:`popover_hhmvN`,"popover-trigger":`popover-trigger_R4ckf`,popoverTrigger:`popover-trigger_R4ckf`,"popover-floating":`popover-floating_mhXrQ`,popoverFloating:`popover-floating_mhXrQ`,"popover-panel":`popover-panel_tVB2k`,popoverPanel:`popover-panel_tVB2k`,popoverIn:`popoverIn_nKOqX`,"popover-arrow":`popover-arrow_B8kB-`,popoverArrow:`popover-arrow_B8kB-`};export{e as default};
|
|
2
|
+
//# sourceMappingURL=popover.module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.module.mjs","names":[],"sources":["../../../../package/common/popover/popover.module.pcss"],"sourcesContent":[".popover {\n position: relative;\n display: inline-flex;\n\n &-trigger {\n display: inline-flex;\n }\n\n &-floating {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1000;\n /* Hidden until usePopoverPosition writes the first coordinates, to avoid a top-left flash. */\n visibility: hidden;\n }\n\n &-panel {\n position: relative;\n /* Above the arrow so the panel background hides the arrow's inner half — only the\n tip pokes out past the panel edge. */\n z-index: 1;\n color: var(--text-color);\n font-family: var(--default-font);\n font-size: var(--default-font-size);\n background: var(--background-modal);\n box-shadow: var(--card-shadow);\n border-radius: calc(var(--default-border-radius) + 4px);\n padding: 12px 14px;\n max-width: min(320px, calc(100vw - 24px));\n animation: popoverIn 0.12s ease forwards;\n }\n\n &-arrow {\n position: absolute;\n width: 10px;\n height: 10px;\n background: var(--background-modal);\n box-shadow: var(--card-shadow);\n transform: rotate(45deg);\n }\n\n /* Arrow sits on the panel edge facing the trigger; --arrow-x / --arrow-y centre it on the trigger. */\n &-floating[data-placement='bottom'] &-arrow {\n top: -5px;\n left: var(--arrow-x, 50%);\n margin-left: -5px;\n }\n &-floating[data-placement='top'] &-arrow {\n bottom: -5px;\n left: var(--arrow-x, 50%);\n margin-left: -5px;\n }\n &-floating[data-placement='right'] &-arrow {\n left: -5px;\n top: var(--arrow-y, 50%);\n margin-top: -5px;\n }\n &-floating[data-placement='left'] &-arrow {\n right: -5px;\n top: var(--arrow-y, 50%);\n margin-top: -5px;\n }\n\n /* Grow from the edge nearest the trigger. */\n &-floating[data-placement='bottom'] &-panel { transform-origin: top center; }\n &-floating[data-placement='top'] &-panel { transform-origin: bottom center; }\n &-floating[data-placement='right'] &-panel { transform-origin: center left; }\n &-floating[data-placement='left'] &-panel { transform-origin: center right; }\n\n @keyframes popoverIn {\n from {\n opacity: 0;\n transform: scale(0.94);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=function(e){return e.Top=`top`,e.Bottom=`bottom`,e.Left=`left`,e.Right=`right`,e}({}),t=function(e){return e.Start=`start`,e.Center=`center`,e.End=`end`,e}({}),n=function(e){return e.Click=`click`,e.Hover=`hover`,e.Focus=`focus`,e}({});export{t as PopoverAlign,e as PopoverPlacement,n as PopoverTrigger};
|
|
2
|
+
//# sourceMappingURL=popover.types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.types.mjs","names":[],"sources":["../../../../package/common/popover/popover.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\n/** Preferred side of the trigger the panel opens on. Flips to the opposite side when there's no room. */\nexport enum PopoverPlacement {\n Top = 'top',\n Bottom = 'bottom',\n Left = 'left',\n Right = 'right',\n}\n\n/** Alignment along the trigger's cross axis (horizontal for top/bottom, vertical for left/right). */\nexport enum PopoverAlign {\n Start = 'start',\n Center = 'center',\n End = 'end',\n}\n\n/** What opens the popover. */\nexport enum PopoverTrigger {\n Click = 'click',\n Hover = 'hover',\n Focus = 'focus',\n}\n\nexport type PopoverSlots = 'root' | 'trigger' | 'floating' | 'panel' | 'arrow';\n\nexport interface PopoverProps extends HtmlProps {\n /** The trigger element. */\n children?: ReactNode;\n /** The popover body. */\n content?: ReactNode;\n /** Preferred side (default `Bottom`). */\n placement?: PopoverPlacement;\n /** Cross-axis alignment (default `Center`). */\n align?: PopoverAlign;\n /** What opens the popover (default `Click`). */\n trigger?: PopoverTrigger;\n /** Controlled open state. Omit for uncontrolled. */\n isOpen?: boolean;\n /** Initial open state when uncontrolled (default `false`). */\n defaultOpen?: boolean;\n /** Fires whenever the popover wants to open or close. */\n onOpenChange?: (isOpen: boolean) => void;\n /** Gap in px between trigger and panel (default `10`). */\n offset?: number;\n /** Render the arrow pointing at the trigger (default `true`). */\n withArrow?: boolean;\n /** Close when clicking outside the panel (default `true`). */\n closeOnOutsideClick?: boolean;\n /** Close when pressing Escape (default `true`). */\n closeOnEscape?: boolean;\n /** Delay in ms before a hover-triggered popover opens (default `100`). */\n openDelay?: number;\n /** Delay in ms before a hover-triggered popover closes (default `120`). */\n closeDelay?: number;\n /** Prevent the popover from opening. */\n disabled?: boolean;\n\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<PopoverSlots>;\n styles?: SlotStyles<PopoverSlots>;\n}\n"],"mappings":"AAIA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,IAAA,MACA,EAAA,OAAA,SACA,EAAA,KAAA,OACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA,EAGY,EAAL,SAAA,EAAA,OACL,GAAA,MAAA,QACA,EAAA,OAAA,SACA,EAAA,IAAA,OACF,EAAA,CAAA,CAAA,EAGY,EAAL,SAAA,EAAA,OACL,GAAA,MAAA,QACA,EAAA,MAAA,QACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{getScrollableAncestors as e,isHiddenByAnyAncestor as t}from"../utils/scrollAncestors.mjs";import{PopoverAlign as n,PopoverPlacement as r}from"./popover.types.mjs";import{useLayoutEffect as i}from"react";var a={[r.Top]:`bottom`,[r.Bottom]:`top`,[r.Left]:`right`,[r.Right]:`left`},o=8;function s({isOpen:s,placement:c,align:l,offset:u,triggerRef:d,floatingRef:f,panelRef:p,arrowRef:m}){i(()=>{if(!s)return;let i,h;function g(){let s=d.current,_=f.current,v=p.current;if(!s||!_||!v){i=requestAnimationFrame(g);return}let y=e(s);function b(){let e=s.getBoundingClientRect(),i=v.offsetWidth,d=v.offsetHeight,f=window.innerWidth,p=window.innerHeight,h={top:e.top,bottom:p-e.bottom,left:e.left,right:f-e.right},g=c===r.Top||c===r.Bottom?d:i,b=c,x=a[c];h[b]<g+u&&h[x]>h[b]&&(b=x);let S=b===`top`||b===`bottom`,C,w;b===`bottom`?C=e.bottom+u:b===`top`?C=e.top-u-d:w=b===`right`?e.right+u:e.left-u-i,S?(w=l===n.Start?e.left:l===n.End?e.right-i:e.left+e.width/2-i/2,w=Math.max(o,Math.min(w,f-i-o))):(C=l===n.Start?e.top:l===n.End?e.bottom-d:e.top+e.height/2-d/2,C=Math.max(o,Math.min(C,p-d-o))),_.style.top=`${C}px`,_.style.left=`${w}px`,_.style.visibility=t(e,y)?`hidden`:`visible`,_.dataset.placement=b;let T=m.current;if(T){let t=T.offsetWidth/2||5;if(S){let n=e.left+e.width/2-w;T.style.setProperty(`--arrow-x`,`${Math.max(t+2,Math.min(n,i-t-2))}px`),T.style.removeProperty(`--arrow-y`)}else{let n=e.top+e.height/2-C;T.style.setProperty(`--arrow-y`,`${Math.max(t+2,Math.min(n,d-t-2))}px`),T.style.removeProperty(`--arrow-x`)}}}b();let x=[window,...y];x.forEach(e=>e.addEventListener(`scroll`,b,{passive:!0})),window.addEventListener(`resize`,b),h=()=>{x.forEach(e=>e.removeEventListener(`scroll`,b)),window.removeEventListener(`resize`,b)}}return g(),()=>{i!==void 0&&cancelAnimationFrame(i),h?.()}},[s,c,l,u,d,f,p,m])}export{s as usePopoverPosition};
|
|
2
|
+
//# sourceMappingURL=usePopoverPosition.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePopoverPosition.mjs","names":[],"sources":["../../../../package/common/popover/usePopoverPosition.ts"],"sourcesContent":["import { useLayoutEffect, type RefObject } from 'react';\nimport { getScrollableAncestors, isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\nimport { PopoverPlacement, PopoverAlign } from './popover.types';\n\ntype Axis = 'top' | 'bottom' | 'left' | 'right';\nconst OPPOSITE: Record<PopoverPlacement, Axis> = {\n [PopoverPlacement.Top]: 'bottom',\n [PopoverPlacement.Bottom]: 'top',\n [PopoverPlacement.Left]: 'right',\n [PopoverPlacement.Right]: 'left',\n};\n\nconst MARGIN = 8; // viewport gutter kept clear when shifting a panel back on-screen\n\nexport interface UsePopoverPositionArgs {\n isOpen: boolean;\n placement: PopoverPlacement;\n align: PopoverAlign;\n offset: number;\n triggerRef: RefObject<HTMLElement | null>;\n /** `position: fixed` wrapper that receives top/left/visibility and the resolved-placement data attribute. */\n floatingRef: RefObject<HTMLElement | null>;\n /** Visible panel, measured to decide flip and shift. */\n panelRef: RefObject<HTMLElement | null>;\n /** Arrow element; gets `--arrow-x` / `--arrow-y` written to it. Pass a null ref when `withArrow` is false. */\n arrowRef: RefObject<HTMLElement | null>;\n}\n\n/**\n * Positions a portaled, `position: fixed` popover on any of the four sides of its trigger with\n * start/center/end cross-axis alignment. Flips to the opposite side when the preferred one has no\n * room, shifts back on-screen along the cross axis, points the arrow at the trigger centre, and\n * hides (not closes) the panel once the trigger scrolls behind a clipping ancestor. Position is\n * written straight to the DOM via refs — going through setState lags the browser's scroll paint.\n */\nexport function usePopoverPosition({\n isOpen, placement, align, offset, triggerRef, floatingRef, panelRef, arrowRef,\n}: UsePopoverPositionArgs) {\n useLayoutEffect(() => {\n if (!isOpen) return;\n\n let rafId: number | undefined;\n let teardown: (() => void) | undefined;\n\n // The portal target (BodyEnd's #bodyEnd) can still be missing on the first commit, so the\n // floating ref lands one render later. Refs don't re-fire the effect, so retry each frame.\n function trySetup() {\n const trigger = triggerRef.current;\n const floating = floatingRef.current;\n const panel = panelRef.current;\n if (!trigger || !floating || !panel) {\n rafId = requestAnimationFrame(trySetup);\n return;\n }\n const ancestors = getScrollableAncestors(trigger);\n\n function updatePos() {\n const t = trigger!.getBoundingClientRect();\n const pw = panel!.offsetWidth;\n const ph = panel!.offsetHeight;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n // Resolve the main-axis side, flipping when the preferred side lacks room and the\n // opposite side has more.\n const room: Record<Axis, number> = {\n top: t.top,\n bottom: vh - t.bottom,\n left: t.left,\n right: vw - t.right,\n };\n const need = (placement === PopoverPlacement.Top || placement === PopoverPlacement.Bottom) ? ph : pw;\n let side: Axis = placement as unknown as Axis;\n const opp = OPPOSITE[placement];\n if (room[side] < need + offset && room[opp] > room[side]) side = opp;\n\n const vertical = side === 'top' || side === 'bottom';\n\n // Main axis: place the panel just outside the trigger on the resolved side.\n let top: number;\n let left: number;\n if (side === 'bottom') { top = t.bottom + offset; }\n else if (side === 'top') { top = t.top - offset - ph; }\n else if (side === 'right') { left = t.right + offset; }\n else { left = t.left - offset - pw; }\n\n // Cross axis: align start/center/end against the trigger, then shift on-screen.\n if (vertical) {\n if (align === PopoverAlign.Start) left = t.left;\n else if (align === PopoverAlign.End) left = t.right - pw;\n else left = t.left + t.width / 2 - pw / 2;\n left = Math.max(MARGIN, Math.min(left!, vw - pw - MARGIN));\n } else {\n if (align === PopoverAlign.Start) top = t.top;\n else if (align === PopoverAlign.End) top = t.bottom - ph;\n else top = t.top + t.height / 2 - ph / 2;\n top = Math.max(MARGIN, Math.min(top!, vh - ph - MARGIN));\n }\n\n floating!.style.top = `${top!}px`;\n floating!.style.left = `${left!}px`;\n floating!.style.visibility = isHiddenByAnyAncestor(t, ancestors) ? 'hidden' : 'visible';\n floating!.dataset.placement = side;\n\n // Arrow: centre it on the trigger along the cross axis, clamped inside the panel edges.\n const arrow = arrowRef.current;\n if (arrow) {\n const half = arrow.offsetWidth / 2 || 5;\n if (vertical) {\n const x = t.left + t.width / 2 - left!;\n arrow.style.setProperty('--arrow-x', `${Math.max(half + 2, Math.min(x, pw - half - 2))}px`);\n arrow.style.removeProperty('--arrow-y');\n } else {\n const y = t.top + t.height / 2 - top!;\n arrow.style.setProperty('--arrow-y', `${Math.max(half + 2, Math.min(y, ph - half - 2))}px`);\n arrow.style.removeProperty('--arrow-x');\n }\n }\n }\n\n updatePos();\n\n const scrollTargets: (Window | HTMLElement)[] = [window, ...ancestors];\n scrollTargets.forEach((tt) => tt.addEventListener('scroll', updatePos, { passive: true }));\n window.addEventListener('resize', updatePos);\n teardown = () => {\n scrollTargets.forEach((tt) => tt.removeEventListener('scroll', updatePos));\n window.removeEventListener('resize', updatePos);\n };\n }\n\n trySetup();\n\n return () => {\n if (rafId !== undefined) cancelAnimationFrame(rafId);\n teardown?.();\n };\n }, [isOpen, placement, align, offset, triggerRef, floatingRef, panelRef, arrowRef]);\n}\n"],"mappings":"kNAKA,IAAM,EAA2C,EAC9C,EAAiB,KAAM,UACvB,EAAiB,QAAS,OAC1B,EAAiB,MAAO,SACxB,EAAiB,OAAQ,MAC5B,EAEM,EAAS,EAuBf,SAAgB,EAAmB,CACjC,SAAQ,YAAW,QAAO,SAAQ,aAAY,cAAa,WAAU,YAC5C,CACzB,MAAsB,CACpB,GAAI,CAAC,EAAQ,OAEb,IAAI,EACA,EAIJ,SAAS,GAAW,CAClB,IAAM,EAAU,EAAW,QACrB,EAAW,EAAY,QACvB,EAAQ,EAAS,QACvB,GAAI,CAAC,GAAW,CAAC,GAAY,CAAC,EAAO,CACnC,EAAQ,sBAAsB,CAAQ,EACtC,MACF,CACA,IAAM,EAAY,EAAuB,CAAO,EAEhD,SAAS,GAAY,CACnB,IAAM,EAAI,EAAS,sBAAsB,EACnC,EAAK,EAAO,YACZ,EAAK,EAAO,aACZ,EAAK,OAAO,WACZ,EAAK,OAAO,YAIZ,EAA6B,CACjC,IAAK,EAAE,IACP,OAAQ,EAAK,EAAE,OACf,KAAM,EAAE,KACR,MAAO,EAAK,EAAE,KAChB,EACM,EAAQ,IAAc,EAAiB,KAAO,IAAc,EAAiB,OAAU,EAAK,EAC9F,EAAa,EACX,EAAM,EAAS,GACjB,EAAK,GAAQ,EAAO,GAAU,EAAK,GAAO,EAAK,KAAO,EAAO,GAEjE,IAAM,EAAW,IAAS,OAAS,IAAS,SAGxC,EACA,EACA,IAAS,SAAY,EAAM,EAAE,OAAS,EACjC,IAAS,MAAS,EAAM,EAAE,IAAM,EAAS,EAC7C,AACE,EADE,IAAS,QAAkB,EAAE,MAAQ,EAChC,EAAE,KAAO,EAAS,EAG5B,GACF,AAEK,EAFD,IAAU,EAAa,MAAc,EAAE,KAClC,IAAU,EAAa,IAAY,EAAE,MAAQ,EAC1C,EAAE,KAAO,EAAE,MAAQ,EAAI,EAAK,EACxC,EAAO,KAAK,IAAI,EAAQ,KAAK,IAAI,EAAO,EAAK,EAAK,CAAM,CAAC,IAEzD,AAEK,EAFD,IAAU,EAAa,MAAa,EAAE,IACjC,IAAU,EAAa,IAAW,EAAE,OAAS,EAC3C,EAAE,IAAM,EAAE,OAAS,EAAI,EAAK,EACvC,EAAM,KAAK,IAAI,EAAQ,KAAK,IAAI,EAAM,EAAK,EAAK,CAAM,CAAC,GAGzD,EAAU,MAAM,IAAM,GAAG,EAAK,IAC9B,EAAU,MAAM,KAAO,GAAG,EAAM,IAChC,EAAU,MAAM,WAAa,EAAsB,EAAG,CAAS,EAAI,SAAW,UAC9E,EAAU,QAAQ,UAAY,EAG9B,IAAM,EAAQ,EAAS,QACvB,GAAI,EAAO,CACT,IAAM,EAAO,EAAM,YAAc,GAAK,EACtC,GAAI,EAAU,CACZ,IAAM,EAAI,EAAE,KAAO,EAAE,MAAQ,EAAI,EACjC,EAAM,MAAM,YAAY,YAAa,GAAG,KAAK,IAAI,EAAO,EAAG,KAAK,IAAI,EAAG,EAAK,EAAO,CAAC,CAAC,EAAE,GAAG,EAC1F,EAAM,MAAM,eAAe,WAAW,CACxC,KAAO,CACL,IAAM,EAAI,EAAE,IAAM,EAAE,OAAS,EAAI,EACjC,EAAM,MAAM,YAAY,YAAa,GAAG,KAAK,IAAI,EAAO,EAAG,KAAK,IAAI,EAAG,EAAK,EAAO,CAAC,CAAC,EAAE,GAAG,EAC1F,EAAM,MAAM,eAAe,WAAW,CACxC,CACF,CACF,CAEA,EAAU,EAEV,IAAM,EAA0C,CAAC,OAAQ,GAAG,CAAS,EACrE,EAAc,QAAS,GAAO,EAAG,iBAAiB,SAAU,EAAW,CAAE,QAAS,EAAK,CAAC,CAAC,EACzF,OAAO,iBAAiB,SAAU,CAAS,EAC3C,MAAiB,CACf,EAAc,QAAS,GAAO,EAAG,oBAAoB,SAAU,CAAS,CAAC,EACzE,OAAO,oBAAoB,SAAU,CAAS,CAChD,CACF,CAIA,OAFA,EAAS,MAEI,CACP,IAAU,IAAA,IAAW,qBAAqB,CAAK,EACnD,IAAW,CACb,CACF,EAAG,CAAC,EAAQ,EAAW,EAAO,EAAQ,EAAY,EAAa,EAAU,CAAQ,CAAC,CACpF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../interactableDiv/index.mjs";import t from"./stepper.module.mjs";import n from"react";import
|
|
1
|
+
import e from"../interactableDiv/index.mjs";import t from"./stepper.module.mjs";import{StepperAlignment as n,StepperCollapse as r,StepperLabelPlacement as i,StepperStyleType as a}from"./stepper.types.mjs";import o,{useEffect as s,useRef as c,useState as l}from"react";import u from"classnames";import{FontAwesomeIcon as d}from"@fortawesome/react-fontawesome";import{jsx as f,jsxs as p}from"react/jsx-runtime";var m={[a.Default]:t.stepperDefault,[a.Outlined]:t.stepperOutlined,[a.Dots]:t.stepperDots},h={[i.Top]:t.stepperLabelTop,[i.Bottom]:t.stepperLabelBottom,[i.Left]:t.stepperLabelLeft,[i.Right]:t.stepperLabelRight};function g(){return f(`svg`,{className:t.stepperCheckmark,strokeLinejoin:`round`,strokeLinecap:`round`,xmlns:`http://www.w3.org/2000/svg`,viewBox:`-0.2 -1.2 3.4 2`,height:`20px`,width:`20px`,children:f(`path`,{d:`M 0 0 l 1 1 l 2 -2`,strokeWidth:`0.4`,fill:`none`})})}function _({open:e,className:n,style:r,children:i}){let a=c(null),[o,d]=l(null);return s(()=>{let e=a.current;if(!e)return;let t=new ResizeObserver(()=>d(e.offsetHeight));return t.observe(e),()=>t.disconnect()},[]),f(`div`,{className:u(t.stepperContent,n),style:{...r,height:e?o??`auto`:0},"aria-hidden":!e,children:f(`div`,{ref:a,className:t.stepperContentInner,children:i})})}function v(e,t){let n=[i.Left,i.Right];return t?e&&n.includes(e)?e:i.Right:e&&!n.includes(e)?e:i.Bottom}function y({steps:i=[],currentStep:s=0,alignment:c=n.Horizontal,onStepClicked:l=null,nonLinear:y=!1,hideLabels:b=!1,styleType:x=a.Default,collapse:S=r.None,labelPlacement:C,className:w,style:T,classNames:E,styles:D,...O}){let k=c===n.Vertical,A=v(C,k);return f(`div`,{...O,className:u(t.stepper,m[x],h[A],{[t.stepperVertical]:k},E?.root,w),style:{...D?.root,...T},children:i.map((n,a)=>{let c=a<s,m=a<=s,h=!!n.error,v=!!l&&!n.disabled&&(y?a!==s:c),x=u(t.stepperEntry,{[t.stepperEntryActive]:m},{[t.stepperEntryDone]:c&&!h},{[t.stepperEntryError]:h},{[t.stepperEntryDisabled]:n.disabled},{[t.stepperClickable]:v},E?.entry),C=n.icon?f(d,{icon:n.icon,className:E?.icon,style:D?.icon}):c&&!h?f(g,{}):a+1,w=f(`div`,{className:u(t.stepperEntryNumber,{[t.stepperEntryNumberDone]:c&&!h},E?.entryNumber),style:D?.entryNumber,children:C}),T=n.optional===!0?`Optional`:n.optional===!1?null:n.optional,O=!b&&p(`div`,{className:t.stepperEntryLabels,children:[f(`div`,{className:u(t.stepperEntryLabel,E?.entryLabel),style:D?.entryLabel,children:n.label}),n.description!=null&&f(`div`,{className:u(t.stepperDescription,E?.description),style:D?.description,children:n.description}),T!=null&&f(`div`,{className:u(t.stepperOptional,E?.optional),style:D?.optional,children:T})]}),A=v?p(e,{className:x,style:D?.entry,onClick:()=>l?.(a),"aria-current":a===s?`step`:void 0,"aria-invalid":h||void 0,children:[w,O]}):p(`div`,{className:x,style:D?.entry,"aria-current":a===s?`step`:void 0,"aria-invalid":h||void 0,children:[w,O]}),j=a<i.length-1&&f(`div`,{className:u(t.stepperConnector,{[t.stepperConnectorFilled]:c},E?.connector),style:D?.connector});if(k){let e=S===r.None?!0:S===r.ActiveOnly?a===s:!c;return p(`div`,{className:t.stepperStep,children:[A,j,n.content!=null&&!b&&f(_,{open:e,className:E?.content,style:D?.content,children:n.content})]},a)}return p(o.Fragment,{children:[A,j]},a)})})}export{y as default};
|
|
2
2
|
//# sourceMappingURL=stepper.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stepper.mjs","names":[],"sources":["../../../../package/common/stepper/stepper.tsx"],"sourcesContent":["import React from 'react';\nimport cx from 'classnames';\nimport styles from './stepper.module.pcss';\nimport InteractableDiv from '../interactableDiv';\nimport type { StepperProps, StepperStep } from './stepper.types';\n\nfunction Checkmark() {\n return (\n <svg\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"-0.2 -1.2 3.4 2\"\n height=\"20px\"\n width=\"20px\"\n >\n <path d=\"M 0 0 l 1 1 l 2 -2\" stroke=\"white\" strokeWidth=\"0.4\" fill=\"none\" />\n </svg>\n );\n}\n\nexport default function Stepper({\n steps = [],\n currentStep = 0,\n alignment = 'horizontal',\n onStepClicked = null,\n nonLinear = false,\n hideLabels = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: StepperProps) {\n const isVertical = alignment === 'vertical';\n\n return (\n <div\n {...rest}\n className={cx(styles.stepper, { [styles.stepperVertical]: isVertical }, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n >\n {steps.map((step: StepperStep, index: number) => {\n const isDone = index < currentStep;\n const isActive = index <= currentStep;\n // nonLinear: every step except the current one is clickable\n // linear: only completed steps are clickable\n const isClickable = !!onStepClicked && (nonLinear ? index !== currentStep : isDone);\n\n const entryClassName = cx(\n styles.stepperEntry,\n { [styles.stepperEntryActive]: isActive },\n { [styles.stepperEntryDone]: isDone },\n { [styles.stepperClickable]: isClickable },\n classNames?.entry\n );\n\n const entryContent = (\n <>\n <div\n className={cx(\n styles.stepperEntryNumber,\n { [styles.stepperEntryNumberDone]: isDone },\n classNames?.entryNumber\n )}\n style={slotStyles?.entryNumber}\n >\n {isDone ? <Checkmark /> : index + 1}\n </div>\n {!hideLabels && (\n <div\n className={cx(\n styles.stepperEntryLabel,\n { [styles.stepperEntryLabelVertical]: isVertical },\n classNames?.entryLabel\n )}\n style={slotStyles?.entryLabel}\n >\n {step.label}\n </div>\n )}\n </>\n );\n\n return (\n <React.Fragment key={index}>\n {isClickable ? (\n <InteractableDiv\n className={entryClassName}\n style={slotStyles?.entry}\n onClick={() => onStepClicked(index)}\n aria-current={index === currentStep ? 'step' : undefined}\n >\n {entryContent}\n </InteractableDiv>\n ) : (\n <div\n className={entryClassName}\n style={slotStyles?.entry}\n aria-current={index === currentStep ? 'step' : undefined}\n >\n {entryContent}\n </div>\n )}\n\n {index < steps.length - 1 && (\n <div\n className={cx(\n styles.stepperConnector,\n { [styles.stepperConnectorFilled]: isDone },\n { [styles.stepperConnectorVertical]: isVertical },\n classNames?.connector\n )}\n style={slotStyles?.connector}\n />\n )}\n </React.Fragment>\n );\n })}\n </div>\n );\n}\n"],"mappings":"+LAMA,SAAS,GAAY,CACnB,OACE,EAAC,MAAD,CACE,eAAe,QACf,cAAc,QACd,MAAM,6BACN,QAAQ,kBACR,OAAO,OACP,MAAM,gBAEN,EAAC,OAAD,CAAM,EAAE,qBAAqB,OAAO,QAAQ,YAAY,MAAM,KAAK,MAAQ,CAAA,CACxE,CAAA,CAET,CAEA,SAAwB,EAAQ,CAC9B,QAAQ,CAAC,EACT,cAAc,EACd,YAAY,aACZ,gBAAgB,KAChB,YAAY,GACZ,aAAa,GACb,YACA,QACA,aACA,OAAQ,EACR,GAAG,GACY,CACf,IAAM,EAAa,IAAc,WAEjC,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,QAAS,EAAG,EAAO,iBAAkB,CAAW,EAAG,GAAY,KAAM,CAAS,EACnG,MAAO,CAAE,GAAG,GAAY,KAAM,GAAG,CAAM,WAEtC,EAAM,KAAK,EAAmB,IAAkB,CAC/C,IAAM,EAAS,EAAQ,EACjB,EAAW,GAAS,EAGpB,EAAc,CAAC,CAAC,IAAkB,EAAY,IAAU,EAAc,GAEtE,EAAiB,EACrB,EAAO,aACP,EAAG,EAAO,oBAAqB,CAAS,EACxC,EAAG,EAAO,kBAAmB,CAAO,EACpC,EAAG,EAAO,kBAAmB,CAAY,EACzC,GAAY,KACd,EAEM,EACJ,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,MAAD,CACE,UAAW,EACT,EAAO,mBACP,EAAG,EAAO,wBAAyB,CAAO,EAC1C,GAAY,WACd,EACA,MAAO,GAAY,qBAElB,EAAS,EAAC,EAAD,CAAY,CAAA,EAAI,EAAQ,CAC/B,CAAA,EACJ,CAAC,GACA,EAAC,MAAD,CACE,UAAW,EACT,EAAO,kBACP,EAAG,EAAO,2BAA4B,CAAW,EACjD,GAAY,UACd,EACA,MAAO,GAAY,oBAElB,EAAK,KACH,CAAA,CAEP,CAAA,CAAA,EAGJ,OACE,EAAC,EAAM,SAAP,CAAA,SAAA,CACG,EACC,EAAC,EAAD,CACE,UAAW,EACX,MAAO,GAAY,MACnB,YAAe,EAAc,CAAK,EAClC,eAAc,IAAU,EAAc,OAAS,IAAA,YAE9C,CACc,CAAA,EAEjB,EAAC,MAAD,CACE,UAAW,EACX,MAAO,GAAY,MACnB,eAAc,IAAU,EAAc,OAAS,IAAA,YAE9C,CACE,CAAA,EAGN,EAAQ,EAAM,OAAS,GACtB,EAAC,MAAD,CACE,UAAW,EACT,EAAO,iBACP,EAAG,EAAO,wBAAyB,CAAO,EAC1C,EAAG,EAAO,0BAA2B,CAAW,EAChD,GAAY,SACd,EACA,MAAO,GAAY,SACpB,CAAA,CAEW,CAAA,EA/BK,CA+BL,CAEpB,CAAC,CACE,CAAA,CAET"}
|
|
1
|
+
{"version":3,"file":"stepper.mjs","names":[],"sources":["../../../../package/common/stepper/stepper.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport styles from './stepper.module.pcss';\nimport InteractableDiv from '../interactableDiv';\nimport {\n StepperAlignment,\n StepperCollapse,\n StepperLabelPlacement,\n StepperStyleType,\n type StepperProps,\n type StepperStep,\n} from './stepper.types';\n\nconst STYLE_CLASS: Record<StepperStyleType, string> = {\n [StepperStyleType.Default]: styles.stepperDefault,\n [StepperStyleType.Outlined]: styles.stepperOutlined,\n [StepperStyleType.Dots]: styles.stepperDots,\n};\n\nconst PLACEMENT_CLASS: Record<StepperLabelPlacement, string> = {\n [StepperLabelPlacement.Top]: styles.stepperLabelTop,\n [StepperLabelPlacement.Bottom]: styles.stepperLabelBottom,\n [StepperLabelPlacement.Left]: styles.stepperLabelLeft,\n [StepperLabelPlacement.Right]: styles.stepperLabelRight,\n};\n\nfunction Checkmark() {\n return (\n <svg\n className={styles.stepperCheckmark}\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"-0.2 -1.2 3.4 2\"\n height=\"20px\"\n width=\"20px\"\n >\n <path d=\"M 0 0 l 1 1 l 2 -2\" strokeWidth=\"0.4\" fill=\"none\" />\n </svg>\n );\n}\n\nfunction StepBody({\n open,\n className,\n style,\n children,\n}: {\n open: boolean;\n className?: string;\n style?: React.CSSProperties;\n children: React.ReactNode;\n}) {\n const innerRef = useRef<HTMLDivElement>(null);\n const [height, setHeight] = useState<number | null>(null);\n\n useEffect(() => {\n const el = innerRef.current;\n if (!el) return;\n const observer = new ResizeObserver(() => setHeight(el.offsetHeight));\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n return (\n <div\n className={cx(styles.stepperContent, className)}\n style={{ ...style, height: open ? (height ?? 'auto') : 0 }}\n aria-hidden={!open}\n >\n <div ref={innerRef} className={styles.stepperContentInner}>\n {children}\n </div>\n </div>\n );\n}\n\nfunction resolvePlacement(\n placement: StepperLabelPlacement | undefined,\n isVertical: boolean,\n): StepperLabelPlacement {\n const verticalValues = [StepperLabelPlacement.Left, StepperLabelPlacement.Right];\n if (isVertical) {\n return placement && verticalValues.includes(placement) ? placement : StepperLabelPlacement.Right;\n }\n return placement && !verticalValues.includes(placement) ? placement : StepperLabelPlacement.Bottom;\n}\n\nexport default function Stepper({\n steps = [],\n currentStep = 0,\n alignment = StepperAlignment.Horizontal,\n onStepClicked = null,\n nonLinear = false,\n hideLabels = false,\n styleType = StepperStyleType.Default,\n collapse = StepperCollapse.None,\n labelPlacement,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: StepperProps) {\n const isVertical = alignment === StepperAlignment.Vertical;\n const placement = resolvePlacement(labelPlacement, isVertical);\n\n return (\n <div\n {...rest}\n className={cx(\n styles.stepper,\n STYLE_CLASS[styleType],\n PLACEMENT_CLASS[placement],\n { [styles.stepperVertical]: isVertical },\n classNames?.root,\n className,\n )}\n style={{ ...slotStyles?.root, ...style }}\n >\n {steps.map((step: StepperStep, index: number) => {\n const isDone = index < currentStep;\n const isActive = index <= currentStep;\n const hasError = !!step.error;\n // nonLinear: every enabled step except the current one is clickable.\n // linear: only completed steps are clickable.\n const isClickable =\n !!onStepClicked && !step.disabled && (nonLinear ? index !== currentStep : isDone);\n\n const entryClassName = cx(\n styles.stepperEntry,\n { [styles.stepperEntryActive]: isActive },\n { [styles.stepperEntryDone]: isDone && !hasError },\n { [styles.stepperEntryError]: hasError },\n { [styles.stepperEntryDisabled]: step.disabled },\n { [styles.stepperClickable]: isClickable },\n classNames?.entry,\n );\n\n const markerContent = step.icon ? (\n <FontAwesomeIcon\n icon={step.icon}\n className={classNames?.icon}\n style={slotStyles?.icon as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n ) : isDone && !hasError ? (\n <Checkmark />\n ) : (\n index + 1\n );\n\n const marker = (\n <div\n className={cx(\n styles.stepperEntryNumber,\n { [styles.stepperEntryNumberDone]: isDone && !hasError },\n classNames?.entryNumber,\n )}\n style={slotStyles?.entryNumber}\n >\n {markerContent}\n </div>\n );\n\n const optionalNode =\n step.optional === true ? 'Optional' : step.optional !== false ? step.optional : null;\n\n const labels = !hideLabels && (\n <div className={styles.stepperEntryLabels}>\n <div\n className={cx(styles.stepperEntryLabel, classNames?.entryLabel)}\n style={slotStyles?.entryLabel}\n >\n {step.label}\n </div>\n {step.description != null && (\n <div\n className={cx(styles.stepperDescription, classNames?.description)}\n style={slotStyles?.description}\n >\n {step.description}\n </div>\n )}\n {optionalNode != null && (\n <div\n className={cx(styles.stepperOptional, classNames?.optional)}\n style={slotStyles?.optional}\n >\n {optionalNode}\n </div>\n )}\n </div>\n );\n\n const header = isClickable ? (\n <InteractableDiv\n className={entryClassName}\n style={slotStyles?.entry}\n onClick={() => onStepClicked?.(index)}\n aria-current={index === currentStep ? 'step' : undefined}\n aria-invalid={hasError || undefined}\n >\n {marker}\n {labels}\n </InteractableDiv>\n ) : (\n <div\n className={entryClassName}\n style={slotStyles?.entry}\n aria-current={index === currentStep ? 'step' : undefined}\n aria-invalid={hasError || undefined}\n >\n {marker}\n {labels}\n </div>\n );\n\n const connector = index < steps.length - 1 && (\n <div\n className={cx(\n styles.stepperConnector,\n { [styles.stepperConnectorFilled]: isDone },\n classNames?.connector,\n )}\n style={slotStyles?.connector}\n />\n );\n\n if (isVertical) {\n const bodyOpen =\n collapse === StepperCollapse.None\n ? true\n : collapse === StepperCollapse.ActiveOnly\n ? index === currentStep\n : !isDone;\n return (\n <div key={index} className={styles.stepperStep}>\n {header}\n {connector}\n {step.content != null && !hideLabels && (\n <StepBody open={bodyOpen} className={classNames?.content} style={slotStyles?.content}>\n {step.content}\n </StepBody>\n )}\n </div>\n );\n }\n\n return (\n <React.Fragment key={index}>\n {header}\n {connector}\n </React.Fragment>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e={stepper:`stepper_kiS2A`,"stepper-
|
|
1
|
+
var e={stepper:`stepper_kiS2A`,"stepper-vertical":`stepper-vertical_2y9rg`,stepperVertical:`stepper-vertical_2y9rg`,"stepper-label-bottom":`stepper-label-bottom_lDfhy`,stepperLabelBottom:`stepper-label-bottom_lDfhy`,"stepper-label-top":`stepper-label-top_sBw4-`,stepperLabelTop:`stepper-label-top_sBw4-`,"stepper-entry":`stepper-entry_KD4JJ`,stepperEntry:`stepper-entry_KD4JJ`,"stepper-clickable":`stepper-clickable_Nm6fP`,stepperClickable:`stepper-clickable_Nm6fP`,"stepper-entry-disabled":`stepper-entry-disabled_T9S5R`,stepperEntryDisabled:`stepper-entry-disabled_T9S5R`,"stepper-entry-number":`stepper-entry-number_J168Q`,stepperEntryNumber:`stepper-entry-number_J168Q`,"stepper-entry-active":`stepper-entry-active_V1aRt`,stepperEntryActive:`stepper-entry-active_V1aRt`,"stepper-entry-done":`stepper-entry-done_M3wb5`,stepperEntryDone:`stepper-entry-done_M3wb5`,"stepper-entry-error":`stepper-entry-error_xjGSr`,stepperEntryError:`stepper-entry-error_xjGSr`,"stepper-checkmark":`stepper-checkmark_iKCap`,stepperCheckmark:`stepper-checkmark_iKCap`,showCheckmark:`showCheckmark_Rd0oW`,"stepper-entry-labels":`stepper-entry-labels_nQT8D`,stepperEntryLabels:`stepper-entry-labels_nQT8D`,"stepper-entry-label":`stepper-entry-label_b94eg`,stepperEntryLabel:`stepper-entry-label_b94eg`,"stepper-description":`stepper-description_5Q0YP`,stepperDescription:`stepper-description_5Q0YP`,"stepper-optional":`stepper-optional_N8mkW`,stepperOptional:`stepper-optional_N8mkW`,"stepper-connector":`stepper-connector_J2FwZ`,stepperConnector:`stepper-connector_J2FwZ`,"stepper-connector-filled":`stepper-connector-filled_W8UZS`,stepperConnectorFilled:`stepper-connector-filled_W8UZS`,"stepper-step":`stepper-step_nUfsV`,stepperStep:`stepper-step_nUfsV`,"stepper-content":`stepper-content_yjlFH`,stepperContent:`stepper-content_yjlFH`,"stepper-label-left":`stepper-label-left_yGbjC`,stepperLabelLeft:`stepper-label-left_yGbjC`,"stepper-content-inner":`stepper-content-inner_0w2wP`,stepperContentInner:`stepper-content-inner_0w2wP`,"stepper-outlined":`stepper-outlined_V7UjP`,stepperOutlined:`stepper-outlined_V7UjP`,"stepper-dots":`stepper-dots_s4cgN`,stepperDots:`stepper-dots_s4cgN`};export{e as default};
|
|
2
2
|
//# sourceMappingURL=stepper.module.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stepper.module.mjs","names":[],"sources":["../../../../package/common/stepper/stepper.module.pcss"],"sourcesContent":[".stepper {\n
|
|
1
|
+
{"version":3,"file":"stepper.module.mjs","names":[],"sources":["../../../../package/common/stepper/stepper.module.pcss"],"sourcesContent":[".stepper {\n /* Theme tokens resolved once, each with a built-in fallback. Set any of the\n public `--stepper-*` variables via ThemeProvider (theme-wide) or `style`\n (per instance) to override; unset ones fall back to the values below. */\n --custom-stepper-marker-size: var(--stepper-marker-size, 40px);\n --custom-stepper-marker-radius: var(--stepper-marker-radius, var(--default-border-radius));\n --custom-stepper-idle-color: var(--stepper-idle-color, var(--primary-lighter));\n --custom-stepper-active-color: var(--stepper-active-color, var(--primary-color));\n --custom-stepper-done-color: var(--stepper-done-color, var(--primary-color));\n --custom-stepper-error-color: var(--stepper-error-color, var(--error-color));\n --custom-stepper-connector-color: var(--stepper-connector-color, var(--primary-color));\n --custom-stepper-connector-thickness: var(--stepper-connector-thickness, 3px);\n --custom-stepper-connector-idle-thickness: var(--stepper-connector-idle-thickness, 1px);\n --custom-stepper-gap: var(--stepper-gap, 12px);\n --custom-stepper-text-on-marker: var(--stepper-text-on-marker, var(--text-on-primary));\n\n user-select: none;\n color: var(--text-color);\n\n &-vertical {\n display: flex;\n flex-flow: column;\n }\n\n &:not(.stepper-vertical) {\n display: flex;\n align-items: center;\n }\n &-label-bottom:not(.stepper-vertical) {\n padding-bottom: 46px;\n }\n &-label-top:not(.stepper-vertical) {\n padding-top: 46px;\n }\n\n /* Entry --------------------------------------------------------------- */\n &-entry {\n display: flex;\n align-items: flex-start;\n gap: var(--custom-stepper-gap);\n box-sizing: border-box;\n }\n &:not(.stepper-vertical) &-entry {\n position: relative;\n flex: 0 0 auto;\n align-items: center;\n gap: 0;\n }\n &-clickable {\n cursor: pointer;\n }\n &-entry-disabled {\n opacity: 0.5;\n }\n\n &-entry-number {\n width: var(--custom-stepper-marker-size);\n height: var(--custom-stepper-marker-size);\n box-sizing: border-box;\n flex-shrink: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n border: 1px solid var(--custom-stepper-idle-color);\n color: var(--custom-stepper-idle-color);\n border-radius: var(--custom-stepper-marker-radius);\n font-weight: 600;\n font-size: calc(var(--custom-stepper-marker-size) * 0.4);\n box-shadow: inset 0px 0px 0px var(--custom-stepper-done-color);\n transition: all 0.4s;\n }\n &-entry-active &-entry-number {\n border: 2px solid var(--custom-stepper-active-color);\n color: var(--custom-stepper-active-color);\n transform: scale3d(1.1, 1.1, 1);\n }\n &-entry-done &-entry-number {\n border-color: var(--custom-stepper-done-color);\n color: var(--custom-stepper-text-on-marker);\n box-shadow: inset 0px 0px 0px 30px var(--custom-stepper-done-color);\n transform: none;\n }\n &-entry-error &-entry-number {\n border: 2px solid var(--custom-stepper-error-color);\n color: var(--custom-stepper-error-color);\n box-shadow: inset 0px 0px 0px var(--custom-stepper-error-color);\n transform: none;\n }\n\n &-checkmark path {\n stroke: var(--custom-stepper-text-on-marker);\n stroke-dasharray: 5;\n stroke-dashoffset: 5;\n animation: showCheckmark 0.4s 0.2s forwards;\n }\n\n &-entry-labels {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n }\n &-entry-label {\n color: var(--text-color);\n }\n &-description {\n color: var(--text-dark);\n font-size: var(--text-small-font-size, 0.85em);\n }\n &-optional {\n color: var(--text-light);\n font-size: var(--text-small-font-size, 0.85em);\n font-style: italic;\n }\n\n &:not(.stepper-vertical) &-entry-labels {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n width: max-content;\n max-width: 160px;\n text-align: center;\n align-items: center;\n }\n &-label-bottom:not(.stepper-vertical) &-entry-labels {\n top: calc(var(--custom-stepper-marker-size) + 6px);\n }\n &-label-top:not(.stepper-vertical) &-entry-labels {\n bottom: calc(var(--custom-stepper-marker-size) + 6px);\n }\n\n &-connector {\n flex: 1 1 auto;\n min-width: 24px;\n height: var(--custom-stepper-connector-idle-thickness);\n border-radius: 999px;\n background-size: 200% 100%;\n background-image: linear-gradient(\n 90deg,\n var(--custom-stepper-connector-color) 0 50%,\n var(--custom-stepper-idle-color) 50% 100%\n );\n background-position: 100% 0;\n transition: background-position 0.6s, height 0.4s, width 0.4s;\n\n &-filled {\n height: var(--custom-stepper-connector-thickness);\n background-position: 0 0;\n }\n }\n\n &-step {\n display: grid;\n grid-template-columns: var(--custom-stepper-marker-size) 1fr;\n column-gap: var(--custom-stepper-gap);\n }\n &-vertical &-entry {\n grid-column: 1 / -1;\n }\n &-vertical &-connector {\n grid-column: 1;\n justify-self: center;\n flex: none;\n width: var(--custom-stepper-connector-idle-thickness);\n min-width: 0;\n height: 100%;\n min-height: 24px;\n background-size: 100% 200%;\n background-image: linear-gradient(\n 180deg,\n var(--custom-stepper-connector-color) 0 50%,\n var(--custom-stepper-idle-color) 50% 100%\n );\n background-position: 0 100%;\n\n &-filled {\n width: var(--custom-stepper-connector-thickness);\n background-position: 0 0;\n }\n }\n &-vertical &-content {\n grid-column: 2;\n }\n\n &-vertical.stepper-label-left &-step {\n grid-template-columns: 1fr var(--custom-stepper-marker-size);\n }\n &-vertical.stepper-label-left &-entry {\n flex-direction: row-reverse;\n }\n &-vertical.stepper-label-left &-connector {\n grid-column: 2;\n }\n &-vertical.stepper-label-left &-content {\n grid-column: 1;\n text-align: right;\n }\n\n &-content {\n overflow: hidden;\n transition: height 0.25s ease;\n }\n &-content-inner {\n padding: 4px 0 12px;\n }\n\n /* Outlined: completed markers stay ringed — a coloured check, no solid fill */\n &-outlined {\n --stepper-text-on-marker: var(--custom-stepper-done-color);\n\n & .stepper-entry-done .stepper-entry-number {\n box-shadow: none;\n color: var(--custom-stepper-done-color);\n }\n }\n &-dots {\n --stepper-marker-size: 16px;\n --stepper-marker-radius: 50%;\n --stepper-gap: 10px;\n\n & .stepper-entry-number {\n font-size: 0;\n border-width: 2px;\n }\n & .stepper-entry-number svg {\n display: none;\n }\n }\n}\n\n@keyframes showCheckmark {\n to {\n stroke-dashoffset: 0;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .stepper-content {\n transition: none;\n }\n .stepper-entry-number,\n .stepper-connector {\n transition: none;\n }\n .stepper-checkmark path {\n animation: none;\n stroke-dashoffset: 0;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=function(e){return e.Horizontal=`horizontal`,e.Vertical=`vertical`,e}({}),t=function(e){return e.Default=`default`,e.Outlined=`outlined`,e.Dots=`dots`,e}({}),n=function(e){return e.None=`none`,e.ActiveOnly=`activeOnly`,e.Completed=`completed`,e}({}),r=function(e){return e.Top=`top`,e.Bottom=`bottom`,e.Left=`left`,e.Right=`right`,e}({});export{e as StepperAlignment,n as StepperCollapse,r as StepperLabelPlacement,t as StepperStyleType};
|
|
2
|
+
//# sourceMappingURL=stepper.types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stepper.types.mjs","names":[],"sources":["../../../../package/common/stepper/stepper.types.ts"],"sourcesContent":["import type React from 'react';\nimport type { IconDefinition } from '@fortawesome/fontawesome-svg-core';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\n/** Layout direction of the stepper. */\nexport enum StepperAlignment {\n Horizontal = 'horizontal',\n Vertical = 'vertical',\n}\n\n/** Visual preset for the step markers and connectors. */\nexport enum StepperStyleType {\n /** Numbered markers, filled solid on completion (the default look). */\n Default = 'default',\n /** Numbered markers that stay ringed when completed — a coloured check, no solid fill. */\n Outlined = 'outlined',\n /** Minimal dots without numbers — compact onboarding / carousel style. */\n Dots = 'dots',\n}\n\n/**\n * Which step bodies (`step.content`) are expanded. Only affects vertical\n * steppers with per-step `content`; ignored otherwise.\n */\nexport enum StepperCollapse {\n /** Every step body stays expanded. */\n None = 'none',\n /** Only the current step's body is expanded (classic vertical wizard). */\n ActiveOnly = 'activeOnly',\n /** Completed (past) step bodies collapse; current and upcoming stay expanded. */\n Completed = 'completed',\n}\n\n/**\n * Where the label block sits relative to the marker. Horizontal steppers use\n * `Top`/`Bottom`; vertical steppers use `Left`/`Right`. An out-of-orientation\n * value falls back to that orientation's default.\n */\nexport enum StepperLabelPlacement {\n Top = 'top',\n Bottom = 'bottom',\n Left = 'left',\n Right = 'right',\n}\n\nexport type StepperSlots =\n | 'root'\n | 'entry'\n | 'entryNumber'\n | 'entryLabel'\n | 'connector'\n | 'description'\n | 'content'\n | 'optional'\n | 'icon';\n\nexport interface StepperStep {\n /** Primary label for the step. */\n label: React.ReactNode;\n /** Secondary line shown under the label. */\n description?: React.ReactNode;\n /** Collapsible body content, rendered under the label (vertical only). */\n content?: React.ReactNode;\n /** FontAwesome icon shown in the marker instead of the step number. */\n icon?: IconDefinition;\n /** Marks the step as errored — recolours the marker with `--stepper-error-color`. */\n error?: boolean;\n /** `true` renders an \"Optional\" hint; a node renders custom hint text. */\n optional?: boolean | React.ReactNode;\n /** Disables this step — never clickable, dimmed. */\n disabled?: boolean;\n}\n\nexport interface StepperProps extends HtmlProps {\n steps?: StepperStep[];\n currentStep?: number;\n alignment?: StepperAlignment | 'horizontal' | 'vertical';\n onStepClicked?: ((index: number) => void) | null;\n /** Allow clicking any step, not just completed ones. */\n nonLinear?: boolean;\n /** Hide the label text (and description) beneath each step entry. */\n hideLabels?: boolean;\n /** Visual preset for markers and connectors (default `Default`). */\n styleType?: StepperStyleType;\n /** Which step bodies are expanded — vertical `content` only (default `None`). */\n collapse?: StepperCollapse;\n /** Label position relative to the marker (default: horizontal `Bottom`, vertical `Right`). */\n labelPlacement?: StepperLabelPlacement;\n className?: string;\n style?: React.CSSProperties;\n classNames?: SlotClassNames<StepperSlots>;\n styles?: SlotStyles<StepperSlots>;\n}\n"],"mappings":"AAKA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,WAAA,aACA,EAAA,SAAA,YACF,EAAA,CAAA,CAAA,EAGY,EAAL,SAAA,EAAA,OAEL,GAAA,QAAA,UAEA,EAAA,SAAA,WAEA,EAAA,KAAA,QACF,EAAA,CAAA,CAAA,EAMY,EAAL,SAAA,EAAA,OAEL,GAAA,KAAA,OAEA,EAAA,WAAA,aAEA,EAAA,UAAA,aACF,EAAA,CAAA,CAAA,EAOY,EAAL,SAAA,EAAA,OACL,GAAA,IAAA,MACA,EAAA,OAAA,SACA,EAAA,KAAA,OACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{defaultTheme as e}from"./defaultTheme.mjs";import t from"./theme.module.mjs";import n,{Component as r}from"react";import i from"classnames";import{jsx as a}from"react/jsx-runtime";var o=class extends r{constructor(...t){super(...t),this.state={resolvedVariables:{},colorFadeActive:!1,currentThemeColor:null},this.colorFadeTimeout=null,this.wrapperRef=n.createRef(),this.themeColorMeta=null,this.createdThemeColorMeta=!1,this.applyTheme=t=>{let n=this.props.themes??[e],r=n.find(e=>!e.baseThemeId)??n[0],i=r?r.variables:{},a=n.find(e=>e.id===t),o=a?this.resolveChain(a.id):[],s=Object.assign({},i,...o);this.setState({resolvedVariables:s,colorFadeActive:!0}),this.colorFadeTimeout&&clearTimeout(this.colorFadeTimeout),this.colorFadeTimeout=setTimeout(()=>{this.setState({colorFadeActive:!1}),this.colorFadeTimeout=null},500),setTimeout(()=>{this.wrapperRef.current&&this.setState({currentThemeColor:getComputedStyle(this.wrapperRef.current).getPropertyValue(`--primary-color`).trim()})},1)}}componentDidMount(){this.applyTheme(this.props.currentThemeId),this.syncThemeColorMeta(this.state.currentThemeColor??``)}componentDidUpdate(e,t){t.currentThemeColor!==this.state.currentThemeColor&&this.syncThemeColorMeta(this.state.currentThemeColor??``),(e.currentThemeId!==this.props.currentThemeId||e.themes!==this.props.themes)&&this.applyTheme(this.props.currentThemeId)}componentWillUnmount(){this.colorFadeTimeout&&clearTimeout(this.colorFadeTimeout),this.createdThemeColorMeta
|
|
1
|
+
import{defaultTheme as e}from"./defaultTheme.mjs";import t from"./theme.module.mjs";import n,{Component as r}from"react";import i from"classnames";import{jsx as a}from"react/jsx-runtime";var o=class extends r{constructor(...t){super(...t),this.state={resolvedVariables:{},colorFadeActive:!1,currentThemeColor:null},this.colorFadeTimeout=null,this.wrapperRef=n.createRef(),this.themeColorMeta=null,this.createdThemeColorMeta=!1,this.applyTheme=t=>{let n=this.props.themes??[e],r=n.find(e=>!e.baseThemeId)??n[0],i=r?r.variables:{},a=n.find(e=>e.id===t),o=a?this.resolveChain(a.id):[],s=Object.assign({},i,...o);this.setState({resolvedVariables:s,colorFadeActive:!0}),this.colorFadeTimeout&&clearTimeout(this.colorFadeTimeout),this.colorFadeTimeout=setTimeout(()=>{this.setState({colorFadeActive:!1}),this.colorFadeTimeout=null},500),setTimeout(()=>{this.wrapperRef.current&&this.setState({currentThemeColor:getComputedStyle(this.wrapperRef.current).getPropertyValue(`--primary-color`).trim()})},1)}}componentDidMount(){this.applyTheme(this.props.currentThemeId),this.syncThemeColorMeta(this.state.currentThemeColor??``)}componentDidUpdate(e,t){t.currentThemeColor!==this.state.currentThemeColor&&this.syncThemeColorMeta(this.state.currentThemeColor??``),(e.currentThemeId!==this.props.currentThemeId||e.themes!==this.props.themes)&&this.applyTheme(this.props.currentThemeId)}componentWillUnmount(){this.colorFadeTimeout&&clearTimeout(this.colorFadeTimeout),this.createdThemeColorMeta&&=(this.themeColorMeta?.remove(),this.themeColorMeta=null,!1)}syncThemeColorMeta(e){if(!(typeof document>`u`)){if(!this.themeColorMeta){let e=document.head.querySelector(`meta[name="theme-color"]`);if(e)this.themeColorMeta=e;else{let e=document.createElement(`meta`);e.setAttribute(`name`,`theme-color`),document.head.appendChild(e),this.themeColorMeta=e,this.createdThemeColorMeta=!0}}this.themeColorMeta.setAttribute(`content`,e)}}resolveChain(t){let n=(this.props.themes??[e]).find(e=>e.id===t);return n?[...n.baseThemeId?this.resolveChain(n.baseThemeId):[],n.variables]:[]}render(){let{children:e}=this.props,{resolvedVariables:n,colorFadeActive:r}=this.state;return a(`div`,{ref:this.wrapperRef,id:`themeProvider`,className:i(t.themeRoot,r&&t.colorFade),style:n,children:e})}};export{o as default};
|
|
2
2
|
//# sourceMappingURL=themeProvider.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themeProvider.mjs","names":[],"sources":["../../../../package/common/themeProvider/themeProvider.tsx"],"sourcesContent":["import React, { Component } from 'react';\nimport cx from 'classnames';\n\nimport type { Theme } from './theme.types';\nimport { defaultTheme } from './defaultTheme';\nimport styles from './theme.module.pcss';\n\ninterface Props {\n children: React.ReactNode;\n themes?: Theme[];\n currentThemeId?: string;\n}\n\ninterface State {\n resolvedVariables: Record<string, string>;\n colorFadeActive: boolean;\n currentThemeColor: string | null;\n}\n\nclass ThemeProvider extends Component<Props, State> {\n state: State = {\n resolvedVariables: {},\n colorFadeActive: false,\n currentThemeColor: null,\n };\n\n private colorFadeTimeout: ReturnType<typeof setTimeout> | null = null;\n private wrapperRef = React.createRef<HTMLDivElement>();\n private themeColorMeta: HTMLMetaElement | null = null;\n private createdThemeColorMeta = false;\n\n componentDidMount() {\n this.applyTheme(this.props.currentThemeId);\n this.syncThemeColorMeta(this.state.currentThemeColor ?? '');\n }\n\n componentDidUpdate(prevProps: Props, prevState: State) {\n if (prevState.currentThemeColor !== this.state.currentThemeColor) {\n this.syncThemeColorMeta(this.state.currentThemeColor ?? '');\n }\n if (\n prevProps.currentThemeId !== this.props.currentThemeId ||\n prevProps.themes !== this.props.themes\n ) {\n this.applyTheme(this.props.currentThemeId);\n }\n }\n\n componentWillUnmount() {\n if (this.colorFadeTimeout) clearTimeout(this.colorFadeTimeout);\n // Only remove the meta tag if we created it; leave a host-app tag intact.\n if (this.createdThemeColorMeta) this.themeColorMeta?.remove();\n }\n\n /**\n * Replaces the former react-helmet usage: keep a single\n * <meta name=\"theme-color\"> in sync with the active theme's primary colour.\n * Reuses a tag the host app already declares; otherwise creates its own\n * (and removes it again on unmount).\n */\n private syncThemeColorMeta(color: string) {\n if (typeof document === 'undefined') return;\n\n if (!this.themeColorMeta) {\n const existing = document.head.querySelector<HTMLMetaElement>(\n 'meta[name=\"theme-color\"]',\n );\n if (existing) {\n this.themeColorMeta = existing;\n } else {\n const meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n document.head.appendChild(meta);\n this.themeColorMeta = meta;\n this.createdThemeColorMeta = true;\n }\n }\n\n this.themeColorMeta.setAttribute('content', color);\n }\n\n /**\n * Resolves the full variable set for a given theme ID by walking up the\n * baseThemeId chain. Returns variables ordered from deepest ancestor to\n * the requested theme so callers can merge in order (later entries win).\n */\n private resolveChain(id: string): Record<string, string>[] {\n const themes = this.props.themes ?? [defaultTheme];\n const theme = themes.find((t) => t.id === id);\n if (!theme) return [];\n\n const parentVars = theme.baseThemeId ? this.resolveChain(theme.baseThemeId) : [];\n\n return [...parentVars, theme.variables as Record<string, string>];\n }\n\n private applyTheme = (currentThemeId: string | undefined) => {\n const themes = this.props.themes ?? [defaultTheme];\n\n // The root theme is the first theme without a baseThemeId.\n // It is always applied as the variable foundation.\n const rootTheme = themes.find((t) => !t.baseThemeId) ?? themes[0];\n const rootVars: Record<string, string> = rootTheme\n ? (rootTheme.variables as Record<string, string>)\n : {};\n\n // Resolve the selected theme's full inheritance chain.\n const selectedTheme = themes.find((t) => t.id === currentThemeId);\n const chainVars = selectedTheme ? this.resolveChain(selectedTheme.id) : [];\n\n // Merge: root foundation → ancestor chain → selected theme (each step overrides)\n const resolvedVariables = Object.assign({}, rootVars, ...chainVars);\n\n this.setState({ resolvedVariables, colorFadeActive: true });\n\n if (this.colorFadeTimeout) clearTimeout(this.colorFadeTimeout);\n this.colorFadeTimeout = setTimeout(() => {\n this.setState({ colorFadeActive: false });\n this.colorFadeTimeout = null;\n }, 500);\n\n // Read --primary-color after the new style is painted for the theme-color meta tag.\n setTimeout(() => {\n if (this.wrapperRef.current) {\n this.setState({\n currentThemeColor: getComputedStyle(this.wrapperRef.current)\n .getPropertyValue('--primary-color')\n .trim(),\n });\n }\n }, 1);\n };\n\n render() {\n const { children } = this.props;\n const { resolvedVariables, colorFadeActive } = this.state;\n\n return (\n <div\n ref={this.wrapperRef}\n id=\"themeProvider\"\n className={cx(styles.themeRoot, colorFadeActive && styles.colorFade)}\n style={resolvedVariables as React.CSSProperties}\n >\n {children}\n </div>\n );\n }\n}\n\nexport default ThemeProvider;\n"],"mappings":"2LAmBA,IAAM,EAAN,cAA4B,CAAwB,0CACnC,CACb,kBAAmB,CAAC,EACpB,gBAAiB,GACjB,kBAAmB,IACrB,wBAEiE,qBAC5C,EAAM,UAA0B,sBACJ,gCACjB,
|
|
1
|
+
{"version":3,"file":"themeProvider.mjs","names":[],"sources":["../../../../package/common/themeProvider/themeProvider.tsx"],"sourcesContent":["import React, { Component } from 'react';\nimport cx from 'classnames';\n\nimport type { Theme } from './theme.types';\nimport { defaultTheme } from './defaultTheme';\nimport styles from './theme.module.pcss';\n\ninterface Props {\n children: React.ReactNode;\n themes?: Theme[];\n currentThemeId?: string;\n}\n\ninterface State {\n resolvedVariables: Record<string, string>;\n colorFadeActive: boolean;\n currentThemeColor: string | null;\n}\n\nclass ThemeProvider extends Component<Props, State> {\n state: State = {\n resolvedVariables: {},\n colorFadeActive: false,\n currentThemeColor: null,\n };\n\n private colorFadeTimeout: ReturnType<typeof setTimeout> | null = null;\n private wrapperRef = React.createRef<HTMLDivElement>();\n private themeColorMeta: HTMLMetaElement | null = null;\n private createdThemeColorMeta = false;\n\n componentDidMount() {\n this.applyTheme(this.props.currentThemeId);\n this.syncThemeColorMeta(this.state.currentThemeColor ?? '');\n }\n\n componentDidUpdate(prevProps: Props, prevState: State) {\n if (prevState.currentThemeColor !== this.state.currentThemeColor) {\n this.syncThemeColorMeta(this.state.currentThemeColor ?? '');\n }\n if (\n prevProps.currentThemeId !== this.props.currentThemeId ||\n prevProps.themes !== this.props.themes\n ) {\n this.applyTheme(this.props.currentThemeId);\n }\n }\n\n componentWillUnmount() {\n if (this.colorFadeTimeout) clearTimeout(this.colorFadeTimeout);\n // Only remove the meta tag if we created it; leave a host-app tag intact.\n // Also clear the cached refs — StrictMode's dev-only mount/unmount/remount\n // cycle reuses this instance, and a stale ref would otherwise point at a\n // detached element on remount instead of re-inserting into <head>.\n if (this.createdThemeColorMeta) {\n this.themeColorMeta?.remove();\n this.themeColorMeta = null;\n this.createdThemeColorMeta = false;\n }\n }\n\n /**\n * Replaces the former react-helmet usage: keep a single\n * <meta name=\"theme-color\"> in sync with the active theme's primary colour.\n * Reuses a tag the host app already declares; otherwise creates its own\n * (and removes it again on unmount).\n */\n private syncThemeColorMeta(color: string) {\n if (typeof document === 'undefined') return;\n\n if (!this.themeColorMeta) {\n const existing = document.head.querySelector<HTMLMetaElement>(\n 'meta[name=\"theme-color\"]',\n );\n if (existing) {\n this.themeColorMeta = existing;\n } else {\n const meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n document.head.appendChild(meta);\n this.themeColorMeta = meta;\n this.createdThemeColorMeta = true;\n }\n }\n\n this.themeColorMeta.setAttribute('content', color);\n }\n\n /**\n * Resolves the full variable set for a given theme ID by walking up the\n * baseThemeId chain. Returns variables ordered from deepest ancestor to\n * the requested theme so callers can merge in order (later entries win).\n */\n private resolveChain(id: string): Record<string, string>[] {\n const themes = this.props.themes ?? [defaultTheme];\n const theme = themes.find((t) => t.id === id);\n if (!theme) return [];\n\n const parentVars = theme.baseThemeId ? this.resolveChain(theme.baseThemeId) : [];\n\n return [...parentVars, theme.variables as Record<string, string>];\n }\n\n private applyTheme = (currentThemeId: string | undefined) => {\n const themes = this.props.themes ?? [defaultTheme];\n\n // The root theme is the first theme without a baseThemeId.\n // It is always applied as the variable foundation.\n const rootTheme = themes.find((t) => !t.baseThemeId) ?? themes[0];\n const rootVars: Record<string, string> = rootTheme\n ? (rootTheme.variables as Record<string, string>)\n : {};\n\n // Resolve the selected theme's full inheritance chain.\n const selectedTheme = themes.find((t) => t.id === currentThemeId);\n const chainVars = selectedTheme ? this.resolveChain(selectedTheme.id) : [];\n\n // Merge: root foundation → ancestor chain → selected theme (each step overrides)\n const resolvedVariables = Object.assign({}, rootVars, ...chainVars);\n\n this.setState({ resolvedVariables, colorFadeActive: true });\n\n if (this.colorFadeTimeout) clearTimeout(this.colorFadeTimeout);\n this.colorFadeTimeout = setTimeout(() => {\n this.setState({ colorFadeActive: false });\n this.colorFadeTimeout = null;\n }, 500);\n\n // Read --primary-color after the new style is painted for the theme-color meta tag.\n setTimeout(() => {\n if (this.wrapperRef.current) {\n this.setState({\n currentThemeColor: getComputedStyle(this.wrapperRef.current)\n .getPropertyValue('--primary-color')\n .trim(),\n });\n }\n }, 1);\n };\n\n render() {\n const { children } = this.props;\n const { resolvedVariables, colorFadeActive } = this.state;\n\n return (\n <div\n ref={this.wrapperRef}\n id=\"themeProvider\"\n className={cx(styles.themeRoot, colorFadeActive && styles.colorFade)}\n style={resolvedVariables as React.CSSProperties}\n >\n {children}\n </div>\n );\n }\n}\n\nexport default ThemeProvider;\n"],"mappings":"2LAmBA,IAAM,EAAN,cAA4B,CAAwB,0CACnC,CACb,kBAAmB,CAAC,EACpB,gBAAiB,GACjB,kBAAmB,IACrB,wBAEiE,qBAC5C,EAAM,UAA0B,sBACJ,gCACjB,mBA0EV,GAAuC,CAC3D,IAAM,EAAS,KAAK,MAAM,QAAU,CAAC,CAAY,EAI3C,EAAY,EAAO,KAAM,GAAM,CAAC,EAAE,WAAW,GAAK,EAAO,GACzD,EAAmC,EACpC,EAAU,UACX,CAAC,EAGC,EAAgB,EAAO,KAAM,GAAM,EAAE,KAAO,CAAc,EAC1D,EAAY,EAAgB,KAAK,aAAa,EAAc,EAAE,EAAI,CAAC,EAGnE,EAAoB,OAAO,OAAO,CAAC,EAAG,EAAU,GAAG,CAAS,EAElE,KAAK,SAAS,CAAE,oBAAmB,gBAAiB,EAAK,CAAC,EAEtD,KAAK,kBAAkB,aAAa,KAAK,gBAAgB,EAC7D,KAAK,iBAAmB,eAAiB,CACvC,KAAK,SAAS,CAAE,gBAAiB,EAAM,CAAC,EACxC,KAAK,iBAAmB,IAC1B,EAAG,GAAG,EAGN,eAAiB,CACX,KAAK,WAAW,SAClB,KAAK,SAAS,CACZ,kBAAmB,iBAAiB,KAAK,WAAW,OAAO,EACxD,iBAAiB,iBAAiB,EAClC,KAAK,CACV,CAAC,CAEL,EAAG,CAAC,CACN,EA3GA,mBAAoB,CAClB,KAAK,WAAW,KAAK,MAAM,cAAc,EACzC,KAAK,mBAAmB,KAAK,MAAM,mBAAqB,EAAE,CAC5D,CAEA,mBAAmB,EAAkB,EAAkB,CACjD,EAAU,oBAAsB,KAAK,MAAM,mBAC7C,KAAK,mBAAmB,KAAK,MAAM,mBAAqB,EAAE,GAG1D,EAAU,iBAAmB,KAAK,MAAM,gBACxC,EAAU,SAAW,KAAK,MAAM,SAEhC,KAAK,WAAW,KAAK,MAAM,cAAc,CAE7C,CAEA,sBAAuB,CACjB,KAAK,kBAAkB,aAAa,KAAK,gBAAgB,EAK7D,AAGE,KAAK,yBAFL,KAAK,gBAAgB,OAAO,EAC5B,KAAK,eAAiB,KACO,GAEjC,CAQA,mBAA2B,EAAe,CACpC,YAAO,SAAa,KAExB,IAAI,CAAC,KAAK,eAAgB,CACxB,IAAM,EAAW,SAAS,KAAK,cAC7B,0BACF,EACA,GAAI,EACF,KAAK,eAAiB,MACjB,CACL,IAAM,EAAO,SAAS,cAAc,MAAM,EAC1C,EAAK,aAAa,OAAQ,aAAa,EACvC,SAAS,KAAK,YAAY,CAAI,EAC9B,KAAK,eAAiB,EACtB,KAAK,sBAAwB,EAC/B,CACF,CAEA,KAAK,eAAe,aAAa,UAAW,CAAK,CAFjD,CAGF,CAOA,aAAqB,EAAsC,CAEzD,IAAM,GADS,KAAK,MAAM,QAAU,CAAC,CAAY,GAC5B,KAAM,GAAM,EAAE,KAAO,CAAE,EAK5C,OAJK,EAIE,CAAC,GAFW,EAAM,YAAc,KAAK,aAAa,EAAM,WAAW,EAAI,CAAC,EAExD,EAAM,SAAmC,EAJ7C,CAAC,CAKtB,CAuCA,QAAS,CACP,GAAM,CAAE,YAAa,KAAK,MACpB,CAAE,oBAAmB,mBAAoB,KAAK,MAEpD,OACE,EAAC,MAAD,CACE,IAAK,KAAK,WACV,GAAG,gBACH,UAAW,EAAG,EAAO,UAAW,GAAmB,EAAO,SAAS,EACnE,MAAO,EAEN,UACE,CAAA,CAET,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../actionIcon/actionIcon.mjs";import t from"./toast.module.mjs";import{useEffect as
|
|
1
|
+
import e from"../actionIcon/actionIcon.mjs";import t from"./toast.module.mjs";import{useSwipeDismiss as n}from"../hooks/useSwipeDismiss.mjs";import{useEffect as r,useRef as i,useState as a}from"react";import o from"classnames";import{FontAwesomeIcon as s}from"@fortawesome/react-fontawesome";import{faBell as c,faCircleCheck as l,faCircleInfo as u,faCircleXmark as d,faTriangleExclamation as f,faXmark as p}from"@fortawesome/free-solid-svg-icons";import{jsx as m,jsxs as h}from"react/jsx-runtime";var g={info:u,success:l,error:d,warn:f,default:c};function _({item:c,isBottom:l,onDismiss:u}){let{id:d,content:f,options:_,dismissing:v}=c,{duration:y,showRemainingTime:b,showCloseButton:x,pauseOnHover:S,type:C,classNames:w,styles:T}=_,[E,D]=a(!1),[O,k]=a(!1),[A,j]=a(!1),{ref:M,isDragging:N}=n({onDismiss:()=>{j(!0),u(d)}}),P=S&&(E||O)||N,F=i(y);return r(()=>{if(y===0||P)return;let e=Date.now(),t=setTimeout(()=>u(d),F.current);return()=>{clearTimeout(t),F.current-=Date.now()-e}},[d,y,u,P]),h(`div`,{ref:M,className:o(t.toast,l?t.toastBottom:null,t[`toast-${C}`],v&&!A&&t.toastDismissing,P&&t.toastPaused,w?.root),style:T?.root,onMouseEnter:S?()=>D(!0):void 0,onMouseLeave:S?()=>D(!1):void 0,onFocus:S?()=>k(!0):void 0,onBlur:S?()=>k(!1):void 0,children:[m(s,{icon:g[C],className:o(t.toastIcon,w?.icon),style:T?.icon}),m(`div`,{className:o(t.toastContent,w?.content),style:T?.content,children:f}),x&&m(e,{icon:p,onClick:()=>u(d),className:o(t.toastCloseButton,w?.closeButton),style:T?.closeButton,"aria-label":`Close`}),b&&y>0&&m(`div`,{className:o(t.toastProgressBar,w?.progressBar),style:{"--toast-duration":`${y}ms`,...T?.progressBar}})]})}export{_ as default};
|
|
2
2
|
//# sourceMappingURL=toast.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.mjs","names":[],"sources":["../../../../package/common/toast/toast.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faCircleInfo,\n faCircleCheck,\n faCircleXmark,\n faTriangleExclamation,\n faBell,\n faXmark,\n} from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './toast.module.pcss';\nimport type { ToastItem } from './toast.types';\nimport ActionIcon from '../actionIcon';\n\ninterface ToastProps {\n item: ToastItem;\n isBottom: boolean;\n onDismiss: (id: string) => void;\n}\n\nconst typeIcons = {\n info: faCircleInfo,\n success: faCircleCheck,\n error: faCircleXmark,\n warn: faTriangleExclamation,\n default: faBell,\n};\n\nfunction Toast({ item, isBottom, onDismiss }: ToastProps) {\n const { id, content, options, dismissing } = item;\n const { duration, showRemainingTime, showCloseButton, pauseOnHover, type, classNames, styles: slotStyles } = options;\n\n const [hovered, setHovered] = useState(false);\n const [focused, setFocused] = useState(false);\n const paused = pauseOnHover && (hovered || focused);\n\n // Remaining time is carried across pause/resume cycles so the timer continues\n // where it left off instead of restarting on every hover.\n const remainingRef = useRef(duration);\n\n useEffect(() => {\n if (duration === 0 || paused) return;\n const start = Date.now();\n const timer = setTimeout(() => onDismiss(id), remainingRef.current);\n return () => {\n clearTimeout(timer);\n remainingRef.current -= Date.now() - start;\n };\n }, [id, duration, onDismiss, paused]);\n\n return (\n <div\n className={cx(\n styles.toast,\n isBottom ? styles.toastBottom : null,\n styles[`toast-${type}`],\n dismissing && styles.toastDismissing,\n paused && styles.toastPaused,\n classNames?.root,\n )}\n style={slotStyles?.root}\n onMouseEnter={pauseOnHover ? () => setHovered(true) : undefined}\n onMouseLeave={pauseOnHover ? () => setHovered(false) : undefined}\n onFocus={pauseOnHover ? () => setFocused(true) : undefined}\n onBlur={pauseOnHover ? () => setFocused(false) : undefined}\n >\n <FontAwesomeIcon\n icon={typeIcons[type]}\n className={cx(styles.toastIcon, classNames?.icon)}\n style={slotStyles?.icon as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n\n <div className={cx(styles.toastContent, classNames?.content)} style={slotStyles?.content}>\n {content}\n </div>\n\n {showCloseButton && (\n <ActionIcon\n icon={faXmark}\n onClick={() => onDismiss(id)}\n className={cx(styles.toastCloseButton, classNames?.closeButton)}\n style={slotStyles?.closeButton}\n aria-label=\"Close\"\n />\n )}\n\n {showRemainingTime && duration > 0 && (\n <div\n className={cx(styles.toastProgressBar, classNames?.progressBar)}\n style={{ '--toast-duration': `${duration}ms`, ...slotStyles?.progressBar } as React.CSSProperties}\n />\n )}\n </div>\n );\n}\n\nexport default Toast;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"toast.mjs","names":[],"sources":["../../../../package/common/toast/toast.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faCircleInfo,\n faCircleCheck,\n faCircleXmark,\n faTriangleExclamation,\n faBell,\n faXmark,\n} from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './toast.module.pcss';\nimport type { ToastItem } from './toast.types';\nimport ActionIcon from '../actionIcon';\nimport { useSwipeDismiss } from '../hooks/useSwipeDismiss';\n\ninterface ToastProps {\n item: ToastItem;\n isBottom: boolean;\n onDismiss: (id: string) => void;\n}\n\nconst typeIcons = {\n info: faCircleInfo,\n success: faCircleCheck,\n error: faCircleXmark,\n warn: faTriangleExclamation,\n default: faBell,\n};\n\nfunction Toast({ item, isBottom, onDismiss }: ToastProps) {\n const { id, content, options, dismissing } = item;\n const { duration, showRemainingTime, showCloseButton, pauseOnHover, type, classNames, styles: slotStyles } = options;\n\n const [hovered, setHovered] = useState(false);\n const [focused, setFocused] = useState(false);\n\n const [swiped, setSwiped] = useState(false);\n const { ref: swipeRef, isDragging } = useSwipeDismiss<HTMLDivElement>({\n onDismiss: () => {\n setSwiped(true);\n onDismiss(id);\n },\n });\n\n const paused = (pauseOnHover && (hovered || focused)) || isDragging;\n\n // Remaining time is carried across pause/resume cycles so the timer continues\n // where it left off instead of restarting on every hover.\n const remainingRef = useRef(duration);\n\n useEffect(() => {\n if (duration === 0 || paused) return;\n const start = Date.now();\n const timer = setTimeout(() => onDismiss(id), remainingRef.current);\n return () => {\n clearTimeout(timer);\n remainingRef.current -= Date.now() - start;\n };\n }, [id, duration, onDismiss, paused]);\n\n return (\n <div\n ref={swipeRef}\n className={cx(\n styles.toast,\n isBottom ? styles.toastBottom : null,\n styles[`toast-${type}`],\n dismissing && !swiped && styles.toastDismissing,\n paused && styles.toastPaused,\n classNames?.root,\n )}\n style={slotStyles?.root}\n onMouseEnter={pauseOnHover ? () => setHovered(true) : undefined}\n onMouseLeave={pauseOnHover ? () => setHovered(false) : undefined}\n onFocus={pauseOnHover ? () => setFocused(true) : undefined}\n onBlur={pauseOnHover ? () => setFocused(false) : undefined}\n >\n <FontAwesomeIcon\n icon={typeIcons[type]}\n className={cx(styles.toastIcon, classNames?.icon)}\n style={slotStyles?.icon as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n\n <div className={cx(styles.toastContent, classNames?.content)} style={slotStyles?.content}>\n {content}\n </div>\n\n {showCloseButton && (\n <ActionIcon\n icon={faXmark}\n onClick={() => onDismiss(id)}\n className={cx(styles.toastCloseButton, classNames?.closeButton)}\n style={slotStyles?.closeButton}\n aria-label=\"Close\"\n />\n )}\n\n {showRemainingTime && duration > 0 && (\n <div\n className={cx(styles.toastProgressBar, classNames?.progressBar)}\n style={{ '--toast-duration': `${duration}ms`, ...slotStyles?.progressBar } as React.CSSProperties}\n />\n )}\n </div>\n );\n}\n\nexport default Toast;\n"],"mappings":"ifAuBA,IAAM,EAAY,CAChB,KAAM,EACN,QAAS,EACT,MAAO,EACP,KAAM,EACN,QAAS,CACX,EAEA,SAAS,EAAM,CAAE,OAAM,WAAU,aAAyB,CACxD,GAAM,CAAE,KAAI,UAAS,UAAS,cAAe,EACvC,CAAE,WAAU,oBAAmB,kBAAiB,eAAc,OAAM,aAAY,OAAQ,GAAe,EAEvG,CAAC,EAAS,GAAc,EAAS,EAAK,EACtC,CAAC,EAAS,GAAc,EAAS,EAAK,EAEtC,CAAC,EAAQ,GAAa,EAAS,EAAK,EACpC,CAAE,IAAK,EAAU,cAAe,EAAgC,CACpE,cAAiB,CACf,EAAU,EAAI,EACd,EAAU,CAAE,CACd,CACF,CAAC,EAEK,EAAU,IAAiB,GAAW,IAAa,EAInD,EAAe,EAAO,CAAQ,EAYpC,OAVA,MAAgB,CACd,GAAI,IAAa,GAAK,EAAQ,OAC9B,IAAM,EAAQ,KAAK,IAAI,EACjB,EAAQ,eAAiB,EAAU,CAAE,EAAG,EAAa,OAAO,EAClE,UAAa,CACX,aAAa,CAAK,EAClB,EAAa,SAAW,KAAK,IAAI,EAAI,CACvC,CACF,EAAG,CAAC,EAAI,EAAU,EAAW,CAAM,CAAC,EAGlC,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EACT,EAAO,MACP,EAAW,EAAO,YAAc,KAChC,EAAO,SAAS,KAChB,GAAc,CAAC,GAAU,EAAO,gBAChC,GAAU,EAAO,YACjB,GAAY,IACd,EACA,MAAO,GAAY,KACnB,aAAc,MAAqB,EAAW,EAAI,EAAI,IAAA,GACtD,aAAc,MAAqB,EAAW,EAAK,EAAI,IAAA,GACvD,QAAS,MAAqB,EAAW,EAAI,EAAI,IAAA,GACjD,OAAQ,MAAqB,EAAW,EAAK,EAAI,IAAA,YAdnD,CAgBE,EAAC,EAAD,CACE,KAAM,EAAU,GAChB,UAAW,EAAG,EAAO,UAAW,GAAY,IAAI,EAChD,MAAO,GAAY,IACpB,CAAA,EAED,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,aAAc,GAAY,OAAO,EAAG,MAAO,GAAY,iBAC9E,CACE,CAAA,EAEJ,GACC,EAAC,EAAD,CACE,KAAM,EACN,YAAe,EAAU,CAAE,EAC3B,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,GAAY,YACnB,aAAW,OACZ,CAAA,EAGF,GAAqB,EAAW,GAC/B,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,CAAE,mBAAoB,GAAG,EAAS,IAAK,GAAG,GAAY,WAAY,CAC1E,CAAA,CAEA,GAET"}
|