@lobehub/ui 5.28.1 → 5.29.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/es/Accordion/AccordionItem.mjs.map +1 -1
- package/es/DraggablePanel/DraggablePanel.mjs +5 -4
- package/es/DraggablePanel/DraggablePanel.mjs.map +1 -1
- package/es/DraggablePanel/type.d.mts +1 -1
- package/es/HotkeyInput/HotkeyInput.mjs.map +1 -1
- package/es/Markdown/SyntaxMarkdown/fenceState.mjs +8 -6
- package/es/Markdown/SyntaxMarkdown/fenceState.mjs.map +1 -1
- package/es/Markdown/plugins/rehypeStreamAnimated.mjs +15 -14
- package/es/Markdown/plugins/rehypeStreamAnimated.mjs.map +1 -1
- package/es/ScrollShadow/ScrollShadow.mjs.map +1 -1
- package/es/ScrollShadow/useScrollOverflow.mjs +9 -8
- package/es/ScrollShadow/useScrollOverflow.mjs.map +1 -1
- package/es/awesome/TypewriterEffect/TypewriterEffect.mjs +17 -16
- package/es/awesome/TypewriterEffect/TypewriterEffect.mjs.map +1 -1
- package/es/base-ui/FloatingSheet/useSnapPoints.mjs +20 -18
- package/es/base-ui/FloatingSheet/useSnapPoints.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionItem.mjs","names":["Flexbox"],"sources":["../../src/Accordion/AccordionItem.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { AnimatePresence } from 'motion/react';\nimport {\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type KeyboardEvent,\n memo,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport useMergeState from 'use-merge-value';\n\nimport Block from '@/Block';\nimport { Flexbox } from '@/Flex';\nimport { type MotionComponentType, useMotionComponent } from '@/MotionProvider';\nimport Text from '@/Text';\nimport { stopPropagation } from '@/utils/dom';\n\nimport ArrowIcon from './ArrowIcon';\nimport { useAccordionConfig, useAccordionItemState } from './context';\nimport { styles } from './style';\nimport { type AccordionItemProps } from './type';\n\ntype AccordionContentBaseProps = {\n children?: ReactNode;\n className?: string;\n contentInnerClassName: string;\n style?: CSSProperties;\n};\n\ntype AccordionStaticContentProps = AccordionContentBaseProps & {\n isOpen: boolean;\n keepContentMounted: boolean;\n};\n\ntype MotionDivProps = ComponentPropsWithoutRef<MotionComponentType['div']>;\n\ntype AccordionMotionContentProps = AccordionContentBaseProps & {\n contextMotionProps?: MotionDivProps;\n isOpen: boolean;\n skipInitialAnimation: boolean;\n};\n\ntype AccordionItemContentProps = AccordionContentBaseProps & {\n contextMotionProps?: MotionDivProps;\n disableAnimation: boolean;\n isOpen: boolean;\n keepContentMounted: boolean;\n skipInitialAnimation: boolean;\n};\n\nconst motionContainerStyle: CSSProperties = { overflow: 'hidden' };\n\nconst AccordionStaticContent = memo<AccordionStaticContentProps>(\n ({ className, style, children, contentInnerClassName, isOpen, keepContentMounted }) => {\n if (keepContentMounted) {\n return (\n <div\n className={className}\n role=\"region\"\n style={{\n display: isOpen ? 'block' : 'none',\n ...style,\n }}\n >\n <div className={contentInnerClassName}>{children}</div>\n </div>\n );\n }\n\n if (!isOpen) return null;\n\n return (\n <div className={className} role=\"region\" style={style}>\n <div className={contentInnerClassName}>{children}</div>\n </div>\n );\n },\n);\n\nAccordionStaticContent.displayName = 'AccordionStaticContent';\n\nconst AccordionMotionContent = memo<AccordionMotionContentProps>(\n ({\n contextMotionProps,\n className,\n style,\n children,\n contentInnerClassName,\n isOpen,\n skipInitialAnimation,\n }) => {\n const Motion = useMotionComponent();\n\n const motionProps = useMemo(\n () => ({\n animate: 'enter',\n exit: 'exit',\n initial: skipInitialAnimation ? false : 'exit',\n variants: {\n enter: {\n height: 'auto',\n opacity: 1,\n transition: {\n duration: 0.2,\n ease: [0.4, 0, 0.2, 1],\n },\n },\n exit: {\n height: 0,\n opacity: 0,\n transition: {\n duration: 0.2,\n ease: [0.4, 0, 0.2, 1],\n },\n },\n },\n ...contextMotionProps,\n }),\n [contextMotionProps, skipInitialAnimation],\n );\n\n return (\n <AnimatePresence initial={false}>\n {isOpen ? (\n <Motion.div {...(motionProps as any)} style={motionContainerStyle}>\n <div className={className} role=\"region\" style={style}>\n <div className={contentInnerClassName}>{children}</div>\n </div>\n </Motion.div>\n ) : null}\n </AnimatePresence>\n );\n },\n);\n\nAccordionMotionContent.displayName = 'AccordionMotionContent';\n\nconst AccordionItemContent = memo<AccordionItemContentProps>(\n ({\n disableAnimation,\n isOpen,\n keepContentMounted,\n className,\n style,\n children,\n contentInnerClassName,\n contextMotionProps,\n skipInitialAnimation,\n }) => {\n if (disableAnimation || !keepContentMounted) {\n return (\n <AccordionStaticContent\n className={className}\n contentInnerClassName={contentInnerClassName}\n isOpen={isOpen}\n keepContentMounted={keepContentMounted}\n style={style}\n >\n {children}\n </AccordionStaticContent>\n );\n }\n\n return (\n <AccordionMotionContent\n className={className}\n contentInnerClassName={contentInnerClassName}\n contextMotionProps={contextMotionProps}\n isOpen={isOpen}\n skipInitialAnimation={skipInitialAnimation}\n style={style}\n >\n {children}\n </AccordionMotionContent>\n );\n },\n);\n\nAccordionItemContent.displayName = 'AccordionItemContent';\n\nconst AccordionItem = memo<AccordionItemProps>(\n ({\n itemKey,\n title,\n children,\n action,\n alwaysShowAction = false,\n disabled = false,\n allowExpand = true,\n hideIndicator: itemHideIndicator,\n indicatorPlacement: itemIndicatorPlacement,\n indicator: customIndicator,\n classNames,\n paddingInline = 16,\n paddingBlock = 8,\n padding,\n ref,\n variant: customVariant,\n styles: customStyles,\n headerWrapper,\n defaultExpand,\n expand,\n onExpandChange,\n }) => {\n // Per-item state context: only this item's provider re-emits when its\n // own isOpen flips, so siblings stay stable across toggles.\n const itemStateContext = useAccordionItemState();\n const configContext = useAccordionConfig();\n\n // Determine if using standalone mode (has expand or defaultExpand props)\n const isStandalone = expand !== undefined || defaultExpand !== undefined;\n\n // Standalone state management\n const [isExpandedStandalone, setIsExpandedStandalone] = useMergeState<boolean>(\n defaultExpand ?? false,\n {\n onChange: onExpandChange,\n value: expand,\n },\n );\n\n const contextHideIndicator = configContext?.hideIndicator;\n const contextIndicatorPlacement = configContext?.indicatorPlacement;\n const contextKeepContentMounted = configContext?.keepContentMounted;\n const contextDisableAnimation = configContext?.disableAnimation;\n const contextMotionProps = configContext?.motionProps;\n const contextVariant = configContext?.variant ?? 'borderless';\n\n const isInitialRenderRef = useRef(true);\n\n useEffect(() => {\n isInitialRenderRef.current = false;\n }, []);\n\n const isDirectContextItem = itemStateContext?.itemKey === itemKey;\n\n // Determine expanded state\n let isOpen = false;\n if (isStandalone) {\n isOpen = isExpandedStandalone;\n } else if (itemStateContext) {\n isOpen = isDirectContextItem\n ? itemStateContext.isOpen\n : itemStateContext.isOpen || itemStateContext.isOpenKey(itemKey);\n }\n\n // Determine other props with fallbacks\n const hideIndicatorFinal = itemHideIndicator ?? contextHideIndicator ?? false;\n const indicatorPlacementFinal = itemIndicatorPlacement ?? contextIndicatorPlacement ?? 'start';\n const keepContentMounted = contextKeepContentMounted ?? true;\n const disableAnimation = contextDisableAnimation ?? false;\n const variant = customVariant || contextVariant;\n\n const contextOnToggle = useCallback(() => {\n if (!itemStateContext) return;\n if (itemStateContext.itemKey === itemKey) {\n itemStateContext.onToggle();\n return;\n }\n itemStateContext.onToggleNestedKey(itemKey);\n }, [itemStateContext, itemKey]);\n\n const handleToggle = useCallback(() => {\n // If allowExpand is false, only allow controlled expansion via expand prop\n if (!allowExpand) return;\n\n if (!disabled) {\n if (isStandalone) {\n setIsExpandedStandalone(!isExpandedStandalone);\n } else if (contextOnToggle) {\n contextOnToggle();\n }\n }\n }, [\n allowExpand,\n disabled,\n isStandalone,\n setIsExpandedStandalone,\n isExpandedStandalone,\n contextOnToggle,\n ]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n // If allowExpand is false, disable keyboard toggle\n if (!allowExpand || disabled) return;\n\n switch (e.key) {\n case 'Enter':\n case ' ': {\n e.preventDefault();\n handleToggle();\n break;\n }\n }\n },\n [allowExpand, disabled, handleToggle],\n );\n\n const preventTitleTextSelection = useCallback((e: any) => {\n // Prevent browser from creating a selection range on double/multi click,\n // which can accidentally select the content region.\n if (e?.detail > 1) e.preventDefault();\n }, []);\n\n // Build indicator\n const indicator = useMemo(() => {\n if (!allowExpand || hideIndicatorFinal) return null;\n\n if (customIndicator) {\n if (typeof customIndicator === 'function') {\n return (\n <span\n aria-hidden=\"true\"\n className={cx(styles.indicator, classNames?.indicator)}\n style={customStyles?.indicator}\n >\n {customIndicator({ isDisabled: disabled, isOpen })}\n </span>\n );\n }\n return (\n <span\n aria-hidden=\"true\"\n className={cx(styles.indicator, classNames?.indicator)}\n style={customStyles?.indicator}\n >\n {customIndicator}\n </span>\n );\n }\n\n return (\n <span\n aria-hidden=\"true\"\n className={cx(styles.indicator, classNames?.indicator)}\n style={customStyles?.indicator}\n >\n <ArrowIcon className={cx(styles.icon, isOpen && styles.iconRotate)} />\n </span>\n );\n }, [\n allowExpand,\n hideIndicatorFinal,\n customIndicator,\n disabled,\n isOpen,\n classNames,\n customStyles,\n ]);\n\n const skipInitialAnimation = isInitialRenderRef.current && isOpen;\n\n const contentClassName = useMemo(\n () => cx('accordion-content', styles.content, classNames?.content),\n [classNames?.content],\n );\n\n const titleNode = useMemo(\n () =>\n typeof title === 'string' ? (\n <Text ellipsis className={classNames?.title} style={customStyles?.title}>\n {title}\n </Text>\n ) : (\n title\n ),\n [title, classNames?.title, customStyles?.title],\n );\n\n const actionNode = useMemo(\n () =>\n action && (\n <Flexbox\n horizontal\n align={'center'}\n flex={'none'}\n gap={4}\n style={customStyles?.action}\n className={cx(\n 'accordion-action',\n styles.action,\n alwaysShowAction && styles.actionVisible,\n classNames?.action,\n )}\n onClick={stopPropagation}\n >\n {action}\n </Flexbox>\n ),\n [action, alwaysShowAction, classNames?.action, customStyles?.action],\n );\n\n const headerElement = useMemo(() => {\n const header = (\n <Block\n horizontal\n className={cx('accordion-header', styles.header, classNames?.header)}\n clickable={!disabled && allowExpand}\n gap={4}\n justify={'space-between'}\n padding={padding}\n paddingBlock={paddingBlock}\n paddingInline={paddingInline}\n ref={ref}\n variant={customVariant || variant}\n style={{\n alignItems: 'center',\n cursor: disabled ? 'not-allowed' : allowExpand ? 'pointer' : 'default',\n opacity: disabled ? 0.5 : undefined,\n overflow: 'hidden',\n width: '100%',\n ...customStyles?.header,\n }}\n onClick={handleToggle}\n onKeyDown={handleKeyDown}\n >\n {indicatorPlacementFinal === 'start' ? (\n <>\n <Flexbox\n horizontal\n align={'center'}\n className={styles.titleWrapper}\n flex={1}\n gap={2}\n style={{\n overflow: 'hidden',\n }}\n onDoubleClick={preventTitleTextSelection}\n onMouseDown={preventTitleTextSelection}\n >\n {titleNode}\n {indicator}\n </Flexbox>\n <Flexbox horizontal align={'center'} flex={'none'} gap={4}>\n {actionNode}\n </Flexbox>\n </>\n ) : (\n <>\n <Flexbox\n horizontal\n align={'center'}\n className={styles.titleWrapper}\n flex={1}\n gap={2}\n style={{\n overflow: 'hidden',\n }}\n onDoubleClick={preventTitleTextSelection}\n onMouseDown={preventTitleTextSelection}\n >\n {titleNode}\n </Flexbox>\n <Flexbox horizontal align={'center'} flex={'none'} gap={4}>\n {actionNode}\n {indicator}\n </Flexbox>\n </>\n )}\n </Block>\n );\n if (headerWrapper) {\n return headerWrapper(header);\n }\n return header;\n }, [\n classNames?.header,\n disabled,\n allowExpand,\n padding,\n paddingBlock,\n paddingInline,\n ref,\n customVariant,\n variant,\n customStyles?.header,\n handleToggle,\n handleKeyDown,\n indicatorPlacementFinal,\n preventTitleTextSelection,\n titleNode,\n indicator,\n actionNode,\n headerWrapper,\n ]);\n\n return (\n <div\n className={cx('accordion-item', styles.item, classNames?.base)}\n style={customStyles?.base}\n >\n {headerElement}\n <AccordionItemContent\n className={contentClassName}\n contentInnerClassName={styles.contentInner}\n contextMotionProps={contextMotionProps}\n disableAnimation={!!disableAnimation}\n isOpen={isOpen}\n keepContentMounted={!!keepContentMounted}\n skipInitialAnimation={skipInitialAnimation}\n style={customStyles?.content}\n >\n {children}\n </AccordionItemContent>\n </div>\n );\n },\n);\n\nAccordionItem.displayName = 'AccordionItem';\n\nexport default AccordionItem;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AccordionItem.mjs","names":["Flexbox"],"sources":["../../src/Accordion/AccordionItem.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { AnimatePresence } from 'motion/react';\nimport {\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type KeyboardEvent,\n memo,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport useMergeState from 'use-merge-value';\n\nimport Block from '@/Block';\nimport { Flexbox } from '@/Flex';\nimport { type MotionComponentType, useMotionComponent } from '@/MotionProvider';\nimport Text from '@/Text';\nimport { stopPropagation } from '@/utils/dom';\n\nimport ArrowIcon from './ArrowIcon';\nimport { useAccordionConfig, useAccordionItemState } from './context';\nimport { styles } from './style';\nimport { type AccordionItemProps } from './type';\n\ntype AccordionContentBaseProps = {\n children?: ReactNode;\n className?: string;\n contentInnerClassName: string;\n style?: CSSProperties;\n};\n\ntype AccordionStaticContentProps = AccordionContentBaseProps & {\n isOpen: boolean;\n keepContentMounted: boolean;\n};\n\ntype MotionDivProps = ComponentPropsWithoutRef<MotionComponentType['div']>;\n\ntype AccordionMotionContentProps = AccordionContentBaseProps & {\n contextMotionProps?: MotionDivProps;\n isOpen: boolean;\n skipInitialAnimation: boolean;\n};\n\ntype AccordionItemContentProps = AccordionContentBaseProps & {\n contextMotionProps?: MotionDivProps;\n disableAnimation: boolean;\n isOpen: boolean;\n keepContentMounted: boolean;\n skipInitialAnimation: boolean;\n};\n\nconst motionContainerStyle: CSSProperties = { overflow: 'hidden' };\n\nconst AccordionStaticContent = memo<AccordionStaticContentProps>(\n ({ className, style, children, contentInnerClassName, isOpen, keepContentMounted }) => {\n if (keepContentMounted) {\n return (\n <div\n className={className}\n role=\"region\"\n style={{\n display: isOpen ? 'block' : 'none',\n ...style,\n }}\n >\n <div className={contentInnerClassName}>{children}</div>\n </div>\n );\n }\n\n if (!isOpen) return null;\n\n return (\n <div className={className} role=\"region\" style={style}>\n <div className={contentInnerClassName}>{children}</div>\n </div>\n );\n },\n);\n\nAccordionStaticContent.displayName = 'AccordionStaticContent';\n\nconst AccordionMotionContent = memo<AccordionMotionContentProps>(\n ({\n contextMotionProps,\n className,\n style,\n children,\n contentInnerClassName,\n isOpen,\n skipInitialAnimation,\n }) => {\n const Motion = useMotionComponent();\n\n const motionProps = useMemo(\n () => ({\n animate: 'enter',\n exit: 'exit',\n initial: skipInitialAnimation ? false : 'exit',\n variants: {\n enter: {\n height: 'auto',\n opacity: 1,\n transition: {\n duration: 0.2,\n ease: [0.4, 0, 0.2, 1],\n },\n },\n exit: {\n height: 0,\n opacity: 0,\n transition: {\n duration: 0.2,\n ease: [0.4, 0, 0.2, 1],\n },\n },\n },\n ...contextMotionProps,\n }),\n [contextMotionProps, skipInitialAnimation],\n );\n\n return (\n <AnimatePresence initial={false}>\n {isOpen ? (\n <Motion.div {...(motionProps as any)} style={motionContainerStyle}>\n <div className={className} role=\"region\" style={style}>\n <div className={contentInnerClassName}>{children}</div>\n </div>\n </Motion.div>\n ) : null}\n </AnimatePresence>\n );\n },\n);\n\nAccordionMotionContent.displayName = 'AccordionMotionContent';\n\nconst AccordionItemContent = memo<AccordionItemContentProps>(\n ({\n disableAnimation,\n isOpen,\n keepContentMounted,\n className,\n style,\n children,\n contentInnerClassName,\n contextMotionProps,\n skipInitialAnimation,\n }) => {\n if (disableAnimation || !keepContentMounted) {\n return (\n <AccordionStaticContent\n className={className}\n contentInnerClassName={contentInnerClassName}\n isOpen={isOpen}\n keepContentMounted={keepContentMounted}\n style={style}\n >\n {children}\n </AccordionStaticContent>\n );\n }\n\n return (\n <AccordionMotionContent\n className={className}\n contentInnerClassName={contentInnerClassName}\n contextMotionProps={contextMotionProps}\n isOpen={isOpen}\n skipInitialAnimation={skipInitialAnimation}\n style={style}\n >\n {children}\n </AccordionMotionContent>\n );\n },\n);\n\nAccordionItemContent.displayName = 'AccordionItemContent';\n\nconst AccordionItem = memo<AccordionItemProps>(\n ({\n itemKey,\n title,\n children,\n action,\n alwaysShowAction = false,\n disabled = false,\n allowExpand = true,\n hideIndicator: itemHideIndicator,\n indicatorPlacement: itemIndicatorPlacement,\n indicator: customIndicator,\n classNames,\n paddingInline = 16,\n paddingBlock = 8,\n padding,\n ref,\n variant: customVariant,\n styles: customStyles,\n headerWrapper,\n defaultExpand,\n expand,\n onExpandChange,\n }) => {\n // Per-item state context: only this item's provider re-emits when its\n // own isOpen flips, so siblings stay stable across toggles.\n const itemStateContext = useAccordionItemState();\n const configContext = useAccordionConfig();\n\n // Determine if using standalone mode (has expand or defaultExpand props)\n const isStandalone = expand !== undefined || defaultExpand !== undefined;\n\n // Standalone state management\n const [isExpandedStandalone, setIsExpandedStandalone] = useMergeState<boolean>(\n defaultExpand ?? false,\n {\n onChange: onExpandChange,\n value: expand,\n },\n );\n\n const contextHideIndicator = configContext?.hideIndicator;\n const contextIndicatorPlacement = configContext?.indicatorPlacement;\n const contextKeepContentMounted = configContext?.keepContentMounted;\n const contextDisableAnimation = configContext?.disableAnimation;\n const contextMotionProps = configContext?.motionProps;\n const contextVariant = configContext?.variant ?? 'borderless';\n\n const isInitialRenderRef = useRef(true);\n\n useEffect(() => {\n isInitialRenderRef.current = false;\n }, []);\n\n const isDirectContextItem = itemStateContext?.itemKey === itemKey;\n\n // Determine expanded state\n let isOpen = false;\n if (isStandalone) {\n isOpen = isExpandedStandalone;\n } else if (itemStateContext) {\n isOpen = isDirectContextItem\n ? itemStateContext.isOpen\n : itemStateContext.isOpen || itemStateContext.isOpenKey(itemKey);\n }\n\n // Determine other props with fallbacks\n const hideIndicatorFinal = itemHideIndicator ?? contextHideIndicator ?? false;\n const indicatorPlacementFinal = itemIndicatorPlacement ?? contextIndicatorPlacement ?? 'start';\n const keepContentMounted = contextKeepContentMounted ?? true;\n const disableAnimation = contextDisableAnimation ?? false;\n const variant = customVariant || contextVariant;\n\n const contextOnToggle = useCallback(() => {\n if (!itemStateContext) return;\n if (itemStateContext.itemKey === itemKey) {\n itemStateContext.onToggle();\n return;\n }\n itemStateContext.onToggleNestedKey(itemKey);\n }, [itemStateContext, itemKey]);\n\n const handleToggle = useCallback(() => {\n // If allowExpand is false, only allow controlled expansion via expand prop\n if (!allowExpand) return;\n\n if (!disabled) {\n if (isStandalone) {\n setIsExpandedStandalone(!isExpandedStandalone);\n } else if (contextOnToggle) {\n contextOnToggle();\n }\n }\n }, [\n allowExpand,\n disabled,\n isStandalone,\n setIsExpandedStandalone,\n isExpandedStandalone,\n contextOnToggle,\n ]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n // If allowExpand is false, disable keyboard toggle\n if (!allowExpand || disabled) return;\n\n switch (e.key) {\n case 'Enter':\n case ' ': {\n e.preventDefault();\n handleToggle();\n break;\n }\n }\n },\n [allowExpand, disabled, handleToggle],\n );\n\n const preventTitleTextSelection = useCallback((e: any) => {\n // Prevent browser from creating a selection range on double/multi click,\n // which can accidentally select the content region.\n if (e?.detail > 1) e.preventDefault();\n }, []);\n\n // Build indicator\n const indicator = useMemo(() => {\n if (!allowExpand || hideIndicatorFinal) return null;\n\n if (customIndicator) {\n if (typeof customIndicator === 'function') {\n return (\n <span\n aria-hidden=\"true\"\n className={cx(styles.indicator, classNames?.indicator)}\n style={customStyles?.indicator}\n >\n {customIndicator({ isDisabled: disabled, isOpen })}\n </span>\n );\n }\n return (\n <span\n aria-hidden=\"true\"\n className={cx(styles.indicator, classNames?.indicator)}\n style={customStyles?.indicator}\n >\n {customIndicator}\n </span>\n );\n }\n\n return (\n <span\n aria-hidden=\"true\"\n className={cx(styles.indicator, classNames?.indicator)}\n style={customStyles?.indicator}\n >\n <ArrowIcon className={cx(styles.icon, isOpen && styles.iconRotate)} />\n </span>\n );\n }, [\n allowExpand,\n hideIndicatorFinal,\n customIndicator,\n disabled,\n isOpen,\n classNames,\n customStyles,\n ]);\n\n const skipInitialAnimation = isInitialRenderRef.current && isOpen;\n\n const contentClassName = useMemo(\n () => cx('accordion-content', styles.content, classNames?.content),\n [classNames?.content],\n );\n\n const titleNode = useMemo(\n () =>\n typeof title === 'string' ? (\n <Text ellipsis className={classNames?.title} style={customStyles?.title}>\n {title}\n </Text>\n ) : (\n title\n ),\n [title, classNames?.title, customStyles?.title],\n );\n\n const actionNode = useMemo(\n () =>\n action && (\n <Flexbox\n horizontal\n align={'center'}\n flex={'none'}\n gap={4}\n style={customStyles?.action}\n className={cx(\n 'accordion-action',\n styles.action,\n alwaysShowAction && styles.actionVisible,\n classNames?.action,\n )}\n onClick={stopPropagation}\n >\n {action}\n </Flexbox>\n ),\n [action, alwaysShowAction, classNames?.action, customStyles?.action],\n );\n\n const headerElement = useMemo(() => {\n const header = (\n <Block\n horizontal\n className={cx('accordion-header', styles.header, classNames?.header)}\n clickable={!disabled && allowExpand}\n gap={4}\n justify={'space-between'}\n padding={padding}\n paddingBlock={paddingBlock}\n paddingInline={paddingInline}\n ref={ref}\n variant={customVariant || variant}\n style={{\n alignItems: 'center',\n cursor: disabled ? 'not-allowed' : allowExpand ? 'pointer' : 'default',\n opacity: disabled ? 0.5 : undefined,\n overflow: 'hidden',\n width: '100%',\n ...customStyles?.header,\n }}\n onClick={handleToggle}\n onKeyDown={handleKeyDown}\n >\n {indicatorPlacementFinal === 'start' ? (\n <>\n <Flexbox\n horizontal\n align={'center'}\n className={styles.titleWrapper}\n flex={1}\n gap={2}\n style={{\n overflow: 'hidden',\n }}\n onDoubleClick={preventTitleTextSelection}\n onMouseDown={preventTitleTextSelection}\n >\n {titleNode}\n {indicator}\n </Flexbox>\n <Flexbox horizontal align={'center'} flex={'none'} gap={4}>\n {actionNode}\n </Flexbox>\n </>\n ) : (\n <>\n <Flexbox\n horizontal\n align={'center'}\n className={styles.titleWrapper}\n flex={1}\n gap={2}\n style={{\n overflow: 'hidden',\n }}\n onDoubleClick={preventTitleTextSelection}\n onMouseDown={preventTitleTextSelection}\n >\n {titleNode}\n </Flexbox>\n <Flexbox horizontal align={'center'} flex={'none'} gap={4}>\n {actionNode}\n {indicator}\n </Flexbox>\n </>\n )}\n </Block>\n );\n if (headerWrapper) {\n return headerWrapper(header);\n }\n return header;\n }, [\n classNames?.header,\n disabled,\n allowExpand,\n padding,\n paddingBlock,\n paddingInline,\n ref,\n customVariant,\n variant,\n customStyles?.header,\n handleToggle,\n handleKeyDown,\n indicatorPlacementFinal,\n preventTitleTextSelection,\n titleNode,\n indicator,\n actionNode,\n headerWrapper,\n ]);\n\n return (\n <div\n className={cx('accordion-item', styles.item, classNames?.base)}\n style={customStyles?.base}\n >\n {headerElement}\n <AccordionItemContent\n className={contentClassName}\n contentInnerClassName={styles.contentInner}\n contextMotionProps={contextMotionProps}\n disableAnimation={!!disableAnimation}\n isOpen={isOpen}\n keepContentMounted={!!keepContentMounted}\n skipInitialAnimation={skipInitialAnimation}\n style={customStyles?.content}\n >\n {children}\n </AccordionItemContent>\n </div>\n );\n },\n);\n\nAccordionItem.displayName = 'AccordionItem';\n\nexport default AccordionItem;\n"],"mappings":"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"}
|
|
@@ -40,7 +40,7 @@ const toCssSize = (value, fallback) => {
|
|
|
40
40
|
if (typeof value === "string" && value.length > 0) return value;
|
|
41
41
|
return fallback;
|
|
42
42
|
};
|
|
43
|
-
const DraggablePanel = memo(({ headerHeight = 0, fullscreen, maxHeight, pin = true, mode = "fixed", children, placement = "right", resize, style, showBorder = true, showHandleHighlight = false, showHandleWideArea = true, backgroundColor, collapseThreshold, size, stableLayout =
|
|
43
|
+
const DraggablePanel = memo(({ headerHeight = 0, fullscreen, maxHeight, pin = true, mode = "fixed", children, placement = "right", resize, style, showBorder = true, showHandleHighlight = false, showHandleWideArea = true, backgroundColor, collapseThreshold, size, stableLayout = true, defaultSize: customizeDefaultSize, minWidth, minHeight, maxWidth, onSizeChange, onSizeDragging, expandable = true, expand, defaultExpand = true, onExpandChange, className, showHandleWhenCollapsed, destroyOnClose, styles: customStyles, classNames, dir }) => {
|
|
44
44
|
const ref = useRef(null);
|
|
45
45
|
const isHovering = useHover(ref);
|
|
46
46
|
const isVertical = placement === "top" || placement === "bottom";
|
|
@@ -335,9 +335,10 @@ const DraggablePanel = memo(({ headerHeight = 0, fullscreen, maxHeight, pin = tr
|
|
|
335
335
|
setShowExpand(true);
|
|
336
336
|
if (usesStableLayout && outerRef.current) {
|
|
337
337
|
outerRef.current.style.removeProperty("transition");
|
|
338
|
-
if (shouldCollapse)
|
|
339
|
-
|
|
340
|
-
|
|
338
|
+
if (shouldCollapse) {
|
|
339
|
+
if (isVertical) outerRef.current.style.height = "0px";
|
|
340
|
+
else outerRef.current.style.width = "0px";
|
|
341
|
+
} else {
|
|
341
342
|
outerRef.current.style.removeProperty("width");
|
|
342
343
|
outerRef.current.style.removeProperty("height");
|
|
343
344
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DraggablePanel.mjs","names":["useControlledState"],"sources":["../../src/DraggablePanel/DraggablePanel.tsx"],"sourcesContent":["'use client';\n\nimport { useHover } from 'ahooks';\nimport { ConfigProvider } from 'antd';\nimport { cx } from 'antd-style';\nimport isEqual from 'fast-deep-equal';\nimport { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from 'lucide-react';\nimport type { Enable, NumberSize, Size } from 're-resizable';\nimport { Resizable } from 're-resizable';\nimport {\n type CSSProperties,\n memo,\n startTransition,\n use,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { Center } from '@/Flex';\nimport Icon from '@/Icon';\n\nimport { handleVariants, panelVariants, styles, toggleVariants } from './style';\nimport type { DraggablePanelProps } from './type';\nimport { isBelowCollapseThreshold, reversePlacement } from './utils';\n\nconst ARROW_MAP = {\n bottom: ChevronUp,\n left: ChevronRight,\n right: ChevronLeft,\n top: ChevronDown,\n} as const;\n\nconst MARGIN_MAP = {\n bottom: { marginTop: 4 },\n left: { marginRight: 4 },\n right: { marginLeft: 4 },\n top: { marginBottom: 4 },\n} as const;\n\nconst DISABLED_RESIZING: Enable = {\n bottom: false,\n bottomLeft: false,\n bottomRight: false,\n left: false,\n right: false,\n top: false,\n topLeft: false,\n topRight: false,\n};\n\nconst toCssSize = (value: string | number | undefined, fallback: string) => {\n if (typeof value === 'number') return `${Math.max(value, 0)}px`;\n if (typeof value === 'string' && value.length > 0) return value;\n return fallback;\n};\n\nconst DraggablePanel = memo<DraggablePanelProps>(\n ({\n headerHeight = 0,\n fullscreen,\n maxHeight,\n pin = true,\n mode = 'fixed',\n children,\n placement = 'right',\n resize,\n style,\n showBorder = true,\n showHandleHighlight = false,\n showHandleWideArea = true,\n backgroundColor,\n collapseThreshold,\n size,\n stableLayout = false,\n defaultSize: customizeDefaultSize,\n minWidth,\n minHeight,\n maxWidth,\n onSizeChange,\n onSizeDragging,\n expandable = true,\n expand,\n defaultExpand = true,\n onExpandChange,\n className,\n showHandleWhenCollapsed,\n destroyOnClose,\n styles: customStyles,\n classNames,\n dir,\n }) => {\n const ref = useRef<HTMLDivElement>(null);\n const isHovering = useHover(ref);\n const isVertical = placement === 'top' || placement === 'bottom';\n const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n const resetTransitionTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n const resizableRef = useRef<Resizable>(null);\n const initialExpandedSizeRef = useRef<Size | undefined>(undefined);\n const resizeStartSizeRef = useRef<Size | undefined>(undefined);\n const outerRef = useRef<HTMLDivElement>(null);\n\n const { direction: antdDirection } = use(ConfigProvider.ConfigContext);\n const direction = dir ?? antdDirection;\n\n const internalPlacement = useMemo(() => {\n if (direction !== 'rtl') return placement;\n if (placement === 'left') return 'right';\n if (placement === 'right') return 'left';\n return placement;\n }, [direction, placement]);\n\n const cssVariables = {\n '--draggable-panel-bg': backgroundColor || '',\n '--draggable-panel-header-height': `${headerHeight}px`,\n } as Record<string, string>;\n\n const [isExpand, setIsExpand] = useControlledState(defaultExpand, {\n onChange: onExpandChange,\n value: expand,\n });\n\n const [shouldTransition, setShouldTransition] = useState(true);\n const [showExpand, setShowExpand] = useState(true);\n const usesStableLayout = stableLayout || collapseThreshold !== undefined;\n\n useEffect(() => {\n if (pin) return;\n\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current);\n }\n\n if (isHovering && !isExpand) {\n startTransition(() => setIsExpand(true));\n } else if (!isHovering && isExpand) {\n hoverTimeoutRef.current = setTimeout(() => {\n startTransition(() => setIsExpand(false));\n }, 150);\n }\n }, [pin, isHovering, isExpand, setIsExpand]);\n\n useEffect(() => {\n return () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current);\n }\n if (resetTransitionTimeoutRef.current) {\n clearTimeout(resetTransitionTimeoutRef.current);\n }\n };\n }, []);\n\n useEffect(() => {\n initialExpandedSizeRef.current = undefined;\n }, [internalPlacement]);\n\n const reversed = reversePlacement(internalPlacement);\n const canResizing = resize !== false && isExpand;\n\n const resizing = useMemo(\n () => ({\n bottom: false,\n bottomLeft: false,\n bottomRight: false,\n left: false,\n right: false,\n top: false,\n topLeft: false,\n topRight: false,\n [reversed]: true,\n ...(resize as Enable),\n }),\n [reversed, resize],\n );\n\n const defaultSize: Size = useMemo(() => {\n if (isVertical) return { height: 180, width: '100%', ...customizeDefaultSize };\n return { height: '100%', width: 280, ...customizeDefaultSize };\n }, [isVertical, customizeDefaultSize]);\n const normalizedMaxHeight = typeof maxHeight === 'number' ? Math.max(maxHeight, 0) : undefined;\n const normalizedMaxWidth = typeof maxWidth === 'number' ? Math.max(maxWidth, 0) : undefined;\n const normalizedMinHeight = typeof minHeight === 'number' ? Math.max(minHeight, 0) : undefined;\n const normalizedMinWidth = typeof minWidth === 'number' ? Math.max(minWidth, 0) : undefined;\n\n const sizeProps = useMemo(() => {\n if (!usesStableLayout && !isExpand) {\n return isVertical\n ? { minHeight: 0, size: { height: 0 } }\n : { minWidth: 0, size: { width: 0 } };\n }\n\n return {\n defaultSize,\n maxHeight: normalizedMaxHeight,\n maxWidth: normalizedMaxWidth,\n minHeight: normalizedMinHeight,\n minWidth: normalizedMinWidth,\n size: size as Size,\n };\n }, [\n usesStableLayout,\n isExpand,\n isVertical,\n defaultSize,\n normalizedMaxHeight,\n normalizedMaxWidth,\n normalizedMinHeight,\n normalizedMinWidth,\n size,\n ]);\n\n const fallbackExpandedSize = isVertical ? '180px' : '280px';\n const controlledExpandedSize = useMemo(() => {\n const controlledSize = isVertical ? size?.height : size?.width;\n if (controlledSize === undefined) return undefined;\n return toCssSize(controlledSize, fallbackExpandedSize);\n }, [isVertical, size?.height, size?.width, fallbackExpandedSize]);\n const defaultExpandedSize = useMemo(() => {\n const initialSize = isVertical ? defaultSize.height : defaultSize.width;\n return toCssSize(initialSize, fallbackExpandedSize);\n }, [isVertical, defaultSize.height, defaultSize.width, fallbackExpandedSize]);\n const [resizedExpandedSize, setResizedExpandedSize] = useState<{\n horizontal?: string;\n vertical?: string;\n }>({});\n const expandedOuterSize =\n controlledExpandedSize ??\n (isVertical ? resizedExpandedSize.vertical : resizedExpandedSize.horizontal) ??\n defaultExpandedSize;\n\n const setExpandedMainSize = useCallback(\n (nextSize: Size) => {\n if (!usesStableLayout) return;\n\n const currentSize = isVertical ? nextSize.height : nextSize.width;\n if (!currentSize) return;\n\n const normalizedSize = toCssSize(currentSize, fallbackExpandedSize);\n setResizedExpandedSize((state) =>\n isVertical\n ? { ...state, vertical: normalizedSize }\n : { ...state, horizontal: normalizedSize },\n );\n },\n [fallbackExpandedSize, isVertical, usesStableLayout],\n );\n\n const readCurrentSize = useCallback((): Size | undefined => {\n const rect = resizableRef.current?.resizable?.getBoundingClientRect();\n if (!rect) return undefined;\n\n return isVertical\n ? { height: rect.height, width: '100%' }\n : { height: '100%', width: rect.width };\n }, [isVertical]);\n\n const captureInitialExpandedSize = useCallback(() => {\n if (initialExpandedSizeRef.current) return initialExpandedSizeRef.current;\n\n const nextInitialSize = readCurrentSize();\n if (!nextInitialSize) return undefined;\n\n initialExpandedSizeRef.current = nextInitialSize;\n return nextInitialSize;\n }, [readCurrentSize]);\n\n useEffect(() => {\n if (!isExpand) return;\n captureInitialExpandedSize();\n }, [captureInitialExpandedSize, isExpand]);\n\n const toggleExpand = useCallback(() => {\n if (expandable) setIsExpand(!isExpand);\n }, [expandable, isExpand, setIsExpand]);\n\n const clampResizeSize = useCallback(\n (el: HTMLElement) => {\n const rect = el.getBoundingClientRect();\n const currentMainSize = isVertical ? rect.height : rect.width;\n const minMainSize = isVertical ? normalizedMinHeight : normalizedMinWidth;\n const maxMainSize = isVertical ? normalizedMaxHeight : normalizedMaxWidth;\n\n let clampedMainSize = currentMainSize;\n if (typeof minMainSize === 'number')\n clampedMainSize = Math.max(clampedMainSize, minMainSize);\n if (typeof maxMainSize === 'number')\n clampedMainSize = Math.min(clampedMainSize, maxMainSize);\n\n if (\n !Number.isFinite(clampedMainSize) ||\n Math.abs(clampedMainSize - currentMainSize) < 0.5\n ) {\n return { height: el.style.height, width: el.style.width };\n }\n\n const width = isVertical ? el.style.width || '100%' : `${clampedMainSize}px`;\n const height = isVertical ? `${clampedMainSize}px` : el.style.height || '100%';\n resizableRef.current?.updateSize({ height, width });\n\n return { height, width };\n },\n [\n isVertical,\n normalizedMaxHeight,\n normalizedMaxWidth,\n normalizedMinHeight,\n normalizedMinWidth,\n ],\n );\n\n const handleResize = useCallback(\n (_event: unknown, _direction: unknown, el: HTMLElement, delta: NumberSize) => {\n const nextSize = clampResizeSize(el);\n const nextCollapsePreview = isBelowCollapseThreshold({\n axis: isVertical ? 'height' : 'width',\n collapseThreshold,\n size: nextSize,\n });\n\n if (usesStableLayout && outerRef.current) {\n // Sync outer DOM width immediately so it doesn't lag behind the\n // re-resizable inline style (which would otherwise trigger a 0.2s\n // width transition on the outer/aside each frame during drag).\n const dimension = isVertical ? nextSize.height : nextSize.width;\n if (dimension) {\n const previewDimension = nextCollapsePreview ? '0px' : dimension;\n if (isVertical) outerRef.current.style.height = previewDimension;\n else outerRef.current.style.width = previewDimension;\n }\n }\n // With drag-to-collapse enabled, defer the persisted expanded size until\n // pointer release. This keeps the pre-drag width as the single source of\n // truth while the outer stable-layout layer previews collapse/restore.\n if (collapseThreshold === undefined) setExpandedMainSize(nextSize);\n onSizeDragging?.(delta, nextSize);\n },\n [\n clampResizeSize,\n collapseThreshold,\n isVertical,\n onSizeDragging,\n setExpandedMainSize,\n usesStableLayout,\n ],\n );\n\n const triggerResetWithoutTransition = useCallback(() => {\n if (resetTransitionTimeoutRef.current) {\n clearTimeout(resetTransitionTimeoutRef.current);\n }\n\n setShouldTransition(false);\n resetTransitionTimeoutRef.current = setTimeout(() => {\n setShouldTransition(true);\n }, 0);\n }, []);\n\n const handleResetSize = useCallback(() => {\n if (!canResizing) return;\n\n const resetSize = captureInitialExpandedSize();\n if (!resetSize) return;\n\n triggerResetWithoutTransition();\n\n const rect = resizableRef.current?.resizable?.getBoundingClientRect();\n const prevMainSize = rect ? (isVertical ? rect.height : rect.width) : 0;\n const resetMainSize = isVertical ? resetSize.height : resetSize.width;\n const nextMainSize = typeof resetMainSize === 'number' ? resetMainSize : prevMainSize;\n\n resizableRef.current?.updateSize(resetSize);\n setExpandedMainSize(resetSize);\n\n onSizeChange?.(\n isVertical\n ? { height: nextMainSize - prevMainSize, width: 0 }\n : { height: 0, width: nextMainSize - prevMainSize },\n resetSize,\n );\n }, [\n canResizing,\n captureInitialExpandedSize,\n isVertical,\n onSizeChange,\n setExpandedMainSize,\n triggerResetWithoutTransition,\n ]);\n\n const handleResizeStart = useCallback(\n (event: { detail?: number }) => {\n if (event.detail === 2) {\n handleResetSize();\n return false;\n }\n\n if (resetTransitionTimeoutRef.current) {\n clearTimeout(resetTransitionTimeoutRef.current);\n resetTransitionTimeoutRef.current = undefined;\n }\n\n resizeStartSizeRef.current = readCurrentSize();\n\n // Synchronously disable the outer transition so the first drag frame\n // does not animate. `setShouldTransition(false)` below is asynchronous\n // and would only take effect after the next React commit.\n if (usesStableLayout && outerRef.current) {\n outerRef.current.style.transition = 'none';\n }\n setShouldTransition(false);\n setShowExpand(false);\n },\n [handleResetSize, readCurrentSize, usesStableLayout],\n );\n\n const handleResizeStop = useCallback(\n (_event: unknown, _direction: unknown, el: HTMLElement, delta: NumberSize) => {\n const nextSize = clampResizeSize(el);\n const shouldCollapse = isBelowCollapseThreshold({\n axis: isVertical ? 'height' : 'width',\n collapseThreshold,\n size: nextSize,\n });\n const committedSize = shouldCollapse ? (resizeStartSizeRef.current ?? nextSize) : nextSize;\n\n resizableRef.current?.updateSize(committedSize);\n if (!shouldCollapse) setExpandedMainSize(committedSize);\n setShouldTransition(true);\n setShowExpand(true);\n // Keep the collapsed main-axis size at zero until the controlled\n // `expand=false` value arrives. Clearing it here would reveal the panel\n // for one render between preview teardown and controlled-state commit.\n if (usesStableLayout && outerRef.current) {\n outerRef.current.style.removeProperty('transition');\n if (shouldCollapse) {\n if (isVertical) outerRef.current.style.height = '0px';\n else outerRef.current.style.width = '0px';\n } else {\n outerRef.current.style.removeProperty('width');\n outerRef.current.style.removeProperty('height');\n }\n }\n if (shouldCollapse) setIsExpand(false);\n\n resizeStartSizeRef.current = undefined;\n onSizeChange?.(delta, committedSize);\n },\n [\n clampResizeSize,\n collapseThreshold,\n isVertical,\n onSizeChange,\n setExpandedMainSize,\n setIsExpand,\n usesStableLayout,\n ],\n );\n\n const resizeHandleClassName = useMemo(\n () =>\n cx(handleVariants({ placement: reversed }), showHandleHighlight && styles.handleHighlight),\n [reversed, showHandleHighlight],\n );\n\n if (fullscreen) {\n return (\n <div className={cx(styles.fullscreen, className)} style={cssVariables}>\n {children}\n </div>\n );\n }\n\n const Arrow = ARROW_MAP[internalPlacement] ?? ChevronLeft;\n const stableOuterFlex = usesStableLayout\n ? ({\n display: 'flex',\n flexDirection: 'column',\n minHeight: 0,\n } as const)\n : {};\n\n const sidebarOuterStyle = isVertical\n ? {\n height: isExpand ? expandedOuterSize : 0,\n overflow: 'hidden',\n transition: shouldTransition ? 'height 0.2s var(--ant-motion-ease-out, ease)' : 'none',\n width: '100%',\n ...stableOuterFlex,\n }\n : {\n overflow: 'hidden',\n transition: shouldTransition ? 'width 0.2s var(--ant-motion-ease-out, ease)' : 'none',\n width: isExpand ? expandedOuterSize : 0,\n ...(usesStableLayout\n ? {\n ...stableOuterFlex,\n flex: 1,\n minWidth: 0,\n height: '100%',\n }\n : {}),\n };\n\n const stableInnerStyle: CSSProperties = {\n display: 'flex',\n flex: 1,\n flexDirection: 'column',\n height: '100%',\n minHeight: 0,\n minWidth: 0,\n width: '100%',\n };\n const sidebarInnerStyle: CSSProperties = usesStableLayout\n ? stableInnerStyle\n : isVertical\n ? { height: '100%', width: '100%' }\n : { width: '100%' };\n\n const stableAsideStyle: CSSProperties = usesStableLayout\n ? {\n display: 'flex',\n flexDirection: 'column',\n minHeight: 0,\n ...(mode === 'fixed' ? { height: '100%' } : {}),\n }\n : {};\n\n const stableResizableStyle: CSSProperties = {\n display: 'flex',\n flex: 1,\n flexDirection: 'column',\n height: '100%',\n minHeight: 0,\n minWidth: 0,\n width: '100%',\n };\n\n const panelNode = (!destroyOnClose || isExpand) && (\n <Resizable\n ref={resizableRef}\n {...sizeProps}\n className={cx(styles.panel, classNames?.content)}\n enable={canResizing ? (resizing as Enable) : DISABLED_RESIZING}\n handleClasses={\n canResizing\n ? {\n [reversed]: resizeHandleClassName,\n }\n : {}\n }\n style={{\n ...cssVariables,\n transition: shouldTransition ? undefined : 'none',\n ...(usesStableLayout ? stableResizableStyle : {}),\n ...style,\n }}\n onResize={handleResize}\n onResizeStart={handleResizeStart}\n onResizeStop={handleResizeStop}\n >\n {usesStableLayout ? <div style={sidebarInnerStyle}>{children}</div> : children}\n </Resizable>\n );\n\n return (\n <aside\n dir={dir}\n ref={ref}\n style={{ ...cssVariables, ...stableAsideStyle }}\n className={cx(\n panelVariants({ isExpand, mode, placement: internalPlacement, showBorder }),\n className,\n )}\n >\n {expandable && showExpand && (\n <Center\n className={toggleVariants({ placement: internalPlacement, showHandleWideArea })}\n style={{\n opacity: isExpand ? (pin ? undefined : 0) : showHandleWhenCollapsed ? 1 : 0,\n }}\n >\n <Center\n className={classNames?.handle}\n style={customStyles?.handle}\n onClick={toggleExpand}\n >\n <Icon\n className={styles.handlerIcon}\n icon={Arrow}\n size={16}\n style={{\n ...MARGIN_MAP[internalPlacement],\n transform: `rotate(${isExpand ? 180 : 0}deg)`,\n transition: 'transform 0.3s ease',\n }}\n />\n </Center>\n </Center>\n )}\n {usesStableLayout ? (\n <div ref={outerRef} style={sidebarOuterStyle}>\n {panelNode}\n </div>\n ) : (\n panelNode\n )}\n </aside>\n );\n },\n isEqual,\n);\n\nDraggablePanel.displayName = 'DraggablePanel';\n\nexport default DraggablePanel;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DraggablePanel.mjs","names":["useControlledState"],"sources":["../../src/DraggablePanel/DraggablePanel.tsx"],"sourcesContent":["'use client';\n\nimport { useHover } from 'ahooks';\nimport { ConfigProvider } from 'antd';\nimport { cx } from 'antd-style';\nimport isEqual from 'fast-deep-equal';\nimport { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from 'lucide-react';\nimport type { Enable, NumberSize, Size } from 're-resizable';\nimport { Resizable } from 're-resizable';\nimport {\n type CSSProperties,\n memo,\n startTransition,\n use,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { Center } from '@/Flex';\nimport Icon from '@/Icon';\n\nimport { handleVariants, panelVariants, styles, toggleVariants } from './style';\nimport type { DraggablePanelProps } from './type';\nimport { isBelowCollapseThreshold, reversePlacement } from './utils';\n\nconst ARROW_MAP = {\n bottom: ChevronUp,\n left: ChevronRight,\n right: ChevronLeft,\n top: ChevronDown,\n} as const;\n\nconst MARGIN_MAP = {\n bottom: { marginTop: 4 },\n left: { marginRight: 4 },\n right: { marginLeft: 4 },\n top: { marginBottom: 4 },\n} as const;\n\nconst DISABLED_RESIZING: Enable = {\n bottom: false,\n bottomLeft: false,\n bottomRight: false,\n left: false,\n right: false,\n top: false,\n topLeft: false,\n topRight: false,\n};\n\nconst toCssSize = (value: string | number | undefined, fallback: string) => {\n if (typeof value === 'number') return `${Math.max(value, 0)}px`;\n if (typeof value === 'string' && value.length > 0) return value;\n return fallback;\n};\n\nconst DraggablePanel = memo<DraggablePanelProps>(\n ({\n headerHeight = 0,\n fullscreen,\n maxHeight,\n pin = true,\n mode = 'fixed',\n children,\n placement = 'right',\n resize,\n style,\n showBorder = true,\n showHandleHighlight = false,\n showHandleWideArea = true,\n backgroundColor,\n collapseThreshold,\n size,\n stableLayout = true,\n defaultSize: customizeDefaultSize,\n minWidth,\n minHeight,\n maxWidth,\n onSizeChange,\n onSizeDragging,\n expandable = true,\n expand,\n defaultExpand = true,\n onExpandChange,\n className,\n showHandleWhenCollapsed,\n destroyOnClose,\n styles: customStyles,\n classNames,\n dir,\n }) => {\n const ref = useRef<HTMLDivElement>(null);\n const isHovering = useHover(ref);\n const isVertical = placement === 'top' || placement === 'bottom';\n const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n const resetTransitionTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n const resizableRef = useRef<Resizable>(null);\n const initialExpandedSizeRef = useRef<Size | undefined>(undefined);\n const resizeStartSizeRef = useRef<Size | undefined>(undefined);\n const outerRef = useRef<HTMLDivElement>(null);\n\n const { direction: antdDirection } = use(ConfigProvider.ConfigContext);\n const direction = dir ?? antdDirection;\n\n const internalPlacement = useMemo(() => {\n if (direction !== 'rtl') return placement;\n if (placement === 'left') return 'right';\n if (placement === 'right') return 'left';\n return placement;\n }, [direction, placement]);\n\n const cssVariables = {\n '--draggable-panel-bg': backgroundColor || '',\n '--draggable-panel-header-height': `${headerHeight}px`,\n } as Record<string, string>;\n\n const [isExpand, setIsExpand] = useControlledState(defaultExpand, {\n onChange: onExpandChange,\n value: expand,\n });\n\n const [shouldTransition, setShouldTransition] = useState(true);\n const [showExpand, setShowExpand] = useState(true);\n const usesStableLayout = stableLayout || collapseThreshold !== undefined;\n\n useEffect(() => {\n if (pin) return;\n\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current);\n }\n\n if (isHovering && !isExpand) {\n startTransition(() => setIsExpand(true));\n } else if (!isHovering && isExpand) {\n hoverTimeoutRef.current = setTimeout(() => {\n startTransition(() => setIsExpand(false));\n }, 150);\n }\n }, [pin, isHovering, isExpand, setIsExpand]);\n\n useEffect(() => {\n return () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current);\n }\n if (resetTransitionTimeoutRef.current) {\n clearTimeout(resetTransitionTimeoutRef.current);\n }\n };\n }, []);\n\n useEffect(() => {\n initialExpandedSizeRef.current = undefined;\n }, [internalPlacement]);\n\n const reversed = reversePlacement(internalPlacement);\n const canResizing = resize !== false && isExpand;\n\n const resizing = useMemo(\n () => ({\n bottom: false,\n bottomLeft: false,\n bottomRight: false,\n left: false,\n right: false,\n top: false,\n topLeft: false,\n topRight: false,\n [reversed]: true,\n ...(resize as Enable),\n }),\n [reversed, resize],\n );\n\n const defaultSize: Size = useMemo(() => {\n if (isVertical) return { height: 180, width: '100%', ...customizeDefaultSize };\n return { height: '100%', width: 280, ...customizeDefaultSize };\n }, [isVertical, customizeDefaultSize]);\n const normalizedMaxHeight = typeof maxHeight === 'number' ? Math.max(maxHeight, 0) : undefined;\n const normalizedMaxWidth = typeof maxWidth === 'number' ? Math.max(maxWidth, 0) : undefined;\n const normalizedMinHeight = typeof minHeight === 'number' ? Math.max(minHeight, 0) : undefined;\n const normalizedMinWidth = typeof minWidth === 'number' ? Math.max(minWidth, 0) : undefined;\n\n const sizeProps = useMemo(() => {\n if (!usesStableLayout && !isExpand) {\n return isVertical\n ? { minHeight: 0, size: { height: 0 } }\n : { minWidth: 0, size: { width: 0 } };\n }\n\n return {\n defaultSize,\n maxHeight: normalizedMaxHeight,\n maxWidth: normalizedMaxWidth,\n minHeight: normalizedMinHeight,\n minWidth: normalizedMinWidth,\n size: size as Size,\n };\n }, [\n usesStableLayout,\n isExpand,\n isVertical,\n defaultSize,\n normalizedMaxHeight,\n normalizedMaxWidth,\n normalizedMinHeight,\n normalizedMinWidth,\n size,\n ]);\n\n const fallbackExpandedSize = isVertical ? '180px' : '280px';\n const controlledExpandedSize = useMemo(() => {\n const controlledSize = isVertical ? size?.height : size?.width;\n if (controlledSize === undefined) return undefined;\n return toCssSize(controlledSize, fallbackExpandedSize);\n }, [isVertical, size?.height, size?.width, fallbackExpandedSize]);\n const defaultExpandedSize = useMemo(() => {\n const initialSize = isVertical ? defaultSize.height : defaultSize.width;\n return toCssSize(initialSize, fallbackExpandedSize);\n }, [isVertical, defaultSize.height, defaultSize.width, fallbackExpandedSize]);\n const [resizedExpandedSize, setResizedExpandedSize] = useState<{\n horizontal?: string;\n vertical?: string;\n }>({});\n const expandedOuterSize =\n controlledExpandedSize ??\n (isVertical ? resizedExpandedSize.vertical : resizedExpandedSize.horizontal) ??\n defaultExpandedSize;\n\n const setExpandedMainSize = useCallback(\n (nextSize: Size) => {\n if (!usesStableLayout) return;\n\n const currentSize = isVertical ? nextSize.height : nextSize.width;\n if (!currentSize) return;\n\n const normalizedSize = toCssSize(currentSize, fallbackExpandedSize);\n setResizedExpandedSize((state) =>\n isVertical\n ? { ...state, vertical: normalizedSize }\n : { ...state, horizontal: normalizedSize },\n );\n },\n [fallbackExpandedSize, isVertical, usesStableLayout],\n );\n\n const readCurrentSize = useCallback((): Size | undefined => {\n const rect = resizableRef.current?.resizable?.getBoundingClientRect();\n if (!rect) return undefined;\n\n return isVertical\n ? { height: rect.height, width: '100%' }\n : { height: '100%', width: rect.width };\n }, [isVertical]);\n\n const captureInitialExpandedSize = useCallback(() => {\n if (initialExpandedSizeRef.current) return initialExpandedSizeRef.current;\n\n const nextInitialSize = readCurrentSize();\n if (!nextInitialSize) return undefined;\n\n initialExpandedSizeRef.current = nextInitialSize;\n return nextInitialSize;\n }, [readCurrentSize]);\n\n useEffect(() => {\n if (!isExpand) return;\n captureInitialExpandedSize();\n }, [captureInitialExpandedSize, isExpand]);\n\n const toggleExpand = useCallback(() => {\n if (expandable) setIsExpand(!isExpand);\n }, [expandable, isExpand, setIsExpand]);\n\n const clampResizeSize = useCallback(\n (el: HTMLElement) => {\n const rect = el.getBoundingClientRect();\n const currentMainSize = isVertical ? rect.height : rect.width;\n const minMainSize = isVertical ? normalizedMinHeight : normalizedMinWidth;\n const maxMainSize = isVertical ? normalizedMaxHeight : normalizedMaxWidth;\n\n let clampedMainSize = currentMainSize;\n if (typeof minMainSize === 'number')\n clampedMainSize = Math.max(clampedMainSize, minMainSize);\n if (typeof maxMainSize === 'number')\n clampedMainSize = Math.min(clampedMainSize, maxMainSize);\n\n if (\n !Number.isFinite(clampedMainSize) ||\n Math.abs(clampedMainSize - currentMainSize) < 0.5\n ) {\n return { height: el.style.height, width: el.style.width };\n }\n\n const width = isVertical ? el.style.width || '100%' : `${clampedMainSize}px`;\n const height = isVertical ? `${clampedMainSize}px` : el.style.height || '100%';\n resizableRef.current?.updateSize({ height, width });\n\n return { height, width };\n },\n [\n isVertical,\n normalizedMaxHeight,\n normalizedMaxWidth,\n normalizedMinHeight,\n normalizedMinWidth,\n ],\n );\n\n const handleResize = useCallback(\n (_event: unknown, _direction: unknown, el: HTMLElement, delta: NumberSize) => {\n const nextSize = clampResizeSize(el);\n const nextCollapsePreview = isBelowCollapseThreshold({\n axis: isVertical ? 'height' : 'width',\n collapseThreshold,\n size: nextSize,\n });\n\n if (usesStableLayout && outerRef.current) {\n // Sync outer DOM width immediately so it doesn't lag behind the\n // re-resizable inline style (which would otherwise trigger a 0.2s\n // width transition on the outer/aside each frame during drag).\n const dimension = isVertical ? nextSize.height : nextSize.width;\n if (dimension) {\n const previewDimension = nextCollapsePreview ? '0px' : dimension;\n if (isVertical) outerRef.current.style.height = previewDimension;\n else outerRef.current.style.width = previewDimension;\n }\n }\n // With drag-to-collapse enabled, defer the persisted expanded size until\n // pointer release. This keeps the pre-drag width as the single source of\n // truth while the outer stable-layout layer previews collapse/restore.\n if (collapseThreshold === undefined) setExpandedMainSize(nextSize);\n onSizeDragging?.(delta, nextSize);\n },\n [\n clampResizeSize,\n collapseThreshold,\n isVertical,\n onSizeDragging,\n setExpandedMainSize,\n usesStableLayout,\n ],\n );\n\n const triggerResetWithoutTransition = useCallback(() => {\n if (resetTransitionTimeoutRef.current) {\n clearTimeout(resetTransitionTimeoutRef.current);\n }\n\n setShouldTransition(false);\n resetTransitionTimeoutRef.current = setTimeout(() => {\n setShouldTransition(true);\n }, 0);\n }, []);\n\n const handleResetSize = useCallback(() => {\n if (!canResizing) return;\n\n const resetSize = captureInitialExpandedSize();\n if (!resetSize) return;\n\n triggerResetWithoutTransition();\n\n const rect = resizableRef.current?.resizable?.getBoundingClientRect();\n const prevMainSize = rect ? (isVertical ? rect.height : rect.width) : 0;\n const resetMainSize = isVertical ? resetSize.height : resetSize.width;\n const nextMainSize = typeof resetMainSize === 'number' ? resetMainSize : prevMainSize;\n\n resizableRef.current?.updateSize(resetSize);\n setExpandedMainSize(resetSize);\n\n onSizeChange?.(\n isVertical\n ? { height: nextMainSize - prevMainSize, width: 0 }\n : { height: 0, width: nextMainSize - prevMainSize },\n resetSize,\n );\n }, [\n canResizing,\n captureInitialExpandedSize,\n isVertical,\n onSizeChange,\n setExpandedMainSize,\n triggerResetWithoutTransition,\n ]);\n\n const handleResizeStart = useCallback(\n (event: { detail?: number }) => {\n if (event.detail === 2) {\n handleResetSize();\n return false;\n }\n\n if (resetTransitionTimeoutRef.current) {\n clearTimeout(resetTransitionTimeoutRef.current);\n resetTransitionTimeoutRef.current = undefined;\n }\n\n resizeStartSizeRef.current = readCurrentSize();\n\n // Synchronously disable the outer transition so the first drag frame\n // does not animate. `setShouldTransition(false)` below is asynchronous\n // and would only take effect after the next React commit.\n if (usesStableLayout && outerRef.current) {\n outerRef.current.style.transition = 'none';\n }\n setShouldTransition(false);\n setShowExpand(false);\n },\n [handleResetSize, readCurrentSize, usesStableLayout],\n );\n\n const handleResizeStop = useCallback(\n (_event: unknown, _direction: unknown, el: HTMLElement, delta: NumberSize) => {\n const nextSize = clampResizeSize(el);\n const shouldCollapse = isBelowCollapseThreshold({\n axis: isVertical ? 'height' : 'width',\n collapseThreshold,\n size: nextSize,\n });\n const committedSize = shouldCollapse ? (resizeStartSizeRef.current ?? nextSize) : nextSize;\n\n resizableRef.current?.updateSize(committedSize);\n if (!shouldCollapse) setExpandedMainSize(committedSize);\n setShouldTransition(true);\n setShowExpand(true);\n // Keep the collapsed main-axis size at zero until the controlled\n // `expand=false` value arrives. Clearing it here would reveal the panel\n // for one render between preview teardown and controlled-state commit.\n if (usesStableLayout && outerRef.current) {\n outerRef.current.style.removeProperty('transition');\n if (shouldCollapse) {\n if (isVertical) outerRef.current.style.height = '0px';\n else outerRef.current.style.width = '0px';\n } else {\n outerRef.current.style.removeProperty('width');\n outerRef.current.style.removeProperty('height');\n }\n }\n if (shouldCollapse) setIsExpand(false);\n\n resizeStartSizeRef.current = undefined;\n onSizeChange?.(delta, committedSize);\n },\n [\n clampResizeSize,\n collapseThreshold,\n isVertical,\n onSizeChange,\n setExpandedMainSize,\n setIsExpand,\n usesStableLayout,\n ],\n );\n\n const resizeHandleClassName = useMemo(\n () =>\n cx(handleVariants({ placement: reversed }), showHandleHighlight && styles.handleHighlight),\n [reversed, showHandleHighlight],\n );\n\n if (fullscreen) {\n return (\n <div className={cx(styles.fullscreen, className)} style={cssVariables}>\n {children}\n </div>\n );\n }\n\n const Arrow = ARROW_MAP[internalPlacement] ?? ChevronLeft;\n const stableOuterFlex = usesStableLayout\n ? ({\n display: 'flex',\n flexDirection: 'column',\n minHeight: 0,\n } as const)\n : {};\n\n const sidebarOuterStyle = isVertical\n ? {\n height: isExpand ? expandedOuterSize : 0,\n overflow: 'hidden',\n transition: shouldTransition ? 'height 0.2s var(--ant-motion-ease-out, ease)' : 'none',\n width: '100%',\n ...stableOuterFlex,\n }\n : {\n overflow: 'hidden',\n transition: shouldTransition ? 'width 0.2s var(--ant-motion-ease-out, ease)' : 'none',\n width: isExpand ? expandedOuterSize : 0,\n ...(usesStableLayout\n ? {\n ...stableOuterFlex,\n flex: 1,\n minWidth: 0,\n height: '100%',\n }\n : {}),\n };\n\n const stableInnerStyle: CSSProperties = {\n display: 'flex',\n flex: 1,\n flexDirection: 'column',\n height: '100%',\n minHeight: 0,\n minWidth: 0,\n width: '100%',\n };\n const sidebarInnerStyle: CSSProperties = usesStableLayout\n ? stableInnerStyle\n : isVertical\n ? { height: '100%', width: '100%' }\n : { width: '100%' };\n\n const stableAsideStyle: CSSProperties = usesStableLayout\n ? {\n display: 'flex',\n flexDirection: 'column',\n minHeight: 0,\n ...(mode === 'fixed' ? { height: '100%' } : {}),\n }\n : {};\n\n const stableResizableStyle: CSSProperties = {\n display: 'flex',\n flex: 1,\n flexDirection: 'column',\n height: '100%',\n minHeight: 0,\n minWidth: 0,\n width: '100%',\n };\n\n const panelNode = (!destroyOnClose || isExpand) && (\n <Resizable\n ref={resizableRef}\n {...sizeProps}\n className={cx(styles.panel, classNames?.content)}\n enable={canResizing ? (resizing as Enable) : DISABLED_RESIZING}\n handleClasses={\n canResizing\n ? {\n [reversed]: resizeHandleClassName,\n }\n : {}\n }\n style={{\n ...cssVariables,\n transition: shouldTransition ? undefined : 'none',\n ...(usesStableLayout ? stableResizableStyle : {}),\n ...style,\n }}\n onResize={handleResize}\n onResizeStart={handleResizeStart}\n onResizeStop={handleResizeStop}\n >\n {usesStableLayout ? <div style={sidebarInnerStyle}>{children}</div> : children}\n </Resizable>\n );\n\n return (\n <aside\n dir={dir}\n ref={ref}\n style={{ ...cssVariables, ...stableAsideStyle }}\n className={cx(\n panelVariants({ isExpand, mode, placement: internalPlacement, showBorder }),\n className,\n )}\n >\n {expandable && showExpand && (\n <Center\n className={toggleVariants({ placement: internalPlacement, showHandleWideArea })}\n style={{\n opacity: isExpand ? (pin ? undefined : 0) : showHandleWhenCollapsed ? 1 : 0,\n }}\n >\n <Center\n className={classNames?.handle}\n style={customStyles?.handle}\n onClick={toggleExpand}\n >\n <Icon\n className={styles.handlerIcon}\n icon={Arrow}\n size={16}\n style={{\n ...MARGIN_MAP[internalPlacement],\n transform: `rotate(${isExpand ? 180 : 0}deg)`,\n transition: 'transform 0.3s ease',\n }}\n />\n </Center>\n </Center>\n )}\n {usesStableLayout ? (\n <div ref={outerRef} style={sidebarOuterStyle}>\n {panelNode}\n </div>\n ) : (\n panelNode\n )}\n </aside>\n );\n },\n isEqual,\n);\n\nDraggablePanel.displayName = 'DraggablePanel';\n\nexport default DraggablePanel;\n"],"mappings":";;;;;;;;;;;;;;;AA6BA,MAAM,YAAY;CAChB,QAAQ;CACR,MAAM;CACN,OAAO;CACP,KAAK;AACP;AAEA,MAAM,aAAa;CACjB,QAAQ,EAAE,WAAW,EAAE;CACvB,MAAM,EAAE,aAAa,EAAE;CACvB,OAAO,EAAE,YAAY,EAAE;CACvB,KAAK,EAAE,cAAc,EAAE;AACzB;AAEA,MAAM,oBAA4B;CAChC,QAAQ;CACR,YAAY;CACZ,aAAa;CACb,MAAM;CACN,OAAO;CACP,KAAK;CACL,SAAS;CACT,UAAU;AACZ;AAEA,MAAM,aAAa,OAAoC,aAAqB;CAC1E,IAAI,OAAO,UAAU,UAAU,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC,EAAE;CAC5D,IAAI,OAAO,UAAU,YAAY,MAAM,SAAS,GAAG,OAAO;CAC1D,OAAO;AACT;AAEA,MAAM,iBAAiB,MACpB,EACC,eAAe,GACf,YACA,WACA,MAAM,MACN,OAAO,SACP,UACA,YAAY,SACZ,QACA,OACA,aAAa,MACb,sBAAsB,OACtB,qBAAqB,MACrB,iBACA,mBACA,MACA,eAAe,MACf,aAAa,sBACb,UACA,WACA,UACA,cACA,gBACA,aAAa,MACb,QACA,gBAAgB,MAChB,gBACA,WACA,yBACA,gBACA,QAAQ,cACR,YACA,UACI;CACJ,MAAM,MAAM,OAAuB,IAAI;CACvC,MAAM,aAAa,SAAS,GAAG;CAC/B,MAAM,aAAa,cAAc,SAAS,cAAc;CACxD,MAAM,kBAAkB,OAAsC,KAAA,CAAS;CACvE,MAAM,4BAA4B,OAAsC,KAAA,CAAS;CACjF,MAAM,eAAe,OAAkB,IAAI;CAC3C,MAAM,yBAAyB,OAAyB,KAAA,CAAS;CACjE,MAAM,qBAAqB,OAAyB,KAAA,CAAS;CAC7D,MAAM,WAAW,OAAuB,IAAI;CAE5C,MAAM,EAAE,WAAW,kBAAkB,IAAI,eAAe,aAAa;CACrE,MAAM,YAAY,OAAO;CAEzB,MAAM,oBAAoB,cAAc;EACtC,IAAI,cAAc,OAAO,OAAO;EAChC,IAAI,cAAc,QAAQ,OAAO;EACjC,IAAI,cAAc,SAAS,OAAO;EAClC,OAAO;CACT,GAAG,CAAC,WAAW,SAAS,CAAC;CAEzB,MAAM,eAAe;EACnB,wBAAwB,mBAAmB;EAC3C,mCAAmC,GAAG,aAAa;CACrD;CAEA,MAAM,CAAC,UAAU,eAAeA,cAAmB,eAAe;EAChE,UAAU;EACV,OAAO;CACT,CAAC;CAED,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,IAAI;CAC7D,MAAM,CAAC,YAAY,iBAAiB,SAAS,IAAI;CACjD,MAAM,mBAAmB,gBAAgB,sBAAsB,KAAA;CAE/D,gBAAgB;EACd,IAAI,KAAK;EAET,IAAI,gBAAgB,SAClB,aAAa,gBAAgB,OAAO;EAGtC,IAAI,cAAc,CAAC,UACjB,sBAAsB,YAAY,IAAI,CAAC;OAClC,IAAI,CAAC,cAAc,UACxB,gBAAgB,UAAU,iBAAiB;GACzC,sBAAsB,YAAY,KAAK,CAAC;EAC1C,GAAG,GAAG;CAEV,GAAG;EAAC;EAAK;EAAY;EAAU;CAAW,CAAC;CAE3C,gBAAgB;EACd,aAAa;GACX,IAAI,gBAAgB,SAClB,aAAa,gBAAgB,OAAO;GAEtC,IAAI,0BAA0B,SAC5B,aAAa,0BAA0B,OAAO;EAElD;CACF,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,uBAAuB,UAAU,KAAA;CACnC,GAAG,CAAC,iBAAiB,CAAC;CAEtB,MAAM,WAAW,iBAAiB,iBAAiB;CACnD,MAAM,cAAc,WAAW,SAAS;CAExC,MAAM,WAAW,eACR;EACL,QAAQ;EACR,YAAY;EACZ,aAAa;EACb,MAAM;EACN,OAAO;EACP,KAAK;EACL,SAAS;EACT,UAAU;GACT,WAAW;EACZ,GAAI;CACN,IACA,CAAC,UAAU,MAAM,CACnB;CAEA,MAAM,cAAoB,cAAc;EACtC,IAAI,YAAY,OAAO;GAAE,QAAQ;GAAK,OAAO;GAAQ,GAAG;EAAqB;EAC7E,OAAO;GAAE,QAAQ;GAAQ,OAAO;GAAK,GAAG;EAAqB;CAC/D,GAAG,CAAC,YAAY,oBAAoB,CAAC;CACrC,MAAM,sBAAsB,OAAO,cAAc,WAAW,KAAK,IAAI,WAAW,CAAC,IAAI,KAAA;CACrF,MAAM,qBAAqB,OAAO,aAAa,WAAW,KAAK,IAAI,UAAU,CAAC,IAAI,KAAA;CAClF,MAAM,sBAAsB,OAAO,cAAc,WAAW,KAAK,IAAI,WAAW,CAAC,IAAI,KAAA;CACrF,MAAM,qBAAqB,OAAO,aAAa,WAAW,KAAK,IAAI,UAAU,CAAC,IAAI,KAAA;CAElF,MAAM,YAAY,cAAc;EAC9B,IAAI,CAAC,oBAAoB,CAAC,UACxB,OAAO,aACH;GAAE,WAAW;GAAG,MAAM,EAAE,QAAQ,EAAE;EAAE,IACpC;GAAE,UAAU;GAAG,MAAM,EAAE,OAAO,EAAE;EAAE;EAGxC,OAAO;GACL;GACA,WAAW;GACX,UAAU;GACV,WAAW;GACX,UAAU;GACJ;EACR;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,uBAAuB,aAAa,UAAU;CACpD,MAAM,yBAAyB,cAAc;EAC3C,MAAM,iBAAiB,aAAa,MAAM,SAAS,MAAM;EACzD,IAAI,mBAAmB,KAAA,GAAW,OAAO,KAAA;EACzC,OAAO,UAAU,gBAAgB,oBAAoB;CACvD,GAAG;EAAC;EAAY,MAAM;EAAQ,MAAM;EAAO;CAAoB,CAAC;CAChE,MAAM,sBAAsB,cAAc;EACxC,MAAM,cAAc,aAAa,YAAY,SAAS,YAAY;EAClE,OAAO,UAAU,aAAa,oBAAoB;CACpD,GAAG;EAAC;EAAY,YAAY;EAAQ,YAAY;EAAO;CAAoB,CAAC;CAC5E,MAAM,CAAC,qBAAqB,0BAA0B,SAGnD,CAAC,CAAC;CACL,MAAM,oBACJ,2BACC,aAAa,oBAAoB,WAAW,oBAAoB,eACjE;CAEF,MAAM,sBAAsB,aACzB,aAAmB;EAClB,IAAI,CAAC,kBAAkB;EAEvB,MAAM,cAAc,aAAa,SAAS,SAAS,SAAS;EAC5D,IAAI,CAAC,aAAa;EAElB,MAAM,iBAAiB,UAAU,aAAa,oBAAoB;EAClE,wBAAwB,UACtB,aACI;GAAE,GAAG;GAAO,UAAU;EAAe,IACrC;GAAE,GAAG;GAAO,YAAY;EAAe,CAC7C;CACF,GACA;EAAC;EAAsB;EAAY;CAAgB,CACrD;CAEA,MAAM,kBAAkB,kBAAoC;EAC1D,MAAM,OAAO,aAAa,SAAS,WAAW,sBAAsB;EACpE,IAAI,CAAC,MAAM,OAAO,KAAA;EAElB,OAAO,aACH;GAAE,QAAQ,KAAK;GAAQ,OAAO;EAAO,IACrC;GAAE,QAAQ;GAAQ,OAAO,KAAK;EAAM;CAC1C,GAAG,CAAC,UAAU,CAAC;CAEf,MAAM,6BAA6B,kBAAkB;EACnD,IAAI,uBAAuB,SAAS,OAAO,uBAAuB;EAElE,MAAM,kBAAkB,gBAAgB;EACxC,IAAI,CAAC,iBAAiB,OAAO,KAAA;EAE7B,uBAAuB,UAAU;EACjC,OAAO;CACT,GAAG,CAAC,eAAe,CAAC;CAEpB,gBAAgB;EACd,IAAI,CAAC,UAAU;EACf,2BAA2B;CAC7B,GAAG,CAAC,4BAA4B,QAAQ,CAAC;CAEzC,MAAM,eAAe,kBAAkB;EACrC,IAAI,YAAY,YAAY,CAAC,QAAQ;CACvC,GAAG;EAAC;EAAY;EAAU;CAAW,CAAC;CAEtC,MAAM,kBAAkB,aACrB,OAAoB;EACnB,MAAM,OAAO,GAAG,sBAAsB;EACtC,MAAM,kBAAkB,aAAa,KAAK,SAAS,KAAK;EACxD,MAAM,cAAc,aAAa,sBAAsB;EACvD,MAAM,cAAc,aAAa,sBAAsB;EAEvD,IAAI,kBAAkB;EACtB,IAAI,OAAO,gBAAgB,UACzB,kBAAkB,KAAK,IAAI,iBAAiB,WAAW;EACzD,IAAI,OAAO,gBAAgB,UACzB,kBAAkB,KAAK,IAAI,iBAAiB,WAAW;EAEzD,IACE,CAAC,OAAO,SAAS,eAAe,KAChC,KAAK,IAAI,kBAAkB,eAAe,IAAI,IAE9C,OAAO;GAAE,QAAQ,GAAG,MAAM;GAAQ,OAAO,GAAG,MAAM;EAAM;EAG1D,MAAM,QAAQ,aAAa,GAAG,MAAM,SAAS,SAAS,GAAG,gBAAgB;EACzE,MAAM,SAAS,aAAa,GAAG,gBAAgB,MAAM,GAAG,MAAM,UAAU;EACxE,aAAa,SAAS,WAAW;GAAE;GAAQ;EAAM,CAAC;EAElD,OAAO;GAAE;GAAQ;EAAM;CACzB,GACA;EACE;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,MAAM,eAAe,aAClB,QAAiB,YAAqB,IAAiB,UAAsB;EAC5E,MAAM,WAAW,gBAAgB,EAAE;EACnC,MAAM,sBAAsB,yBAAyB;GACnD,MAAM,aAAa,WAAW;GAC9B;GACA,MAAM;EACR,CAAC;EAED,IAAI,oBAAoB,SAAS,SAAS;GAIxC,MAAM,YAAY,aAAa,SAAS,SAAS,SAAS;GAC1D,IAAI,WAAW;IACb,MAAM,mBAAmB,sBAAsB,QAAQ;IACvD,IAAI,YAAY,SAAS,QAAQ,MAAM,SAAS;SAC3C,SAAS,QAAQ,MAAM,QAAQ;GACtC;EACF;EAIA,IAAI,sBAAsB,KAAA,GAAW,oBAAoB,QAAQ;EACjE,iBAAiB,OAAO,QAAQ;CAClC,GACA;EACE;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,MAAM,gCAAgC,kBAAkB;EACtD,IAAI,0BAA0B,SAC5B,aAAa,0BAA0B,OAAO;EAGhD,oBAAoB,KAAK;EACzB,0BAA0B,UAAU,iBAAiB;GACnD,oBAAoB,IAAI;EAC1B,GAAG,CAAC;CACN,GAAG,CAAC,CAAC;CAEL,MAAM,kBAAkB,kBAAkB;EACxC,IAAI,CAAC,aAAa;EAElB,MAAM,YAAY,2BAA2B;EAC7C,IAAI,CAAC,WAAW;EAEhB,8BAA8B;EAE9B,MAAM,OAAO,aAAa,SAAS,WAAW,sBAAsB;EACpE,MAAM,eAAe,OAAQ,aAAa,KAAK,SAAS,KAAK,QAAS;EACtE,MAAM,gBAAgB,aAAa,UAAU,SAAS,UAAU;EAChE,MAAM,eAAe,OAAO,kBAAkB,WAAW,gBAAgB;EAEzE,aAAa,SAAS,WAAW,SAAS;EAC1C,oBAAoB,SAAS;EAE7B,eACE,aACI;GAAE,QAAQ,eAAe;GAAc,OAAO;EAAE,IAChD;GAAE,QAAQ;GAAG,OAAO,eAAe;EAAa,GACpD,SACF;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,oBAAoB,aACvB,UAA+B;EAC9B,IAAI,MAAM,WAAW,GAAG;GACtB,gBAAgB;GAChB,OAAO;EACT;EAEA,IAAI,0BAA0B,SAAS;GACrC,aAAa,0BAA0B,OAAO;GAC9C,0BAA0B,UAAU,KAAA;EACtC;EAEA,mBAAmB,UAAU,gBAAgB;EAK7C,IAAI,oBAAoB,SAAS,SAC/B,SAAS,QAAQ,MAAM,aAAa;EAEtC,oBAAoB,KAAK;EACzB,cAAc,KAAK;CACrB,GACA;EAAC;EAAiB;EAAiB;CAAgB,CACrD;CAEA,MAAM,mBAAmB,aACtB,QAAiB,YAAqB,IAAiB,UAAsB;EAC5E,MAAM,WAAW,gBAAgB,EAAE;EACnC,MAAM,iBAAiB,yBAAyB;GAC9C,MAAM,aAAa,WAAW;GAC9B;GACA,MAAM;EACR,CAAC;EACD,MAAM,gBAAgB,iBAAkB,mBAAmB,WAAW,WAAY;EAElF,aAAa,SAAS,WAAW,aAAa;EAC9C,IAAI,CAAC,gBAAgB,oBAAoB,aAAa;EACtD,oBAAoB,IAAI;EACxB,cAAc,IAAI;EAIlB,IAAI,oBAAoB,SAAS,SAAS;GACxC,SAAS,QAAQ,MAAM,eAAe,YAAY;GAClD,IAAI,gBAAgB;IAClB,IAAI,YAAY,SAAS,QAAQ,MAAM,SAAS;SAC3C,SAAS,QAAQ,MAAM,QAAQ;GACtC,OAAO;IACL,SAAS,QAAQ,MAAM,eAAe,OAAO;IAC7C,SAAS,QAAQ,MAAM,eAAe,QAAQ;GAChD;EACF;EACA,IAAI,gBAAgB,YAAY,KAAK;EAErC,mBAAmB,UAAU,KAAA;EAC7B,eAAe,OAAO,aAAa;CACrC,GACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,MAAM,wBAAwB,cAE1B,GAAG,eAAe,EAAE,WAAW,SAAS,CAAC,GAAG,uBAAuB,OAAO,eAAe,GAC3F,CAAC,UAAU,mBAAmB,CAChC;CAEA,IAAI,YACF,OACE,oBAAC,OAAD;EAAK,WAAW,GAAG,OAAO,YAAY,SAAS;EAAG,OAAO;EACtD;CACE,CAAA;CAIT,MAAM,QAAQ,UAAU,sBAAsB;CAC9C,MAAM,kBAAkB,mBACnB;EACC,SAAS;EACT,eAAe;EACf,WAAW;CACb,IACA,CAAC;CAEL,MAAM,oBAAoB,aACtB;EACE,QAAQ,WAAW,oBAAoB;EACvC,UAAU;EACV,YAAY,mBAAmB,iDAAiD;EAChF,OAAO;EACP,GAAG;CACL,IACA;EACE,UAAU;EACV,YAAY,mBAAmB,gDAAgD;EAC/E,OAAO,WAAW,oBAAoB;EACtC,GAAI,mBACA;GACE,GAAG;GACH,MAAM;GACN,UAAU;GACV,QAAQ;EACV,IACA,CAAC;CACP;CAWJ,MAAM,oBAAmC,mBACrC;EATF,SAAS;EACT,MAAM;EACN,eAAe;EACf,QAAQ;EACR,WAAW;EACX,UAAU;EACV,OAAO;CAGU,IACf,aACE;EAAE,QAAQ;EAAQ,OAAO;CAAO,IAChC,EAAE,OAAO,OAAO;CAEtB,MAAM,mBAAkC,mBACpC;EACE,SAAS;EACT,eAAe;EACf,WAAW;EACX,GAAI,SAAS,UAAU,EAAE,QAAQ,OAAO,IAAI,CAAC;CAC/C,IACA,CAAC;CAEL,MAAM,uBAAsC;EAC1C,SAAS;EACT,MAAM;EACN,eAAe;EACf,QAAQ;EACR,WAAW;EACX,UAAU;EACV,OAAO;CACT;CAEA,MAAM,aAAa,CAAC,kBAAkB,aACpC,oBAAC,WAAD;EACE,KAAK;EACL,GAAI;EACJ,WAAW,GAAG,OAAO,OAAO,YAAY,OAAO;EAC/C,QAAQ,cAAe,WAAsB;EAC7C,eACE,cACI,GACG,WAAW,sBACd,IACA,CAAC;EAEP,OAAO;GACL,GAAG;GACH,YAAY,mBAAmB,KAAA,IAAY;GAC3C,GAAI,mBAAmB,uBAAuB,CAAC;GAC/C,GAAG;EACL;EACA,UAAU;EACV,eAAe;EACf,cAAc;EAEb,UAAA,mBAAmB,oBAAC,OAAD;GAAK,OAAO;GAAoB;EAAc,CAAA,IAAI;CAC7D,CAAA;CAGb,OACE,qBAAC,SAAD;EACO;EACA;EACL,OAAO;GAAE,GAAG;GAAc,GAAG;EAAiB;EAC9C,WAAW,GACT,cAAc;GAAE;GAAU;GAAM,WAAW;GAAmB;EAAW,CAAC,GAC1E,SACF;EAPF,UAAA,CASG,cAAc,cACb,oBAAC,QAAD;GACE,WAAW,eAAe;IAAE,WAAW;IAAmB;GAAmB,CAAC;GAC9E,OAAO,EACL,SAAS,WAAY,MAAM,KAAA,IAAY,IAAK,0BAA0B,IAAI,EAC5E;GAEA,UAAA,oBAAC,QAAD;IACE,WAAW,YAAY;IACvB,OAAO,cAAc;IACrB,SAAS;IAET,UAAA,oBAAC,MAAD;KACE,WAAW,OAAO;KAClB,MAAM;KACN,MAAM;KACN,OAAO;MACL,GAAG,WAAW;MACd,WAAW,UAAU,WAAW,MAAM,EAAE;MACxC,YAAY;KACd;IACD,CAAA;GACK,CAAA;EACF,CAAA,GAET,mBACC,oBAAC,OAAD;GAAK,KAAK;GAAU,OAAO;GACxB,UAAA;EACE,CAAA,IAEL,SAEG;;AAEX,GACA,OACF;AAEA,eAAe,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HotkeyInput.mjs","names":["hotkeyMessages","useControlledState","Flexbox"],"sources":["../../src/HotkeyInput/HotkeyInput.tsx"],"sourcesContent":["'use client';\n\nimport { type InputRef } from 'antd';\nimport { cx, useThemeMode } from 'antd-style';\nimport { isEqual } from 'es-toolkit/compat';\nimport { Undo2Icon, XIcon } from 'lucide-react';\nimport {\n type FocusEvent,\n memo,\n type MouseEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useHotkeys, useRecordHotkeys } from 'react-hotkeys-hook';\nimport useControlledState from 'use-merge-value';\n\nimport ActionIcon from '@/ActionIcon';\nimport { Flexbox } from '@/Flex';\nimport Hotkey from '@/Hotkey';\nimport { checkIsAppleDevice, NORMATIVE_MODIFIER, splitKeysByPlus } from '@/Hotkey/utils';\nimport hotkeyMessages from '@/i18n/resources/en/hotkey';\nimport { useTranslation } from '@/i18n/useTranslation';\n\nimport { styles, variants } from './style';\nimport { type HotkeyInputProps } from './type';\n\nconst HotkeyInput = memo<HotkeyInputProps>(\n ({\n value = '',\n defaultValue = '',\n resetValue = '',\n onChange,\n onClear,\n onConflict,\n placeholder,\n disabled,\n shadow,\n allowClear,\n allowReset = true,\n style,\n className,\n hotkeyConflicts = [],\n variant,\n texts,\n isApple,\n onBlur,\n onReset,\n onFocus,\n }) => {\n const [isFocused, setIsFocused] = useState(false);\n const [hasConflict, setHasConflict] = useState(false);\n const [hasInvalidCombination, setHasInvalidCombination] = useState(false);\n const inputRef = useRef<InputRef>(null);\n const { isDarkMode } = useThemeMode();\n const { t } = useTranslation(hotkeyMessages);\n const isAppleDevice = useMemo(() => checkIsAppleDevice(isApple), [isApple]);\n const [hotkeyValue, setHotkeyValue] = useControlledState(defaultValue, {\n defaultValue,\n onChange,\n value,\n });\n\n // 使用 useRecordHotkeys 处理快捷键录入\n const [recordedKeys, { start, stop, isRecording, resetKeys }] = useRecordHotkeys();\n\n useHotkeys(\n '*',\n () => {\n inputRef.current?.blur();\n },\n {\n enableOnContentEditable: true,\n enableOnFormTags: true,\n enabled: isRecording && !disabled,\n keydown: false,\n keyup: true,\n preventDefault: true,\n },\n );\n\n // 处理按键,保证格式正确:修饰键在前,最多一个非修饰键在后\n const formatKeys = useCallback((keysSet: Set<string>) => {\n const modifiers: string[] = [];\n const normalKeys: string[] = [];\n\n for (const key of keysSet) {\n // 处理不同表示的修饰键\n const normalizedKey: any = key.toLowerCase();\n if (NORMATIVE_MODIFIER.includes(normalizedKey)) {\n // 统一修饰键表示\n if (\n (!isAppleDevice && normalizedKey === 'ctrl') ||\n (isAppleDevice && normalizedKey === 'meta')\n ) {\n if (!modifiers.includes('mod')) modifiers.push('mod');\n } else if (!modifiers.includes(normalizedKey)) {\n modifiers.push(normalizedKey);\n }\n } else {\n normalKeys.push(key);\n }\n }\n\n // 至少需要一个修饰键\n if (modifiers.length === 0 && normalKeys.length > 0) {\n return { isValid: false, keys: [] };\n }\n\n // 只允许一个非修饰键,如果有多个,只保留最后一个\n const finalKey = normalKeys.length > 0 ? [normalKeys.at(-1)] : [];\n const shortcuts = [modifiers, finalKey];\n\n return {\n // 组合必须包含至少一个按键\n isValid: shortcuts.every((k) => k.length > 0),\n keys: shortcuts.flat(),\n };\n }, []);\n\n // 获取格式化后的按键字符串\n const { isValid, keys } = formatKeys(recordedKeys);\n const keysString = keys.join('+');\n\n // 检查快捷键冲突\n const checkHotkeyConflict = useCallback(\n (newHotkey: string): boolean => {\n return hotkeyConflicts\n .filter((conflictKey) => conflictKey !== resetValue)\n .some((conflictKey) => {\n const newKeys = splitKeysByPlus(newHotkey);\n const conflictKeys = splitKeysByPlus(conflictKey);\n return isEqual(newKeys, conflictKeys);\n });\n },\n [hotkeyConflicts],\n );\n\n // 当按键组合完成时处理结果\n useEffect(() => {\n if (recordedKeys.size > 0 && !isRecording) {\n if (!isValid) {\n setHasInvalidCombination(true);\n setHasConflict(false);\n return;\n }\n\n setHasInvalidCombination(false);\n const newKeysString = keysString;\n\n // 检查冲突\n const conflict = checkHotkeyConflict(newKeysString);\n if (conflict) {\n setHasConflict(true);\n onConflict?.(newKeysString);\n } else {\n setHasConflict(false);\n setHotkeyValue?.(newKeysString);\n }\n }\n }, [\n recordedKeys,\n isRecording,\n isValid,\n keysString,\n checkHotkeyConflict,\n setHotkeyValue,\n onConflict,\n ]);\n\n // 处理输入框焦点\n const handleFocus = (e: FocusEvent<HTMLInputElement>) => {\n if (disabled) return;\n setIsFocused(true);\n setHasConflict(false);\n setHasInvalidCombination(false);\n start(); // 开始记录\n onFocus?.(e);\n };\n\n const handleBlur = (e: FocusEvent<HTMLInputElement>) => {\n setIsFocused(false);\n stop(); // 停止记录\n onBlur?.(e);\n };\n\n const handleClear = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setHotkeyValue?.('');\n resetKeys();\n setHasConflict(false);\n setHasInvalidCombination(false);\n setIsFocused(false);\n stop();\n onClear?.(hotkeyValue);\n };\n\n // 重置功能\n const handleReset = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setHotkeyValue?.(resetValue);\n resetKeys();\n setHasConflict(false);\n setHasInvalidCombination(false);\n setIsFocused(false);\n stop(); // 停止记录\n onReset?.(hotkeyValue, resetValue);\n };\n\n const handleClick = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (disabled || isFocused) return;\n inputRef.current?.focus();\n };\n\n const placeholderText = placeholder ?? t('hotkey.placeholder');\n const resetTitle = texts?.reset ?? t('hotkey.reset');\n const clearTitle = texts?.clear ?? t('hotkey.clear');\n const conflictText = texts?.conflicts ?? t('hotkey.conflict');\n const invalidText = texts?.invalidCombination ?? t('hotkey.invalidCombination');\n\n return (\n <Flexbox\n className={className}\n gap={8}\n style={{\n position: 'relative',\n ...style,\n }}\n >\n <Flexbox\n horizontal\n align={'center'}\n justify={'space-between'}\n className={cx(\n variants({\n disabled,\n error: hasConflict || hasInvalidCombination,\n focused: isFocused,\n shadow,\n variant: variant || (isDarkMode ? 'filled' : 'outlined'),\n }),\n )}\n onClick={handleClick}\n >\n <div style={{ pointerEvents: 'none' }}>\n {isRecording ? (\n <span className={styles.placeholder}>\n {keys.length > 0 ? <Hotkey keys={keysString} /> : placeholderText}\n </span>\n ) : hotkeyValue ? (\n <Hotkey keys={hotkeyValue} />\n ) : (\n <span className={styles.placeholder}>{placeholderText}</span>\n )}\n </div>\n\n {/* 隐藏的输入框,用于接收焦点 */}\n <input\n readOnly\n className={styles.hiddenInput}\n disabled={disabled}\n ref={inputRef as any}\n style={{ pointerEvents: 'none' }}\n onBlur={handleBlur}\n onFocus={handleFocus}\n />\n\n {!isFocused && hotkeyValue && !disabled && (allowReset || allowClear) && (\n <Flexbox horizontal gap={4}>\n {allowReset && hotkeyValue !== resetValue && (\n <ActionIcon\n icon={Undo2Icon}\n size={'small'}\n title={resetTitle}\n variant={'filled'}\n onClick={handleReset}\n />\n )}\n {allowClear && (\n <ActionIcon\n icon={XIcon}\n size={'small'}\n title={clearTitle}\n variant={'filled'}\n onClick={handleClear}\n />\n )}\n </Flexbox>\n )}\n </Flexbox>\n {hasConflict && <div className={styles.errorText}>{conflictText}</div>}\n {hasInvalidCombination && <div className={styles.errorText}>{invalidText}</div>}\n </Flexbox>\n );\n },\n);\n\nHotkeyInput.displayName = 'HotkeyInput';\n\nexport default HotkeyInput;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HotkeyInput.mjs","names":["hotkeyMessages","useControlledState","Flexbox"],"sources":["../../src/HotkeyInput/HotkeyInput.tsx"],"sourcesContent":["'use client';\n\nimport { type InputRef } from 'antd';\nimport { cx, useThemeMode } from 'antd-style';\nimport { isEqual } from 'es-toolkit/compat';\nimport { Undo2Icon, XIcon } from 'lucide-react';\nimport {\n type FocusEvent,\n memo,\n type MouseEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useHotkeys, useRecordHotkeys } from 'react-hotkeys-hook';\nimport useControlledState from 'use-merge-value';\n\nimport ActionIcon from '@/ActionIcon';\nimport { Flexbox } from '@/Flex';\nimport Hotkey from '@/Hotkey';\nimport { checkIsAppleDevice, NORMATIVE_MODIFIER, splitKeysByPlus } from '@/Hotkey/utils';\nimport hotkeyMessages from '@/i18n/resources/en/hotkey';\nimport { useTranslation } from '@/i18n/useTranslation';\n\nimport { styles, variants } from './style';\nimport { type HotkeyInputProps } from './type';\n\nconst HotkeyInput = memo<HotkeyInputProps>(\n ({\n value = '',\n defaultValue = '',\n resetValue = '',\n onChange,\n onClear,\n onConflict,\n placeholder,\n disabled,\n shadow,\n allowClear,\n allowReset = true,\n style,\n className,\n hotkeyConflicts = [],\n variant,\n texts,\n isApple,\n onBlur,\n onReset,\n onFocus,\n }) => {\n const [isFocused, setIsFocused] = useState(false);\n const [hasConflict, setHasConflict] = useState(false);\n const [hasInvalidCombination, setHasInvalidCombination] = useState(false);\n const inputRef = useRef<InputRef>(null);\n const { isDarkMode } = useThemeMode();\n const { t } = useTranslation(hotkeyMessages);\n const isAppleDevice = useMemo(() => checkIsAppleDevice(isApple), [isApple]);\n const [hotkeyValue, setHotkeyValue] = useControlledState(defaultValue, {\n defaultValue,\n onChange,\n value,\n });\n\n // 使用 useRecordHotkeys 处理快捷键录入\n const [recordedKeys, { start, stop, isRecording, resetKeys }] = useRecordHotkeys();\n\n useHotkeys(\n '*',\n () => {\n inputRef.current?.blur();\n },\n {\n enableOnContentEditable: true,\n enableOnFormTags: true,\n enabled: isRecording && !disabled,\n keydown: false,\n keyup: true,\n preventDefault: true,\n },\n );\n\n // 处理按键,保证格式正确:修饰键在前,最多一个非修饰键在后\n const formatKeys = useCallback((keysSet: Set<string>) => {\n const modifiers: string[] = [];\n const normalKeys: string[] = [];\n\n for (const key of keysSet) {\n // 处理不同表示的修饰键\n const normalizedKey: any = key.toLowerCase();\n if (NORMATIVE_MODIFIER.includes(normalizedKey)) {\n // 统一修饰键表示\n if (\n (!isAppleDevice && normalizedKey === 'ctrl') ||\n (isAppleDevice && normalizedKey === 'meta')\n ) {\n if (!modifiers.includes('mod')) modifiers.push('mod');\n } else if (!modifiers.includes(normalizedKey)) {\n modifiers.push(normalizedKey);\n }\n } else {\n normalKeys.push(key);\n }\n }\n\n // 至少需要一个修饰键\n if (modifiers.length === 0 && normalKeys.length > 0) {\n return { isValid: false, keys: [] };\n }\n\n // 只允许一个非修饰键,如果有多个,只保留最后一个\n const finalKey = normalKeys.length > 0 ? [normalKeys.at(-1)] : [];\n const shortcuts = [modifiers, finalKey];\n\n return {\n // 组合必须包含至少一个按键\n isValid: shortcuts.every((k) => k.length > 0),\n keys: shortcuts.flat(),\n };\n }, []);\n\n // 获取格式化后的按键字符串\n const { isValid, keys } = formatKeys(recordedKeys);\n const keysString = keys.join('+');\n\n // 检查快捷键冲突\n const checkHotkeyConflict = useCallback(\n (newHotkey: string): boolean => {\n return hotkeyConflicts\n .filter((conflictKey) => conflictKey !== resetValue)\n .some((conflictKey) => {\n const newKeys = splitKeysByPlus(newHotkey);\n const conflictKeys = splitKeysByPlus(conflictKey);\n return isEqual(newKeys, conflictKeys);\n });\n },\n [hotkeyConflicts],\n );\n\n // 当按键组合完成时处理结果\n useEffect(() => {\n if (recordedKeys.size > 0 && !isRecording) {\n if (!isValid) {\n setHasInvalidCombination(true);\n setHasConflict(false);\n return;\n }\n\n setHasInvalidCombination(false);\n const newKeysString = keysString;\n\n // 检查冲突\n const conflict = checkHotkeyConflict(newKeysString);\n if (conflict) {\n setHasConflict(true);\n onConflict?.(newKeysString);\n } else {\n setHasConflict(false);\n setHotkeyValue?.(newKeysString);\n }\n }\n }, [\n recordedKeys,\n isRecording,\n isValid,\n keysString,\n checkHotkeyConflict,\n setHotkeyValue,\n onConflict,\n ]);\n\n // 处理输入框焦点\n const handleFocus = (e: FocusEvent<HTMLInputElement>) => {\n if (disabled) return;\n setIsFocused(true);\n setHasConflict(false);\n setHasInvalidCombination(false);\n start(); // 开始记录\n onFocus?.(e);\n };\n\n const handleBlur = (e: FocusEvent<HTMLInputElement>) => {\n setIsFocused(false);\n stop(); // 停止记录\n onBlur?.(e);\n };\n\n const handleClear = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setHotkeyValue?.('');\n resetKeys();\n setHasConflict(false);\n setHasInvalidCombination(false);\n setIsFocused(false);\n stop();\n onClear?.(hotkeyValue);\n };\n\n // 重置功能\n const handleReset = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setHotkeyValue?.(resetValue);\n resetKeys();\n setHasConflict(false);\n setHasInvalidCombination(false);\n setIsFocused(false);\n stop(); // 停止记录\n onReset?.(hotkeyValue, resetValue);\n };\n\n const handleClick = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (disabled || isFocused) return;\n inputRef.current?.focus();\n };\n\n const placeholderText = placeholder ?? t('hotkey.placeholder');\n const resetTitle = texts?.reset ?? t('hotkey.reset');\n const clearTitle = texts?.clear ?? t('hotkey.clear');\n const conflictText = texts?.conflicts ?? t('hotkey.conflict');\n const invalidText = texts?.invalidCombination ?? t('hotkey.invalidCombination');\n\n return (\n <Flexbox\n className={className}\n gap={8}\n style={{\n position: 'relative',\n ...style,\n }}\n >\n <Flexbox\n horizontal\n align={'center'}\n justify={'space-between'}\n className={cx(\n variants({\n disabled,\n error: hasConflict || hasInvalidCombination,\n focused: isFocused,\n shadow,\n variant: variant || (isDarkMode ? 'filled' : 'outlined'),\n }),\n )}\n onClick={handleClick}\n >\n <div style={{ pointerEvents: 'none' }}>\n {isRecording ? (\n <span className={styles.placeholder}>\n {keys.length > 0 ? <Hotkey keys={keysString} /> : placeholderText}\n </span>\n ) : hotkeyValue ? (\n <Hotkey keys={hotkeyValue} />\n ) : (\n <span className={styles.placeholder}>{placeholderText}</span>\n )}\n </div>\n\n {/* 隐藏的输入框,用于接收焦点 */}\n <input\n readOnly\n className={styles.hiddenInput}\n disabled={disabled}\n ref={inputRef as any}\n style={{ pointerEvents: 'none' }}\n onBlur={handleBlur}\n onFocus={handleFocus}\n />\n\n {!isFocused && hotkeyValue && !disabled && (allowReset || allowClear) && (\n <Flexbox horizontal gap={4}>\n {allowReset && hotkeyValue !== resetValue && (\n <ActionIcon\n icon={Undo2Icon}\n size={'small'}\n title={resetTitle}\n variant={'filled'}\n onClick={handleReset}\n />\n )}\n {allowClear && (\n <ActionIcon\n icon={XIcon}\n size={'small'}\n title={clearTitle}\n variant={'filled'}\n onClick={handleClear}\n />\n )}\n </Flexbox>\n )}\n </Flexbox>\n {hasConflict && <div className={styles.errorText}>{conflictText}</div>}\n {hasInvalidCombination && <div className={styles.errorText}>{invalidText}</div>}\n </Flexbox>\n );\n },\n);\n\nHotkeyInput.displayName = 'HotkeyInput';\n\nexport default HotkeyInput;\n"],"mappings":";;;;;;;;;;;;;;;;AA6BA,MAAM,cAAc,MACjB,EACC,QAAQ,IACR,eAAe,IACf,aAAa,IACb,UACA,SACA,YACA,aACA,UACA,QACA,YACA,aAAa,MACb,OACA,WACA,kBAAkB,CAAC,GACnB,SACA,OACA,SACA,QACA,SACA,cACI;CACJ,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,CAAC,uBAAuB,4BAA4B,SAAS,KAAK;CACxE,MAAM,WAAW,OAAiB,IAAI;CACtC,MAAM,EAAE,eAAe,aAAa;CACpC,MAAM,EAAE,MAAM,eAAeA,cAAc;CAC3C,MAAM,gBAAgB,cAAc,mBAAmB,OAAO,GAAG,CAAC,OAAO,CAAC;CAC1E,MAAM,CAAC,aAAa,kBAAkBC,cAAmB,cAAc;EACrE;EACA;EACA;CACF,CAAC;CAGD,MAAM,CAAC,cAAc,EAAE,OAAO,MAAM,aAAa,eAAe,iBAAiB;CAEjF,WACE,WACM;EACJ,SAAS,SAAS,KAAK;CACzB,GACA;EACE,yBAAyB;EACzB,kBAAkB;EAClB,SAAS,eAAe,CAAC;EACzB,SAAS;EACT,OAAO;EACP,gBAAgB;CAClB,CACF;CA0CA,MAAM,EAAE,SAAS,SAvCE,aAAa,YAAyB;EACvD,MAAM,YAAsB,CAAC;EAC7B,MAAM,aAAuB,CAAC;EAE9B,KAAK,MAAM,OAAO,SAAS;GAEzB,MAAM,gBAAqB,IAAI,YAAY;GAC3C,IAAI,mBAAmB,SAAS,aAAa,GAAG;IAE9C,IACG,CAAC,iBAAiB,kBAAkB,UACpC,iBAAiB,kBAAkB,QAEhC;SAAA,CAAC,UAAU,SAAS,KAAK,GAAG,UAAU,KAAK,KAAK;IAAA,OAC/C,IAAI,CAAC,UAAU,SAAS,aAAa,GAC1C,UAAU,KAAK,aAAa;GAEhC,OACE,WAAW,KAAK,GAAG;EAEvB;EAGA,IAAI,UAAU,WAAW,KAAK,WAAW,SAAS,GAChD,OAAO;GAAE,SAAS;GAAO,MAAM,CAAC;EAAE;EAKpC,MAAM,YAAY,CAAC,WADF,WAAW,SAAS,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,CAC1B;EAEtC,OAAO;GAEL,SAAS,UAAU,OAAO,MAAM,EAAE,SAAS,CAAC;GAC5C,MAAM,UAAU,KAAK;EACvB;CACF,GAAG,CAAC,CAG+B,CAAC,CAAC,YAAY;CACjD,MAAM,aAAa,KAAK,KAAK,GAAG;CAGhC,MAAM,sBAAsB,aACzB,cAA+B;EAC9B,OAAO,gBACJ,QAAQ,gBAAgB,gBAAgB,UAAU,CAAC,CACnD,MAAM,gBAAgB;GACrB,MAAM,UAAU,gBAAgB,SAAS;GACzC,MAAM,eAAe,gBAAgB,WAAW;GAChD,OAAO,QAAQ,SAAS,YAAY;EACtC,CAAC;CACL,GACA,CAAC,eAAe,CAClB;CAGA,gBAAgB;EACd,IAAI,aAAa,OAAO,KAAK,CAAC,aAAa;GACzC,IAAI,CAAC,SAAS;IACZ,yBAAyB,IAAI;IAC7B,eAAe,KAAK;IACpB;GACF;GAEA,yBAAyB,KAAK;GAC9B,MAAM,gBAAgB;GAItB,IADiB,oBAAoB,aAC1B,GAAG;IACZ,eAAe,IAAI;IACnB,aAAa,aAAa;GAC5B,OAAO;IACL,eAAe,KAAK;IACpB,iBAAiB,aAAa;GAChC;EACF;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAGD,MAAM,eAAe,MAAoC;EACvD,IAAI,UAAU;EACd,aAAa,IAAI;EACjB,eAAe,KAAK;EACpB,yBAAyB,KAAK;EAC9B,MAAM;EACN,UAAU,CAAC;CACb;CAEA,MAAM,cAAc,MAAoC;EACtD,aAAa,KAAK;EAClB,KAAK;EACL,SAAS,CAAC;CACZ;CAEA,MAAM,eAAe,MAAkB;EACrC,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAClB,iBAAiB,EAAE;EACnB,UAAU;EACV,eAAe,KAAK;EACpB,yBAAyB,KAAK;EAC9B,aAAa,KAAK;EAClB,KAAK;EACL,UAAU,WAAW;CACvB;CAGA,MAAM,eAAe,MAAkB;EACrC,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAClB,iBAAiB,UAAU;EAC3B,UAAU;EACV,eAAe,KAAK;EACpB,yBAAyB,KAAK;EAC9B,aAAa,KAAK;EAClB,KAAK;EACL,UAAU,aAAa,UAAU;CACnC;CAEA,MAAM,eAAe,MAAkB;EACrC,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAClB,IAAI,YAAY,WAAW;EAC3B,SAAS,SAAS,MAAM;CAC1B;CAEA,MAAM,kBAAkB,eAAe,EAAE,oBAAoB;CAC7D,MAAM,aAAa,OAAO,SAAS,EAAE,cAAc;CACnD,MAAM,aAAa,OAAO,SAAS,EAAE,cAAc;CACnD,MAAM,eAAe,OAAO,aAAa,EAAE,iBAAiB;CAC5D,MAAM,cAAc,OAAO,sBAAsB,EAAE,2BAA2B;CAE9E,OACE,qBAACC,mBAAD;EACa;EACX,KAAK;EACL,OAAO;GACL,UAAU;GACV,GAAG;EACL;EANF,UAAA;GAQE,qBAACA,mBAAD;IACE,YAAA;IACA,OAAO;IACP,SAAS;IACT,WAAW,GACT,SAAS;KACP;KACA,OAAO,eAAe;KACtB,SAAS;KACT;KACA,SAAS,YAAY,aAAa,WAAW;IAC/C,CAAC,CACH;IACA,SAAS;IAbX,UAAA;KAeE,oBAAC,OAAD;MAAK,OAAO,EAAE,eAAe,OAAO;MACjC,UAAA,cACC,oBAAC,QAAD;OAAM,WAAW,OAAO;OACrB,UAAA,KAAK,SAAS,IAAI,oBAAC,QAAD,EAAQ,MAAM,WAAa,CAAA,IAAI;MAC9C,CAAA,IACJ,cACF,oBAAC,QAAD,EAAQ,MAAM,YAAc,CAAA,IAE5B,oBAAC,QAAD;OAAM,WAAW,OAAO;OAAc,UAAA;MAAsB,CAAA;KAE3D,CAAA;KAGL,oBAAC,SAAD;MACE,UAAA;MACA,WAAW,OAAO;MACR;MACV,KAAK;MACL,OAAO,EAAE,eAAe,OAAO;MAC/B,QAAQ;MACR,SAAS;KACV,CAAA;KAEA,CAAC,aAAa,eAAe,CAAC,aAAa,cAAc,eACxD,qBAACA,mBAAD;MAAS,YAAA;MAAW,KAAK;MAAzB,UAAA,CACG,cAAc,gBAAgB,cAC7B,oBAAC,YAAD;OACE,MAAM;OACN,MAAM;OACN,OAAO;OACP,SAAS;OACT,SAAS;MACV,CAAA,GAEF,cACC,oBAAC,YAAD;OACE,MAAM;OACN,MAAM;OACN,OAAO;OACP,SAAS;OACT,SAAS;MACV,CAAA,CAEI;;IAEJ;;GACR,eAAe,oBAAC,OAAD;IAAK,WAAW,OAAO;IAAY,UAAA;GAAkB,CAAA;GACpE,yBAAyB,oBAAC,OAAD;IAAK,WAAW,OAAO;IAAY,UAAA;GAAiB,CAAA;EACvE;;AAEb,CACF;AAEA,YAAY,cAAc"}
|
|
@@ -22,12 +22,14 @@ const findOpenFenceLanguage = (content) => {
|
|
|
22
22
|
const nl = content.indexOf("\n", i);
|
|
23
23
|
const lineEnd = nl === -1 ? len : nl;
|
|
24
24
|
const line = content.slice(i, lineEnd);
|
|
25
|
-
if (line.startsWith("```"))
|
|
26
|
-
inFence
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
if (line.startsWith("```")) {
|
|
26
|
+
if (inFence) {
|
|
27
|
+
inFence = false;
|
|
28
|
+
lang = "";
|
|
29
|
+
} else {
|
|
30
|
+
inFence = true;
|
|
31
|
+
lang = line.slice(3).trim().toLowerCase();
|
|
32
|
+
}
|
|
31
33
|
}
|
|
32
34
|
if (nl === -1) break;
|
|
33
35
|
i = nl + 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fenceState.mjs","names":[],"sources":["../../../src/Markdown/SyntaxMarkdown/fenceState.ts"],"sourcesContent":["/**\n * Walk `content` and return the language of the last *unclosed* fenced\n * code block, or `null` if every fence is closed (or there are none).\n *\n * Used by the smoother to decide whether to bypass its buffer for the\n * current input. CommonMark recognises an opening fence as a line whose\n * first non-space chars are 3+ backticks; we deliberately stay simple:\n * 3 literal backticks at line start, language word after. That covers\n * the markdown LLMs actually emit; tildes and indented fences fall back\n * to normal smoothing rather than getting clever.\n *\n * Linear scan over the input, ~10ns per char on V8. Called on every\n * smoothing tick during streaming so the simplicity matters.\n */\nexport const findOpenFenceLanguage = (content: string): string | null => {\n let inFence = false;\n let lang = '';\n let i = 0;\n const len = content.length;\n while (i < len) {\n const nl = content.indexOf('\\n', i);\n const lineEnd = nl === -1 ? len : nl;\n const line = content.slice(i, lineEnd);\n if (line.startsWith('```')) {\n if (inFence) {\n inFence = false;\n lang = '';\n } else {\n inFence = true;\n lang = line.slice(3).trim().toLowerCase();\n }\n }\n if (nl === -1) break;\n i = nl + 1;\n }\n return inFence ? lang : null;\n};\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,yBAAyB,YAAmC;CACvE,IAAI,UAAU;CACd,IAAI,OAAO;CACX,IAAI,IAAI;CACR,MAAM,MAAM,QAAQ;CACpB,OAAO,IAAI,KAAK;EACd,MAAM,KAAK,QAAQ,QAAQ,MAAM,CAAC;EAClC,MAAM,UAAU,OAAO,KAAK,MAAM;EAClC,MAAM,OAAO,QAAQ,MAAM,GAAG,OAAO;EACrC,IAAI,KAAK,WAAW,KAAK,
|
|
1
|
+
{"version":3,"file":"fenceState.mjs","names":[],"sources":["../../../src/Markdown/SyntaxMarkdown/fenceState.ts"],"sourcesContent":["/**\n * Walk `content` and return the language of the last *unclosed* fenced\n * code block, or `null` if every fence is closed (or there are none).\n *\n * Used by the smoother to decide whether to bypass its buffer for the\n * current input. CommonMark recognises an opening fence as a line whose\n * first non-space chars are 3+ backticks; we deliberately stay simple:\n * 3 literal backticks at line start, language word after. That covers\n * the markdown LLMs actually emit; tildes and indented fences fall back\n * to normal smoothing rather than getting clever.\n *\n * Linear scan over the input, ~10ns per char on V8. Called on every\n * smoothing tick during streaming so the simplicity matters.\n */\nexport const findOpenFenceLanguage = (content: string): string | null => {\n let inFence = false;\n let lang = '';\n let i = 0;\n const len = content.length;\n while (i < len) {\n const nl = content.indexOf('\\n', i);\n const lineEnd = nl === -1 ? len : nl;\n const line = content.slice(i, lineEnd);\n if (line.startsWith('```')) {\n if (inFence) {\n inFence = false;\n lang = '';\n } else {\n inFence = true;\n lang = line.slice(3).trim().toLowerCase();\n }\n }\n if (nl === -1) break;\n i = nl + 1;\n }\n return inFence ? lang : null;\n};\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,yBAAyB,YAAmC;CACvE,IAAI,UAAU;CACd,IAAI,OAAO;CACX,IAAI,IAAI;CACR,MAAM,MAAM,QAAQ;CACpB,OAAO,IAAI,KAAK;EACd,MAAM,KAAK,QAAQ,QAAQ,MAAM,CAAC;EAClC,MAAM,UAAU,OAAO,KAAK,MAAM;EAClC,MAAM,OAAO,QAAQ,MAAM,GAAG,OAAO;EACrC,IAAI,KAAK,WAAW,KAAK,GAAG;GAC1B,IAAI,SAAS;IACX,UAAU;IACV,OAAO;GACT,OAAO;IACL,UAAU;IACV,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY;GAC1C;EACF;EACA,IAAI,OAAO,IAAI;EACf,IAAI,KAAK;CACX;CACA,OAAO,UAAU,OAAO;AAC1B"}
|
|
@@ -80,20 +80,21 @@ const rehypeStreamAnimated = (options = {}) => {
|
|
|
80
80
|
};
|
|
81
81
|
const wrapText = (node) => {
|
|
82
82
|
const newChildren = [];
|
|
83
|
-
for (const child of node.children) if (child.type === "text")
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
83
|
+
for (const child of node.children) if (child.type === "text") {
|
|
84
|
+
if (granularity === "word") for (const segment of segmentWords(child.value)) {
|
|
85
|
+
const startIndex = globalCharIndex;
|
|
86
|
+
for (const _char of segment) globalCharIndex++;
|
|
87
|
+
if (segment.trim() === "") newChildren.push({
|
|
88
|
+
type: "text",
|
|
89
|
+
value: segment
|
|
90
|
+
});
|
|
91
|
+
else newChildren.push(buildSpan(segment, startIndex));
|
|
92
|
+
}
|
|
93
|
+
else for (const char of child.value) {
|
|
94
|
+
newChildren.push(buildSpan(char, globalCharIndex));
|
|
95
|
+
globalCharIndex++;
|
|
96
|
+
}
|
|
97
|
+
} else if (child.type === "element") {
|
|
97
98
|
if (!shouldSkip(child)) wrapText(child);
|
|
98
99
|
newChildren.push(child);
|
|
99
100
|
} else newChildren.push(child);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rehypeStreamAnimated.mjs","names":[],"sources":["../../../src/Markdown/plugins/rehypeStreamAnimated.ts"],"sourcesContent":["import { type Element, type ElementContent, type Root } from 'hast';\nimport { type BuildVisitor } from 'unist-util-visit';\nimport { visit } from 'unist-util-visit';\n\nimport { getNow } from '@/utils/getNow';\n\nexport interface StreamAnimatedRuntime {\n births: number[];\n /**\n * Write-once per-char render cache, indexed like `births`:\n * `undefined` = char not rendered yet, `null` = born fully revealed,\n * string = inline style frozen at first render.\n * Freezing the style keeps span props referentially stable across the\n * tail block's re-renders, so React never rewrites `animation-delay`\n * on an in-flight fade (a rewrite restarts the CSS animation).\n */\n styles: (string | null | undefined)[];\n}\n\nexport interface StreamAnimatedOptions {\n births?: number[];\n fadeDuration?: number;\n /**\n * `'word'` wraps whitespace-delimited runs in one span instead of one\n * span per char. Every concurrent CSS animation keeps the compositor\n * producing frames and fires animationstart/end through React's root\n * event delegation, so animating ~5x fewer nodes is the main CPU lever —\n * char-level remains available for the finer-grained look.\n */\n granularity?: 'char' | 'word';\n nowMs?: number;\n revealed?: boolean;\n runtime?: StreamAnimatedRuntime;\n}\n\n// Intl.Segmenter splits CJK runs into words too — the whitespace regex\n// fallback would otherwise fade an entire unspaced CJK paragraph as one\n// unit.\nconst WORD_SEGMENT_RE = /\\s+|\\S+/g;\n\nconst wordSegmenter =\n typeof Intl !== 'undefined' && 'Segmenter' in Intl\n ? new Intl.Segmenter(undefined, { granularity: 'word' })\n : null;\n\nconst segmentWords = (value: string): string[] => {\n if (!wordSegmenter) return value.match(WORD_SEGMENT_RE) ?? [];\n\n const segments: string[] = [];\n for (const item of wordSegmenter.segment(value)) {\n segments.push(item.segment);\n }\n return segments;\n};\n\nconst BLOCK_TAGS = new Set(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li']);\nconst SKIP_TAGS = new Set(['pre', 'code', 'table', 'svg']);\n\nfunction hasClass(node: Element, cls: string): boolean {\n const cn: unknown = node.properties?.className;\n if (Array.isArray(cn)) return cn.some((c) => String(c).includes(cls));\n return false;\n}\n\nexport const rehypeStreamAnimated = (options: StreamAnimatedOptions = {}) => {\n const {\n births,\n fadeDuration = 150,\n granularity = 'char',\n nowMs,\n revealed = false,\n runtime,\n } = options;\n // Legacy births/nowMs callers share the runtime path through a throwaway\n // cache: the plugin factory runs once per render, so their styles are\n // recomputed against the caller's nowMs each run, exactly as before.\n const resolvedRuntime = revealed\n ? undefined\n : (runtime ??\n (Array.isArray(births) && typeof nowMs === 'number' ? { births, styles: [] } : undefined));\n const nowOverride = runtime ? undefined : nowMs;\n\n return (tree: Root) => {\n let globalCharIndex = 0;\n const now = nowOverride ?? (resolvedRuntime ? getNow() : 0);\n\n const shouldSkip = (node: Element): boolean => {\n return SKIP_TAGS.has(node.tagName) || hasClass(node, 'katex');\n };\n\n const resolveStyle = (index: number): string | null => {\n const styles = resolvedRuntime!.styles;\n const cached = styles[index];\n if (cached !== undefined) return cached;\n\n const birthTs = resolvedRuntime!.births[index];\n let resolved: string | null;\n if (birthTs === undefined) {\n resolved = null;\n } else {\n const elapsed = now - birthTs;\n // Negative delay = already elapsed ms into the fade. Positive\n // delay = not started yet (char born in the future, i.e.\n // staggered within the same commit).\n resolved = elapsed >= fadeDuration ? null : `animation-delay:${-elapsed}ms`;\n }\n styles[index] = resolved;\n return resolved;\n };\n\n const buildSpan = (value: string, startIndex: number): ElementContent => {\n let className = 'stream-char';\n let style: string | undefined;\n\n if (revealed) {\n className = 'stream-char stream-char-revealed';\n } else if (resolvedRuntime) {\n const resolved = resolveStyle(startIndex);\n if (resolved === null) {\n className = 'stream-char stream-char-revealed';\n } else {\n style = resolved;\n }\n }\n\n const properties: Record<string, any> = { className };\n if (style !== undefined) {\n properties.style = style;\n }\n return {\n children: [{ type: 'text', value }],\n properties,\n tagName: 'span',\n type: 'element',\n };\n };\n\n const wrapText = (node: Element) => {\n const newChildren: ElementContent[] = [];\n for (const child of node.children) {\n if (child.type === 'text') {\n if (granularity === 'word') {\n for (const segment of segmentWords(child.value)) {\n const startIndex = globalCharIndex;\n for (const _char of segment) globalCharIndex++;\n\n if (segment.trim() === '') {\n newChildren.push({ type: 'text', value: segment });\n } else {\n newChildren.push(buildSpan(segment, startIndex));\n }\n }\n } else {\n for (const char of child.value) {\n newChildren.push(buildSpan(char, globalCharIndex));\n globalCharIndex++;\n }\n }\n } else if (child.type === 'element') {\n if (!shouldSkip(child)) {\n wrapText(child);\n }\n newChildren.push(child);\n } else {\n newChildren.push(child);\n }\n }\n node.children = newChildren;\n };\n\n visit(tree, 'element', ((node: Element) => {\n if (shouldSkip(node)) return 'skip';\n if (BLOCK_TAGS.has(node.tagName)) {\n wrapText(node);\n return 'skip';\n }\n }) as BuildVisitor<Root, 'element'>);\n };\n};\n"],"mappings":";;;AAsCA,MAAM,kBAAkB;AAExB,MAAM,gBACJ,OAAO,SAAS,eAAe,eAAe,OAC1C,IAAI,KAAK,UAAU,KAAA,GAAW,EAAE,aAAa,OAAO,CAAC,IACrD;AAEN,MAAM,gBAAgB,UAA4B;CAChD,IAAI,CAAC,eAAe,OAAO,MAAM,MAAM,eAAe,KAAK,CAAC;CAE5D,MAAM,WAAqB,CAAC;CAC5B,KAAK,MAAM,QAAQ,cAAc,QAAQ,KAAK,GAC5C,SAAS,KAAK,KAAK,OAAO;CAE5B,OAAO;AACT;AAEA,MAAM,6BAAa,IAAI,IAAI;CAAC;CAAK;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,CAAC;AAC1E,MAAM,4BAAY,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAS;AAAK,CAAC;AAEzD,SAAS,SAAS,MAAe,KAAsB;CACrD,MAAM,KAAc,KAAK,YAAY;CACrC,IAAI,MAAM,QAAQ,EAAE,GAAG,OAAO,GAAG,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC;CACpE,OAAO;AACT;AAEA,MAAa,wBAAwB,UAAiC,CAAC,MAAM;CAC3E,MAAM,EACJ,QACA,eAAe,KACf,cAAc,QACd,OACA,WAAW,OACX,YACE;CAIJ,MAAM,kBAAkB,WACpB,KAAA,IACC,YACA,MAAM,QAAQ,MAAM,KAAK,OAAO,UAAU,WAAW;EAAE;EAAQ,QAAQ,CAAC;CAAE,IAAI,KAAA;CACnF,MAAM,cAAc,UAAU,KAAA,IAAY;CAE1C,QAAQ,SAAe;EACrB,IAAI,kBAAkB;EACtB,MAAM,MAAM,gBAAgB,kBAAkB,OAAO,IAAI;EAEzD,MAAM,cAAc,SAA2B;GAC7C,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,SAAS,MAAM,OAAO;EAC9D;EAEA,MAAM,gBAAgB,UAAiC;GACrD,MAAM,SAAS,gBAAiB;GAChC,MAAM,SAAS,OAAO;GACtB,IAAI,WAAW,KAAA,GAAW,OAAO;GAEjC,MAAM,UAAU,gBAAiB,OAAO;GACxC,IAAI;GACJ,IAAI,YAAY,KAAA,GACd,WAAW;QACN;IACL,MAAM,UAAU,MAAM;IAItB,WAAW,WAAW,eAAe,OAAO,mBAAmB,CAAC,QAAQ;GAC1E;GACA,OAAO,SAAS;GAChB,OAAO;EACT;EAEA,MAAM,aAAa,OAAe,eAAuC;GACvE,IAAI,YAAY;GAChB,IAAI;GAEJ,IAAI,UACF,YAAY;QACP,IAAI,iBAAiB;IAC1B,MAAM,WAAW,aAAa,UAAU;IACxC,IAAI,aAAa,MACf,YAAY;SAEZ,QAAQ;GAEZ;GAEA,MAAM,aAAkC,EAAE,UAAU;GACpD,IAAI,UAAU,KAAA,GACZ,WAAW,QAAQ;GAErB,OAAO;IACL,UAAU,CAAC;KAAE,MAAM;KAAQ;IAAM,CAAC;IAClC;IACA,SAAS;IACT,MAAM;GACR;EACF;EAEA,MAAM,YAAY,SAAkB;GAClC,MAAM,cAAgC,CAAC;GACvC,KAAK,MAAM,SAAS,KAAK,UACvB,IAAI,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"rehypeStreamAnimated.mjs","names":[],"sources":["../../../src/Markdown/plugins/rehypeStreamAnimated.ts"],"sourcesContent":["import { type Element, type ElementContent, type Root } from 'hast';\nimport { type BuildVisitor } from 'unist-util-visit';\nimport { visit } from 'unist-util-visit';\n\nimport { getNow } from '@/utils/getNow';\n\nexport interface StreamAnimatedRuntime {\n births: number[];\n /**\n * Write-once per-char render cache, indexed like `births`:\n * `undefined` = char not rendered yet, `null` = born fully revealed,\n * string = inline style frozen at first render.\n * Freezing the style keeps span props referentially stable across the\n * tail block's re-renders, so React never rewrites `animation-delay`\n * on an in-flight fade (a rewrite restarts the CSS animation).\n */\n styles: (string | null | undefined)[];\n}\n\nexport interface StreamAnimatedOptions {\n births?: number[];\n fadeDuration?: number;\n /**\n * `'word'` wraps whitespace-delimited runs in one span instead of one\n * span per char. Every concurrent CSS animation keeps the compositor\n * producing frames and fires animationstart/end through React's root\n * event delegation, so animating ~5x fewer nodes is the main CPU lever —\n * char-level remains available for the finer-grained look.\n */\n granularity?: 'char' | 'word';\n nowMs?: number;\n revealed?: boolean;\n runtime?: StreamAnimatedRuntime;\n}\n\n// Intl.Segmenter splits CJK runs into words too — the whitespace regex\n// fallback would otherwise fade an entire unspaced CJK paragraph as one\n// unit.\nconst WORD_SEGMENT_RE = /\\s+|\\S+/g;\n\nconst wordSegmenter =\n typeof Intl !== 'undefined' && 'Segmenter' in Intl\n ? new Intl.Segmenter(undefined, { granularity: 'word' })\n : null;\n\nconst segmentWords = (value: string): string[] => {\n if (!wordSegmenter) return value.match(WORD_SEGMENT_RE) ?? [];\n\n const segments: string[] = [];\n for (const item of wordSegmenter.segment(value)) {\n segments.push(item.segment);\n }\n return segments;\n};\n\nconst BLOCK_TAGS = new Set(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li']);\nconst SKIP_TAGS = new Set(['pre', 'code', 'table', 'svg']);\n\nfunction hasClass(node: Element, cls: string): boolean {\n const cn: unknown = node.properties?.className;\n if (Array.isArray(cn)) return cn.some((c) => String(c).includes(cls));\n return false;\n}\n\nexport const rehypeStreamAnimated = (options: StreamAnimatedOptions = {}) => {\n const {\n births,\n fadeDuration = 150,\n granularity = 'char',\n nowMs,\n revealed = false,\n runtime,\n } = options;\n // Legacy births/nowMs callers share the runtime path through a throwaway\n // cache: the plugin factory runs once per render, so their styles are\n // recomputed against the caller's nowMs each run, exactly as before.\n const resolvedRuntime = revealed\n ? undefined\n : (runtime ??\n (Array.isArray(births) && typeof nowMs === 'number' ? { births, styles: [] } : undefined));\n const nowOverride = runtime ? undefined : nowMs;\n\n return (tree: Root) => {\n let globalCharIndex = 0;\n const now = nowOverride ?? (resolvedRuntime ? getNow() : 0);\n\n const shouldSkip = (node: Element): boolean => {\n return SKIP_TAGS.has(node.tagName) || hasClass(node, 'katex');\n };\n\n const resolveStyle = (index: number): string | null => {\n const styles = resolvedRuntime!.styles;\n const cached = styles[index];\n if (cached !== undefined) return cached;\n\n const birthTs = resolvedRuntime!.births[index];\n let resolved: string | null;\n if (birthTs === undefined) {\n resolved = null;\n } else {\n const elapsed = now - birthTs;\n // Negative delay = already elapsed ms into the fade. Positive\n // delay = not started yet (char born in the future, i.e.\n // staggered within the same commit).\n resolved = elapsed >= fadeDuration ? null : `animation-delay:${-elapsed}ms`;\n }\n styles[index] = resolved;\n return resolved;\n };\n\n const buildSpan = (value: string, startIndex: number): ElementContent => {\n let className = 'stream-char';\n let style: string | undefined;\n\n if (revealed) {\n className = 'stream-char stream-char-revealed';\n } else if (resolvedRuntime) {\n const resolved = resolveStyle(startIndex);\n if (resolved === null) {\n className = 'stream-char stream-char-revealed';\n } else {\n style = resolved;\n }\n }\n\n const properties: Record<string, any> = { className };\n if (style !== undefined) {\n properties.style = style;\n }\n return {\n children: [{ type: 'text', value }],\n properties,\n tagName: 'span',\n type: 'element',\n };\n };\n\n const wrapText = (node: Element) => {\n const newChildren: ElementContent[] = [];\n for (const child of node.children) {\n if (child.type === 'text') {\n if (granularity === 'word') {\n for (const segment of segmentWords(child.value)) {\n const startIndex = globalCharIndex;\n for (const _char of segment) globalCharIndex++;\n\n if (segment.trim() === '') {\n newChildren.push({ type: 'text', value: segment });\n } else {\n newChildren.push(buildSpan(segment, startIndex));\n }\n }\n } else {\n for (const char of child.value) {\n newChildren.push(buildSpan(char, globalCharIndex));\n globalCharIndex++;\n }\n }\n } else if (child.type === 'element') {\n if (!shouldSkip(child)) {\n wrapText(child);\n }\n newChildren.push(child);\n } else {\n newChildren.push(child);\n }\n }\n node.children = newChildren;\n };\n\n visit(tree, 'element', ((node: Element) => {\n if (shouldSkip(node)) return 'skip';\n if (BLOCK_TAGS.has(node.tagName)) {\n wrapText(node);\n return 'skip';\n }\n }) as BuildVisitor<Root, 'element'>);\n };\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollShadow.mjs","names":["Flexbox"],"sources":["../../src/ScrollShadow/ScrollShadow.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport type { FC } from 'react';\nimport { useMemo, useRef } from 'react';\nimport { mergeRefs } from 'react-merge-refs';\n\nimport { Flexbox } from '@/Flex';\nimport { useEventCallback } from '@/hooks/useEventCallback';\n\nimport { variants } from './style';\nimport type { ScrollShadowProps } from './type';\nimport { useScrollOverflow } from './useScrollOverflow';\n\nconst ScrollShadow: FC<ScrollShadowProps> = ({\n className,\n children,\n orientation = 'vertical',\n hideScrollBar = false,\n size = 16,\n offset = 8,\n visibility = 'auto',\n isEnabled = true,\n onVisibilityChange,\n style,\n ref,\n ...rest\n}) => {\n // Convert size prop to CSS variable\n const cssVariables = useMemo<Record<string, string>>(\n () => ({\n '--scroll-shadow-size': `${size}%`,\n }),\n [size],\n );\n const domRef = useRef<HTMLDivElement>(null);\n\n const onVisibilityChangeEvent = useEventCallback<\n NonNullable<ScrollShadowProps['onVisibilityChange']>\n >((visibility) => {\n onVisibilityChange?.(visibility);\n });\n // 使用滚动检测钩子\n const scrollState = useScrollOverflow({\n domRef,\n isEnabled: isEnabled && visibility === 'auto',\n offset,\n onVisibilityChange: onVisibilityChangeEvent,\n orientation,\n updateDeps: [children],\n });\n\n // 决定最终的滚动状态\n const finalScrollState = useMemo(() => {\n if (visibility === 'always') {\n return {\n bottom: true,\n left: true,\n right: true,\n top: true,\n };\n }\n\n if (visibility === 'never') {\n return {\n bottom: false,\n left: false,\n right: false,\n top: false,\n };\n }\n\n return scrollState;\n }, [visibility, scrollState]);\n\n // 计算数据属性\n const dataAttributes = useMemo(() => {\n const attributes: Record<string, boolean | string> = {\n 'data-orientation': orientation,\n };\n\n if (orientation === 'vertical') {\n if (finalScrollState.top && finalScrollState.bottom) {\n attributes['data-top-bottom-scroll'] = true;\n } else if (finalScrollState.top) {\n attributes['data-top-scroll'] = true;\n } else if (finalScrollState.bottom) {\n attributes['data-bottom-scroll'] = true;\n }\n } else {\n if (finalScrollState.left && finalScrollState.right) {\n attributes['data-left-right-scroll'] = true;\n } else if (finalScrollState.left) {\n attributes['data-left-scroll'] = true;\n } else if (finalScrollState.right) {\n attributes['data-right-scroll'] = true;\n }\n }\n\n return attributes;\n }, [orientation, finalScrollState]);\n\n // 计算滚动位置变体\n const scrollPosition = useMemo(() => {\n if (orientation === 'vertical') {\n if (finalScrollState.top && finalScrollState.bottom) return 'top-bottom';\n if (finalScrollState.top) return 'top';\n if (finalScrollState.bottom) return 'bottom';\n } else {\n if (finalScrollState.left && finalScrollState.right) return 'left-right';\n if (finalScrollState.left) return 'left';\n if (finalScrollState.right) return 'right';\n }\n return 'none';\n }, [orientation, finalScrollState]);\n\n return (\n <Flexbox\n className={cx(variants({ hideScrollBar, orientation, scrollPosition }), className)}\n ref={mergeRefs<HTMLDivElement>([domRef, ref])}\n style={{\n ...cssVariables,\n ...style,\n }}\n {...dataAttributes}\n {...rest}\n >\n {children}\n </Flexbox>\n );\n};\n\nScrollShadow.displayName = 'ScrollShadow';\n\nexport default ScrollShadow;\n"],"mappings":";;;;;;;;;;AAcA,MAAM,gBAAuC,EAC3C,WACA,UACA,cAAc,YACd,gBAAgB,OAChB,OAAO,IACP,SAAS,GACT,aAAa,QACb,YAAY,MACZ,oBACA,OACA,KACA,GAAG,WACC;CAEJ,MAAM,eAAe,eACZ,EACL,wBAAwB,GAAG,KAAK,GAClC,IACA,CAAC,IAAI,CACP;CACA,MAAM,SAAS,OAAuB,IAAI;CAE1C,MAAM,0BAA0B,kBAE7B,eAAe;EAChB,qBAAqB,UAAU;CACjC,CAAC;CAED,MAAM,cAAc,kBAAkB;EACpC;EACA,WAAW,aAAa,eAAe;EACvC;EACA,oBAAoB;EACpB;EACA,YAAY,CAAC,QAAQ;CACvB,CAAC;CAGD,MAAM,mBAAmB,cAAc;EACrC,IAAI,eAAe,UACjB,OAAO;GACL,QAAQ;GACR,MAAM;GACN,OAAO;GACP,KAAK;EACP;EAGF,IAAI,eAAe,SACjB,OAAO;GACL,QAAQ;GACR,MAAM;GACN,OAAO;GACP,KAAK;EACP;EAGF,OAAO;CACT,GAAG,CAAC,YAAY,WAAW,CAAC;CAG5B,MAAM,iBAAiB,cAAc;EACnC,MAAM,aAA+C,EACnD,oBAAoB,YACtB;EAEA,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"ScrollShadow.mjs","names":["Flexbox"],"sources":["../../src/ScrollShadow/ScrollShadow.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport type { FC } from 'react';\nimport { useMemo, useRef } from 'react';\nimport { mergeRefs } from 'react-merge-refs';\n\nimport { Flexbox } from '@/Flex';\nimport { useEventCallback } from '@/hooks/useEventCallback';\n\nimport { variants } from './style';\nimport type { ScrollShadowProps } from './type';\nimport { useScrollOverflow } from './useScrollOverflow';\n\nconst ScrollShadow: FC<ScrollShadowProps> = ({\n className,\n children,\n orientation = 'vertical',\n hideScrollBar = false,\n size = 16,\n offset = 8,\n visibility = 'auto',\n isEnabled = true,\n onVisibilityChange,\n style,\n ref,\n ...rest\n}) => {\n // Convert size prop to CSS variable\n const cssVariables = useMemo<Record<string, string>>(\n () => ({\n '--scroll-shadow-size': `${size}%`,\n }),\n [size],\n );\n const domRef = useRef<HTMLDivElement>(null);\n\n const onVisibilityChangeEvent = useEventCallback<\n NonNullable<ScrollShadowProps['onVisibilityChange']>\n >((visibility) => {\n onVisibilityChange?.(visibility);\n });\n // 使用滚动检测钩子\n const scrollState = useScrollOverflow({\n domRef,\n isEnabled: isEnabled && visibility === 'auto',\n offset,\n onVisibilityChange: onVisibilityChangeEvent,\n orientation,\n updateDeps: [children],\n });\n\n // 决定最终的滚动状态\n const finalScrollState = useMemo(() => {\n if (visibility === 'always') {\n return {\n bottom: true,\n left: true,\n right: true,\n top: true,\n };\n }\n\n if (visibility === 'never') {\n return {\n bottom: false,\n left: false,\n right: false,\n top: false,\n };\n }\n\n return scrollState;\n }, [visibility, scrollState]);\n\n // 计算数据属性\n const dataAttributes = useMemo(() => {\n const attributes: Record<string, boolean | string> = {\n 'data-orientation': orientation,\n };\n\n if (orientation === 'vertical') {\n if (finalScrollState.top && finalScrollState.bottom) {\n attributes['data-top-bottom-scroll'] = true;\n } else if (finalScrollState.top) {\n attributes['data-top-scroll'] = true;\n } else if (finalScrollState.bottom) {\n attributes['data-bottom-scroll'] = true;\n }\n } else {\n if (finalScrollState.left && finalScrollState.right) {\n attributes['data-left-right-scroll'] = true;\n } else if (finalScrollState.left) {\n attributes['data-left-scroll'] = true;\n } else if (finalScrollState.right) {\n attributes['data-right-scroll'] = true;\n }\n }\n\n return attributes;\n }, [orientation, finalScrollState]);\n\n // 计算滚动位置变体\n const scrollPosition = useMemo(() => {\n if (orientation === 'vertical') {\n if (finalScrollState.top && finalScrollState.bottom) return 'top-bottom';\n if (finalScrollState.top) return 'top';\n if (finalScrollState.bottom) return 'bottom';\n } else {\n if (finalScrollState.left && finalScrollState.right) return 'left-right';\n if (finalScrollState.left) return 'left';\n if (finalScrollState.right) return 'right';\n }\n return 'none';\n }, [orientation, finalScrollState]);\n\n return (\n <Flexbox\n className={cx(variants({ hideScrollBar, orientation, scrollPosition }), className)}\n ref={mergeRefs<HTMLDivElement>([domRef, ref])}\n style={{\n ...cssVariables,\n ...style,\n }}\n {...dataAttributes}\n {...rest}\n >\n {children}\n </Flexbox>\n );\n};\n\nScrollShadow.displayName = 'ScrollShadow';\n\nexport default ScrollShadow;\n"],"mappings":";;;;;;;;;;AAcA,MAAM,gBAAuC,EAC3C,WACA,UACA,cAAc,YACd,gBAAgB,OAChB,OAAO,IACP,SAAS,GACT,aAAa,QACb,YAAY,MACZ,oBACA,OACA,KACA,GAAG,WACC;CAEJ,MAAM,eAAe,eACZ,EACL,wBAAwB,GAAG,KAAK,GAClC,IACA,CAAC,IAAI,CACP;CACA,MAAM,SAAS,OAAuB,IAAI;CAE1C,MAAM,0BAA0B,kBAE7B,eAAe;EAChB,qBAAqB,UAAU;CACjC,CAAC;CAED,MAAM,cAAc,kBAAkB;EACpC;EACA,WAAW,aAAa,eAAe;EACvC;EACA,oBAAoB;EACpB;EACA,YAAY,CAAC,QAAQ;CACvB,CAAC;CAGD,MAAM,mBAAmB,cAAc;EACrC,IAAI,eAAe,UACjB,OAAO;GACL,QAAQ;GACR,MAAM;GACN,OAAO;GACP,KAAK;EACP;EAGF,IAAI,eAAe,SACjB,OAAO;GACL,QAAQ;GACR,MAAM;GACN,OAAO;GACP,KAAK;EACP;EAGF,OAAO;CACT,GAAG,CAAC,YAAY,WAAW,CAAC;CAG5B,MAAM,iBAAiB,cAAc;EACnC,MAAM,aAA+C,EACnD,oBAAoB,YACtB;EAEA,IAAI,gBAAgB,YAAY;GAC9B,IAAI,iBAAiB,OAAO,iBAAiB,QAC3C,WAAW,4BAA4B;QAClC,IAAI,iBAAiB,KAC1B,WAAW,qBAAqB;QAC3B,IAAI,iBAAiB,QAC1B,WAAW,wBAAwB;EAEvC,OACE,IAAI,iBAAiB,QAAQ,iBAAiB,OAC5C,WAAW,4BAA4B;OAClC,IAAI,iBAAiB,MAC1B,WAAW,sBAAsB;OAC5B,IAAI,iBAAiB,OAC1B,WAAW,uBAAuB;EAItC,OAAO;CACT,GAAG,CAAC,aAAa,gBAAgB,CAAC;CAGlC,MAAM,iBAAiB,cAAc;EACnC,IAAI,gBAAgB,YAAY;GAC9B,IAAI,iBAAiB,OAAO,iBAAiB,QAAQ,OAAO;GAC5D,IAAI,iBAAiB,KAAK,OAAO;GACjC,IAAI,iBAAiB,QAAQ,OAAO;EACtC,OAAO;GACL,IAAI,iBAAiB,QAAQ,iBAAiB,OAAO,OAAO;GAC5D,IAAI,iBAAiB,MAAM,OAAO;GAClC,IAAI,iBAAiB,OAAO,OAAO;EACrC;EACA,OAAO;CACT,GAAG,CAAC,aAAa,gBAAgB,CAAC;CAElC,OACE,oBAACA,mBAAD;EACE,WAAW,GAAG,SAAS;GAAE;GAAe;GAAa;EAAe,CAAC,GAAG,SAAS;EACjF,KAAK,UAA0B,CAAC,QAAQ,GAAG,CAAC;EAC5C,OAAO;GACL,GAAG;GACH,GAAG;EACL;EACA,GAAI;EACJ,GAAI;EAEH;CACM,CAAA;AAEb;AAEA,aAAa,cAAc"}
|
|
@@ -15,14 +15,15 @@ const useScrollOverflow = ({ domRef, offset = 0, orientation = "vertical", isEna
|
|
|
15
15
|
if (!element || !isEnabled) return;
|
|
16
16
|
const checkScroll = () => {
|
|
17
17
|
const newState = { ...initialScrollState };
|
|
18
|
-
if (orientation === "vertical")
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
if (orientation === "vertical") {
|
|
19
|
+
if (element.scrollHeight > element.clientHeight) {
|
|
20
|
+
newState.top = element.scrollTop > offset;
|
|
21
|
+
newState.bottom = element.scrollTop + element.clientHeight < element.scrollHeight - offset;
|
|
22
|
+
} else {
|
|
23
|
+
newState.top = false;
|
|
24
|
+
newState.bottom = false;
|
|
25
|
+
}
|
|
26
|
+
} else if (element.scrollWidth > element.clientWidth) {
|
|
26
27
|
newState.left = element.scrollLeft > offset;
|
|
27
28
|
newState.right = element.scrollLeft + element.clientWidth < element.scrollWidth - offset;
|
|
28
29
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollOverflow.mjs","names":[],"sources":["../../src/ScrollShadow/useScrollOverflow.ts"],"sourcesContent":["import { type RefObject, useEffect, useRef, useState } from 'react';\n\ninterface ScrollState {\n bottom: boolean;\n left: boolean;\n right: boolean;\n top: boolean;\n}\n\nconst initialScrollState: ScrollState = {\n bottom: false,\n left: false,\n right: false,\n top: false,\n};\n\nconst isSameScrollState = (a: ScrollState, b: ScrollState) =>\n a.bottom === b.bottom && a.left === b.left && a.right === b.right && a.top === b.top;\n\ninterface UseScrollOverflowProps {\n domRef: RefObject<HTMLElement | null>;\n isEnabled?: boolean;\n offset?: number;\n onVisibilityChange?: (visibility: {\n bottom?: boolean;\n left?: boolean;\n right?: boolean;\n top?: boolean;\n }) => void;\n orientation?: 'vertical' | 'horizontal';\n updateDeps?: any[];\n}\n\nexport const useScrollOverflow = ({\n domRef,\n offset = 0,\n orientation = 'vertical',\n isEnabled = true,\n onVisibilityChange,\n updateDeps = [],\n}: UseScrollOverflowProps) => {\n const [scrollState, setScrollState] = useState(initialScrollState);\n const scrollStateRef = useRef(initialScrollState);\n\n useEffect(() => {\n const element = domRef.current;\n if (!element || !isEnabled) return;\n\n const checkScroll = () => {\n const newState = { ...initialScrollState };\n\n if (orientation === 'vertical') {\n const hasVerticalScroll = element.scrollHeight > element.clientHeight;\n\n if (hasVerticalScroll) {\n newState.top = element.scrollTop > offset;\n newState.bottom =\n element.scrollTop + element.clientHeight < element.scrollHeight - offset;\n } else {\n newState.top = false;\n newState.bottom = false;\n }\n } else {\n const hasHorizontalScroll = element.scrollWidth > element.clientWidth;\n\n if (hasHorizontalScroll) {\n newState.left = element.scrollLeft > offset;\n newState.right = element.scrollLeft + element.clientWidth < element.scrollWidth - offset;\n } else {\n newState.left = false;\n newState.right = false;\n }\n }\n\n if (isSameScrollState(scrollStateRef.current, newState)) return;\n\n scrollStateRef.current = newState;\n setScrollState(newState);\n onVisibilityChange?.(newState);\n };\n\n // 初始检查\n checkScroll();\n\n // 监听滚动事件\n element.addEventListener('scroll', checkScroll);\n window.addEventListener('resize', checkScroll);\n\n // 观察内容变化\n const resizeObserver = new ResizeObserver(checkScroll);\n resizeObserver.observe(element);\n\n return () => {\n element.removeEventListener('scroll', checkScroll);\n window.removeEventListener('resize', checkScroll);\n resizeObserver.disconnect();\n };\n }, [domRef, offset, orientation, isEnabled, ...updateDeps]);\n\n return scrollState;\n};\n"],"mappings":";;AASA,MAAM,qBAAkC;CACtC,QAAQ;CACR,MAAM;CACN,OAAO;CACP,KAAK;AACP;AAEA,MAAM,qBAAqB,GAAgB,MACzC,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE;AAgBnF,MAAa,qBAAqB,EAChC,QACA,SAAS,GACT,cAAc,YACd,YAAY,MACZ,oBACA,aAAa,CAAC,QACc;CAC5B,MAAM,CAAC,aAAa,kBAAkB,SAAS,kBAAkB;CACjE,MAAM,iBAAiB,OAAO,kBAAkB;CAEhD,gBAAgB;EACd,MAAM,UAAU,OAAO;EACvB,IAAI,CAAC,WAAW,CAAC,WAAW;EAE5B,MAAM,oBAAoB;GACxB,MAAM,WAAW,EAAE,GAAG,mBAAmB;GAEzC,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"useScrollOverflow.mjs","names":[],"sources":["../../src/ScrollShadow/useScrollOverflow.ts"],"sourcesContent":["import { type RefObject, useEffect, useRef, useState } from 'react';\n\ninterface ScrollState {\n bottom: boolean;\n left: boolean;\n right: boolean;\n top: boolean;\n}\n\nconst initialScrollState: ScrollState = {\n bottom: false,\n left: false,\n right: false,\n top: false,\n};\n\nconst isSameScrollState = (a: ScrollState, b: ScrollState) =>\n a.bottom === b.bottom && a.left === b.left && a.right === b.right && a.top === b.top;\n\ninterface UseScrollOverflowProps {\n domRef: RefObject<HTMLElement | null>;\n isEnabled?: boolean;\n offset?: number;\n onVisibilityChange?: (visibility: {\n bottom?: boolean;\n left?: boolean;\n right?: boolean;\n top?: boolean;\n }) => void;\n orientation?: 'vertical' | 'horizontal';\n updateDeps?: any[];\n}\n\nexport const useScrollOverflow = ({\n domRef,\n offset = 0,\n orientation = 'vertical',\n isEnabled = true,\n onVisibilityChange,\n updateDeps = [],\n}: UseScrollOverflowProps) => {\n const [scrollState, setScrollState] = useState(initialScrollState);\n const scrollStateRef = useRef(initialScrollState);\n\n useEffect(() => {\n const element = domRef.current;\n if (!element || !isEnabled) return;\n\n const checkScroll = () => {\n const newState = { ...initialScrollState };\n\n if (orientation === 'vertical') {\n const hasVerticalScroll = element.scrollHeight > element.clientHeight;\n\n if (hasVerticalScroll) {\n newState.top = element.scrollTop > offset;\n newState.bottom =\n element.scrollTop + element.clientHeight < element.scrollHeight - offset;\n } else {\n newState.top = false;\n newState.bottom = false;\n }\n } else {\n const hasHorizontalScroll = element.scrollWidth > element.clientWidth;\n\n if (hasHorizontalScroll) {\n newState.left = element.scrollLeft > offset;\n newState.right = element.scrollLeft + element.clientWidth < element.scrollWidth - offset;\n } else {\n newState.left = false;\n newState.right = false;\n }\n }\n\n if (isSameScrollState(scrollStateRef.current, newState)) return;\n\n scrollStateRef.current = newState;\n setScrollState(newState);\n onVisibilityChange?.(newState);\n };\n\n // 初始检查\n checkScroll();\n\n // 监听滚动事件\n element.addEventListener('scroll', checkScroll);\n window.addEventListener('resize', checkScroll);\n\n // 观察内容变化\n const resizeObserver = new ResizeObserver(checkScroll);\n resizeObserver.observe(element);\n\n return () => {\n element.removeEventListener('scroll', checkScroll);\n window.removeEventListener('resize', checkScroll);\n resizeObserver.disconnect();\n };\n }, [domRef, offset, orientation, isEnabled, ...updateDeps]);\n\n return scrollState;\n};\n"],"mappings":";;AASA,MAAM,qBAAkC;CACtC,QAAQ;CACR,MAAM;CACN,OAAO;CACP,KAAK;AACP;AAEA,MAAM,qBAAqB,GAAgB,MACzC,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE;AAgBnF,MAAa,qBAAqB,EAChC,QACA,SAAS,GACT,cAAc,YACd,YAAY,MACZ,oBACA,aAAa,CAAC,QACc;CAC5B,MAAM,CAAC,aAAa,kBAAkB,SAAS,kBAAkB;CACjE,MAAM,iBAAiB,OAAO,kBAAkB;CAEhD,gBAAgB;EACd,MAAM,UAAU,OAAO;EACvB,IAAI,CAAC,WAAW,CAAC,WAAW;EAE5B,MAAM,oBAAoB;GACxB,MAAM,WAAW,EAAE,GAAG,mBAAmB;GAEzC,IAAI,gBAAgB,YAAY;IAG9B,IAF0B,QAAQ,eAAe,QAAQ,cAElC;KACrB,SAAS,MAAM,QAAQ,YAAY;KACnC,SAAS,SACP,QAAQ,YAAY,QAAQ,eAAe,QAAQ,eAAe;IACtE,OAAO;KACL,SAAS,MAAM;KACf,SAAS,SAAS;IACpB;GACF,OAGE,IAF4B,QAAQ,cAAc,QAAQ,aAEjC;IACvB,SAAS,OAAO,QAAQ,aAAa;IACrC,SAAS,QAAQ,QAAQ,aAAa,QAAQ,cAAc,QAAQ,cAAc;GACpF,OAAO;IACL,SAAS,OAAO;IAChB,SAAS,QAAQ;GACnB;GAGF,IAAI,kBAAkB,eAAe,SAAS,QAAQ,GAAG;GAEzD,eAAe,UAAU;GACzB,eAAe,QAAQ;GACvB,qBAAqB,QAAQ;EAC/B;EAGA,YAAY;EAGZ,QAAQ,iBAAiB,UAAU,WAAW;EAC9C,OAAO,iBAAiB,UAAU,WAAW;EAG7C,MAAM,iBAAiB,IAAI,eAAe,WAAW;EACrD,eAAe,QAAQ,OAAO;EAE9B,aAAa;GACX,QAAQ,oBAAoB,UAAU,WAAW;GACjD,OAAO,oBAAoB,UAAU,WAAW;GAChD,eAAe,WAAW;EAC5B;CACF,GAAG;EAAC;EAAQ;EAAQ;EAAa;EAAW,GAAG;CAAU,CAAC;CAE1D,OAAO;AACT"}
|
|
@@ -59,22 +59,23 @@ const TypewriterEffect = memo(({ sentences, as: Component = "div", typingSpeed =
|
|
|
59
59
|
return () => clearTimeout(timeout);
|
|
60
60
|
}
|
|
61
61
|
const executeTypingAnimation = () => {
|
|
62
|
-
if (isDeleting)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
62
|
+
if (isDeleting) {
|
|
63
|
+
if (displayedText === "") {
|
|
64
|
+
setIsDeleting(false);
|
|
65
|
+
if (currentTextIndex === textArray.length - 1 && !loop) return;
|
|
66
|
+
if (onSentenceComplete) onSentenceComplete(textArray[currentTextIndex], currentTextIndex);
|
|
67
|
+
setCurrentTextIndex((prev) => (prev + 1) % textArray.length);
|
|
68
|
+
setCurrentCharIndex(0);
|
|
69
|
+
if (deletePauseDuration > 0) {
|
|
70
|
+
setIsDeletePausing(true);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
} else timeout = setTimeout(() => {
|
|
74
|
+
setDisplayedText((prev) => {
|
|
75
|
+
return splitText(prev).slice(0, -1).join("");
|
|
76
|
+
});
|
|
77
|
+
}, deletingSpeed);
|
|
78
|
+
} else {
|
|
78
79
|
const processedSegments = splitText(processedText);
|
|
79
80
|
if (currentCharIndex < processedSegments.length) timeout = setTimeout(() => {
|
|
80
81
|
setDisplayedText((prev) => prev + processedSegments[currentCharIndex]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypewriterEffect.mjs","names":[],"sources":["../../../src/awesome/TypewriterEffect/TypewriterEffect.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { createElement, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useMotionComponent } from '@/MotionProvider';\n\nimport { styles } from './style';\nimport type { TypewriterEffectProps } from './type';\n\nconst TypewriterEffect = memo<TypewriterEffectProps>(\n ({\n sentences,\n as: Component = 'div',\n typingSpeed = 100,\n initialDelay = 0,\n pauseDuration = 2000,\n deletingSpeed = 50,\n deletePauseDuration = 0,\n loop = true,\n className = '',\n color,\n showCursor = true,\n hideCursorWhileTyping = false,\n cursorCharacter,\n cursorClassName = '',\n cursorColor,\n cursorBlinkDuration = 0.8,\n cursorFade = true,\n cursorStyle = 'pipe',\n textColors = [],\n variableSpeed,\n onSentenceComplete,\n startOnVisible = false,\n reverseMode = false,\n segmentMode = 'grapheme',\n ...props\n }: TypewriterEffectProps) => {\n const Motion = useMotionComponent();\n const cxStyles = cx;\n const [displayedText, setDisplayedText] = useState('');\n const [currentCharIndex, setCurrentCharIndex] = useState(0);\n const [isDeleting, setIsDeleting] = useState(false);\n const [currentTextIndex, setCurrentTextIndex] = useState(0);\n const [isVisible, setIsVisible] = useState(!startOnVisible);\n const [isDeletePausing, setIsDeletePausing] = useState(false);\n const containerRef = useRef<HTMLElement>(null);\n\n const textArray = useMemo(\n () => (Array.isArray(sentences) ? sentences : [sentences]),\n [sentences],\n );\n\n // Helper function to split text based on segment mode\n const splitText = useCallback(\n (text: string): string[] => {\n // Use Intl.Segmenter if available\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\n const segmenter = new Intl.Segmenter(undefined, { granularity: segmentMode });\n return Array.from(segmenter.segment(text), (segment) => segment.segment);\n }\n\n // Fallback when Intl.Segmenter is not available\n if (segmentMode === 'word') {\n // Simple word splitting fallback\n return text.split(/(\\s+)/).filter(Boolean);\n }\n\n // Grapheme fallback\n return Array.from(text);\n },\n [segmentMode],\n );\n\n const getRandomSpeed = useCallback(() => {\n if (!variableSpeed) return typingSpeed;\n const { min, max } = variableSpeed;\n return Math.random() * (max - min) + min;\n }, [variableSpeed, typingSpeed]);\n\n const getCurrentTextColor = () => {\n if (textColors.length > 0) {\n return textColors[currentTextIndex % textColors.length];\n }\n return color;\n };\n\n const getCurrentCursorColor = () => {\n return cursorColor || color;\n };\n\n useEffect(() => {\n if (!startOnVisible || !containerRef.current) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n setIsVisible(true);\n }\n });\n },\n { threshold: 0.1 },\n );\n\n observer.observe(containerRef.current);\n\n return () => observer.disconnect();\n }, [startOnVisible]);\n\n useEffect(() => {\n if (!isVisible) return;\n\n let timeout: ReturnType<typeof setTimeout>;\n\n const currentText = textArray[currentTextIndex];\n // Split text based on segment mode\n const textSegments = splitText(currentText);\n const processedText = reverseMode ? textSegments.reverse().join('') : currentText;\n\n // Handle delete pause state\n if (isDeletePausing) {\n timeout = setTimeout(() => {\n setIsDeletePausing(false);\n }, deletePauseDuration);\n return () => clearTimeout(timeout);\n }\n\n const executeTypingAnimation = () => {\n if (isDeleting) {\n if (displayedText === '') {\n setIsDeleting(false);\n if (currentTextIndex === textArray.length - 1 && !loop) {\n return;\n }\n if (onSentenceComplete) {\n onSentenceComplete(textArray[currentTextIndex], currentTextIndex);\n }\n setCurrentTextIndex((prev) => (prev + 1) % textArray.length);\n setCurrentCharIndex(0);\n\n if (deletePauseDuration > 0) {\n setIsDeletePausing(true);\n return;\n }\n } else {\n timeout = setTimeout(() => {\n setDisplayedText((prev) => {\n const segments = splitText(prev);\n return segments.slice(0, -1).join('');\n });\n }, deletingSpeed);\n }\n } else {\n const processedSegments = splitText(processedText);\n if (currentCharIndex < processedSegments.length) {\n timeout = setTimeout(\n () => {\n setDisplayedText((prev) => prev + processedSegments[currentCharIndex]);\n setCurrentCharIndex((prev) => prev + 1);\n },\n variableSpeed ? getRandomSpeed() : typingSpeed,\n );\n } else if (textArray.length >= 1) {\n if (!loop && currentTextIndex === textArray.length - 1) return;\n\n timeout = setTimeout(() => {\n setIsDeleting(true);\n }, pauseDuration);\n }\n }\n };\n\n if (currentCharIndex === 0 && !isDeleting && displayedText === '') {\n timeout = setTimeout(executeTypingAnimation, initialDelay);\n } else {\n executeTypingAnimation();\n }\n\n return () => clearTimeout(timeout);\n }, [\n currentCharIndex,\n displayedText,\n isDeleting,\n isDeletePausing,\n typingSpeed,\n deletingSpeed,\n deletePauseDuration,\n pauseDuration,\n textArray,\n currentTextIndex,\n loop,\n initialDelay,\n isVisible,\n reverseMode,\n variableSpeed,\n onSentenceComplete,\n getRandomSpeed,\n splitText,\n ]);\n\n const getCursorStyle = () => {\n if (cursorCharacter) return styles.cursorCustom;\n\n switch (cursorStyle) {\n case 'block': {\n return styles.cursorBlock;\n }\n case 'dot': {\n return styles.cursorDot;\n }\n case 'underscore': {\n return styles.cursorUnderscore;\n }\n case 'pipe': {\n return styles.cursor;\n }\n }\n };\n\n const currentTextLength = splitText(textArray[currentTextIndex]).length;\n const isTyping = currentCharIndex < currentTextLength && !isDeleting;\n const isAfterTyping = currentCharIndex === currentTextLength && !isDeleting;\n\n const shouldHideCursor = (() => {\n if (hideCursorWhileTyping === true) return true; // 完全隐藏\n if (hideCursorWhileTyping === 'typing') return isTyping || isDeleting; // 打字和删除时隐藏\n if (hideCursorWhileTyping === 'afterTyping') return isAfterTyping; // 打字完成后隐藏\n return false;\n })();\n\n const textColor = getCurrentTextColor();\n const finalCursorColor = getCurrentCursorColor();\n\n // Split displayed text for animation\n const characters = splitText(displayedText);\n\n return createElement(\n Component,\n {\n className: cxStyles(styles.container, className),\n ref: containerRef,\n ...props,\n },\n <>\n <span className={styles.text} style={textColor ? { color: textColor } : undefined}>\n {characters.map((char, index) => (\n <Motion.span\n animate={{ opacity: 1 }}\n initial={{ opacity: 0 }}\n key={`${currentTextIndex}-${index}`}\n style={{ display: 'inline-block' }}\n transition={{\n duration: typingSpeed / 500,\n ease: 'easeInOut',\n }}\n >\n {char === ' ' ? '\\u00A0' : char}\n </Motion.span>\n ))}\n </span>\n {showCursor &&\n (cursorFade ? (\n <Motion.span\n animate={{ opacity: shouldHideCursor ? 0 : 1 }}\n className={cxStyles(getCursorStyle(), cursorClassName)}\n initial={{ opacity: 0 }}\n style={finalCursorColor ? { backgroundColor: finalCursorColor } : undefined}\n transition={{\n duration: shouldHideCursor ? 0.2 : cursorBlinkDuration,\n ease: 'easeInOut',\n repeat: shouldHideCursor ? 0 : Number.POSITIVE_INFINITY,\n repeatType: 'reverse',\n }}\n >\n {cursorCharacter}\n </Motion.span>\n ) : (\n <span\n className={cxStyles(getCursorStyle(), cursorClassName)}\n style={{\n backgroundColor: finalCursorColor,\n opacity: shouldHideCursor ? 0 : 1,\n }}\n >\n {cursorCharacter}\n </span>\n ))}\n </>,\n );\n },\n);\n\nTypewriterEffect.displayName = 'TypewriterEffect';\n\nexport default TypewriterEffect;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TypewriterEffect.mjs","names":[],"sources":["../../../src/awesome/TypewriterEffect/TypewriterEffect.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { createElement, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useMotionComponent } from '@/MotionProvider';\n\nimport { styles } from './style';\nimport type { TypewriterEffectProps } from './type';\n\nconst TypewriterEffect = memo<TypewriterEffectProps>(\n ({\n sentences,\n as: Component = 'div',\n typingSpeed = 100,\n initialDelay = 0,\n pauseDuration = 2000,\n deletingSpeed = 50,\n deletePauseDuration = 0,\n loop = true,\n className = '',\n color,\n showCursor = true,\n hideCursorWhileTyping = false,\n cursorCharacter,\n cursorClassName = '',\n cursorColor,\n cursorBlinkDuration = 0.8,\n cursorFade = true,\n cursorStyle = 'pipe',\n textColors = [],\n variableSpeed,\n onSentenceComplete,\n startOnVisible = false,\n reverseMode = false,\n segmentMode = 'grapheme',\n ...props\n }: TypewriterEffectProps) => {\n const Motion = useMotionComponent();\n const cxStyles = cx;\n const [displayedText, setDisplayedText] = useState('');\n const [currentCharIndex, setCurrentCharIndex] = useState(0);\n const [isDeleting, setIsDeleting] = useState(false);\n const [currentTextIndex, setCurrentTextIndex] = useState(0);\n const [isVisible, setIsVisible] = useState(!startOnVisible);\n const [isDeletePausing, setIsDeletePausing] = useState(false);\n const containerRef = useRef<HTMLElement>(null);\n\n const textArray = useMemo(\n () => (Array.isArray(sentences) ? sentences : [sentences]),\n [sentences],\n );\n\n // Helper function to split text based on segment mode\n const splitText = useCallback(\n (text: string): string[] => {\n // Use Intl.Segmenter if available\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\n const segmenter = new Intl.Segmenter(undefined, { granularity: segmentMode });\n return Array.from(segmenter.segment(text), (segment) => segment.segment);\n }\n\n // Fallback when Intl.Segmenter is not available\n if (segmentMode === 'word') {\n // Simple word splitting fallback\n return text.split(/(\\s+)/).filter(Boolean);\n }\n\n // Grapheme fallback\n return Array.from(text);\n },\n [segmentMode],\n );\n\n const getRandomSpeed = useCallback(() => {\n if (!variableSpeed) return typingSpeed;\n const { min, max } = variableSpeed;\n return Math.random() * (max - min) + min;\n }, [variableSpeed, typingSpeed]);\n\n const getCurrentTextColor = () => {\n if (textColors.length > 0) {\n return textColors[currentTextIndex % textColors.length];\n }\n return color;\n };\n\n const getCurrentCursorColor = () => {\n return cursorColor || color;\n };\n\n useEffect(() => {\n if (!startOnVisible || !containerRef.current) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n setIsVisible(true);\n }\n });\n },\n { threshold: 0.1 },\n );\n\n observer.observe(containerRef.current);\n\n return () => observer.disconnect();\n }, [startOnVisible]);\n\n useEffect(() => {\n if (!isVisible) return;\n\n let timeout: ReturnType<typeof setTimeout>;\n\n const currentText = textArray[currentTextIndex];\n // Split text based on segment mode\n const textSegments = splitText(currentText);\n const processedText = reverseMode ? textSegments.reverse().join('') : currentText;\n\n // Handle delete pause state\n if (isDeletePausing) {\n timeout = setTimeout(() => {\n setIsDeletePausing(false);\n }, deletePauseDuration);\n return () => clearTimeout(timeout);\n }\n\n const executeTypingAnimation = () => {\n if (isDeleting) {\n if (displayedText === '') {\n setIsDeleting(false);\n if (currentTextIndex === textArray.length - 1 && !loop) {\n return;\n }\n if (onSentenceComplete) {\n onSentenceComplete(textArray[currentTextIndex], currentTextIndex);\n }\n setCurrentTextIndex((prev) => (prev + 1) % textArray.length);\n setCurrentCharIndex(0);\n\n if (deletePauseDuration > 0) {\n setIsDeletePausing(true);\n return;\n }\n } else {\n timeout = setTimeout(() => {\n setDisplayedText((prev) => {\n const segments = splitText(prev);\n return segments.slice(0, -1).join('');\n });\n }, deletingSpeed);\n }\n } else {\n const processedSegments = splitText(processedText);\n if (currentCharIndex < processedSegments.length) {\n timeout = setTimeout(\n () => {\n setDisplayedText((prev) => prev + processedSegments[currentCharIndex]);\n setCurrentCharIndex((prev) => prev + 1);\n },\n variableSpeed ? getRandomSpeed() : typingSpeed,\n );\n } else if (textArray.length >= 1) {\n if (!loop && currentTextIndex === textArray.length - 1) return;\n\n timeout = setTimeout(() => {\n setIsDeleting(true);\n }, pauseDuration);\n }\n }\n };\n\n if (currentCharIndex === 0 && !isDeleting && displayedText === '') {\n timeout = setTimeout(executeTypingAnimation, initialDelay);\n } else {\n executeTypingAnimation();\n }\n\n return () => clearTimeout(timeout);\n }, [\n currentCharIndex,\n displayedText,\n isDeleting,\n isDeletePausing,\n typingSpeed,\n deletingSpeed,\n deletePauseDuration,\n pauseDuration,\n textArray,\n currentTextIndex,\n loop,\n initialDelay,\n isVisible,\n reverseMode,\n variableSpeed,\n onSentenceComplete,\n getRandomSpeed,\n splitText,\n ]);\n\n const getCursorStyle = () => {\n if (cursorCharacter) return styles.cursorCustom;\n\n switch (cursorStyle) {\n case 'block': {\n return styles.cursorBlock;\n }\n case 'dot': {\n return styles.cursorDot;\n }\n case 'underscore': {\n return styles.cursorUnderscore;\n }\n case 'pipe': {\n return styles.cursor;\n }\n }\n };\n\n const currentTextLength = splitText(textArray[currentTextIndex]).length;\n const isTyping = currentCharIndex < currentTextLength && !isDeleting;\n const isAfterTyping = currentCharIndex === currentTextLength && !isDeleting;\n\n const shouldHideCursor = (() => {\n if (hideCursorWhileTyping === true) return true; // 完全隐藏\n if (hideCursorWhileTyping === 'typing') return isTyping || isDeleting; // 打字和删除时隐藏\n if (hideCursorWhileTyping === 'afterTyping') return isAfterTyping; // 打字完成后隐藏\n return false;\n })();\n\n const textColor = getCurrentTextColor();\n const finalCursorColor = getCurrentCursorColor();\n\n // Split displayed text for animation\n const characters = splitText(displayedText);\n\n return createElement(\n Component,\n {\n className: cxStyles(styles.container, className),\n ref: containerRef,\n ...props,\n },\n <>\n <span className={styles.text} style={textColor ? { color: textColor } : undefined}>\n {characters.map((char, index) => (\n <Motion.span\n animate={{ opacity: 1 }}\n initial={{ opacity: 0 }}\n key={`${currentTextIndex}-${index}`}\n style={{ display: 'inline-block' }}\n transition={{\n duration: typingSpeed / 500,\n ease: 'easeInOut',\n }}\n >\n {char === ' ' ? '\\u00A0' : char}\n </Motion.span>\n ))}\n </span>\n {showCursor &&\n (cursorFade ? (\n <Motion.span\n animate={{ opacity: shouldHideCursor ? 0 : 1 }}\n className={cxStyles(getCursorStyle(), cursorClassName)}\n initial={{ opacity: 0 }}\n style={finalCursorColor ? { backgroundColor: finalCursorColor } : undefined}\n transition={{\n duration: shouldHideCursor ? 0.2 : cursorBlinkDuration,\n ease: 'easeInOut',\n repeat: shouldHideCursor ? 0 : Number.POSITIVE_INFINITY,\n repeatType: 'reverse',\n }}\n >\n {cursorCharacter}\n </Motion.span>\n ) : (\n <span\n className={cxStyles(getCursorStyle(), cursorClassName)}\n style={{\n backgroundColor: finalCursorColor,\n opacity: shouldHideCursor ? 0 : 1,\n }}\n >\n {cursorCharacter}\n </span>\n ))}\n </>,\n );\n },\n);\n\nTypewriterEffect.displayName = 'TypewriterEffect';\n\nexport default TypewriterEffect;\n"],"mappings":"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"}
|
|
@@ -31,24 +31,26 @@ function useSnapPoints({ closeThreshold, snapPoints, containerHeight, minHeightP
|
|
|
31
31
|
const nextHigherSnapPoint = snapPointHeights[Math.min(activeIndex + 1, snapPointHeights.length - 1)] ?? highestSnapPoint;
|
|
32
32
|
const nextLowerSnapPoint = snapPointHeights[Math.max(activeIndex - 1, 0)] ?? lowestSnapPoint;
|
|
33
33
|
const sheetHeight = snapPointHeights[activeIndex] ?? currentHeight;
|
|
34
|
-
if (velocity > VELOCITY_THRESHOLD && Math.abs(draggedDistance) < sheetHeight * DRAG_DISTANCE_RATIO)
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
type: "
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
if (velocity > VELOCITY_THRESHOLD && Math.abs(draggedDistance) < sheetHeight * DRAG_DISTANCE_RATIO) {
|
|
35
|
+
if (isDraggingUp) {
|
|
36
|
+
if (isLast) return {
|
|
37
|
+
type: "snap",
|
|
38
|
+
height: highestSnapPoint
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
type: "snap",
|
|
42
|
+
height: nextHigherSnapPoint
|
|
43
|
+
};
|
|
44
|
+
} else {
|
|
45
|
+
if (isFirst) return dismissible ? { type: "dismiss" } : {
|
|
46
|
+
type: "snap",
|
|
47
|
+
height: lowestSnapPoint
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
type: "snap",
|
|
51
|
+
height: nextLowerSnapPoint
|
|
52
|
+
};
|
|
53
|
+
}
|
|
52
54
|
}
|
|
53
55
|
if (dismissible && isFirst && !isDraggingUp && currentHeight < lowestSnapPoint * closeThreshold) return { type: "dismiss" };
|
|
54
56
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSnapPoints.mjs","names":[],"sources":["../../../src/base-ui/FloatingSheet/useSnapPoints.ts"],"sourcesContent":["import { type RefObject, useMemo } from 'react';\n\nimport { clamp, resolveSize } from './helpers';\n\nconst VELOCITY_THRESHOLD = 0.4;\nconst DRAG_DISTANCE_RATIO = 0.4;\n\ninterface UseSnapPointsOptions {\n closeThreshold: number;\n containerHeight: number;\n containerRef: RefObject<HTMLElement | null>;\n maxHeightPx: number;\n minHeightPx: number;\n snapPoints: number[];\n}\n\ninterface SnapReleaseParams {\n activeIndex: number;\n currentHeight: number;\n dismissible: boolean;\n draggedDistance: number; // positive = upward (growing), negative = downward (shrinking)\n velocity: number;\n}\n\ntype SnapReleaseResult = { type: 'snap'; height: number } | { type: 'dismiss' };\n\nexport function useSnapPoints({\n closeThreshold,\n snapPoints,\n containerHeight,\n minHeightPx,\n maxHeightPx,\n}: UseSnapPointsOptions) {\n const snapPointHeights = useMemo(() => {\n if (!containerHeight) return [];\n\n const resolved = snapPoints\n .map((sp) => clamp(resolveSize(sp, containerHeight), minHeightPx, maxHeightPx))\n .sort((a, b) => a - b);\n\n // Remove duplicates\n return [...new Set(resolved)];\n }, [snapPoints, containerHeight, minHeightPx, maxHeightPx]);\n\n function findClosestSnapPoint(height: number): number {\n if (snapPointHeights.length === 0) return clamp(height, minHeightPx, maxHeightPx);\n\n return snapPointHeights.reduce((prev, curr) =>\n Math.abs(curr - height) < Math.abs(prev - height) ? curr : prev,\n );\n }\n\n function findActiveIndex(height: number): number {\n const closest = findClosestSnapPoint(height);\n return snapPointHeights.indexOf(closest);\n }\n\n function getSnapRelease({\n currentHeight,\n activeIndex,\n draggedDistance,\n velocity,\n dismissible,\n }: SnapReleaseParams): SnapReleaseResult {\n const isFirst = activeIndex === 0;\n const isLast = activeIndex === snapPointHeights.length - 1;\n const isDraggingUp = draggedDistance > 0;\n const highestSnapPoint = snapPointHeights.at(-1) ?? maxHeightPx;\n const lowestSnapPoint = snapPointHeights[0] ?? minHeightPx;\n const nextHigherSnapPoint =\n snapPointHeights[Math.min(activeIndex + 1, snapPointHeights.length - 1)] ?? highestSnapPoint;\n const nextLowerSnapPoint = snapPointHeights[Math.max(activeIndex - 1, 0)] ?? lowestSnapPoint;\n const sheetHeight = snapPointHeights[activeIndex] ?? currentHeight;\n\n // High velocity handling\n if (\n velocity > VELOCITY_THRESHOLD &&\n Math.abs(draggedDistance) < sheetHeight * DRAG_DISTANCE_RATIO\n ) {\n if (isDraggingUp) {\n // Fling upward: go to next higher snap, cap at highest\n if (isLast) return { type: 'snap', height: highestSnapPoint };\n\n return { type: 'snap', height: nextHigherSnapPoint };\n } else {\n // Fling downward: go to next lower snap, or dismiss if at lowest\n if (isFirst) {\n return dismissible ? { type: 'dismiss' } : { type: 'snap', height: lowestSnapPoint };\n }\n\n return { type: 'snap', height: nextLowerSnapPoint };\n }\n }\n\n if (\n dismissible &&\n isFirst &&\n !isDraggingUp &&\n currentHeight < lowestSnapPoint * closeThreshold\n ) {\n return { type: 'dismiss' };\n }\n\n // Low velocity: snap to closest\n const closest = findClosestSnapPoint(currentHeight);\n return { type: 'snap', height: closest };\n }\n\n return {\n snapPointHeights,\n findClosestSnapPoint,\n findActiveIndex,\n getSnapRelease,\n };\n}\n"],"mappings":";;;AAIA,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAqB5B,SAAgB,cAAc,EAC5B,gBACA,YACA,iBACA,aACA,eACuB;CACvB,MAAM,mBAAmB,cAAc;EACrC,IAAI,CAAC,iBAAiB,OAAO,CAAC;EAE9B,MAAM,WAAW,WACd,KAAK,OAAO,MAAM,YAAY,IAAI,eAAe,GAAG,aAAa,WAAW,CAAC,CAAC,CAC9E,MAAM,GAAG,MAAM,IAAI,CAAC;EAGvB,OAAO,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;CAC9B,GAAG;EAAC;EAAY;EAAiB;EAAa;CAAW,CAAC;CAE1D,SAAS,qBAAqB,QAAwB;EACpD,IAAI,iBAAiB,WAAW,GAAG,OAAO,MAAM,QAAQ,aAAa,WAAW;EAEhF,OAAO,iBAAiB,QAAQ,MAAM,SACpC,KAAK,IAAI,OAAO,MAAM,IAAI,KAAK,IAAI,OAAO,MAAM,IAAI,OAAO,IAC7D;CACF;CAEA,SAAS,gBAAgB,QAAwB;EAC/C,MAAM,UAAU,qBAAqB,MAAM;EAC3C,OAAO,iBAAiB,QAAQ,OAAO;CACzC;CAEA,SAAS,eAAe,EACtB,eACA,aACA,iBACA,UACA,eACuC;EACvC,MAAM,UAAU,gBAAgB;EAChC,MAAM,SAAS,gBAAgB,iBAAiB,SAAS;EACzD,MAAM,eAAe,kBAAkB;EACvC,MAAM,mBAAmB,iBAAiB,GAAG,EAAE,KAAK;EACpD,MAAM,kBAAkB,iBAAiB,MAAM;EAC/C,MAAM,sBACJ,iBAAiB,KAAK,IAAI,cAAc,GAAG,iBAAiB,SAAS,CAAC,MAAM;EAC9E,MAAM,qBAAqB,iBAAiB,KAAK,IAAI,cAAc,GAAG,CAAC,MAAM;EAC7E,MAAM,cAAc,iBAAiB,gBAAgB;EAGrD,IACE,WAAW,sBACX,KAAK,IAAI,eAAe,IAAI,cAAc,
|
|
1
|
+
{"version":3,"file":"useSnapPoints.mjs","names":[],"sources":["../../../src/base-ui/FloatingSheet/useSnapPoints.ts"],"sourcesContent":["import { type RefObject, useMemo } from 'react';\n\nimport { clamp, resolveSize } from './helpers';\n\nconst VELOCITY_THRESHOLD = 0.4;\nconst DRAG_DISTANCE_RATIO = 0.4;\n\ninterface UseSnapPointsOptions {\n closeThreshold: number;\n containerHeight: number;\n containerRef: RefObject<HTMLElement | null>;\n maxHeightPx: number;\n minHeightPx: number;\n snapPoints: number[];\n}\n\ninterface SnapReleaseParams {\n activeIndex: number;\n currentHeight: number;\n dismissible: boolean;\n draggedDistance: number; // positive = upward (growing), negative = downward (shrinking)\n velocity: number;\n}\n\ntype SnapReleaseResult = { type: 'snap'; height: number } | { type: 'dismiss' };\n\nexport function useSnapPoints({\n closeThreshold,\n snapPoints,\n containerHeight,\n minHeightPx,\n maxHeightPx,\n}: UseSnapPointsOptions) {\n const snapPointHeights = useMemo(() => {\n if (!containerHeight) return [];\n\n const resolved = snapPoints\n .map((sp) => clamp(resolveSize(sp, containerHeight), minHeightPx, maxHeightPx))\n .sort((a, b) => a - b);\n\n // Remove duplicates\n return [...new Set(resolved)];\n }, [snapPoints, containerHeight, minHeightPx, maxHeightPx]);\n\n function findClosestSnapPoint(height: number): number {\n if (snapPointHeights.length === 0) return clamp(height, minHeightPx, maxHeightPx);\n\n return snapPointHeights.reduce((prev, curr) =>\n Math.abs(curr - height) < Math.abs(prev - height) ? curr : prev,\n );\n }\n\n function findActiveIndex(height: number): number {\n const closest = findClosestSnapPoint(height);\n return snapPointHeights.indexOf(closest);\n }\n\n function getSnapRelease({\n currentHeight,\n activeIndex,\n draggedDistance,\n velocity,\n dismissible,\n }: SnapReleaseParams): SnapReleaseResult {\n const isFirst = activeIndex === 0;\n const isLast = activeIndex === snapPointHeights.length - 1;\n const isDraggingUp = draggedDistance > 0;\n const highestSnapPoint = snapPointHeights.at(-1) ?? maxHeightPx;\n const lowestSnapPoint = snapPointHeights[0] ?? minHeightPx;\n const nextHigherSnapPoint =\n snapPointHeights[Math.min(activeIndex + 1, snapPointHeights.length - 1)] ?? highestSnapPoint;\n const nextLowerSnapPoint = snapPointHeights[Math.max(activeIndex - 1, 0)] ?? lowestSnapPoint;\n const sheetHeight = snapPointHeights[activeIndex] ?? currentHeight;\n\n // High velocity handling\n if (\n velocity > VELOCITY_THRESHOLD &&\n Math.abs(draggedDistance) < sheetHeight * DRAG_DISTANCE_RATIO\n ) {\n if (isDraggingUp) {\n // Fling upward: go to next higher snap, cap at highest\n if (isLast) return { type: 'snap', height: highestSnapPoint };\n\n return { type: 'snap', height: nextHigherSnapPoint };\n } else {\n // Fling downward: go to next lower snap, or dismiss if at lowest\n if (isFirst) {\n return dismissible ? { type: 'dismiss' } : { type: 'snap', height: lowestSnapPoint };\n }\n\n return { type: 'snap', height: nextLowerSnapPoint };\n }\n }\n\n if (\n dismissible &&\n isFirst &&\n !isDraggingUp &&\n currentHeight < lowestSnapPoint * closeThreshold\n ) {\n return { type: 'dismiss' };\n }\n\n // Low velocity: snap to closest\n const closest = findClosestSnapPoint(currentHeight);\n return { type: 'snap', height: closest };\n }\n\n return {\n snapPointHeights,\n findClosestSnapPoint,\n findActiveIndex,\n getSnapRelease,\n };\n}\n"],"mappings":";;;AAIA,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAqB5B,SAAgB,cAAc,EAC5B,gBACA,YACA,iBACA,aACA,eACuB;CACvB,MAAM,mBAAmB,cAAc;EACrC,IAAI,CAAC,iBAAiB,OAAO,CAAC;EAE9B,MAAM,WAAW,WACd,KAAK,OAAO,MAAM,YAAY,IAAI,eAAe,GAAG,aAAa,WAAW,CAAC,CAAC,CAC9E,MAAM,GAAG,MAAM,IAAI,CAAC;EAGvB,OAAO,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;CAC9B,GAAG;EAAC;EAAY;EAAiB;EAAa;CAAW,CAAC;CAE1D,SAAS,qBAAqB,QAAwB;EACpD,IAAI,iBAAiB,WAAW,GAAG,OAAO,MAAM,QAAQ,aAAa,WAAW;EAEhF,OAAO,iBAAiB,QAAQ,MAAM,SACpC,KAAK,IAAI,OAAO,MAAM,IAAI,KAAK,IAAI,OAAO,MAAM,IAAI,OAAO,IAC7D;CACF;CAEA,SAAS,gBAAgB,QAAwB;EAC/C,MAAM,UAAU,qBAAqB,MAAM;EAC3C,OAAO,iBAAiB,QAAQ,OAAO;CACzC;CAEA,SAAS,eAAe,EACtB,eACA,aACA,iBACA,UACA,eACuC;EACvC,MAAM,UAAU,gBAAgB;EAChC,MAAM,SAAS,gBAAgB,iBAAiB,SAAS;EACzD,MAAM,eAAe,kBAAkB;EACvC,MAAM,mBAAmB,iBAAiB,GAAG,EAAE,KAAK;EACpD,MAAM,kBAAkB,iBAAiB,MAAM;EAC/C,MAAM,sBACJ,iBAAiB,KAAK,IAAI,cAAc,GAAG,iBAAiB,SAAS,CAAC,MAAM;EAC9E,MAAM,qBAAqB,iBAAiB,KAAK,IAAI,cAAc,GAAG,CAAC,MAAM;EAC7E,MAAM,cAAc,iBAAiB,gBAAgB;EAGrD,IACE,WAAW,sBACX,KAAK,IAAI,eAAe,IAAI,cAAc,qBAC1C;GACA,IAAI,cAAc;IAEhB,IAAI,QAAQ,OAAO;KAAE,MAAM;KAAQ,QAAQ;IAAiB;IAE5D,OAAO;KAAE,MAAM;KAAQ,QAAQ;IAAoB;GACrD,OAAO;IAEL,IAAI,SACF,OAAO,cAAc,EAAE,MAAM,UAAU,IAAI;KAAE,MAAM;KAAQ,QAAQ;IAAgB;IAGrF,OAAO;KAAE,MAAM;KAAQ,QAAQ;IAAmB;GACpD;EACF;EAEA,IACE,eACA,WACA,CAAC,gBACD,gBAAgB,kBAAkB,gBAElC,OAAO,EAAE,MAAM,UAAU;EAK3B,OAAO;GAAE,MAAM;GAAQ,QADP,qBAAqB,aACA;EAAE;CACzC;CAEA,OAAO;EACL;EACA;EACA;EACA;CACF;AACF"}
|