@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,62 @@
1
+ @import "@/styles/mixins";
2
+
3
+ .root {
4
+ width: 100%;
5
+ display: flex;
6
+ gap: 50px;
7
+
8
+ // &[article-direction="left"] {
9
+ // flex-direction: row-reverse;
10
+ // }
11
+
12
+ figure {
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: 10px;
16
+ flex: 0 0 30%;
17
+ &:hover {
18
+ figcaption {
19
+ font-size: px(14);
20
+ opacity: 1;
21
+ }
22
+ }
23
+ figcaption {
24
+ font-size: px(14);
25
+ opacity: 0.5;
26
+ transition: 0.5s;
27
+ opacity: 0.5;
28
+ }
29
+ }
30
+
31
+ section {
32
+ flex: 1;
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 30px;
36
+
37
+ &.phptos {
38
+ }
39
+ }
40
+
41
+ hgroup {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: 10px;
45
+ h3 {
46
+ font-size: px(24);
47
+ font-weight: 500;
48
+ line-height: 1.3;
49
+ }
50
+ p {
51
+ font-size: px(16);
52
+ }
53
+ }
54
+ button {
55
+ font-size: px(14);
56
+ font-weight: 400;
57
+ text-transform: uppercase;
58
+ color: #fff;
59
+ padding: 12px 35px;
60
+ background-color: #5b5b5b;
61
+ }
62
+ }
@@ -0,0 +1,82 @@
1
+ @import "@/styles/mixins";
2
+
3
+ .root {
4
+ width: 100%;
5
+ max-width: 900px;
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: 50px;
9
+
10
+ &[article-width="full"] {
11
+ max-width: max-content;
12
+ }
13
+
14
+ // &[article-direction="left"] {
15
+ // flex-direction: row-reverse;
16
+ // }
17
+
18
+ .content {
19
+ flex: 1;
20
+ display: flex;
21
+ gap: 30px;
22
+ }
23
+
24
+ .photos {
25
+ flex: 1;
26
+ display: flex;
27
+ flex-direction: row;
28
+ flex-wrap: wrap;
29
+ gap: 50px;
30
+ }
31
+
32
+ figure {
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 10px;
36
+ flex: 1;
37
+ &:hover {
38
+ figcaption {
39
+ font-size: px(14);
40
+ opacity: 1;
41
+ }
42
+ }
43
+ figcaption {
44
+ font-size: px(14);
45
+ opacity: 0.5;
46
+ transition: 0.5s;
47
+ opacity: 0.5;
48
+ }
49
+ }
50
+
51
+ hgroup {
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 10px;
55
+ h3 {
56
+ font-size: px(24);
57
+ font-weight: 500;
58
+ line-height: 1.3;
59
+ }
60
+ h6 {
61
+ font-size: px(18);
62
+ font-weight: 500;
63
+ line-height: 1.3;
64
+ }
65
+ h3 + p,
66
+ h6 + p {
67
+ margin-top: 10px;
68
+ }
69
+ p {
70
+ font-size: px(16);
71
+ }
72
+ }
73
+ button {
74
+ font-size: px(14);
75
+ font-weight: 400;
76
+ text-transform: uppercase;
77
+ white-space: nowrap;
78
+ color: #fff;
79
+ padding: 12px 35px;
80
+ background-color: #5b5b5b;
81
+ }
82
+ }
@@ -0,0 +1,2 @@
1
+ export { default as ArticleBasic } from "./Article.Basic"
2
+ export { default as ArticleFigure } from "./Article.Figure"
@@ -0,0 +1,27 @@
1
+ "use client"
2
+
3
+ interface PropsType extends
4
+ React.HTMLAttributes<HTMLDivElement> {
5
+ as?: React.ElementType
6
+ children: React.ReactNode
7
+ name?: string
8
+ }
9
+
10
+ const CollapseBody: React.FC<PropsType> = (props) => {
11
+ const {
12
+ children,
13
+ name,
14
+ as: RootComponent = "div",
15
+ ...others
16
+ } = props
17
+
18
+ return (
19
+ <RootComponent {...others} data-collapse-content={name ?? ""}>
20
+ {children}
21
+ </RootComponent>
22
+ )
23
+ };
24
+
25
+ CollapseBody.displayName = "CollapseBody"
26
+
27
+ export default CollapseBody
@@ -0,0 +1,56 @@
1
+ "use client"
2
+
3
+ import { useEffect, useMemo, useRef, useState } from "react"
4
+ import styles from "./Collapse.module.scss"
5
+ import { useCollapseWrapperContext, ContainerContext } from "./CollapseContext"
6
+
7
+ interface PropsType extends
8
+ React.HTMLAttributes<HTMLDivElement> {
9
+ as?: React.ElementType
10
+ children: React.ReactNode
11
+ name?: string
12
+ open?: boolean
13
+ }
14
+
15
+ const CollapseContainer: React.FC<PropsType> = (props) => {
16
+ const {
17
+ children,
18
+ name,
19
+ as: RootComponent = "div",
20
+ className,
21
+ open = false,
22
+ ...others
23
+ } = props
24
+
25
+
26
+ const [active, setActive] = useState(false)
27
+
28
+ const contextValue = useMemo(() => ({
29
+ active,
30
+ setActive,
31
+ }), [active])
32
+
33
+
34
+
35
+ useEffect(() => {
36
+ setActive(open ?? false)
37
+ }, [open])
38
+
39
+ return (
40
+ <ContainerContext.Provider value={contextValue}>
41
+ <RootComponent
42
+ {...others}
43
+ className={styles.root + " " + styles.easeInOutExpo + " " + className}
44
+ data-collapse-active={active ? "open" : ""}
45
+ data-collapse-container={name ?? ""}
46
+ >
47
+ {children}, {JSON.stringify(active)}
48
+ </RootComponent>
49
+ </ContainerContext.Provider>
50
+
51
+ )
52
+ };
53
+
54
+ CollapseContainer.displayName = "CollapseContainer"
55
+
56
+ export default CollapseContainer
@@ -0,0 +1,39 @@
1
+ "use client"
2
+
3
+ import { useCollapseContainerContext } from "./CollapseContext";
4
+
5
+ interface PropsType extends
6
+ React.HTMLAttributes<HTMLDivElement> {
7
+ as?: React.ElementType
8
+ children: React.ReactNode
9
+ name?: string
10
+ }
11
+
12
+ const CollapseHead: React.FC<PropsType> = (props) => {
13
+ const {
14
+ children,
15
+ name,
16
+ as: RootComponent = "div",
17
+ ...others
18
+ } = props
19
+
20
+
21
+ const {
22
+ active,
23
+ setActive
24
+ } = useCollapseContainerContext()
25
+
26
+ return (
27
+ <RootComponent
28
+ {...others}
29
+ data-collapse-head={name ?? ""}
30
+ onClick={() => setActive && setActive(prev => !prev)}
31
+ >
32
+ {children}
33
+ </RootComponent>
34
+ )
35
+ };
36
+
37
+ CollapseHead.displayName = "CollapseHead"
38
+
39
+ export default CollapseHead
@@ -0,0 +1,46 @@
1
+ "use client"
2
+
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { WrapperContext } from "./CollapseContext";
5
+
6
+ interface PropsType extends
7
+ React.HTMLAttributes<HTMLDivElement> {
8
+ as?: React.ElementType
9
+ children: React.ReactNode
10
+ name?: string
11
+ openAll?: boolean
12
+ }
13
+
14
+ const CollapseWrapper: React.FC<PropsType> = (props) => {
15
+ const {
16
+ children,
17
+ name,
18
+ as: RootComponent = "div",
19
+ openAll = false,
20
+ ...others
21
+ } = props
22
+
23
+ const [activeAll, setActiveAll] = useState(false)
24
+
25
+ const contextValue = useMemo(() => ({
26
+ setActiveAll,
27
+ activeAll,
28
+ }), [activeAll])
29
+
30
+ useEffect(() => {
31
+ setActiveAll(openAll)
32
+ }, [openAll])
33
+
34
+ return (
35
+ <WrapperContext.Provider value={contextValue}>
36
+ <div onClick={() => setActiveAll(prev => !prev)}>open all</div>
37
+ <RootComponent {...others} data-collapse-wrapper={name ?? ""}>
38
+ {children}
39
+ </RootComponent>
40
+ </WrapperContext.Provider>
41
+ )
42
+ };
43
+
44
+ CollapseWrapper.displayName = "CollapseWrapper"
45
+
46
+ export default CollapseWrapper
@@ -0,0 +1,23 @@
1
+ .root {
2
+ display: grid;
3
+ grid-template-rows: auto 0fr;
4
+ transition-duration: 0.5s;
5
+ transition-property: grid-template-rows;
6
+
7
+ &[data-collapse-active="open"] {
8
+ grid-template-rows: auto 1fr;
9
+ }
10
+
11
+ &[data-direction="columns"] {
12
+ grid-template-columns: auto 0fr;
13
+ transition-property: grid-template-columns;
14
+
15
+ &[data-collapse-active="open"] {
16
+ grid-template-columns: auto 1fr;
17
+ }
18
+ }
19
+
20
+ &.easeInOutExpo {
21
+ transition-timing-function: cubic-bezier(0.87, 0, 0.13, 1);
22
+ }
23
+ }
@@ -0,0 +1,11 @@
1
+ import CollapseWrapper from "./Collapse.Wrapper"
2
+ import CollapseBody from "./Collapse.Body"
3
+ import CollapseContainer from "./Collapse.Container"
4
+ import CollapseHead from "./Collapse.Head"
5
+
6
+ export const Collapse = Object.assign({}, {
7
+ Head: CollapseHead,
8
+ Body: CollapseBody,
9
+ Container: CollapseContainer,
10
+ Wrapper: CollapseWrapper,
11
+ })
@@ -0,0 +1,21 @@
1
+ 'use client'
2
+
3
+ import { createContext, use } from "react"
4
+
5
+
6
+ export interface WrapperContextType {
7
+ activeAll?: boolean
8
+ setActiveAll?: React.Dispatch<React.SetStateAction<boolean>>
9
+ }
10
+
11
+ export interface ContainerContextType {
12
+ active?: boolean
13
+ setActive?: React.Dispatch<React.SetStateAction<boolean>>
14
+ }
15
+
16
+ export const WrapperContext = createContext<WrapperContextType>({})
17
+ export const ContainerContext = createContext<ContainerContextType>({})
18
+
19
+ export const useCollapseWrapperContext = () => use(WrapperContext)
20
+ export const useCollapseContainerContext = () => use(ContainerContext)
21
+
@@ -0,0 +1 @@
1
+ export * from "./Collapse"
@@ -0,0 +1,84 @@
1
+ .root {
2
+ width: 100dvw;
3
+ height: 100dvh;
4
+ display: flex;
5
+ flex-direction: column;
6
+ position: fixed;
7
+ top: 0;
8
+ left: 0;
9
+ z-index: 2;
10
+
11
+ &.upperLeft {
12
+ justify-content: flex-start;
13
+ align-items: flex-start;
14
+ }
15
+ &.upper {
16
+ justify-content: center;
17
+ align-items: flex-start;
18
+ }
19
+ &.upperRight {
20
+ justify-content: flex-end;
21
+ align-items: flex-start;
22
+ }
23
+ &.left {
24
+ justify-content: flex-start;
25
+ align-items: center;
26
+ }
27
+ &.center {
28
+ justify-content: center;
29
+ align-items: center;
30
+ }
31
+ &.right {
32
+ justify-content: flex-end;
33
+ align-items: center;
34
+ }
35
+ &.lowerLeft {
36
+ justify-content: flex-start;
37
+ align-items: flex-end;
38
+ }
39
+ &.lower {
40
+ justify-content: center;
41
+ align-items: flex-end;
42
+ }
43
+ &.lowerRight {
44
+ justify-content: flex-end;
45
+ align-items: flex-end;
46
+ }
47
+ }
48
+
49
+ .container {
50
+ width: 100%;
51
+ height: 100%;
52
+ max-width: 990px;
53
+ max-height: 750px;
54
+ background-color: var(--base-bg-color);
55
+ border-radius: 3px;
56
+ display: flex;
57
+ flex-direction: column;
58
+ transition: 0.5s;
59
+
60
+ &.fade {
61
+ opacity: 0;
62
+ transform: translateY(2.5%);
63
+ }
64
+ &.scale {
65
+ opacity: 0;
66
+ transform: scale(0.95);
67
+ }
68
+
69
+ .active & {
70
+ &.fade {
71
+ opacity: 1;
72
+ transform: translateY(0);
73
+ }
74
+ &.scale {
75
+ opacity: 1;
76
+ transform: scale(1);
77
+ }
78
+ }
79
+ }
80
+
81
+ .backdrop {
82
+ position: fixed;
83
+ inset: 0;
84
+ }
@@ -0,0 +1,103 @@
1
+ /* eslint-disable react-hooks/exhaustive-deps */
2
+ "use client"
3
+
4
+ import * as React from "react"
5
+ import { createPortal } from 'react-dom'
6
+ import { Overlay } from "@/fesd/components"
7
+ import { mergeClassName, delay } from "@/fesd/tools"
8
+ import { ModalsTypes } from "./Modals.types"
9
+ import styles from "./Modals.module.scss"
10
+
11
+ const Modals: React.FC<ModalsTypes> = (props) => {
12
+
13
+ const {
14
+ open = false,
15
+ openInBody = false,
16
+ transitionMode = "fade",
17
+ position = "center",
18
+ backdropClose = false,
19
+ ref,
20
+ children,
21
+ slots = {},
22
+ setClose,
23
+ onTransitionEnter,
24
+ onTransitionExit,
25
+ ...others
26
+ } = props
27
+
28
+ const containerRef = React.useRef(null)
29
+
30
+ const [active, setActive] = React.useState(false)
31
+ const [display, setDisplay] = React.useState(false)
32
+
33
+ const Root = slots.root ?? "div"
34
+ const Backdrop = slots.backdrop ?? "div"
35
+
36
+ const transitionEvent = (event: string) => {
37
+ event == "enter" && onTransitionEnter?.()
38
+ event == "exit" && onTransitionExit?.()
39
+ }
40
+
41
+ const setActiveHandler = async () => {
42
+ if (active || display) return
43
+ setDisplay(true)
44
+ await delay(100)
45
+ setActive(true)
46
+ await delay(500)
47
+ transitionEvent("enter")
48
+ }
49
+ const setCloseHandler = async () => {
50
+ if (!active || !display) return
51
+ setActive(false)
52
+ await delay(600)
53
+ setDisplay(false)
54
+ transitionEvent("exit")
55
+ }
56
+
57
+ const setBackdropClose = () => {
58
+ if (!backdropClose) return
59
+ setClose()
60
+ }
61
+
62
+ const rootClass = mergeClassName(
63
+ styles.root,
64
+ styles[position],
65
+ active ? styles.active : ""
66
+ )
67
+
68
+ const containerClass = mergeClassName(
69
+ styles.container,
70
+ styles[transitionMode],
71
+ styles.active
72
+ )
73
+
74
+ const RootComponent = (
75
+ <Root {...others} ref={ref} className={rootClass}>
76
+ <Backdrop className={styles.backdrop} onClick={setBackdropClose}>
77
+ <Overlay open={open} />
78
+ </Backdrop>
79
+ <div ref={containerRef} className={containerClass}>
80
+ {children}
81
+ <button onClick={setClose}>Close</button>
82
+ </div>
83
+ </Root>
84
+ )
85
+
86
+ React.useEffect(() => {
87
+ open ? setActiveHandler() : setCloseHandler()
88
+ }, [open])
89
+
90
+ return (
91
+ <React.Fragment>
92
+ {display && openInBody
93
+ ? createPortal(RootComponent, document.body) as React.ReactPortal
94
+ : display ? RootComponent : null
95
+ }
96
+ </React.Fragment>
97
+ )
98
+
99
+ }
100
+
101
+ Modals.displayName = "Modals"
102
+
103
+ export default Modals
@@ -0,0 +1,52 @@
1
+ export interface ModalsSlots {
2
+ root?: React.ElementType
3
+ backdrop?: React.ElementType
4
+ }
5
+
6
+ export interface ModalsTypes {
7
+
8
+ ref: React.MutableRefObject<HTMLElement | null>
9
+
10
+ //A singal chil content element.
11
+ children: React.ReactElement
12
+
13
+ //A function called, when a transition enters
14
+ onTransitionEnter?: () => void
15
+
16
+ //A function called, when a transition has exited.
17
+ onTransitionExit?: () => void
18
+
19
+ //If "true", the component is shown.
20
+ //Default:"false"
21
+ open?: boolean
22
+
23
+ //A function called when close the component.
24
+ setClose: () => void
25
+
26
+ //Container position
27
+ //Default:"center"
28
+ position?: "upperLeft"
29
+ | "upper"
30
+ | "upperRight"
31
+ | "left"
32
+ | "center"
33
+ | "right"
34
+ | "lowerLeft"
35
+ | "lower"
36
+ | "lowerRight"
37
+
38
+ //Transition Mode
39
+ //Default:"Fade"
40
+ transitionMode?: "fade"
41
+ | "scale"
42
+
43
+ //Append Modals in Body
44
+ //Default: false
45
+ openInBody?: boolean
46
+
47
+ //A function called when click in backdrop.
48
+ //Default:false
49
+ backdropClose?: boolean
50
+
51
+ slots?: ModalsSlots
52
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Modals } from "./Modals"
2
+ export * from "./Modals.types"
@@ -0,0 +1,14 @@
1
+ .root {
2
+ width: 100dvw;
3
+ height: 100dvh;
4
+ background-color: rgba(0, 0, 0, 0.5);
5
+ position: absolute;
6
+ top: 0;
7
+ left: 0;
8
+ z-index: -1;
9
+ opacity: 0;
10
+ transition: var(--trans-time);
11
+ &.active {
12
+ opacity: 1;
13
+ }
14
+ }
@@ -0,0 +1,50 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { delay, mergeClassName } from "@/fesd/tools"
5
+ import { OverlayType } from "@/fesd/components"
6
+ import styles from "./Overlay.module.scss"
7
+
8
+ const Overlay: React.FC<OverlayType> = ({
9
+ open = false,
10
+ time = 500,
11
+ ...props
12
+ }) => {
13
+
14
+ const [display, setDisplay] = React.useState(false)
15
+ const [active, setActive] = React.useState(false)
16
+
17
+ const setActiveHandler = async () => {
18
+ setDisplay(true)
19
+ await delay(100)
20
+ setActive(true)
21
+ }
22
+ const setCloseHandler = async () => {
23
+ setActive(false)
24
+ await delay(600)
25
+ setDisplay(false)
26
+ }
27
+
28
+ const rootClass = mergeClassName(
29
+ styles.root,
30
+ active ? styles.active : ""
31
+ )
32
+
33
+ const rootStyle = {
34
+ "--trans-time": String(time / 1000) + "s"
35
+ } as React.CSSProperties
36
+
37
+ React.useEffect(() => {
38
+ open ? setActiveHandler() : setCloseHandler()
39
+ }, [open])
40
+
41
+ return (
42
+ <>
43
+ {display && <div {...props} className={rootClass} style={rootStyle} />}
44
+ </>
45
+ )
46
+
47
+ };
48
+
49
+ Overlay.displayName = "Overlay"
50
+ export default Overlay
@@ -0,0 +1,5 @@
1
+ export interface OverlayType extends
2
+ Omit<React.HTMLAttributes<HTMLElement>, "style"> {
3
+ open?: boolean
4
+ time?: number
5
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Overlay } from "./Overlay"
2
+ export * from "./Overlay.types"