@xwadex/fesd-next 0.1.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.
Files changed (40) hide show
  1. package/README.md +35 -0
  2. package/package.json +45 -0
  3. package/src/fesd/components/Anchors/Anchor.Controller.tsx +101 -0
  4. package/src/fesd/components/Anchors/Anchor.Offseter.tsx +36 -0
  5. package/src/fesd/components/Anchors/Anchor.Target.tsx +97 -0
  6. package/src/fesd/components/Anchors/Anchor.Wrapper.tsx +160 -0
  7. package/src/fesd/components/Anchors/Anchors.tsx +12 -0
  8. package/src/fesd/components/Anchors/index.ts +2 -0
  9. package/src/fesd/components/Articles/Article.Basic.tsx +49 -0
  10. package/src/fesd/components/Articles/Article.Figure.tsx +113 -0
  11. package/src/fesd/components/Articles/ArticleBasic.module.scss +62 -0
  12. package/src/fesd/components/Articles/ArticleFigure.module.scss +82 -0
  13. package/src/fesd/components/Articles/index.ts +2 -0
  14. package/src/fesd/components/Collapse/Collapse.Body.tsx +27 -0
  15. package/src/fesd/components/Collapse/Collapse.Container.tsx +56 -0
  16. package/src/fesd/components/Collapse/Collapse.Head.tsx +39 -0
  17. package/src/fesd/components/Collapse/Collapse.Wrapper.tsx +46 -0
  18. package/src/fesd/components/Collapse/Collapse.module.scss +23 -0
  19. package/src/fesd/components/Collapse/Collapse.tsx +11 -0
  20. package/src/fesd/components/Collapse/CollapseContext.tsx +21 -0
  21. package/src/fesd/components/Collapse/index.ts +1 -0
  22. package/src/fesd/components/Modals/Modals.module.scss +84 -0
  23. package/src/fesd/components/Modals/Modals.tsx +103 -0
  24. package/src/fesd/components/Modals/Modals.types.ts +52 -0
  25. package/src/fesd/components/Modals/index.ts +2 -0
  26. package/src/fesd/components/Overlay/Overlay.module.scss +14 -0
  27. package/src/fesd/components/Overlay/Overlay.tsx +50 -0
  28. package/src/fesd/components/Overlay/Overlay.types.ts +5 -0
  29. package/src/fesd/components/Overlay/index.ts +2 -0
  30. package/src/fesd/components/index.ts +5 -0
  31. package/src/fesd/hooks/index.ts +2 -0
  32. package/src/fesd/hooks/useAnchor4/Anchor4.ts +185 -0
  33. package/src/fesd/hooks/useAnchor4/index.ts +2 -0
  34. package/src/fesd/hooks/useAnchor4/useAnchor4.tsx +88 -0
  35. package/src/fesd/hooks/useDragScroll4.tsx +139 -0
  36. package/src/fesd/hooks/useTransitionend.tsx +3 -0
  37. package/src/fesd/methods/Easing4/Easing4.ts +374 -0
  38. package/src/fesd/methods/Easing4/index.ts +2 -0
  39. package/src/fesd/methods/index.ts +1 -0
  40. package/src/fesd/tools.ts +69 -0
