deepsea-components 2.3.2 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.tsx CHANGED
@@ -501,111 +501,96 @@ export const Trapezium = forwardRef<HTMLDivElement, TrapeziumProps>((props, ref)
501
501
  return <div ref={ref} style={{ width: bottom, height, clipPath: `path("M ${diff + f} ${0} A ${borderRadius} ${borderRadius} 0 0 0 ${diff - g} ${h} L ${c} ${height - d} A ${borderRadius} ${borderRadius} 0 0 0 ${b} ${height} L ${bottom - b} ${height} A ${borderRadius} ${borderRadius} 0 0 0 ${bottom - c} ${height - d} L ${top + diff + g} ${h} A ${borderRadius} ${borderRadius} 0 0 0 ${top + diff - f} ${0} Z")`, ...style }} {...other} />
502
502
  })
503
503
 
504
- export interface LoopSwiperProps<T> {
505
- /** 源数据 */
506
- data: T[]
507
- /** 渲染函数 */
508
- render: (item: T, index: number, array: T[]) => ReactNode
509
- /** 每个元素的key */
510
- keyExactor?: (item: T, index: number, array: T[]) => string
511
- /** 水平方向是宽度,垂直方向是高度 */
512
- size: number
513
- /** 元素之间间隔 */
514
- gap?: number
515
- /** 起始位置 */
516
- start?: number
517
- /** 速度,水平方向正数为向左,水平方向负数为向右,垂直方向正数为向上,水平方向负数为向下 */
518
- speed: number
519
- /** 是否暂停播放 */
520
- paused?: boolean
521
- /** 容器的类名 */
522
- className?: string
523
- /** x 水平方向,y 垂直方向 */
524
- direction?: "x" | "y"
525
- }
526
-
527
- export interface LoopSwiperItem {
528
- key: string
529
- dom: HTMLDivElement | null
530
- offset: number
504
+ export interface LoopSwiperProps extends HTMLAttributes<HTMLDivElement> {
505
+ direction?: "horizontal" | "vertical"
506
+ reverse?: boolean
507
+ period: number
508
+ gap?: CSSProperties["gap"]
531
509
  }
532
510
 
533
- /** 循环播放组件 */
534
- export function LoopSwiper<T>(props: LoopSwiperProps<T>) {
535
- const { data, render, keyExactor, size, gap = 0, start = 0, speed, paused = false, className = "", direction = "x" } = props
536
- if (!(size > 0 && (speed > 0 || speed < 0))) {
537
- throw new RangeError("size 必须是正数,speed 必须非0")
511
+ css`
512
+ @keyframes deepsea-horizontal-loop-swipe {
513
+ from {
514
+ transform: translateX(0);
515
+ }
516
+ to {
517
+ transform: translateX(-100%);
518
+ }
519
+ }
520
+ @keyframes deepsea-reverse-horizontal-loop-swipe {
521
+ from {
522
+ transform: translateX(0);
523
+ }
524
+ to {
525
+ transform: translateX(100%);
526
+ }
538
527
  }
539
- const keys = data.map((it, idx, arr) => (keyExactor ? keyExactor(it, idx, arr) : String(idx)))
540
- const keysRef = useRef(keys)
541
- const cache = useRef({ size, gap, speed, keys, paused, className, direction })
542
- cache.current = { size, gap, speed, keys, paused, className, direction }
543
- const eles = useRef<LoopSwiperItem[]>(keys.map((key, idx) => ({ key, dom: null, offset: idx * (size + gap) + start })))
544
-
545
- if (keysRef.current.length !== keys.length || keysRef.current.some((it, idx) => it !== keys[idx])) {
546
- keysRef.current = keys
547
- eles.current = keys.map((key, idx) => ({ key, dom: null, offset: idx * (size + gap) + start }))
528
+ @keyframes deepsea-vertical-loop-swipe {
529
+ from {
530
+ transform: translateY(0);
531
+ }
532
+ to {
533
+ transform: translateY(-100%);
534
+ }
548
535
  }
549
-
550
- function setStyles() {
551
- const { size, speed, className, direction } = cache.current
552
- eles.current.forEach(it => {
553
- it.dom!.className = className
554
- it.dom!.style.setProperty("position", `absolute`)
555
- it.dom!.style.setProperty("width", `${size}px`)
556
- direction === "x" && speed < 0 ? it.dom!.style.setProperty("right", `0`) : it.dom!.style.setProperty("left", `0`)
557
- direction === "y" && speed < 0 ? it.dom!.style.setProperty("bottom", `0`) : it.dom!.style.setProperty("top", `0`)
558
- it.dom!.style.setProperty("transform", `translate${direction.toUpperCase()}(${it.offset * (speed > 0 ? 1 : -1)}px)`)
559
- })
536
+ @keyframes deepsea-reverse-vertical-loop-swipe {
537
+ from {
538
+ transform: translateY(0);
539
+ }
540
+ to {
541
+ transform: translateY(100%);
542
+ }
560
543
  }
544
+ `
561
545
 
562
- useEffect(() => {
563
- setStyles()
564
- }, [])
546
+ /** 循环播放组件 */
547
+ export const LoopSwiper = forwardRef<HTMLDivElement, LoopSwiperProps>((props, ref) => {
548
+ const { style, children, direction, period, reverse, gap, ...others } = props
549
+ const wrapper = useRef<HTMLDivElement>(null)
550
+ const container = useRef<HTMLDivElement>(null)
551
+ const [swiper, setSwiper] = useState(false)
552
+ const directionRef = useRef(direction)
553
+ directionRef.current = direction
554
+ const flexDirection: CSSProperties["flexDirection"] = direction === "vertical" ? (reverse ? "column-reverse" : "column") : reverse ? "row-reverse" : "row"
555
+ const animationName = swiper ? (direction === "vertical" ? (reverse ? "deepsea-reverse-vertical-loop-swipe" : "deepsea-vertical-loop-swipe") : reverse ? "deepsea-reverse-horizontal-loop-swipe" : "deepsea-horizontal-loop-swipe") : "none"
556
+ const animationDuration = `${period}ms`
557
+ const animationTimingFunction = "linear"
558
+ const animationIterationCount = "infinite"
559
+
560
+ useImperativeHandle(ref, () => wrapper.current!)
565
561
 
566
562
  useEffect(() => {
567
- const stop = setFrameInterval(() => {
568
- const { size, gap, speed, keys, paused } = cache.current
569
- if (paused) return
570
- eles.current.length = keys.length
571
- let minIndex = 0
572
- eles.current.forEach((it, idx) => {
573
- if (it.offset < eles.current[minIndex].offset) {
574
- minIndex = idx
575
- }
576
- })
577
- const minOffset = eles.current[minIndex].offset
578
- eles.current.forEach((it, idx) => {
579
- let index = idx
580
- if (idx < minIndex) index = eles.current.length + idx
581
- it.offset = minOffset + (index - minIndex) * (size + gap)
582
- let newOffset = it.offset - Math.abs(speed)
583
- if (newOffset + size + gap <= 0) {
584
- newOffset += eles.current.length * (size + gap)
563
+ const wrapperEle = wrapper.current!
564
+ const containerEle = container.current!
565
+ let wrapperWidth = 0
566
+ let wrapperHeight = 0
567
+ let containerWidth = 0
568
+ let containerHeight = 0
569
+ const observer = new ResizeObserver(entries => {
570
+ entries.forEach(entry => {
571
+ if (entry.target === wrapperEle) {
572
+ wrapperWidth = entry.contentRect.width
573
+ wrapperHeight = entry.contentRect.height
574
+ } else if (entry.target === containerEle) {
575
+ containerWidth = entry.contentRect.width
576
+ containerHeight = entry.contentRect.height
585
577
  }
586
- it.offset = newOffset
587
578
  })
588
- setStyles()
589
- }, 1)
590
-
591
- return stop
579
+ setSwiper(directionRef.current === "vertical" ? containerHeight > wrapperHeight : containerWidth > wrapperWidth)
580
+ })
581
+ observer.observe(wrapperEle)
582
+ observer.observe(containerEle)
592
583
  }, [])
593
584
 
594
- function ref(dom: HTMLDivElement | null, index: number) {
595
- if (!eles.current[index]) return
596
- eles.current[index].dom = dom
597
- }
598
-
599
585
  return (
600
- <Fragment>
601
- {data.map((it, idx, arr) => (
602
- <div key={keys[idx]} ref={dom => ref(dom, idx)}>
603
- {render(it, idx, arr)}
604
- </div>
605
- ))}
606
- </Fragment>
586
+ <div ref={wrapper} style={{ display: "flex", flexDirection, gap, ...style }} {...others}>
587
+ <div ref={container} style={{ display: "flex", flexDirection, gap, animationName, animationTimingFunction, animationDuration, animationIterationCount }}>
588
+ {children}
589
+ </div>
590
+ <div style={{ display: swiper ? "flex" : "none", flexDirection, gap, animationName, animationTimingFunction, animationDuration, animationIterationCount }}>{children}</div>
591
+ </div>
607
592
  )
608
- }
593
+ })
609
594
 
610
595
  export interface SectionRingProps extends HTMLAttributes<HTMLDivElement> {
611
596
  outerRadius: number
@@ -814,12 +799,8 @@ export const AutoSizeTextArea = forwardRef<HTMLTextAreaElement, TextareaHTMLAttr
814
799
  textarea.style.height = `${textarea.scrollHeight + textarea.offsetHeight - textarea.clientHeight}px`
815
800
  }
816
801
  textarea.addEventListener("input", resizeTextarea)
817
- textarea.addEventListener("change", resizeTextarea)
818
802
 
819
- return () => {
820
- textarea.removeEventListener("input", resizeTextarea)
821
- textarea.removeEventListener("change", resizeTextarea)
822
- }
803
+ return () => textarea.removeEventListener("input", resizeTextarea)
823
804
  }, [])
824
805
 
825
806
  return <textarea ref={ele} style={{ ...otherStyle, resize: "none", overflowY: "hidden" }} {...others} />