packages/storybook/stories/react-chunk.stories.tsx (169 lines of code) (raw):
/* eslint-disable @typescript-eslint/no-unused-vars */
import { DebugFlags, Size, StyleProps, SyntheticPointerEvent } from '@canvas-ui/core'
import { Canvas, Chunk, Flex, ScrollView, Text } from '@canvas-ui/react'
import type { StoryObj } from '@storybook/react'
import React, { FC, useEffect, useState } from 'react'
const rowSize = Size.fromWH(200, 24)
type RowSchema = {
id: number
content: string
}
type RowProps = {
row: RowSchema
top: number
onInsertAfter?: (row: RowSchema) => void
onRemove?: (row: RowSchema) => void
}
const Row: FC<RowProps> = ({
row,
top,
onInsertAfter,
onRemove,
}) => {
const style: StyleProps = {
top,
width: rowSize.width,
height: rowSize.height,
}
const handlePointerUp = (event: SyntheticPointerEvent<Flex>) => {
if (event.target?.id === 'insertAfter') {
onInsertAfter?.(row)
} else if (event.target?.id === 'remove') {
onRemove?.(row)
}
}
return (
<Flex id={row.id} style={style} onPointerUp={handlePointerUp}>
<Text id="insertAfter" style={{ cursor: 'pointer' }}>[+]</Text>
<Text id="CHUNK_DEBUG_ID" style={{ marginLeft: 8, marginRight: 8, flexGrow: 1 }}>{row.content}</Text>
<Text id="remove" style={{ cursor: 'pointer' }}>[-]</Text>
</Flex>
)
}
export const ChunkTest: StoryObj<React.FC> = () => {
useEffect(() => {
DebugFlags.set(
DebugFlags.NodeBounds
| DebugFlags.LayerBounds
| DebugFlags.RasterCacheWaterMark
)
return () => {
DebugFlags.set(0)
}
}, [])
const [createRow] = useState(() => {
let nextRowId = 0
return (label = ''): RowSchema => {
const id = nextRowId++
return {
id,
content: `${label}:${id}`,
}
}
})
const [rows, setRows] = useState<RowSchema[]>(() => {
const INITIAL_COUNT = 10
return Array.from(new Array(INITIAL_COUNT).keys(), () => {
return createRow('initial')
})
})
const [actions] = useState(() => {
return {
append() {
setRows(prev => {
const row = createRow('append')
return [...prev, row]
})
},
prepend() {
setRows(prev => {
const row = createRow('prepend')
return [row, ...prev]
})
},
insertBefore() {
setRows(prev => {
const row = createRow('insertBefore')
const next = prev.slice()
const pos = 3
next.splice(pos, 0, row)
return next
})
},
removeFirst() {
setRows(prev => {
const next = prev.slice()
next.shift()
return next
})
},
removeLast() {
setRows(prev => {
const next = prev.slice()
next.pop()
return next
})
},
removeAt() {
setRows(prev => {
const pos = 4
const next = prev.slice()
next.splice(pos, 1)
return next
})
},
insertAfter(row: RowSchema) {
setRows(prev => {
const pos = prev.findIndex(it => it === row)
if (pos !== -1) {
const newRow = createRow(`insertAfter(${row.id})`)
const next = prev.slice()
next.splice(pos + 1, 0, newRow)
return next
}
return prev
})
},
remove(row: RowSchema) {
setRows(prev => {
const pos = prev.findIndex(it => it === row)
if (pos !== -1) {
const next = prev.slice()
next.splice(pos, 1)
return next
}
return prev
})
}
}
})
const nodes = rows.map((it, index) => {
return (
<Row key={it.id} row={it} top={index * rowSize.height} onInsertAfter={actions.insertAfter} onRemove={actions.remove} />
)
})
return (
<div style={{ height: '100%' }}>
<div style={{ marginBottom: 8 }}>
<button onClick={actions.append}>append</button>
<button onClick={actions.prepend}>prepend</button>
<button onClick={actions.insertBefore}>insertBefore(4)</button>
<br />
<button onClick={actions.removeFirst}>removeFirst</button>
<button onClick={actions.removeLast}>removeLast</button>
<button onClick={actions.removeAt}>removeAt(4)</button>
</div>
<Canvas>
<ScrollView style={{ width: rowSize.width, height: 250 }}>
<Chunk style={{ height: rows.length * rowSize.height, width: rowSize.width }}>
{nodes}
</Chunk>
</ScrollView>
</Canvas>
</div>
)
}
ChunkTest.storyName = 'Chunk'
export default {
title: 'react',
component: ChunkTest,
decorators: [(Story: React.ComponentType) => <div style={{ backgroundColor: '#efefef', width: '100%', height: '100vh' }}><Story /></div>],
}