@ilokesto/utilinent 0.0.26 → 1.0.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.
- package/README.md +59 -254
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,285 +1,90 @@
|
|
|
1
|
-
|
|
1
|
+
[](https://bundlephobia.com/result?p=@ilokesto/utilinent)
|
|
2
|
+
[](https://www.npmjs.com/package/@ilokesto/utilinent)
|
|
3
|
+
[](https://www.npmjs.com/package/@ilokesto/utilinent)
|
|
2
4
|
|
|
3
|
-
React를 위한 유용하고 재사용 가능한 컴포넌트 및 훅 모음입니다.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
[Official documents](https://ilokesto.vercel.app/utilinent)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
npm install @ilokesto/utilinent
|
|
13
|
-
# 또는
|
|
14
|
-
yarn add @ilokesto/utilinent
|
|
15
|
-
# 또는
|
|
16
|
-
pnpm add @ilokesto/utilinent
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## 주요 기능
|
|
20
|
-
|
|
21
|
-
### 기본 컴포넌트
|
|
22
|
-
|
|
23
|
-
기본적으로 다음 컴포넌트들을 가져와 사용할 수 있습니다.
|
|
24
|
-
|
|
25
|
-
```tsx
|
|
26
|
-
import { Show, For, Repeat, Observer, OptionalWrapper, useIntersectionObserver } from '@ilokesto/utilinent';
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
#### `<Show>`
|
|
30
|
-
|
|
31
|
-
조건부 렌더링을 위한 컴포넌트입니다. `when` prop이 `true`일 때만 `children`을 렌더링합니다.
|
|
32
|
-
|
|
33
|
-
또한, `Show.div`, `Show.span`과 같이 HTML 태그를 직접 사용하여 래퍼(wrapper) 컴포넌트를 지정할 수 있습니다. 이 경우, `when` prop이 `true`일 때 해당 태그로 감싸진 `children`이 렌더링됩니다.
|
|
34
|
-
|
|
35
|
-
**사용 예시:**
|
|
36
|
-
|
|
37
|
-
```tsx
|
|
38
|
-
import { Show } from '@ilokesto/utilinent';
|
|
39
|
-
|
|
40
|
-
function UserProfile({ user }) {
|
|
41
|
-
return (
|
|
42
|
-
<div>
|
|
43
|
-
<Show when={user.isLoggedIn} fallback={<div>로그인이 필요합니다.</div>}>
|
|
44
|
-
<h1>{user.name}님, 환영합니다!</h1>
|
|
45
|
-
</Show>
|
|
46
|
-
|
|
47
|
-
{/* HTML 태그와 함께 사용 */}
|
|
48
|
-
<Show.div when={user.isAdmin} className="admin-badge">
|
|
49
|
-
관리자
|
|
50
|
-
</Show.div>
|
|
51
|
-
</div>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
#### `<For>`
|
|
57
|
-
|
|
58
|
-
배열을 순회하며 각 항목을 렌더링합니다. `Array.prototype.map`과 유사하지만, 배열이 비어있을 경우를 위한 `fallback`을 지원합니다.
|
|
12
|
+
As React apps grow, JSX often becomes cluttered with nested ternary operators and bloated map callbacks, which rapidly degrades readability. utilinent was created to solve these recurring UI patterns by providing small, declarative components.
|
|
59
13
|
|
|
60
|
-
|
|
14
|
+
Inspired by the concise and expressive style of SolidJS, utilinent encapsulates common tasks — conditional rendering, list rendering, and lazy loading — into clear APIs. For example, replace complex ternaries with a `Show` component, or use `For` to render arrays along with a built-in fallback for empty data.
|
|
61
15
|
|
|
62
|
-
|
|
16
|
+
By moving noisy logic out of views and into reusable components, utilinent improves readability, maintainability, and lets developers focus more on business logic while boosting team productivity.
|
|
63
17
|
|
|
64
|
-
|
|
65
|
-
import { For } from '@ilokesto/utilinent';
|
|
66
|
-
|
|
67
|
-
function TodoList({ todos }) {
|
|
68
|
-
return (
|
|
69
|
-
<For.ul each={todos} fallback={<li>할 일이 없습니다.</li>} className="todo-list">
|
|
70
|
-
{(todo, index) => <li key={index}>{todo.text}</li>}
|
|
71
|
-
</For.ul>
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
#### `<Repeat>`
|
|
77
|
-
|
|
78
|
-
주어진 횟수(`times`)만큼 `children` 함수를 반복하여 렌더링합니다.
|
|
18
|
+
|
|
79
19
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
**사용 예시:**
|
|
83
|
-
|
|
84
|
-
```tsx
|
|
85
|
-
import { Repeat } from '@ilokesto/utilinent';
|
|
86
|
-
|
|
87
|
-
function StarRating({ rating }) {
|
|
88
|
-
return (
|
|
89
|
-
<Repeat.div times={rating} className="star-container">
|
|
90
|
-
{(index) => <span key={index}>⭐️</span>}
|
|
91
|
-
</Repeat.div>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
```
|
|
20
|
+
## Installation
|
|
95
21
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
컴포넌트가 화면에 보일 때(intersect) `children`을 렌더링합니다. Intersection Observer API를 기반으로 하며, 지연 로딩(lazy loading) 구현에 유용합니다.
|
|
99
|
-
|
|
100
|
-
**사용 예시:**
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
import { Observer } from '@ilokesto/utilinent';
|
|
104
|
-
|
|
105
|
-
function LazyComponent() {
|
|
106
|
-
return (
|
|
107
|
-
<Observer fallback={<div>로딩 중...</div>}>
|
|
108
|
-
{/* 화면에 보일 때 렌더링될 무거운 컴포넌트 */}
|
|
109
|
-
<HeavyComponent />
|
|
110
|
-
</Observer>
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
#### `<OptionalWrapper>`
|
|
116
|
-
|
|
117
|
-
`when` prop이 `true`일 때만 `children`을 `wrapper` 함수로 감싸줍니다.
|
|
118
|
-
|
|
119
|
-
**사용 예시:**
|
|
120
|
-
|
|
121
|
-
```tsx
|
|
122
|
-
import { OptionalWrapper } from '@ilokesto/utilinent';
|
|
22
|
+
utilinent can be installed using several methods listed below.
|
|
123
23
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
>
|
|
130
|
-
<h2>{post.title}</h2>
|
|
131
|
-
<p>{post.summary}</p>
|
|
132
|
-
</OptionalWrapper>
|
|
133
|
-
);
|
|
134
|
-
}
|
|
24
|
+
```bash
|
|
25
|
+
npm install @ilokesto/utilinent
|
|
26
|
+
pnpm add @ilokesto/utilinent
|
|
27
|
+
yarn add @ilokesto/utilinent
|
|
28
|
+
bun add @ilokesto/utilinent
|
|
135
29
|
```
|
|
136
30
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
#### `useIntersectionObserver`
|
|
31
|
+
|
|
140
32
|
|
|
141
|
-
|
|
33
|
+
## Quick start
|
|
142
34
|
|
|
143
|
-
|
|
35
|
+
When handling async data in React, it's common to render different UI for loading, empty, or populated states. The examples below show typical patterns and how utilinent components simplify them.
|
|
144
36
|
|
|
145
37
|
```tsx
|
|
146
|
-
import {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const { ref, isIntersecting } = useIntersectionObserver({ threshold: 0.5 });
|
|
38
|
+
import React, { useState, useEffect } from 'react';
|
|
39
|
+
|
|
40
|
+
const UserList = () => {
|
|
41
|
+
const { data: users } = useQuery( ... )
|
|
151
42
|
|
|
152
43
|
return (
|
|
153
|
-
<div
|
|
154
|
-
|
|
44
|
+
<div>
|
|
45
|
+
<h2>User List</h2>
|
|
46
|
+
{loading ? (
|
|
47
|
+
<p>Loading users...</p>
|
|
48
|
+
) : (
|
|
49
|
+
users.length > 0 ? (
|
|
50
|
+
<ul>
|
|
51
|
+
{users.map(user => (
|
|
52
|
+
<li key={user.id}>{user.name}</li>
|
|
53
|
+
))}
|
|
54
|
+
</ul>
|
|
55
|
+
) : (
|
|
56
|
+
<p>No users found.</p>
|
|
57
|
+
)
|
|
58
|
+
)}
|
|
155
59
|
</div>
|
|
156
60
|
);
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### 실험적 기능
|
|
161
|
-
|
|
162
|
-
실험적인 컴포넌트 및 훅은 `experimental` 경로에서 가져올 수 있습니다. 이 기능들은 API가 변경될 수 있습니다.
|
|
163
|
-
|
|
164
|
-
```tsx
|
|
165
|
-
import { Mount, Slacker, createSwitcher, Slot, Slottable } from '@ilokesto/utilinent/experimental';
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
#### `<Slot>` 및 `<Slottable>`
|
|
169
|
-
|
|
170
|
-
자식 컴포넌트에 props를 전달하고 병합하는 Radix UI의 `<Slot>`과 유사한 패턴을 구현합니다. `<Slot>`은 자신의 props를 자식 요소에 병합합니다. 여러 자식 중 특정 자식에게 props를 전달하고 싶을 때는 `<Slottable>`로 감싸주면 됩니다.
|
|
171
|
-
|
|
172
|
-
Props 병합 규칙은 다음과 같습니다:
|
|
173
|
-
* **`className`**: 부모와 자식의 `className`이 합쳐집니다.
|
|
174
|
-
* **`style`**: 부모와 자식의 `style` 객체가 병합됩니다 (부모 우선).
|
|
175
|
-
* **이벤트 핸들러**: 부모와 자식의 이벤트 핸들러가 모두 순차적으로 호출됩니다.
|
|
176
|
-
* **`ref`**: 부모와 자식의 `ref`가 모두 연결됩니다.
|
|
177
|
-
* **기타 props**: 부모의 props가 자식의 props를 덮어씁니다.
|
|
178
|
-
|
|
179
|
-
**사용 예시:**
|
|
180
|
-
|
|
181
|
-
```tsx
|
|
182
|
-
import { Slot, Slottable } from '@ilokesto/utilinent/experimental';
|
|
183
|
-
|
|
184
|
-
const Button = ({ asChild = false, ...props }) => {
|
|
185
|
-
const Comp = asChild ? Slot : 'button';
|
|
186
|
-
return <Comp {...props} />;
|
|
187
61
|
};
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
<Button onClick={() => alert('Clicked!')}>Click Me</Button>
|
|
191
|
-
|
|
192
|
-
// 다른 컴포넌트(a 태그)를 렌더링하면서 props를 전달
|
|
193
|
-
<Button asChild>
|
|
194
|
-
<a href="/home">Go Home</a>
|
|
195
|
-
</Button>
|
|
196
|
-
|
|
197
|
-
// 여러 자식 중 특정 자식에게 props 전달
|
|
198
|
-
<Button asChild>
|
|
199
|
-
<div>
|
|
200
|
-
<span>Icon</span>
|
|
201
|
-
<Slottable>Text</Slottable>
|
|
202
|
-
</div>
|
|
203
|
-
</Button>
|
|
62
|
+
|
|
63
|
+
export default UserList;
|
|
204
64
|
```
|
|
205
65
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
컴포넌트가 마운트될 때 비동기적으로 `children`을 렌더링합니다. `children`으로 비동기 함수를 전달할 수 있습니다.
|
|
209
|
-
|
|
210
|
-
**사용 예시:**
|
|
211
|
-
|
|
212
|
-
```tsx
|
|
213
|
-
import { Mount } from '@ilokesto/utilinent/experimental';
|
|
214
|
-
|
|
215
|
-
function AsyncComponent() {
|
|
216
|
-
return (
|
|
217
|
-
<Mount fallback={<div>로딩 중...</div>}>
|
|
218
|
-
{async () => {
|
|
219
|
-
const { HeavyComponent } = await import('./HeavyComponent');
|
|
220
|
-
return <HeavyComponent />;
|
|
221
|
-
}}
|
|
222
|
-
</Mount>
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
#### `<Slacker>`
|
|
228
|
-
|
|
229
|
-
컴포넌트나 데이터의 지연 로딩(lazy loading)을 위한 고급 컴포넌트입니다. 뷰포트에 들어왔을 때 `loader` 함수를 실행하여 비동기 작업을 처리하고, 로딩이 완료되면 결과를 `children`에게 전달하여 렌더링합니다.
|
|
230
|
-
|
|
231
|
-
**사용 예시:**
|
|
232
|
-
|
|
233
|
-
```tsx
|
|
234
|
-
import { Slacker } from '@ilokesto/utilinent/experimental';
|
|
235
|
-
|
|
236
|
-
// 데이터 지연 로딩
|
|
237
|
-
function LazyUserData({ userId }) {
|
|
238
|
-
return (
|
|
239
|
-
<Slacker
|
|
240
|
-
fallback={<div>사용자 정보 로딩 중...</div>}
|
|
241
|
-
loader={async () => {
|
|
242
|
-
const response = await fetch(`/api/users/${userId}`);
|
|
243
|
-
return response.json();
|
|
244
|
-
}}
|
|
245
|
-
>
|
|
246
|
-
{(user) => (
|
|
247
|
-
<div>
|
|
248
|
-
<h1>{user.name}</h1>
|
|
249
|
-
<p>{user.email}</p>
|
|
250
|
-
</div>
|
|
251
|
-
)}
|
|
252
|
-
</Slacker>
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
#### `createSwitcher` / `<Switch>` / `<Match>`
|
|
258
|
-
|
|
259
|
-
주어진 데이터와 조건에 따라 여러 `<Match>` 컴포넌트 중 하나를 선택하여 렌더링합니다. `createSwitcher` 팩토리 함수를 통해 `<Switch>`와 `<Match>` 컴포넌트를 생성하여 사용합니다.
|
|
260
|
-
|
|
261
|
-
**사용 예시:**
|
|
66
|
+
utilinent's `Show` and `For` components make conditional and list rendering more declarative and concise. They help express loading and list states clearly so your UI intent is easier to read and maintain.
|
|
262
67
|
|
|
263
68
|
```tsx
|
|
264
|
-
import {
|
|
69
|
+
import React, { useState, useEffect } from 'react';
|
|
70
|
+
import { Show, For } from '@ilokesto/utilinent';
|
|
265
71
|
|
|
266
|
-
const
|
|
267
|
-
const {
|
|
72
|
+
const UserListAfter = () => {
|
|
73
|
+
const { data: users } = useQuery( ... )
|
|
268
74
|
|
|
269
|
-
function Media() {
|
|
270
75
|
return (
|
|
271
|
-
<
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
76
|
+
<div>
|
|
77
|
+
<h2>User List</h2>
|
|
78
|
+
<Show when={!loading} fallback={<p>Loading users...</p>}>
|
|
79
|
+
<For.ul each={users} fallback={<p>No users found.</p>}>
|
|
80
|
+
{(user) => (
|
|
81
|
+
<li key={user.id}>{user.name}</li>
|
|
82
|
+
)}
|
|
83
|
+
</For.ul>
|
|
84
|
+
</Show>
|
|
85
|
+
</div>
|
|
279
86
|
);
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
## 라이선스
|
|
87
|
+
};
|
|
284
88
|
|
|
285
|
-
|
|
89
|
+
export default UserListAfter;
|
|
90
|
+
```
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ilokesto/utilinent",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/ilokesto/utilinent.git"
|
|
7
7
|
},
|
|
8
|
+
"homepage": "https://ilokesto.vercel.app/utilinent",
|
|
8
9
|
"sideEffects": false,
|
|
9
10
|
"types": "dist/index.d.ts",
|
|
10
11
|
"module": "dist/index.js",
|