@jongh/cli 1.0.11 → 1.1.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.
@@ -1,140 +0,0 @@
1
- import { useState } from "react"
2
- import { useControlledState } from "../../hooks/useControllableState"
3
-
4
- type Props = {
5
- min: number
6
- max: number
7
- value: number
8
- defaultValue?: number
9
- onChange: (value: number) => void
10
- }
11
-
12
- const getPercentage = (value: number, min: number, max: number) =>
13
- ((value - min) / (max - min)) * 100
14
-
15
- const isTouchEvent = (e: TouchEvent | MouseEvent): e is TouchEvent => {
16
- return e && "touches" in e
17
- }
18
-
19
- const isMouseEvent = (e: TouchEvent | MouseEvent): e is MouseEvent => {
20
- return e && "screenX" in e
21
- }
22
-
23
- const getClientX = (
24
- e: React.TouchEvent<HTMLElement> | React.MouseEvent<HTMLElement>,
25
- ) => {
26
- let clientX = 0
27
- if (isMouseEvent(e.nativeEvent)) {
28
- clientX = e.nativeEvent.clientX
29
- } else if (isTouchEvent(e.nativeEvent)) {
30
- clientX =
31
- e.nativeEvent.touches.length > 0
32
- ? e.nativeEvent.touches[0].clientX
33
- : e.nativeEvent.changedTouches[0].clientX
34
- }
35
- return clientX
36
- }
37
-
38
- export const Slider = ({
39
- min = 0,
40
- max = 100,
41
- value,
42
- onChange,
43
- defaultValue,
44
- }: Props) => {
45
- const [isDragging, setIsDragging] = useState(false)
46
-
47
- const [innerValue = 0, setValue] = useControlledState({
48
- prop: value,
49
- defaultProp: defaultValue || min,
50
- onChange,
51
- })
52
-
53
- const handlePointerDown = (e: React.PointerEvent) => {
54
- e.preventDefault()
55
- setIsDragging(true)
56
- e.currentTarget.setPointerCapture(e.pointerId)
57
- }
58
-
59
- const handlePointerUp = (e: React.PointerEvent) => {
60
- e.preventDefault()
61
- setIsDragging(false)
62
- e.currentTarget.releasePointerCapture(e.pointerId)
63
- }
64
-
65
- const percentage = getPercentage(innerValue, min, max)
66
-
67
- const handleMouseMove = (e: React.PointerEvent<HTMLElement>) => {
68
- e.preventDefault()
69
- if (!isDragging) return
70
- //width는 본인의 상위태그여야함..
71
- const { left, width } = e.currentTarget.getBoundingClientRect()
72
- let percentage = (getClientX(e) - left) / width
73
- console.log(left, width)
74
- percentage = Math.min(Math.max(percentage, 0), 1)
75
- console.log(percentage)
76
- const newValue = min + percentage * (max - min)
77
- setValue(newValue)
78
- }
79
-
80
- return (
81
- <>
82
- <span
83
- className="slider-wrapper"
84
- style={{
85
- position: "relative",
86
- display: "flex",
87
- alignItems: "center",
88
- width: "200px",
89
- height: "50px",
90
- }}
91
- >
92
- <span
93
- className="slider-track"
94
- onPointerDownCapture={handlePointerDown}
95
- onPointerUpCapture={handlePointerUp}
96
- onPointerMoveCapture={handleMouseMove}
97
- onPointerCancelCapture={handlePointerUp}
98
- style={{
99
- position: "relative",
100
- backgroundColor: "black",
101
- flexGrow: 1,
102
- borderRadius: "9999px",
103
- height: "10px",
104
- }}
105
- >
106
- <span
107
- className="slider-value"
108
- style={{
109
- backgroundColor: "white",
110
- borderRadius: "9999px",
111
- height: "100%",
112
- position: "absolute",
113
- width: `${percentage}%`,
114
- }}
115
- ></span>
116
- <span
117
- className="slider-thumb"
118
- style={{
119
- position: "absolute",
120
- left: `${percentage}%`,
121
- transform: "translateX(-50%)",
122
- }}
123
- >
124
- <span
125
- style={{
126
- width: "10px",
127
- height: "10px",
128
- borderRadius: "100px",
129
- backgroundColor: "pink",
130
- opacity: "0.5",
131
- display: "block",
132
- }}
133
- ></span>
134
- </span>
135
- </span>
136
- </span>
137
- <div style={{ color: "pink" }}>{innerValue}</div>
138
- </>
139
- )
140
- }
@@ -1,42 +0,0 @@
1
- import { define } from "../../../dev"
2
-
3
- export const sliderRecipe = define.recipe({
4
- className: "slider",
5
- base: {
6
- WebkitAppearance: "none",
7
- height: "4px",
8
- borderRadius: "lg",
9
- backgroundColor: "grey_300",
10
- backgroundImage: "linear-gradient(#7DD3FC, #7DD3FC)",
11
- backgroundSize: "var(--range-size)",
12
- backgroundRepeat: "no-repeat",
13
- "&::-webkit-slider-thumb": {
14
- WebkitAppearance: "none",
15
- width: "20px",
16
- height: "20px",
17
- backgroundColor: "grey_300",
18
- borderRadius: "rounded",
19
- border: "none",
20
- cursor: "pointer",
21
- },
22
- "&::-moz-range-thumb": {
23
- WebkitAppearance: "none",
24
- width: "20px",
25
- height: "20px",
26
- backgroundColor: "grey_300",
27
- borderRadius: "rounded",
28
- border: "none",
29
- cursor: "pointer",
30
- },
31
- },
32
- variants: {
33
- orientation: {
34
- horizontal: {
35
- writingMode: "horizontal-tb",
36
- },
37
- vertical: {
38
- writingMode: "vertical-rl",
39
- },
40
- },
41
- },
42
- })
@@ -1,35 +0,0 @@
1
- import { forwardRef, useId, type ReactNode } from "react"
2
- import { useControlledState } from "../../hooks/useControllableState"
3
- import { Slot } from "@radix-ui/react-slot"
4
- import { TabProvider } from "./useTabContext"
5
-
6
- export interface TabProps {
7
- children: ReactNode
8
- selected?: string
9
- defaultValue?: string
10
- onSelect?: (value: string) => void
11
- asChild?: boolean
12
- }
13
-
14
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
- export const Tab = forwardRef<any, TabProps>(
16
- ({ children, selected, defaultValue, onSelect, asChild }, ref) => {
17
- const Element = asChild ? Slot : "div"
18
-
19
- const [value, setValue] = useControlledState({
20
- prop: selected,
21
- onChange: onSelect,
22
- defaultProp: defaultValue,
23
- })
24
-
25
- const onSelectItem = (value: string) => {
26
- setValue(value)
27
- }
28
-
29
- return (
30
- <TabProvider selected={value} onSelect={onSelectItem} tabId={useId()}>
31
- <Element ref={ref}>{children}</Element>
32
- </TabProvider>
33
- )
34
- },
35
- )
@@ -1,60 +0,0 @@
1
- import { type ReactNode } from "react"
2
- import { useTabContext } from "./useTabContext"
3
- import { motion } from "framer-motion"
4
-
5
- interface TabContentProps {
6
- children: ReactNode
7
- value: string
8
- }
9
-
10
- const tabContentVariant = {
11
- active: {
12
- display: "block",
13
- transition: {
14
- staggerChildren: 0.2,
15
- },
16
- },
17
- inactive: {
18
- display: "none",
19
- },
20
- } as const
21
-
22
- const cardVariant = {
23
- active: {
24
- opacity: 1,
25
- x: 0,
26
- transition: {
27
- duration: 0.3,
28
- },
29
- },
30
- inactive: {
31
- opacity: 0,
32
- x: 10,
33
- transition: {
34
- duration: 0.3,
35
- },
36
- },
37
- }
38
- export const TabContent = ({ children, value }: TabContentProps) => {
39
- const { selected, tabId } = useTabContext("tab")
40
-
41
- const isSelected = selected === value
42
-
43
- return (
44
- <motion.div
45
- role="tabpanel"
46
- tabIndex={0}
47
- id={tabId + "-tabpanel-" + value}
48
- data-state={isSelected ? "active" : "inactive"}
49
- aria-labelledby={tabId + "-tabitem-" + value}
50
- key={tabId + "-tabpanel-" + value}
51
- variants={tabContentVariant}
52
- animate={isSelected ? "active" : "inactive"}
53
- initial="inactive"
54
- >
55
- <motion.div key={value} variants={cardVariant}>
56
- {isSelected && children}
57
- </motion.div>
58
- </motion.div>
59
- )
60
- }
@@ -1,19 +0,0 @@
1
- import { css } from "@styled-system/css"
2
- import { motion } from "framer-motion"
3
-
4
- export const TabIndicator = () => {
5
- return (
6
- <motion.div
7
- className={css({
8
- width: "var(--indicator-width)",
9
- height: "2px",
10
- transform: "translateZ(0px)",
11
- position: "absolute",
12
- bottom: 0,
13
- left: `var(--indicator-left)`,
14
- background: "red_300",
15
- borderRadius: "rounded",
16
- })}
17
- ></motion.div>
18
- )
19
- }
@@ -1,118 +0,0 @@
1
- import {
2
- type ReactNode,
3
- type ReactElement,
4
- type ComponentPropsWithRef,
5
- forwardRef,
6
- } from "react"
7
- import { useTabContext } from "./useTabContext"
8
-
9
- import { css, cx } from "@styled-system/css"
10
- import { RovingTabIndexRoot, useRovingTabIndex } from "./useRovingTabIndex"
11
- import isHotkey from "is-hotkey"
12
- import { Slot } from "@radix-ui/react-slot"
13
- import { composeRefs } from "../../hooks/useComposedRefs"
14
- import {
15
- getNextFocusableId,
16
- getPrevFocusableId,
17
- } from "../../utils/getFocusableId"
18
-
19
- interface TabListProps {
20
- children: ReactNode
21
- className?: string
22
- }
23
-
24
- const setIndicatorStyle = (target: HTMLElement) => {
25
- const targetRect = target.getBoundingClientRect()
26
- const parentRect = target.parentElement?.getBoundingClientRect()
27
- if (!targetRect || !parentRect) {
28
- return
29
- }
30
- document.documentElement.style.setProperty(
31
- "--indicator-left",
32
- `${Math.abs(parentRect.left - targetRect.left)}px`,
33
- )
34
- document.documentElement.style.setProperty(
35
- "--indicator-width",
36
- `${Math.abs(targetRect.width)}px`,
37
- )
38
- }
39
-
40
- export const TabList = ({ children, className }: TabListProps) => {
41
- const { selected } = useTabContext("tab")
42
- return (
43
- <RovingTabIndexRoot as="div" active={selected}>
44
- <div
45
- role="tablist"
46
- className={cx(
47
- className,
48
- css({ position: "relative", display: "flex" }),
49
- )}
50
- >
51
- {children}
52
- </div>
53
- </RovingTabIndexRoot>
54
- )
55
- }
56
- type TabItemProps = ComponentPropsWithRef<"button"> & {
57
- value: string
58
- }
59
-
60
- export const RovingItem = ({
61
- value,
62
- children,
63
- }: {
64
- value: string
65
- children: ReactElement
66
- }) => {
67
- const { getOrderedItems, getRovingProps } = useRovingTabIndex(value)
68
- return (
69
- <Slot
70
- {...getRovingProps<"button">({
71
- onKeyDown: (e) => {
72
- const items = getOrderedItems()
73
- let nextItem
74
- if (isHotkey("right", e)) {
75
- nextItem = getNextFocusableId(items, value)
76
- } else if (isHotkey("left", e)) {
77
- nextItem = getPrevFocusableId(items, value)
78
- }
79
- nextItem?.element.focus()
80
- },
81
- })}
82
- >
83
- {children}
84
- </Slot>
85
- )
86
- }
87
-
88
- export const TabItem = forwardRef<HTMLButtonElement, TabItemProps>(
89
- ({ children, className, value, ...props }: TabItemProps, forwardRef) => {
90
- const { selected, onSelect, tabId } = useTabContext("tab")
91
- const isSelected = selected === value
92
-
93
- const handleSelect = () => {
94
- onSelect?.(value)
95
- }
96
-
97
- return (
98
- <RovingItem value={value}>
99
- <button
100
- ref={composeRefs((node) => {
101
- if (isSelected && node) {
102
- setIndicatorStyle(node as HTMLElement)
103
- }
104
- }, forwardRef)}
105
- onClick={handleSelect}
106
- onFocus={handleSelect}
107
- role="tab"
108
- aria-selected={isSelected}
109
- id={tabId + "-tabitem-" + value}
110
- aria-controls={tabId + "-tabpanel-" + value}
111
- {...props}
112
- >
113
- {children}
114
- </button>
115
- </RovingItem>
116
- )
117
- },
118
- )
@@ -1,4 +0,0 @@
1
- export * from "./Tab"
2
- export * from "./TabList"
3
- export * from "./TabContent"
4
- export * from "./TabIndicator"
@@ -1,9 +0,0 @@
1
- import { define } from "../../../dev"
2
-
3
- export const tabRecipe = define.recipe({
4
- className: "tab",
5
- base: {
6
- display: "flex",
7
- flexDirection: "row",
8
- },
9
- })
@@ -1,172 +0,0 @@
1
- import isHotkey from "is-hotkey"
2
- import {
3
- ReactNode,
4
- useCallback,
5
- useRef,
6
- useState,
7
- FocusEvent,
8
- MouseEvent,
9
- KeyboardEvent,
10
- ComponentPropsWithoutRef,
11
- ElementType,
12
- MutableRefObject,
13
- } from "react"
14
- import { useControlledState } from "../../hooks/useControllableState"
15
- import { createContext } from "../../hooks/createContext"
16
- import { composeRefs } from "../../hooks/useComposedRefs"
17
-
18
- export type RovingTabIndexItem = {
19
- value: string
20
- element: HTMLElement
21
- }
22
-
23
- function onFocusFirst(candidates: HTMLElement[]) {
24
- const previousFocus = document.activeElement
25
- while (document.activeElement === previousFocus && candidates.length > 0) {
26
- candidates.shift()?.focus()
27
- }
28
- }
29
-
30
- type RovingTabIndexContext = {
31
- currentFocusedValue: string | null
32
- setFocusableId: (id: string) => void
33
- onShiftTab: () => void
34
- getOrderedItems: () => RovingTabIndexItem[]
35
- elements: MutableRefObject<Map<string, HTMLElement>>
36
- }
37
-
38
- const [RovingTabIndexProvider, useRovingTabIndexContext] =
39
- createContext<RovingTabIndexContext>("rovingTabIndex")
40
-
41
- const NODE_SELECTOR = "data-roving-tabindex-node"
42
- const ROOT_SELECTOR = "data-roving-tabindex-root"
43
- const NOT_FOCUSABLE_SELECTOR = "data-roving-tabindex-not-focusable"
44
- const SELECTOR_ACTIVE = `:where([${NODE_SELECTOR}=true]):not(:where([${NOT_FOCUSABLE_SELECTOR}=true] *))`
45
-
46
- type RovingTabIndexRootBaseProps<T> = {
47
- children: ReactNode | ReactNode[]
48
- active?: string
49
- setActive?: (value: string) => void
50
- as?: T
51
- }
52
-
53
- type RovingTabIndexRootProps<T extends ElementType> =
54
- RovingTabIndexRootBaseProps<T> &
55
- Omit<ComponentPropsWithoutRef<T>, keyof RovingTabIndexRootBaseProps<T>>
56
-
57
- export const RovingTabIndexRoot = <T extends ElementType>({
58
- children,
59
- active,
60
- setActive,
61
- as,
62
- ref,
63
- ...props
64
- }: RovingTabIndexRootProps<T>) => {
65
- const Component = as || "div"
66
- const [isShiftTabbing, setIsShiftTabbing] = useState(false)
67
-
68
- const [value = null, setValue] = useControlledState({
69
- prop: active,
70
- onChange: setActive,
71
- })
72
-
73
- const rootRef = useRef<HTMLDivElement | null>(null)
74
- const elementsRef = useRef<Map<string, HTMLElement>>(new Map())
75
- const getOrderedItems = useCallback(() => {
76
- if (!rootRef.current) return []
77
- const activeElements = Array.from(
78
- rootRef.current.querySelectorAll(SELECTOR_ACTIVE),
79
- )
80
-
81
- return Array.from(elementsRef.current)
82
- .sort(
83
- (a, b) => activeElements.indexOf(a[1]) - activeElements.indexOf(b[1]),
84
- )
85
- .map(([value, element]) => ({ value, element }))
86
- }, [])
87
-
88
- return (
89
- <RovingTabIndexProvider
90
- setFocusableId={(value: string) => {
91
- setValue(value)
92
- }}
93
- onShiftTab={() => {
94
- setIsShiftTabbing(true)
95
- }}
96
- currentFocusedValue={value}
97
- getOrderedItems={getOrderedItems}
98
- elements={elementsRef}
99
- >
100
- <Component
101
- {...{ [ROOT_SELECTOR]: true }}
102
- // tabIndex={isShiftTabbing ? -1 : 0}
103
- onFocus={(e) => {
104
- console.log("parent focus")
105
- if (e.target !== e.currentTarget) return
106
- if (isShiftTabbing) return
107
- const orderedItems = getOrderedItems()
108
- if (orderedItems.length === 0) return
109
-
110
- const candidates = [
111
- elementsRef.current.get(value ?? ""),
112
- ...orderedItems.map((i) => i.element),
113
- ].filter((element): element is HTMLElement => element != null)
114
-
115
- onFocusFirst(candidates)
116
- }}
117
- onBlur={() => setIsShiftTabbing(false)}
118
- ref={composeRefs(ref, rootRef)}
119
- {...props}
120
- >
121
- {children}
122
- </Component>
123
- </RovingTabIndexProvider>
124
- )
125
- }
126
-
127
- export const useRovingTabIndex = (value: string) => {
128
- const {
129
- currentFocusedValue,
130
- setFocusableId,
131
- onShiftTab,
132
- getOrderedItems,
133
- elements,
134
- } = useRovingTabIndexContext("rovingTabIndex")
135
-
136
- return {
137
- getOrderedItems,
138
- isFocusable: currentFocusedValue === value,
139
- getRovingProps: <T extends ElementType>(
140
- props?: ComponentPropsWithoutRef<T>,
141
- ) => ({
142
- ...props,
143
- ref: (element: HTMLElement | null) => {
144
- if (element) {
145
- elements.current.set(value, element)
146
- } else {
147
- elements.current.delete(value)
148
- }
149
- },
150
- onMouseDown: (e: MouseEvent) => {
151
- props?.onMouseDown?.(e)
152
- if (e.target !== e.currentTarget) return
153
- setFocusableId(value)
154
- },
155
- onKeyDown: (e: KeyboardEvent) => {
156
- props?.onKeyDown?.(e)
157
- if (e.target !== e.currentTarget) return
158
- if (isHotkey("shift+tab", e)) {
159
- onShiftTab()
160
- return
161
- }
162
- },
163
- onFocus: (e: FocusEvent) => {
164
- props?.onFocus?.(e)
165
- if (e.target !== e.currentTarget) return
166
- setFocusableId(value)
167
- },
168
- [NODE_SELECTOR]: true,
169
- tabIndex: currentFocusedValue === value ? 0 : -1,
170
- }),
171
- }
172
- }
@@ -1,11 +0,0 @@
1
- import { createContext } from "../../hooks/createContext"
2
-
3
- type Value = string
4
-
5
- export interface TabContext {
6
- selected?: Value
7
- onSelect?: (index: Value) => void
8
- tabId: string
9
- }
10
-
11
- export const [TabProvider, useTabContext] = createContext<TabContext>("tab")
@@ -1,75 +0,0 @@
1
- // import { cx } from "@styled-system/css"
2
- // // import { tagButton, type TagButtonVariant } from "@styled-system/recipes"
3
- // import { forwardRef } from "react"
4
- // import { useControlledState } from "../../hooks/useControllableState"
5
-
6
- // type TagButtonProps = Partial<TagButtonVariant> & {
7
- // /** 버튼 내부에 표시될 텍스트 */
8
- // children: string
9
-
10
- // /** 버튼의 비활성화 여부를 지정합니다. true일 경우 버튼이 비활성화됩니다. */
11
- // disabled?: boolean
12
-
13
- // /** 버튼에 적용할 추가적인 CSS 클래스명 */
14
- // className?: string
15
-
16
- // /** 버튼의 고유 식별자 */
17
- // id?: string
18
-
19
- // /**
20
- // * 버튼 클릭 시 실행될 함수
21
- // * @param e 선택적 boolean 매개변수
22
- // */
23
- // onClick?: (e?: boolean) => void
24
-
25
- // /** 버튼의 클릭 상태를 나타냅니다. true일 경우 클릭된 상태를 의미합니다. */
26
- // isClicked?: boolean
27
-
28
- // /** 버튼의 초기 클릭 상태를 설정합니다. true일 경우 처음부터 클릭된 상태로 시작합니다. */
29
- // defaultClick?: boolean
30
- // }
31
-
32
- // export const TagButton = forwardRef<HTMLSpanElement, TagButtonProps>(
33
- // (
34
- // {
35
- // children,
36
- // disabled = false,
37
- // className,
38
- // id,
39
- // onClick,
40
- // isClicked,
41
- // defaultClick = false,
42
- // ...rest
43
- // },
44
- // ref,
45
- // ) => {
46
- // const [clicked, setClicked] = useControlledState({
47
- // prop: isClicked,
48
- // defaultProp: defaultClick,
49
- // onChange: onClick,
50
- // })
51
- // //
52
- // return (
53
- // <span
54
- // role="button"
55
- // ref={ref}
56
- // id={id}
57
- // className={cx(tagButton({ ...rest }), className)}
58
- // aria-disabled={disabled}
59
- // aria-pressed={clicked}
60
- // {...(disabled && { "data-invalid": "true" })}
61
- // data-testid={id}
62
- // onClick={() => {
63
- // if (disabled) {
64
- // return
65
- // }
66
- // setClicked((prev) => !prev)
67
- // }}
68
- // >
69
- // {children}
70
- // </span>
71
- // )
72
- // },
73
- // )
74
-
75
- // TagButton.displayName = "TagButton"