packages/storybook/stories/react-use-popup.stories.tsx (107 lines of code) (raw):

import { DebugFlags, RenderText, SyntheticPointerEvent } from '@canvas-ui/core' import { Canvas, Flex, ScrollView, StyleProps, Text, usePopup } from '@canvas-ui/react' import type { StoryObj } from '@storybook/react' import { assert } from '@canvas-ui/assert' import React, { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react' const textStyle: StyleProps = { marginBottom: 12, cursor: 'text', } export const UsePopupTest: StoryObj<React.FC> = () => { useEffect(() => { DebugFlags.set( 0 | DebugFlags.NodeBounds | DebugFlags.LayerBounds | DebugFlags.RasterCacheWaterMark | DebugFlags.TextLineBounds ) }, []) const [editor, setEditor] = useState<ReactNode | null>(null) const editorRef = useRef<HTMLTextAreaElement | null>(null) const [value, setValue] = useState('3. 那只敏捷的棕毛狐狸跃过了那只狗\nThe quick brown fox jumps over the lazy dog') const { handlePointerDown: handlePointerDown1, open } = usePopup<RenderText, CSSProperties>({ hideTriggerOnOpen: false, onOpen(state) { const { bounds, target, payload } = state assert(target) const { computedStyle } = target.paragraph const style: CSSProperties = { position: 'absolute', left: bounds.left, top: bounds.top, width: bounds.width, height: bounds.height, background: 'transparent', border: payload?.border ?? 'none', // 可以获取 payload margin: 0, padding: 0, outline: 'none', font: computedStyle.font, color: computedStyle.color, lineHeight: `${computedStyle.lineHeight}px`, // 不加 px 会被识别成按字体大小比例行高 textRendering: 'geometricPrecision', textDecoration: 'none', } const handleBlur = () => { state.close() } setEditor( <textarea ref={editorRef} autoFocus={true} onBlur={handleBlur} style={style} defaultValue={value} /> ) }, onUpdate(state) { this.onOpen?.(state) }, onClose() { assert(editorRef.current) setValue(editorRef.current.value) setEditor(null) }, }) const handlePointerDown2 = (event: SyntheticPointerEvent<RenderText>) => { assert(event.target) // 可以传递 payload open(event.target) } return ( <div style={{ height: '100%' }}> <div style={{ padding: 24, height: '100%' }}> <Canvas> <ScrollView style={{ width: 300, height: 80 }}> <Flex style={{ width: 400, flexDirection: 'column' }}> <Text onPointerDown={handlePointerDown1} style={textStyle}>{value}</Text> <Text onPointerDown={handlePointerDown2} style={textStyle}>{value}</Text> </Flex> </ScrollView> </Canvas> </div> {editor} </div> ) } UsePopupTest.storyName = 'usePopup' export default { title: 'react', component: UsePopupTest, decorators: [(Story: React.ComponentType) => <div style={{ backgroundColor: '#efefef', width: '100%', height: '100vh' }}><Story /></div>], }