@jongh/cli 1.1.0 → 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.
- package/dist/index.js +1 -1
- package/package.json +16 -3
- package/.lintstagedrc.json +0 -4
- package/CHANGELOG.md +0 -7
- package/dist/components/Accordion/Accordion.tsx +0 -281
- package/dist/components/Accordion/index.tsx +0 -37
- package/dist/components/Accordion/useAccordionHeight.ts +0 -25
- package/dist/components/Avatar/Avatar.tsx +0 -18
- package/dist/components/Avatar/useAvatar.ts +0 -73
- package/dist/components/Button/index.tsx +0 -32
- package/dist/components/Primitive/index.tsx +0 -58
- package/dist/components/RovingIndex/RovingItem.tsx +0 -47
- package/dist/components/RovingIndex/RovingTabIndexRoot.tsx +0 -92
- package/dist/components/RovingIndex/index.ts +0 -3
- package/dist/components/RovingIndex/useRovingTabIndex.tsx +0 -76
- package/dist/components/Select/index.tsx +0 -231
- package/dist/components/Slider/index.tsx +0 -141
- package/dist/components/Slider/style.ts +0 -29
- package/dist/components/Tabs/Tab.tsx +0 -39
- package/dist/components/Tabs/TabContent.tsx +0 -62
- package/dist/components/Tabs/TabIndicator.tsx +0 -6
- package/dist/components/Tabs/TabList.tsx +0 -117
- package/dist/components/Tabs/index.ts +0 -43
- package/dist/components/Tabs/useRovingTabIndex.tsx +0 -171
- package/dist/components/Tabs/useTabContext.ts +0 -11
- package/dist/components/TagButton/TagButton.tsx +0 -75
- package/dist/components/TagButton/style.ts +0 -35
- package/dist/components/core/Polymorphic/index.ts +0 -26
- package/dist/components/index.ts +0 -5
- package/src/copyComponent.ts +0 -29
- package/src/getConfig.ts +0 -56
- package/src/index.ts +0 -46
- package/tsconfig.json +0 -14
- package/tsup.config.ts +0 -14
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import x from"yargs";import{hideBin as A}from"yargs/helpers";import*as r from"@clack/prompts";import{packageDirectory as j}from"pkg-dir";import u from"fs-extra";import h from"path";import d from"fast-glob";import v from"fs-extra";import{loadConfig as g}from"tsconfig-paths";function a(t){let i=g(t);if(i?.resultType==="failed"||!Object.entries(i?.paths).length)return{baseAlias:null,styledSystemAlias:null};let s=null,n=null;for(let[o,e]of Object.entries(i.paths))e.includes("./styled-system/*")&&(n=o.replace(/\/\*$/,"")),(e.includes("./*")||e.includes("./src/*")||e.includes("./app/*"))&&(s=o.replace(/\/\*$/,""));return s||(s=Object.keys(i?.paths)?.[0].replace(/\/\*$/,"")??null),n||(n="."),{baseAlias:s,styledSystemAlias:n}}async function c(t){let i=await d.glob(["panda.config.*"],{cwd:t});return i.length?i[0]:null}var p="@pandacss/dev";async function l(t){let i=JSON.parse(u.readFileSync(h.join(t,"package.json"),"utf-8")),s=Object.keys(i.devDependencies).includes(p)||Object.keys(i.dependencies).includes(p),n=await c(t);return s&&!!n}import y from"path";import w from"fs-extra";async function f(t){return await w.pathExists(y.join(t,"components.json"))}import k from"fs-extra";import b from"path";async function m(){let t=await j();if(!t)throw new Error("Failed to find package root");if(await f(t))throw new Error("Already initialized");if(await l(t))throw new Error("install pandacss");let{baseAlias:n,styledSystemAlias:o}=a(t);if(!n||!o)throw new Error("Failed to find tsconfig alias");let e={utils:`${n}/utils`,components:`${n}/components`,hooks:`${n}/hooks`,styledsystem:o};await k.writeFile(b.resolve(t,"components.json"),JSON.stringify(e),"utf-8")}var I=async()=>x(A(process.argv)).command("init","initialize the project",()=>{},async()=>{r.note("Initializing project ...");try{await m()}catch(t){t instanceof Error&&r.cancel("Failed to initialize project: "+t.message)}});I();
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jongh/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "",
|
|
5
|
-
"main": "index.js",
|
|
6
5
|
"bin": "./dist/index.js",
|
|
7
6
|
"type": "module",
|
|
8
7
|
"keywords": [],
|
|
@@ -11,16 +10,27 @@
|
|
|
11
10
|
"publishConfig": {
|
|
12
11
|
"access": "public"
|
|
13
12
|
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"package.json"
|
|
16
|
+
],
|
|
14
17
|
"dependencies": {
|
|
18
|
+
"@babel/generator": "^7.26.3",
|
|
19
|
+
"@babel/parser": "^7.26.3",
|
|
20
|
+
"@babel/traverse": "^7.26.4",
|
|
15
21
|
"@clack/prompts": "^0.7.0",
|
|
16
22
|
"@effect/platform": "^0.69.13",
|
|
17
23
|
"@effect/schema": "^0.75.5",
|
|
24
|
+
"@types/babel__traverse": "^7.20.6",
|
|
18
25
|
"effect": "^3.10.8",
|
|
26
|
+
"fast-glob": "^3.3.2",
|
|
19
27
|
"fs-extra": "^11.2.0",
|
|
20
28
|
"pkg-dir": "^8.0.0",
|
|
29
|
+
"tsconfig-paths": "^4.2.0",
|
|
21
30
|
"yargs": "^17.7.2"
|
|
22
31
|
},
|
|
23
32
|
"devDependencies": {
|
|
33
|
+
"@types/babel__generator": "^7.6.8",
|
|
24
34
|
"@types/fs-extra": "^11.0.4",
|
|
25
35
|
"@types/node": "^22.8.6",
|
|
26
36
|
"@types/yargs": "^17.0.33",
|
|
@@ -30,6 +40,9 @@
|
|
|
30
40
|
},
|
|
31
41
|
"scripts": {
|
|
32
42
|
"build": "tsup",
|
|
33
|
-
"release": "pnpm publish -no-git-checks"
|
|
43
|
+
"release": "pnpm publish -no-git-checks",
|
|
44
|
+
"lint": "eslint . --max-warnings 0",
|
|
45
|
+
"check-type": "tsc --noEmit",
|
|
46
|
+
"test": "vitest"
|
|
34
47
|
}
|
|
35
48
|
}
|
package/.lintstagedrc.json
DELETED
package/CHANGELOG.md
DELETED
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { createContext } from "../../hooks/createContext"
|
|
3
|
-
import { useControlledState } from "../../hooks/useControllableState"
|
|
4
|
-
import { useKeyboardEvent } from "../../hooks/useKeyboardEvent"
|
|
5
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
6
|
-
import { composeRefs } from "src/hooks/useComposedRefs"
|
|
7
|
-
|
|
8
|
-
const ACCORDION_KEYS = [
|
|
9
|
-
"Home",
|
|
10
|
-
"End",
|
|
11
|
-
"ArrowDown",
|
|
12
|
-
"ArrowUp",
|
|
13
|
-
"ArrowLeft",
|
|
14
|
-
"ArrowRight",
|
|
15
|
-
]
|
|
16
|
-
export type TAccordionContext = {
|
|
17
|
-
selected?: string[]
|
|
18
|
-
onItemOpen: (value: string) => void
|
|
19
|
-
onItemClose: (value: string) => void
|
|
20
|
-
refs?: HTMLElement[]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const [AccordionProvider, useAccordionContext] =
|
|
24
|
-
createContext<TAccordionContext>("accordion")
|
|
25
|
-
|
|
26
|
-
export interface AccordionProps {
|
|
27
|
-
value?: string[]
|
|
28
|
-
defaultValue?: string[]
|
|
29
|
-
onValueChange?: (value: string[]) => void
|
|
30
|
-
asChild?: boolean
|
|
31
|
-
type?: "single" | "multi"
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
|
|
35
|
-
(props, ref) => {
|
|
36
|
-
const { type = "single", ...accordionProps } = props
|
|
37
|
-
if (type === "single") {
|
|
38
|
-
return <SingleAccordion {...accordionProps} ref={ref} />
|
|
39
|
-
}
|
|
40
|
-
if (type === "multi") {
|
|
41
|
-
return <MultiAccordion {...accordionProps} />
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
Accordion.displayName = "Accordion"
|
|
47
|
-
|
|
48
|
-
interface AccordionImplSingleProps {
|
|
49
|
-
value?: string[] // 현재 선택되어있는 item들을 담아놓는 용도
|
|
50
|
-
defaultValue?: string[]
|
|
51
|
-
onValueChange?: (value: string[]) => void
|
|
52
|
-
asChild?: boolean
|
|
53
|
-
children?: React.ReactNode
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const SingleAccordion = React.forwardRef<
|
|
57
|
-
HTMLDivElement,
|
|
58
|
-
AccordionImplSingleProps
|
|
59
|
-
>(
|
|
60
|
-
(
|
|
61
|
-
{ value, defaultValue = [], onValueChange, children, asChild, ...props },
|
|
62
|
-
forwardedRef,
|
|
63
|
-
) => {
|
|
64
|
-
const [selected = [], setSelected] = useControlledState({
|
|
65
|
-
prop: value,
|
|
66
|
-
defaultProp: defaultValue,
|
|
67
|
-
onChange: onValueChange,
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
const { refs: accordionRefs, handleKeyDown } = useKeyboardEvent({
|
|
71
|
-
keyList: ACCORDION_KEYS,
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
const Comp = asChild ? Slot : "div"
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<AccordionProvider
|
|
78
|
-
selected={selected}
|
|
79
|
-
onItemOpen={(value) => setSelected((_) => [value])}
|
|
80
|
-
onItemClose={() => setSelected((_) => [])}
|
|
81
|
-
refs={accordionRefs.current || []}
|
|
82
|
-
>
|
|
83
|
-
<Comp
|
|
84
|
-
ref={composeRefs((node) => {
|
|
85
|
-
accordionRefs.current = Array.from(
|
|
86
|
-
node?.children || [],
|
|
87
|
-
) as HTMLElement[]
|
|
88
|
-
}, forwardedRef)}
|
|
89
|
-
onKeyDown={(e) => {
|
|
90
|
-
handleKeyDown(e)
|
|
91
|
-
}}
|
|
92
|
-
{...props}
|
|
93
|
-
>
|
|
94
|
-
{children}
|
|
95
|
-
</Comp>
|
|
96
|
-
</AccordionProvider>
|
|
97
|
-
)
|
|
98
|
-
},
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
interface AccordionImplMultiProps {
|
|
102
|
-
value?: string[] // 현재 선택되어있는 item들을 담아놓는 용도
|
|
103
|
-
defaultValue?: string[]
|
|
104
|
-
onValueChange?: (value: string[]) => void
|
|
105
|
-
asChild?: boolean
|
|
106
|
-
children?: React.ReactNode
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const MultiAccordion = React.forwardRef<
|
|
110
|
-
HTMLDivElement,
|
|
111
|
-
AccordionImplMultiProps
|
|
112
|
-
>(
|
|
113
|
-
(
|
|
114
|
-
{ value, defaultValue, onValueChange, children, asChild, ...props },
|
|
115
|
-
forwardedRef,
|
|
116
|
-
) => {
|
|
117
|
-
const [selected, setSelected] = useControlledState({
|
|
118
|
-
prop: value,
|
|
119
|
-
defaultProp: defaultValue,
|
|
120
|
-
onChange: onValueChange,
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
const handleItemOpen = React.useCallback(
|
|
124
|
-
(item: string) => {
|
|
125
|
-
setSelected((prev = []) => [...prev, item])
|
|
126
|
-
},
|
|
127
|
-
[setSelected],
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
const handleItemClose = React.useCallback(
|
|
131
|
-
(item: string) =>
|
|
132
|
-
setSelected((prev = []) => prev.filter((value) => value !== item)),
|
|
133
|
-
[setSelected],
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
const { refs: accordionRefs, handleKeyDown } = useKeyboardEvent({
|
|
137
|
-
keyList: ACCORDION_KEYS,
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
const Comp = asChild ? Slot : "div"
|
|
141
|
-
|
|
142
|
-
return (
|
|
143
|
-
<AccordionProvider
|
|
144
|
-
selected={selected}
|
|
145
|
-
onItemOpen={handleItemOpen}
|
|
146
|
-
onItemClose={handleItemClose}
|
|
147
|
-
>
|
|
148
|
-
<Comp
|
|
149
|
-
ref={(node) => {
|
|
150
|
-
accordionRefs.current = Array.from(
|
|
151
|
-
node?.children || [],
|
|
152
|
-
) as HTMLElement[]
|
|
153
|
-
if (typeof forwardedRef === "function") {
|
|
154
|
-
forwardedRef(node)
|
|
155
|
-
} else if (forwardedRef) {
|
|
156
|
-
;(
|
|
157
|
-
forwardedRef as React.MutableRefObject<HTMLDivElement | null>
|
|
158
|
-
).current = node
|
|
159
|
-
}
|
|
160
|
-
}}
|
|
161
|
-
onKeyDown={handleKeyDown}
|
|
162
|
-
{...props}
|
|
163
|
-
>
|
|
164
|
-
{children}
|
|
165
|
-
</Comp>
|
|
166
|
-
</AccordionProvider>
|
|
167
|
-
)
|
|
168
|
-
},
|
|
169
|
-
)
|
|
170
|
-
//AccordionItem
|
|
171
|
-
interface TAccordionItemContext {
|
|
172
|
-
isOpen: boolean
|
|
173
|
-
onToggle: () => void
|
|
174
|
-
value?: string
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const [AccordionItemProvider, useAccordionItemProvider] =
|
|
178
|
-
createContext<TAccordionItemContext>("accordionItem")
|
|
179
|
-
export interface AccordionItemProps {
|
|
180
|
-
value: string //unique value
|
|
181
|
-
disabled?: boolean
|
|
182
|
-
children: React.ReactNode
|
|
183
|
-
asChild?: boolean
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export const AccordionItem = React.forwardRef<
|
|
187
|
-
HTMLDivElement,
|
|
188
|
-
AccordionItemProps
|
|
189
|
-
>(({ value, disabled = false, children, asChild, ...props }, forwardedRef) => {
|
|
190
|
-
const { selected, onItemOpen, onItemClose } = useAccordionContext("accordion")
|
|
191
|
-
|
|
192
|
-
const isOpen = selected?.includes(value) && !disabled
|
|
193
|
-
|
|
194
|
-
const onToggle = () => {
|
|
195
|
-
if (disabled) {
|
|
196
|
-
return
|
|
197
|
-
}
|
|
198
|
-
isOpen ? onItemClose(value) : onItemOpen(value)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const Comp = asChild ? Slot : "div"
|
|
202
|
-
|
|
203
|
-
return (
|
|
204
|
-
<AccordionItemProvider isOpen={!!isOpen} onToggle={onToggle} value={value}>
|
|
205
|
-
<Comp
|
|
206
|
-
ref={forwardedRef}
|
|
207
|
-
data-state={isOpen ? "open" : "close"}
|
|
208
|
-
tabIndex={0}
|
|
209
|
-
onKeyDown={(e) => {
|
|
210
|
-
if (e.key === "Enter") {
|
|
211
|
-
onToggle()
|
|
212
|
-
}
|
|
213
|
-
}}
|
|
214
|
-
{...props}
|
|
215
|
-
>
|
|
216
|
-
{children}
|
|
217
|
-
</Comp>
|
|
218
|
-
</AccordionItemProvider>
|
|
219
|
-
)
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
export interface AccordionTriggerProps extends React.PropsWithChildren {}
|
|
223
|
-
export const AccordionTrigger = ({
|
|
224
|
-
children,
|
|
225
|
-
...props
|
|
226
|
-
}: AccordionTriggerProps) => {
|
|
227
|
-
const { onToggle, isOpen, value } = useAccordionItemProvider("accordionItem")
|
|
228
|
-
return (
|
|
229
|
-
<h3 data-state={isOpen ? "open" : "close"} onClick={onToggle} {...props}>
|
|
230
|
-
<button
|
|
231
|
-
aria-expanded={isOpen ? "true" : "false"}
|
|
232
|
-
aria-controls={`content-${value}`}
|
|
233
|
-
id={`trigger-${value}`}
|
|
234
|
-
>
|
|
235
|
-
{children}
|
|
236
|
-
</button>
|
|
237
|
-
</h3>
|
|
238
|
-
)
|
|
239
|
-
}
|
|
240
|
-
//AccordionContent
|
|
241
|
-
export interface AccordionContentProps extends React.PropsWithChildren {
|
|
242
|
-
duration?: number
|
|
243
|
-
asChild?: boolean
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export const AccordionContent = ({
|
|
247
|
-
children,
|
|
248
|
-
asChild,
|
|
249
|
-
...props
|
|
250
|
-
}: AccordionContentProps) => {
|
|
251
|
-
const Comp = asChild ? Slot : "div"
|
|
252
|
-
const { isOpen, value } = useAccordionItemProvider("accordionItem")
|
|
253
|
-
const contentRef = React.useRef<HTMLDivElement>(null)
|
|
254
|
-
|
|
255
|
-
React.useEffect(() => {
|
|
256
|
-
if (contentRef.current) {
|
|
257
|
-
const element = contentRef.current
|
|
258
|
-
if (isOpen) {
|
|
259
|
-
element.style.setProperty(
|
|
260
|
-
"--accordion-height",
|
|
261
|
-
`${element.scrollHeight}px`,
|
|
262
|
-
)
|
|
263
|
-
} else {
|
|
264
|
-
element.style.setProperty("--accordion-height", "0px")
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}, [isOpen])
|
|
268
|
-
|
|
269
|
-
return (
|
|
270
|
-
<Comp
|
|
271
|
-
ref={contentRef}
|
|
272
|
-
data-state={isOpen ? "open" : "close"}
|
|
273
|
-
id={`content-${value}`}
|
|
274
|
-
aria-labelledby={`trigger-${value}`}
|
|
275
|
-
role="region"
|
|
276
|
-
{...props}
|
|
277
|
-
>
|
|
278
|
-
{isOpen && children}
|
|
279
|
-
</Comp>
|
|
280
|
-
)
|
|
281
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { accordion, type AccordionVariantProps } from "@styled-system/recipes"
|
|
2
|
-
import { createStyleContext } from "../../utils/createStyleContext"
|
|
3
|
-
import type { ComponentProps, HTMLStyledProps } from "@styled-system/types"
|
|
4
|
-
import type { Assign } from "../../types"
|
|
5
|
-
import {
|
|
6
|
-
Accordion as AccordionProvider,
|
|
7
|
-
AccordionContent,
|
|
8
|
-
AccordionItem,
|
|
9
|
-
AccordionTrigger,
|
|
10
|
-
type AccordionContentProps,
|
|
11
|
-
type AccordionItemProps,
|
|
12
|
-
type AccordionProps,
|
|
13
|
-
type AccordionTriggerProps,
|
|
14
|
-
} from "./Accordion"
|
|
15
|
-
|
|
16
|
-
const { withProvider, withContext } = createStyleContext(accordion)
|
|
17
|
-
|
|
18
|
-
export type RootProviderProps = ComponentProps<typeof AccordionProvider>
|
|
19
|
-
export const Accordion = withProvider<
|
|
20
|
-
HTMLDivElement,
|
|
21
|
-
Assign<Assign<HTMLStyledProps<"div">, AccordionProps>, AccordionVariantProps>
|
|
22
|
-
>(AccordionProvider, "root")
|
|
23
|
-
|
|
24
|
-
export const Item = withContext<
|
|
25
|
-
HTMLDivElement,
|
|
26
|
-
Assign<HTMLStyledProps<"div">, AccordionItemProps>
|
|
27
|
-
>(AccordionItem, "item")
|
|
28
|
-
|
|
29
|
-
export const Trigger = withContext<
|
|
30
|
-
HTMLButtonElement,
|
|
31
|
-
Assign<HTMLStyledProps<"button">, AccordionTriggerProps>
|
|
32
|
-
>(AccordionTrigger, "trigger")
|
|
33
|
-
|
|
34
|
-
export const Content = withContext<
|
|
35
|
-
HTMLDivElement,
|
|
36
|
-
Assign<HTMLStyledProps<"div">, AccordionContentProps>
|
|
37
|
-
>(AccordionContent, "content")
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from "react"
|
|
2
|
-
|
|
3
|
-
const ACCORDION_HEIGHT = "--accordion-height"
|
|
4
|
-
|
|
5
|
-
export const useAccordionHeight = <T extends HTMLElement>(isOpen: boolean) => {
|
|
6
|
-
const ref = useRef<T>(null)
|
|
7
|
-
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
const element = ref.current
|
|
10
|
-
if (!element) return
|
|
11
|
-
|
|
12
|
-
if (isOpen) {
|
|
13
|
-
// 열릴 때 높이를 scrollHeight로 설정
|
|
14
|
-
const newHeight = element.scrollHeight
|
|
15
|
-
element.style.setProperty(ACCORDION_HEIGHT, `${newHeight}px`)
|
|
16
|
-
element.style.height = `${newHeight}px`
|
|
17
|
-
} else {
|
|
18
|
-
// 닫힐 때 높이를 0으로 설정
|
|
19
|
-
element.style.setProperty(ACCORDION_HEIGHT, `0px`)
|
|
20
|
-
element.style.height = "0px"
|
|
21
|
-
}
|
|
22
|
-
}, [isOpen])
|
|
23
|
-
|
|
24
|
-
return ref
|
|
25
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
2
|
-
import { useAvatar, type UseAvatarStatusProps } from "./useAvatar"
|
|
3
|
-
import { forwardRef } from "react"
|
|
4
|
-
|
|
5
|
-
interface AvatarProps extends UseAvatarStatusProps {
|
|
6
|
-
asChild?: boolean
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const Avatar = forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => {
|
|
10
|
-
const { asChild, src, onStatusChange } = props
|
|
11
|
-
const { getRootProps, getImgProps } = useAvatar({ src, onStatusChange })
|
|
12
|
-
const Comp = asChild ? Slot : "span"
|
|
13
|
-
return (
|
|
14
|
-
<Comp ref={ref} {...getRootProps()}>
|
|
15
|
-
<img {...getImgProps()}></img>
|
|
16
|
-
</Comp>
|
|
17
|
-
)
|
|
18
|
-
})
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useLayoutEffect,
|
|
3
|
-
useState,
|
|
4
|
-
type ComponentProps,
|
|
5
|
-
type HTMLAttributes,
|
|
6
|
-
} from "react"
|
|
7
|
-
|
|
8
|
-
type Status = "loading" | "loaded" | "error"
|
|
9
|
-
|
|
10
|
-
export interface UseAvatarStatusProps {
|
|
11
|
-
src?: string
|
|
12
|
-
onStatusChange?: (status: Status) => void
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const useAvatarStatus = ({
|
|
16
|
-
src,
|
|
17
|
-
onStatusChange,
|
|
18
|
-
}: UseAvatarStatusProps) => {
|
|
19
|
-
const [status, setStatus] = useState<Status>("loading")
|
|
20
|
-
|
|
21
|
-
useLayoutEffect(() => {
|
|
22
|
-
if (!src) {
|
|
23
|
-
setStatus("error")
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
let isMounted: boolean = true
|
|
27
|
-
const image = new window.Image()
|
|
28
|
-
|
|
29
|
-
const updateStatus = (status: Status) => () => {
|
|
30
|
-
if (!isMounted) return
|
|
31
|
-
setStatus(status)
|
|
32
|
-
onStatusChange?.(status)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
setStatus("loading")
|
|
36
|
-
|
|
37
|
-
image.src = src
|
|
38
|
-
image.onload = updateStatus("loaded")
|
|
39
|
-
image.onerror = updateStatus("error")
|
|
40
|
-
|
|
41
|
-
return () => {
|
|
42
|
-
isMounted = false
|
|
43
|
-
}
|
|
44
|
-
}, [src])
|
|
45
|
-
|
|
46
|
-
return status
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
type DataAttr = Record<`data-${string}`, string | undefined>
|
|
50
|
-
|
|
51
|
-
const elementProps = (props: HTMLAttributes<HTMLElement> & DataAttr) => props
|
|
52
|
-
|
|
53
|
-
const imgProps = (props: ComponentProps<"img"> & DataAttr) => props
|
|
54
|
-
|
|
55
|
-
interface UseAvatarProps extends UseAvatarStatusProps {}
|
|
56
|
-
export const useAvatar = ({ src, onStatusChange }: UseAvatarProps) => {
|
|
57
|
-
const status = useAvatarStatus({ src, onStatusChange })
|
|
58
|
-
const isLoaded = status === "loaded"
|
|
59
|
-
return {
|
|
60
|
-
getRootProps() {
|
|
61
|
-
return elementProps({
|
|
62
|
-
"data-loading-state": status,
|
|
63
|
-
})
|
|
64
|
-
},
|
|
65
|
-
getImgProps() {
|
|
66
|
-
return imgProps({
|
|
67
|
-
hidden: !isLoaded,
|
|
68
|
-
"data-visible": `${isLoaded}`,
|
|
69
|
-
src,
|
|
70
|
-
})
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { forwardRef, ComponentPropsWithoutRef, type ReactNode } from "react"
|
|
2
|
-
import { button, type ButtonVariant } from "@styled-system/recipes"
|
|
3
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
4
|
-
import { cx } from "@styled-system/css"
|
|
5
|
-
|
|
6
|
-
export type ButtonProps = ComponentPropsWithoutRef<"button"> & {
|
|
7
|
-
children: ReactNode
|
|
8
|
-
as?: boolean
|
|
9
|
-
disabled?: boolean
|
|
10
|
-
} & Partial<ButtonVariant>
|
|
11
|
-
|
|
12
|
-
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
13
|
-
({ as, disabled, id, onClick, children, ...rest }, ref) => {
|
|
14
|
-
const [buttonProps] = button.splitVariantProps(rest)
|
|
15
|
-
|
|
16
|
-
const Comp = as ? Slot : "button"
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<Comp
|
|
20
|
-
role="button"
|
|
21
|
-
ref={ref}
|
|
22
|
-
disabled={disabled}
|
|
23
|
-
id={id}
|
|
24
|
-
onClick={onClick}
|
|
25
|
-
className={cx(button(buttonProps))}
|
|
26
|
-
{...rest}
|
|
27
|
-
>
|
|
28
|
-
{children}
|
|
29
|
-
</Comp>
|
|
30
|
-
)
|
|
31
|
-
},
|
|
32
|
-
)
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
//radix ui Primitive를 참고하여 작성한 코드
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
5
|
-
|
|
6
|
-
const NODES = [
|
|
7
|
-
"a",
|
|
8
|
-
"button",
|
|
9
|
-
"div",
|
|
10
|
-
"form",
|
|
11
|
-
"h2",
|
|
12
|
-
"h3",
|
|
13
|
-
"img",
|
|
14
|
-
"input",
|
|
15
|
-
"label",
|
|
16
|
-
"li",
|
|
17
|
-
"nav",
|
|
18
|
-
"ol",
|
|
19
|
-
"p",
|
|
20
|
-
"span",
|
|
21
|
-
"svg",
|
|
22
|
-
"ul",
|
|
23
|
-
] as const
|
|
24
|
-
|
|
25
|
-
type Primitives = {
|
|
26
|
-
[E in (typeof NODES)[number]]: PrimitiveForwardRefComponent<E>
|
|
27
|
-
}
|
|
28
|
-
type PrimitivePropsWithRef<E extends React.ElementType> =
|
|
29
|
-
React.ComponentPropsWithRef<E> & {
|
|
30
|
-
asChild?: boolean
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
interface PrimitiveForwardRefComponent<E extends React.ElementType>
|
|
34
|
-
extends React.ForwardRefExoticComponent<PrimitivePropsWithRef<E>> {}
|
|
35
|
-
|
|
36
|
-
/* -------------------------------------------------------------------------------------------------
|
|
37
|
-
* Primitive
|
|
38
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
39
|
-
|
|
40
|
-
const Primitive = NODES.reduce((primitive, node) => {
|
|
41
|
-
const Node = React.forwardRef(
|
|
42
|
-
(props: PrimitivePropsWithRef<typeof node>, forwardedRef: any) => {
|
|
43
|
-
const { asChild, ...primitiveProps } = props
|
|
44
|
-
const Comp: any = asChild ? Slot : node
|
|
45
|
-
|
|
46
|
-
return <Comp {...primitiveProps} ref={forwardedRef} />
|
|
47
|
-
},
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
Node.displayName = `Primitive.${node}`
|
|
51
|
-
|
|
52
|
-
return { ...primitive, [node]: Node }
|
|
53
|
-
}, {} as Primitives)
|
|
54
|
-
|
|
55
|
-
const Root = Primitive
|
|
56
|
-
|
|
57
|
-
export { Primitive, Root }
|
|
58
|
-
export type { PrimitivePropsWithRef }
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { ReactElement } from "react"
|
|
2
|
-
import { useRovingTabIndex } from "./useRovingTabIndex"
|
|
3
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
4
|
-
import isHotkey from "is-hotkey"
|
|
5
|
-
import {
|
|
6
|
-
getNextFocusableId,
|
|
7
|
-
getPrevFocusableId,
|
|
8
|
-
} from "../../utils/getFocusableId"
|
|
9
|
-
|
|
10
|
-
export const RovingItem = ({
|
|
11
|
-
value,
|
|
12
|
-
children,
|
|
13
|
-
}: {
|
|
14
|
-
value: string
|
|
15
|
-
children: ReactElement
|
|
16
|
-
}) => {
|
|
17
|
-
const { getOrderedItems, getRovingProps, dir } = useRovingTabIndex(value)
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<Slot
|
|
21
|
-
{...getRovingProps<"button">({
|
|
22
|
-
onKeyDown: (e) => {
|
|
23
|
-
const items = getOrderedItems()
|
|
24
|
-
let nextItem
|
|
25
|
-
if (dir === "horizontal") {
|
|
26
|
-
if (isHotkey("right", e)) {
|
|
27
|
-
nextItem = getNextFocusableId(items, value)
|
|
28
|
-
} else if (isHotkey("left", e)) {
|
|
29
|
-
nextItem = getPrevFocusableId(items, value)
|
|
30
|
-
}
|
|
31
|
-
nextItem?.element.focus()
|
|
32
|
-
}
|
|
33
|
-
if (dir === "vertical") {
|
|
34
|
-
if (e.key === "ArrowDown") {
|
|
35
|
-
nextItem = getNextFocusableId(items, value)
|
|
36
|
-
} else if (e.key === "ArrowUp") {
|
|
37
|
-
nextItem = getPrevFocusableId(items, value)
|
|
38
|
-
}
|
|
39
|
-
nextItem?.element.focus()
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
})}
|
|
43
|
-
>
|
|
44
|
-
{children}
|
|
45
|
-
</Slot>
|
|
46
|
-
)
|
|
47
|
-
}
|