@@ -0,0 +1,5 @@
1
+ export * from "./Anchors"
2
+ export * from "./Articles"
3
+ export * from "./Collapse"
4
+ export * from "./Modals"
5
+ export * from "./Overlay"
@@ -0,0 +1,2 @@
1
+ export * from "./useAnchor4"
2
+ export * from "./useDragScroll4"
@@ -0,0 +1,185 @@
1
+ /* 2024.06.10 */
2
+ "use client"
3
+
4
+ import { Easing4, Easing4Type } from "@/fesd/methods"
5
+ import { debug, isElement, delay as timeout } from "@/fesd/tools"
6
+
7
+ export type EventCallback = (
8
+ event: string,
9
+ state: boolean,
10
+ options?: Anchor4OptionsType
11
+ ) => void
12
+
13
+ export interface Anchor4OptionsType {
14
+ target?: string
15
+ scroller: string
16
+ offseter?: string
17
+ offset?: number
18
+ easing?: Easing4Type
19
+ duration?: number
20
+ center?: boolean
21
+ delay?: number
22
+ direction?: "scrollLeft" | "scrollTop"
23
+ onceEvent?: boolean
24
+ onBeforeScroll?: EventCallback
25
+ onAfterScroll?: EventCallback
26
+ onScrolling?: EventCallback
27
+ debug?: boolean
28
+ }
29
+
30
+ export interface Anchor4Type extends Anchor4OptionsType {
31
+ targetEl?: Element | null
32
+ scrollerEl?: Element | string | null
33
+ offseterEls?: NodeListOf<Element> | null
34
+ eventCalled?: boolean
35
+ setScrolling?: React.Dispatch<boolean>
36
+ setEventCalled?: React.Dispatch<boolean>
37
+ }
38
+
39
+ export const Anchor4 = async (options: Anchor4Type) => {
40
+ const {
41
+ targetEl,
42
+ scrollerEl = "body",
43
+ offseterEls,
44
+
45
+ eventCalled = false,
46
+ setScrolling,
47
+ setEventCalled,
48
+
49
+ offset = 0,
50
+ easing = "easeInOutExpo",
51
+ duration = 1000,
52
+ onceEvent = false,
53
+ center = false,
54
+ delay,
55
+ direction = "scrollTop",
56
+ onBeforeScroll,
57
+ onAfterScroll,
58
+ onScrolling,
59
+ debug: debugMode = false,
60
+ } = options
61
+
62
+ // Init Options
63
+ const isScrollBody = scrollerEl == "body"
64
+ const scrollerElement = isScrollBody ? document.scrollingElement : scrollerEl
65
+ const scrollerContainer = isScrollBody ? document.body : scrollerElement
66
+
67
+ if (!isElement(scrollerElement) || !isElement(scrollerContainer)) {
68
+ throw new Error('Anchor4, scrollerElement or scrollerContainer is not Element');
69
+ }
70
+
71
+ const isScrollTop = direction == "scrollTop"
72
+ const property = isScrollTop ? "height" : "width"
73
+ const padding = isScrollTop ? "padding-top" : "padding-left"
74
+ const rect = isScrollTop ? "top" : "left"
75
+
76
+ const targetElRect = targetEl ? targetEl.getBoundingClientRect()[rect] : 0
77
+
78
+ const scrollerElRect = scrollerElement.getBoundingClientRect()
79
+ const scrollerElProperty = scrollerElRect[property]
80
+ const scrollerElPadding = getContainerPadding(scrollerContainer, padding)
81
+ const scrollerElOffset = isScrollBody ? 0 : scrollerElRect[rect]
82
+ const scrollerElCenterOffset = center ? (scrollerElProperty - scrollerElPadding) * 0.5 : 0
83
+
84
+ const offseterElsProperty = offseterEls ? offsetTargetsProperty(offseterEls, property) : 0
85
+ const offsetValue = scrollerElOffset
86
+ + scrollerElCenterOffset
87
+ + offseterElsProperty
88
+ + offset
89
+
90
+ const startScrollValue = scrollerElement[direction]
91
+ const distanceValue = targetEl
92
+ ? targetElRect - offsetValue
93
+ : targetElRect - offsetValue - startScrollValue
94
+
95
+ const endScrollValue = startScrollValue + distanceValue
96
+ const totalScrollValue = scrollerElement.scrollHeight - scrollerElement.clientHeight
97
+
98
+ // Check FinalDistanceValue
99
+ let finalDistanceValue = Math.round(distanceValue)
100
+
101
+ if (distanceValue > 0 && endScrollValue >= totalScrollValue)
102
+ finalDistanceValue = totalScrollValue - startScrollValue
103
+
104
+ if (distanceValue < 0 && endScrollValue <= 0)
105
+ finalDistanceValue = 0 - startScrollValue
106
+
107
+ if (finalDistanceValue == 0) return
108
+
109
+ // Scroll Process
110
+ let requestID: number[] = []
111
+ let currentTime: number
112
+
113
+ const setScrollElScrolling = (isScrolling: boolean) => isScrolling
114
+ ? scrollerContainer.setAttribute("anchor-scrolling", "")
115
+ : scrollerContainer.removeAttribute("anchor-scrolling")
116
+
117
+ const startScrollAnimation = (state: boolean) => state
118
+ ? requestID.push(requestAnimationFrame(scrollAnimationHandler))
119
+ : requestID.length && requestID.forEach((id: number) => cancelAnimationFrame(id))
120
+
121
+ const endScrollAnimation = () => {
122
+ startScrollAnimation(false)
123
+ setScrollElScrolling(false)
124
+
125
+ if (!eventCalled) onAfterScroll?.("onAfterScroll", false, options)
126
+ if (!eventCalled) onScrolling?.("onScrollEnd", false, options)
127
+ if (onceEvent) setEventCalled?.(true)
128
+
129
+ setScrolling?.(false)
130
+ }
131
+
132
+ const containerScrollHandler = (time: number) => scrollerElement[direction] = Math.round(
133
+ Easing4[easing](time, startScrollValue, Math.round(finalDistanceValue), duration)
134
+ )
135
+
136
+ const scrollAnimationHandler = (requestTime: number) => {
137
+ currentTime = currentTime ?? requestTime
138
+ const time = requestTime - currentTime
139
+
140
+ if (time < duration) startScrollAnimation(true)
141
+ if (time >= duration) endScrollAnimation()
142
+ containerScrollHandler(time)
143
+ }
144
+
145
+ const Anchor4Active = () => {
146
+ setScrollElScrolling(true)
147
+ startScrollAnimation(true)
148
+
149
+ if (!eventCalled) onScrolling?.("onScrolling", true, options)
150
+ setScrolling?.(true)
151
+ }
152
+
153
+ // if (debugMode) debug(target ?? "Null", {
154
+ // rect,
155
+ // padding,
156
+ // property,
157
+ // targetElRect,
158
+ // scrollerElProperty,
159
+ // scrollerElPadding,
160
+ // scrollerElCenterOffset,
161
+ // offseterElsProperty,
162
+ // offsetValue,
163
+ // startScrollValue,
164
+ // distanceValue,
165
+ // options: options,
166
+ // },
167
+ // "Anchor4",
168
+ // hooksName
169
+ // )
170
+
171
+ if (!eventCalled) onBeforeScroll?.("onBeforeScroll", true, options)
172
+ if (delay) await timeout(delay)
173
+
174
+ Anchor4Active()
175
+ }
176
+
177
+ export const getContainerPadding = (scrollerEl: Element | HTMLElement, padding: string) =>
178
+ parseInt(getComputedStyle(scrollerEl)[padding as any])
179
+
180
+ export const offsetTargetsProperty = (offsetEls: NodeListOf<Element>, property: "width" | "height") => {
181
+ return offsetEls && offsetEls.length ? [...offsetEls]
182
+ .map(element => element.getBoundingClientRect()[property])
183
+ .reduce((value, current) => value + current, 0) : 0
184
+ }
185
+
@@ -0,0 +1,2 @@
1
+ export * from "./Anchor4"
2
+ export * from "./useAnchor4"
@@ -0,0 +1,88 @@
1
+ /* 2024.06.10 */
2
+ "use client"
3
+
4
+ import * as React from "react"
5
+ import { Anchor4, Anchor4OptionsType } from "./Anchor4"
6
+ import { query, queryAll } from "@/fesd/tools"
7
+
8
+ export interface useAnchor4Type extends
9
+ Anchor4OptionsType {
10
+ as?: React.ElementType
11
+ href?: string
12
+ hash?: boolean
13
+ history?: boolean
14
+ }
15
+
16
+ export interface useAnchor4SettingType {
17
+ targetAttr?: string
18
+ scrollerAttr?: string
19
+ offseterAttr?: string
20
+ }
21
+
22
+ export const useAnchor4 = (setting: useAnchor4SettingType = {}) => {
23
+ const {
24
+ targetAttr = "anchor-target",
25
+ scrollerAttr = "anchor-scroller",
26
+ offseterAttr = "anchor-offseter"
27
+ } = setting
28
+
29
+ const [scrolling, setScrolling] = React.useState(false)
30
+ const [eventCalled, setEventCalled] = React.useState(false)
31
+
32
+ const getTarget = (target: string) =>
33
+ query(`[${targetAttr}="${target}"]`)
34
+
35
+ const getScroller = (scroller: string) =>
36
+ query(`[${scrollerAttr}="${scroller}"]`)
37
+
38
+ const getOffseter = (offseter: string) =>
39
+ queryAll(`[${offseterAttr}="${offseter}"]`)
40
+
41
+ const getElements = (options: useAnchor4Type) => {
42
+ const { target, scroller, offseter } = options
43
+
44
+ const scrollerEl = scroller == "body" ? scroller : scroller
45
+ ? getScroller(scroller) : undefined
46
+
47
+ const targetEl = target
48
+ ? getTarget(target) : undefined
49
+
50
+ const offseterEls = offseter
51
+ ? getOffseter(offseter) : undefined
52
+
53
+ return { targetEl, scrollerEl, offseterEls }
54
+ }
55
+
56
+ const scrollToAnchor = async (options: useAnchor4Type) => {
57
+ if (scrolling) return
58
+
59
+ const {
60
+ targetEl,
61
+ scrollerEl,
62
+ offseterEls
63
+ } = getElements(options)
64
+
65
+ Anchor4({
66
+ ...options,
67
+ setScrolling,
68
+ setEventCalled,
69
+ eventCalled,
70
+ targetEl,
71
+ scrollerEl,
72
+ offseterEls,
73
+ })
74
+ }
75
+
76
+ return {
77
+ scrolling,
78
+ eventCalled,
79
+ scrollToAnchor,
80
+ methods: {
81
+ getTarget,
82
+ getScroller,
83
+ getOffseter,
84
+ getElements,
85
+ }
86
+ }
87
+
88
+ };
@@ -0,0 +1,139 @@
1
+ /* eslint-disable react-hooks/exhaustive-deps */
2
+ /* 2024.06.10 */
3
+ "use client"
4
+
5
+ import { useEffect, useRef } from 'react';
6
+
7
+ interface useDragScroll4Type {
8
+ current: HTMLElement | null,
9
+ active: boolean
10
+ chilPointer?: boolean
11
+ cursorGrab?: boolean
12
+ className?: string
13
+ attributeKey?: string
14
+ attributeValue?: string
15
+ onBeforeDrag?: (e: MouseEvent) => void,
16
+ onAfterDrag?: (e: MouseEvent) => void,
17
+ onDraging?: (e: MouseEvent) => void,
18
+ debug?: boolean
19
+ }
20
+
21
+ export function useDragScroll4(options: useDragScroll4Type) {
22
+
23
+ const {
24
+ current,
25
+ active = false,
26
+ chilPointer = true,
27
+ cursorGrab = true,
28
+ attributeKey: attrKey = "drag-scrolling",
29
+ attributeValue: attrValue = "",
30
+ className,
31
+ onBeforeDrag,
32
+ onAfterDrag,
33
+ onDraging,
34
+ debug,
35
+ } = options
36
+
37
+ const mouseDown = useRef(false)
38
+ const clientX = useRef(0)
39
+ const clientY = useRef(0)
40
+
41
+ const setCursorGrab = (element: HTMLElement, state: string) => {
42
+ if (state) element.style.cursor = active ? state : ""
43
+ }
44
+
45
+ const setDragScrolling = (element: HTMLElement, state: string) => {
46
+ if (state == "add") element.setAttribute(attrKey, attrValue)
47
+ if (state == "remove") element.removeAttribute(attrKey)
48
+ }
49
+
50
+ const setChilPointer = (nodes: HTMLCollection, state: string) => {
51
+ [...nodes].forEach((node: any) => node.style.pointerEvents = state)
52
+ }
53
+
54
+ const setClassName = (element: HTMLElement, classname: string, action: string) => {
55
+ if (!element || !classname || !action) return
56
+ if (action == "add") element.classList.add(classname)
57
+ if (action == "remove") element.classList.remove(classname)
58
+ }
59
+
60
+ const mousedown = (e: MouseEvent) => {
61
+ e.preventDefault();
62
+
63
+ if (!current) return
64
+ if (e.button === 2) return
65
+
66
+ mouseDown.current = true
67
+ clientX.current = e.clientX
68
+ clientY.current = e.clientY
69
+ onBeforeDrag?.(e)
70
+ }
71
+
72
+ const mousemove = (e: MouseEvent) => {
73
+ const container = current
74
+
75
+ if (!mouseDown.current) return
76
+ if (!container) return
77
+ if (
78
+ Math.abs(clientX.current - e.clientX) > 10 ||
79
+ Math.abs(clientY.current - e.clientY) > 10
80
+ ) {
81
+ if (className) setClassName(container, className, "add")
82
+ if (cursorGrab) setCursorGrab(container, "grabbing")
83
+ if (chilPointer) setChilPointer(container.children, "none")
84
+
85
+ container.scrollTop -= e.clientY - clientY.current
86
+ container.scrollLeft -= e.clientX - clientX.current
87
+ setDragScrolling(container, "add")
88
+ onDraging?.(e)
89
+ }
90
+ clientX.current = e.clientX
91
+ clientY.current = e.clientY
92
+
93
+ }
94
+
95
+ const mouseup = (e: MouseEvent) => {
96
+ e.preventDefault();
97
+
98
+ const container = current
99
+
100
+ if (!mouseDown.current) return
101
+ if (!container) return
102
+
103
+ if (className) setClassName(container, className, "remove")
104
+ if (chilPointer) setChilPointer(container.children, "auto")
105
+
106
+ mouseDown.current = false
107
+ setDragScrolling(container, "remove")
108
+ onAfterDrag?.(e)
109
+ }
110
+
111
+ useEffect(() => {
112
+ if (!active) return
113
+ if (!current) return
114
+
115
+ const container = current
116
+
117
+ current.setAttribute("drag4-scroll", "")
118
+
119
+ if (cursorGrab) setCursorGrab(container, "grab")
120
+ window.addEventListener("mousemove", mousemove)
121
+ window.addEventListener("mouseup", mouseup)
122
+ // window.addEventListener("touchmove", mousemove)
123
+ // window.addEventListener("touchend", mouseup)
124
+
125
+ container.addEventListener("mousedown", mousedown)
126
+ // container.addEventListener("touchstart", mousedown)
127
+
128
+ return () => {
129
+ window.removeEventListener("mousemove", mousemove)
130
+ window.removeEventListener("mouseup", mouseup)
131
+ // window.removeEventListener("touchmove", mousemove)
132
+ // window.removeEventListener("touchend", mouseup)
133
+
134
+ container.removeEventListener("mousedown", mousedown)
135
+ // container.removeEventListener("touchstart", mousedown)
136
+ }
137
+ }, [current, active])
138
+
139
+ }
@@ -0,0 +1,3 @@
1
+ // export default function useTransitionend(params) {
2
+
3
+ // };