@ilokesto/utilinent 1.0.14 → 1.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.
- package/dist/components/For.js +7 -43
- package/dist/components/Mount.d.ts +2 -0
- package/dist/components/Mount.js +70 -0
- package/dist/components/OptionalWrapper.d.ts +1 -1
- package/dist/components/Repeat.js +8 -44
- package/dist/components/Show.js +5 -42
- package/dist/components/Switch.d.ts +4 -0
- package/dist/components/Switch.js +39 -0
- package/dist/core/PluginManager.d.ts +6 -5
- package/dist/core/PluginManager.js +2 -0
- package/dist/core/createTagProxy.d.ts +3 -0
- package/dist/core/createTagProxy.js +30 -0
- package/dist/core/tagProxyTypes.d.ts +1 -0
- package/dist/core/tagProxyTypes.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/types/for.d.ts +0 -2
- package/dist/types/index.d.ts +3 -7
- package/dist/types/mount.d.ts +20 -0
- package/dist/types/mount.js +1 -0
- package/dist/types/register.d.ts +6 -0
- package/dist/types/switch.d.ts +27 -0
- package/dist/types/switch.js +1 -0
- package/dist/utils/resolveWhen.d.ts +1 -0
- package/dist/utils/resolveWhen.js +1 -0
- package/package.json +1 -5
- package/dist/experimental/Mount.d.ts +0 -2
- package/dist/experimental/Mount.js +0 -8
- package/dist/experimental/Switch.d.ts +0 -8
- package/dist/experimental/Switch.js +0 -21
- package/dist/experimental.d.ts +0 -2
- package/dist/experimental.js +0 -2
package/dist/components/For.js
CHANGED
|
@@ -1,48 +1,12 @@
|
|
|
1
|
-
import { Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
import { createElement, forwardRef } from "react";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const content = each && each.length > 0 ? each.map(children) : fallback;
|
|
7
|
-
return (_jsxs(_Fragment, { children: [before, content, after] }));
|
|
2
|
+
import { createTagProxy } from "../core/createTagProxy";
|
|
3
|
+
function BaseFor({ each, children, fallback = null, }) {
|
|
4
|
+
return each && each.length > 0 ? each.map(children) : fallback;
|
|
8
5
|
}
|
|
9
6
|
const renderForTag = (tag) =>
|
|
10
7
|
// forward ref so consumers can attach a ref to the underlying DOM element
|
|
11
|
-
forwardRef(({ each, children, fallback = null,
|
|
12
|
-
const content =
|
|
13
|
-
return createElement(tag, { ...props, ref },
|
|
14
|
-
});
|
|
15
|
-
// HTML 태그들을 등록
|
|
16
|
-
const tagEntries = htmlTags.reduce((acc, tag) => {
|
|
17
|
-
acc[tag] = renderForTag(tag);
|
|
18
|
-
return acc;
|
|
19
|
-
}, {});
|
|
20
|
-
// Proxy를 사용하여 동적으로 플러그인 조회
|
|
21
|
-
export const For = new Proxy(Object.assign(BaseFor, tagEntries), {
|
|
22
|
-
get(target, prop) {
|
|
23
|
-
// 기존 속성이 있으면 반환
|
|
24
|
-
if (prop in target) {
|
|
25
|
-
return target[prop];
|
|
26
|
-
}
|
|
27
|
-
// 플러그인에서 동적으로 조회
|
|
28
|
-
const propName = String(prop);
|
|
29
|
-
// 'for' 카테고리에서 먼저 찾기
|
|
30
|
-
if (PluginManager.has('for', propName)) {
|
|
31
|
-
const component = PluginManager.get('for', propName);
|
|
32
|
-
const specialized = renderForTag(component);
|
|
33
|
-
// 캐싱하여 다음 조회 시 동일한 참조 반환
|
|
34
|
-
target[prop] = specialized;
|
|
35
|
-
return specialized;
|
|
36
|
-
}
|
|
37
|
-
// 'base' 카테고리에서 찾기
|
|
38
|
-
if (PluginManager.has('base', propName)) {
|
|
39
|
-
const component = PluginManager.get('base', propName);
|
|
40
|
-
const specialized = renderForTag(component);
|
|
41
|
-
// 캐싱하여 다음 조회 시 동일한 참조 반환
|
|
42
|
-
target[prop] = specialized;
|
|
43
|
-
return specialized;
|
|
44
|
-
}
|
|
45
|
-
// 찾지 못하면 undefined 반환
|
|
46
|
-
return undefined;
|
|
47
|
-
}
|
|
8
|
+
forwardRef(({ each, children, fallback = null, ...props }, ref) => {
|
|
9
|
+
const content = BaseFor({ each, children, fallback });
|
|
10
|
+
return createElement(tag, { ...props, ref }, content);
|
|
48
11
|
});
|
|
12
|
+
export const For = createTagProxy(BaseFor, renderForTag, "for");
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createElement, forwardRef, useEffect, useLayoutEffect, useRef, useState, } from "react";
|
|
2
|
+
import { createTagProxy } from "../core/createTagProxy";
|
|
3
|
+
const isPromiseLike = (value) => (typeof value === "object" || typeof value === "function") &&
|
|
4
|
+
value !== null &&
|
|
5
|
+
typeof value.then === "function";
|
|
6
|
+
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
7
|
+
function BaseMount({ children, fallback = null, onError }) {
|
|
8
|
+
const isFunction = typeof children === "function";
|
|
9
|
+
const [resolvedChildren, setResolvedChildren] = useState(() => isFunction ? fallback : children);
|
|
10
|
+
const [status, setStatus] = useState(() => isFunction ? "fallback" : "resolved");
|
|
11
|
+
const callIdRef = useRef(0);
|
|
12
|
+
useIsomorphicLayoutEffect(() => {
|
|
13
|
+
const callId = ++callIdRef.current;
|
|
14
|
+
let canceled = false;
|
|
15
|
+
if (typeof children !== "function") {
|
|
16
|
+
setResolvedChildren(children);
|
|
17
|
+
setStatus("resolved");
|
|
18
|
+
return () => {
|
|
19
|
+
canceled = true;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
let result;
|
|
23
|
+
try {
|
|
24
|
+
result = children();
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
setStatus("fallback");
|
|
28
|
+
console.error("Mount children threw:", error);
|
|
29
|
+
onError?.(error);
|
|
30
|
+
return () => {
|
|
31
|
+
canceled = true;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (isPromiseLike(result)) {
|
|
35
|
+
setStatus("fallback");
|
|
36
|
+
result
|
|
37
|
+
.then((value) => {
|
|
38
|
+
if (canceled || callId !== callIdRef.current) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
setResolvedChildren(value);
|
|
42
|
+
setStatus("resolved");
|
|
43
|
+
})
|
|
44
|
+
.catch((error) => {
|
|
45
|
+
if (canceled || callId !== callIdRef.current) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
setStatus("fallback");
|
|
49
|
+
console.error("Mount children promise rejected:", error);
|
|
50
|
+
onError?.(error);
|
|
51
|
+
});
|
|
52
|
+
return () => {
|
|
53
|
+
canceled = true;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
setResolvedChildren(result);
|
|
57
|
+
setStatus("resolved");
|
|
58
|
+
return () => {
|
|
59
|
+
canceled = true;
|
|
60
|
+
};
|
|
61
|
+
}, [children, onError]);
|
|
62
|
+
return status === "resolved" ? resolvedChildren : fallback;
|
|
63
|
+
}
|
|
64
|
+
const renderForTag = (tag) =>
|
|
65
|
+
// forward ref so consumers can attach a ref to the underlying DOM element
|
|
66
|
+
forwardRef(function Render({ children, fallback = null, onError, ...props }, ref) {
|
|
67
|
+
const content = BaseMount({ children, fallback, onError });
|
|
68
|
+
return createElement(tag, { ...props, ref }, content);
|
|
69
|
+
});
|
|
70
|
+
export const Mount = createTagProxy(BaseMount, renderForTag, "mount");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { OptionalWrapperProps } from "../types";
|
|
2
|
-
export declare function OptionalWrapper({ when, children, wrapper, fallback }: OptionalWrapperProps): React.ReactNode;
|
|
2
|
+
export declare function OptionalWrapper<T>({ when, children, wrapper, fallback }: OptionalWrapperProps<T>): React.ReactNode;
|
|
@@ -1,52 +1,16 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createElement, forwardRef } from "react";
|
|
3
|
-
import {
|
|
4
|
-
import { PluginManager } from "../core/PluginManager";
|
|
5
|
-
import { For } from "./For";
|
|
3
|
+
import { createTagProxy } from "../core/createTagProxy";
|
|
6
4
|
function BaseRepeat({ times, children, fallback = null }) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return _jsx(
|
|
5
|
+
const content = times && times > 0 && Number.isInteger(times)
|
|
6
|
+
? Array.from({ length: times }, (_, i) => children(i))
|
|
7
|
+
: fallback ?? null;
|
|
8
|
+
return _jsx(_Fragment, { children: content });
|
|
11
9
|
}
|
|
12
10
|
const renderForTag = (tag) =>
|
|
13
11
|
// forward ref so consumers can attach a ref to the underlying DOM element
|
|
14
12
|
forwardRef(({ times, children, fallback = null, ...props }, ref) => {
|
|
15
|
-
const content =
|
|
16
|
-
? Array.from({ length: times }, (_, i) => children(i))
|
|
17
|
-
: fallback ?? null;
|
|
13
|
+
const content = BaseRepeat({ times, children, fallback });
|
|
18
14
|
return createElement(tag, { ...props, ref }, content);
|
|
19
15
|
});
|
|
20
|
-
|
|
21
|
-
const tagEntries = htmlTags.reduce((acc, tag) => {
|
|
22
|
-
acc[tag] = renderForTag(tag);
|
|
23
|
-
return acc;
|
|
24
|
-
}, {});
|
|
25
|
-
export const Repeat = new Proxy(Object.assign(BaseRepeat, tagEntries), {
|
|
26
|
-
get(target, prop) {
|
|
27
|
-
// 기존 속성이 있으면 반환
|
|
28
|
-
if (prop in target) {
|
|
29
|
-
return target[prop];
|
|
30
|
-
}
|
|
31
|
-
// 플러그인에서 동적으로 조회
|
|
32
|
-
const propName = String(prop);
|
|
33
|
-
// 'repeat' 카테고리에서 먼저 찾기
|
|
34
|
-
if (PluginManager.has('repeat', propName)) {
|
|
35
|
-
const component = PluginManager.get('repeat', propName);
|
|
36
|
-
const specialized = renderForTag(component);
|
|
37
|
-
// 캐싱하여 다음 조회 시 동일한 참조 반환
|
|
38
|
-
target[prop] = specialized;
|
|
39
|
-
return specialized;
|
|
40
|
-
}
|
|
41
|
-
// 'base' 카테고리에서 찾기
|
|
42
|
-
if (PluginManager.has('base', propName)) {
|
|
43
|
-
const component = PluginManager.get('base', propName);
|
|
44
|
-
const specialized = renderForTag(component);
|
|
45
|
-
// 캐싱하여 다음 조회 시 동일한 참조 반환
|
|
46
|
-
target[prop] = specialized;
|
|
47
|
-
return specialized;
|
|
48
|
-
}
|
|
49
|
-
// 찾지 못하면 undefined 반환
|
|
50
|
-
return undefined;
|
|
51
|
-
}
|
|
52
|
-
});
|
|
16
|
+
export const Repeat = createTagProxy(BaseRepeat, renderForTag, "repeat");
|
package/dist/components/Show.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createElement, forwardRef } from "react";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createTagProxy } from "../core/createTagProxy";
|
|
3
|
+
import { resolveWhen } from "../utils/resolveWhen";
|
|
4
4
|
const BaseShow = ({ when, children, fallback = null }) => {
|
|
5
|
-
const shouldRender =
|
|
5
|
+
const shouldRender = resolveWhen(when);
|
|
6
6
|
return shouldRender
|
|
7
7
|
? typeof children === "function"
|
|
8
8
|
? children(when)
|
|
@@ -12,44 +12,7 @@ const BaseShow = ({ when, children, fallback = null }) => {
|
|
|
12
12
|
const renderForTag = (tag) =>
|
|
13
13
|
// forward ref so consumers like Observer can pass a ref to the real DOM element
|
|
14
14
|
forwardRef(function Render({ when, children, fallback = null, ...props }, ref) {
|
|
15
|
-
const
|
|
16
|
-
const content = shouldRender
|
|
17
|
-
? typeof children === "function"
|
|
18
|
-
? children(when)
|
|
19
|
-
: children
|
|
20
|
-
: fallback;
|
|
15
|
+
const content = BaseShow({ when, children, fallback });
|
|
21
16
|
return createElement(tag, { ...props, ref }, content);
|
|
22
17
|
});
|
|
23
|
-
|
|
24
|
-
const tagEntries = htmlTags.reduce((acc, tag) => {
|
|
25
|
-
acc[tag] = renderForTag(tag);
|
|
26
|
-
return acc;
|
|
27
|
-
}, {});
|
|
28
|
-
export const Show = new Proxy(Object.assign(BaseShow, tagEntries), {
|
|
29
|
-
get(target, prop) {
|
|
30
|
-
// 기존 속성이 있으면 반환
|
|
31
|
-
if (prop in target) {
|
|
32
|
-
return target[prop];
|
|
33
|
-
}
|
|
34
|
-
// 플러그인에서 동적으로 조회
|
|
35
|
-
const propName = String(prop);
|
|
36
|
-
// 'show' 카테고리에서 먼저 찾기
|
|
37
|
-
if (PluginManager.has('show', propName)) {
|
|
38
|
-
const component = PluginManager.get('show', propName);
|
|
39
|
-
const specialized = renderForTag(component);
|
|
40
|
-
// 캐싱하여 다음 조회 시 동일한 참조 반환
|
|
41
|
-
target[prop] = specialized;
|
|
42
|
-
return specialized;
|
|
43
|
-
}
|
|
44
|
-
// 'base' 카테고리에서 찾기
|
|
45
|
-
if (PluginManager.has('base', propName)) {
|
|
46
|
-
const component = PluginManager.get('base', propName);
|
|
47
|
-
const specialized = renderForTag(component);
|
|
48
|
-
// 캐싱하여 다음 조회 시 동일한 참조 반환
|
|
49
|
-
target[prop] = specialized;
|
|
50
|
-
return specialized;
|
|
51
|
-
}
|
|
52
|
-
// 찾지 못하면 undefined 반환
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
18
|
+
export const Show = createTagProxy(BaseShow, renderForTag, "show");
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Children, Fragment, createElement, forwardRef, isValidElement, } from "react";
|
|
3
|
+
import { createTagProxy } from "../core/createTagProxy";
|
|
4
|
+
import { resolveWhen } from "../utils/resolveWhen";
|
|
5
|
+
const flattenChildren = (nodes) => Children.toArray(nodes).flatMap((child) => {
|
|
6
|
+
if (isValidElement(child) && child.type === Fragment) {
|
|
7
|
+
return flattenChildren(child.props.children);
|
|
8
|
+
}
|
|
9
|
+
return [child];
|
|
10
|
+
});
|
|
11
|
+
const isMatchElement = (child) => isValidElement(child) && child.type === Match;
|
|
12
|
+
function BaseSwitch({ children, fallback = null }) {
|
|
13
|
+
const childArray = flattenChildren(children);
|
|
14
|
+
for (const child of childArray) {
|
|
15
|
+
if (!isMatchElement(child)) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const { when } = child.props;
|
|
19
|
+
if (!resolveWhen(when)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
return child;
|
|
23
|
+
}
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
26
|
+
const renderForTag = (tag) =>
|
|
27
|
+
// forward ref so consumers can attach a ref to the underlying DOM element
|
|
28
|
+
forwardRef(function Render({ children, fallback = null, ...props }, ref) {
|
|
29
|
+
return createElement(tag, { ...props, ref }, _jsx(BaseSwitch, { fallback: fallback, children: children }));
|
|
30
|
+
});
|
|
31
|
+
export const Switch = createTagProxy(BaseSwitch, renderForTag, "switch");
|
|
32
|
+
export function Match({ when, children }) {
|
|
33
|
+
if (!resolveWhen(when)) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return typeof children === "function"
|
|
37
|
+
? children(when)
|
|
38
|
+
: children;
|
|
39
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { TagProxyCategory } from "./tagProxyTypes";
|
|
1
2
|
/**
|
|
2
3
|
* 플러그인 등록을 위한 타입
|
|
3
4
|
* Register 인터페이스의 각 카테고리에 대해 부분적으로 등록 가능
|
|
4
5
|
*/
|
|
5
6
|
type PluginRegistration = {
|
|
6
|
-
[K in
|
|
7
|
+
[K in TagProxyCategory]?: Record<string, any>;
|
|
7
8
|
};
|
|
8
9
|
/**
|
|
9
10
|
* 플러그인 컴포넌트를 등록하고 관리하는 싱글턴 클래스
|
|
@@ -71,18 +72,18 @@ export declare class PluginManager {
|
|
|
71
72
|
/**
|
|
72
73
|
* 등록된 플러그인 컴포넌트를 가져옵니다 (내부용)
|
|
73
74
|
*/
|
|
74
|
-
static get<K extends
|
|
75
|
+
static get<K extends TagProxyCategory>(category: K, name: string): any;
|
|
75
76
|
/**
|
|
76
77
|
* 특정 카테고리의 모든 플러그인을 가져옵니다 (내부용)
|
|
77
78
|
*/
|
|
78
|
-
static getAll<K extends
|
|
79
|
+
static getAll<K extends TagProxyCategory>(category: K): Map<string, any>;
|
|
79
80
|
/**
|
|
80
81
|
* 플러그인이 등록되어 있는지 확인합니다
|
|
81
82
|
*/
|
|
82
|
-
static has<K extends
|
|
83
|
+
static has<K extends TagProxyCategory>(category: K, name: string): boolean;
|
|
83
84
|
/**
|
|
84
85
|
* 플러그인을 제거합니다
|
|
85
86
|
*/
|
|
86
|
-
static unregister<K extends
|
|
87
|
+
static unregister<K extends TagProxyCategory>(category: K, name: string): boolean;
|
|
87
88
|
}
|
|
88
89
|
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { TagProxyCategory } from "./tagProxyTypes";
|
|
2
|
+
export type { TagProxyCategory } from "./tagProxyTypes";
|
|
3
|
+
export declare function createTagProxy<TProxy extends object, TBase extends object = TProxy>(base: TBase, renderForTag: (tag: any) => any, category: TagProxyCategory): TProxy;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { htmlTags } from "../constants/htmlTags";
|
|
2
|
+
import { PluginManager } from "./PluginManager";
|
|
3
|
+
export function createTagProxy(base, renderForTag, category) {
|
|
4
|
+
const tagEntries = htmlTags.reduce((acc, tag) => {
|
|
5
|
+
acc[tag] = renderForTag(tag);
|
|
6
|
+
return acc;
|
|
7
|
+
}, {});
|
|
8
|
+
const target = Object.assign(base, tagEntries);
|
|
9
|
+
return new Proxy(target, {
|
|
10
|
+
get(currentTarget, prop) {
|
|
11
|
+
if (prop in currentTarget) {
|
|
12
|
+
return currentTarget[prop];
|
|
13
|
+
}
|
|
14
|
+
const propName = String(prop);
|
|
15
|
+
if (PluginManager.has(category, propName)) {
|
|
16
|
+
const component = PluginManager.get(category, propName);
|
|
17
|
+
const specialized = renderForTag(component);
|
|
18
|
+
currentTarget[prop] = specialized;
|
|
19
|
+
return specialized;
|
|
20
|
+
}
|
|
21
|
+
if (PluginManager.has("base", propName)) {
|
|
22
|
+
const component = PluginManager.get("base", propName);
|
|
23
|
+
const specialized = renderForTag(component);
|
|
24
|
+
currentTarget[prop] = specialized;
|
|
25
|
+
return specialized;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type TagProxyCategory = "show" | "for" | "repeat" | "mount" | "switch" | "base";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from './components/For';
|
|
2
|
+
export * from './components/Mount';
|
|
2
3
|
export * from './components/Observer';
|
|
3
4
|
export * from './components/OptionalWrapper';
|
|
4
5
|
export * from './components/Repeat';
|
|
5
6
|
export * from './components/Show';
|
|
7
|
+
export * from './components/Switch';
|
|
6
8
|
export * from './components/Slacker';
|
|
7
9
|
export * from './components/Slot';
|
|
8
10
|
export * from './hooks/useIntersectionObserver';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from './components/For';
|
|
2
|
+
export * from './components/Mount';
|
|
2
3
|
export * from './components/Observer';
|
|
3
4
|
export * from './components/OptionalWrapper';
|
|
4
5
|
export * from './components/Repeat';
|
|
5
6
|
export * from './components/Show';
|
|
7
|
+
export * from './components/Switch';
|
|
6
8
|
export * from './components/Slacker';
|
|
7
9
|
export * from './components/Slot';
|
|
8
10
|
export * from './hooks/useIntersectionObserver';
|
package/dist/types/for.d.ts
CHANGED
|
@@ -4,8 +4,6 @@ import { UtilinentRegisterBase, UtilinentRegisterFor } from "./register";
|
|
|
4
4
|
export interface ForProps<T extends Array<unknown>> extends Fallback {
|
|
5
5
|
each: T | null | undefined;
|
|
6
6
|
children: (item: T[number], index: number) => React.ReactNode;
|
|
7
|
-
before?: React.ReactNode;
|
|
8
|
-
after?: React.ReactNode;
|
|
9
7
|
}
|
|
10
8
|
type ForTagHelper<K extends HtmlTag> = {
|
|
11
9
|
<const T extends Array<unknown>>(props: ForProps<T> & Omit<React.ComponentPropsWithRef<K>, 'children'>): React.ReactNode;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ReactElement } from "react";
|
|
2
1
|
export type { UtilinentRegister } from "./register";
|
|
3
2
|
export interface Fallback {
|
|
4
3
|
fallback?: React.ReactNode;
|
|
@@ -6,8 +5,8 @@ export interface Fallback {
|
|
|
6
5
|
export type NonNullableElements<T extends readonly any[]> = {
|
|
7
6
|
-readonly [P in keyof T]: NonNullable<T[P]>;
|
|
8
7
|
};
|
|
9
|
-
export interface OptionalWrapperProps {
|
|
10
|
-
when:
|
|
8
|
+
export interface OptionalWrapperProps<T = unknown> {
|
|
9
|
+
when: T;
|
|
11
10
|
children: React.ReactNode;
|
|
12
11
|
wrapper: (children: React.ReactNode) => React.ReactNode;
|
|
13
12
|
fallback?: (children: React.ReactNode) => React.ReactNode;
|
|
@@ -19,12 +18,9 @@ export interface ObserverProps extends Fallback {
|
|
|
19
18
|
triggerOnce?: boolean;
|
|
20
19
|
onIntersect?: (isIntersecting: boolean, entry: IntersectionObserverEntry) => void;
|
|
21
20
|
}
|
|
22
|
-
export interface SwitchProps<T, K extends LiteralKeys<T>> extends Fallback {
|
|
23
|
-
children: Array<ReactElement>;
|
|
24
|
-
when: K;
|
|
25
|
-
}
|
|
26
21
|
export interface MountProps extends Fallback {
|
|
27
22
|
children: React.ReactNode | (() => React.ReactNode | Promise<React.ReactNode>);
|
|
23
|
+
onError?: (error: unknown) => void;
|
|
28
24
|
}
|
|
29
25
|
export type ExtractValues<T, K extends keyof T> = T extends any ? T[K] : never;
|
|
30
26
|
type IsUnion<T, U = T> = T extends any ? [U] extends [T] ? false : true : false;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from "react";
|
|
2
|
+
import { HtmlTag } from "../constants/htmlTags";
|
|
3
|
+
import { MountProps } from ".";
|
|
4
|
+
import { UtilinentRegisterBase, UtilinentRegisterMount } from "./register";
|
|
5
|
+
type MountTagHelper<K extends HtmlTag> = {
|
|
6
|
+
(props: MountProps & Omit<ComponentPropsWithRef<K>, "children">): React.ReactNode;
|
|
7
|
+
};
|
|
8
|
+
type MountRegisterHelper<C> = C extends React.ComponentType<infer P> ? {
|
|
9
|
+
(props: Omit<P, "children"> & MountProps): React.ReactNode;
|
|
10
|
+
} : C;
|
|
11
|
+
export type MountType = {
|
|
12
|
+
(props: MountProps): React.ReactNode;
|
|
13
|
+
} & {
|
|
14
|
+
[K in HtmlTag]: MountTagHelper<K>;
|
|
15
|
+
} & {
|
|
16
|
+
[K in keyof UtilinentRegisterMount]: MountRegisterHelper<UtilinentRegisterMount[K]>;
|
|
17
|
+
} & {
|
|
18
|
+
[K in keyof UtilinentRegisterBase]: MountRegisterHelper<UtilinentRegisterBase[K]>;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types/register.d.ts
CHANGED
|
@@ -12,3 +12,9 @@ export type UtilinentRegisterFor = UtilinentRegister extends {
|
|
|
12
12
|
export type UtilinentRegisterRepeat = UtilinentRegister extends {
|
|
13
13
|
repeat: infer Repeat;
|
|
14
14
|
} ? Repeat : never;
|
|
15
|
+
export type UtilinentRegisterMount = UtilinentRegister extends {
|
|
16
|
+
mount: infer Mount;
|
|
17
|
+
} ? Mount : never;
|
|
18
|
+
export type UtilinentRegisterSwitch = UtilinentRegister extends {
|
|
19
|
+
switch: infer Switch;
|
|
20
|
+
} ? Switch : never;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from "react";
|
|
2
|
+
import { HtmlTag } from "../constants/htmlTags";
|
|
3
|
+
import { Fallback } from ".";
|
|
4
|
+
import { UtilinentRegisterBase, UtilinentRegisterSwitch } from "./register";
|
|
5
|
+
export interface MatchProps<T = unknown> {
|
|
6
|
+
when: T | null | undefined | false;
|
|
7
|
+
children: React.ReactNode | ((item: NonNullable<T>) => React.ReactNode);
|
|
8
|
+
}
|
|
9
|
+
export interface SwitchProps extends Fallback {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
type SwitchTagHelper<K extends HtmlTag> = {
|
|
13
|
+
(props: SwitchProps & Omit<ComponentPropsWithRef<K>, "children">): React.ReactNode;
|
|
14
|
+
};
|
|
15
|
+
type SwitchRegisterHelper<C> = C extends React.ComponentType<infer P> ? {
|
|
16
|
+
(props: Omit<P, "children"> & SwitchProps): React.ReactNode;
|
|
17
|
+
} : C;
|
|
18
|
+
export type SwitchType = {
|
|
19
|
+
(props: SwitchProps): React.ReactNode;
|
|
20
|
+
} & {
|
|
21
|
+
[K in HtmlTag]: SwitchTagHelper<K>;
|
|
22
|
+
} & {
|
|
23
|
+
[K in keyof UtilinentRegisterSwitch]: SwitchRegisterHelper<UtilinentRegisterSwitch[K]>;
|
|
24
|
+
} & {
|
|
25
|
+
[K in keyof UtilinentRegisterBase]: SwitchRegisterHelper<UtilinentRegisterBase[K]>;
|
|
26
|
+
};
|
|
27
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const resolveWhen: (value: unknown) => boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const resolveWhen = (value) => Array.isArray(value) ? value.every(Boolean) : !!value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ilokesto/utilinent",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/ilokesto/utilinent.git"
|
|
@@ -13,10 +13,6 @@
|
|
|
13
13
|
".": {
|
|
14
14
|
"import": "./dist/index.js",
|
|
15
15
|
"types": "./dist/index.d.ts"
|
|
16
|
-
},
|
|
17
|
-
"./experimental": {
|
|
18
|
-
"import": "./dist/experimental.js",
|
|
19
|
-
"types": "./dist/experimental.d.ts"
|
|
20
16
|
}
|
|
21
17
|
},
|
|
22
18
|
"files": [
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
export function Mount({ children, fallback = null }) {
|
|
3
|
-
const [resolvedChildren, setResolvedChildren] = useState(fallback);
|
|
4
|
-
useEffect(() => {
|
|
5
|
-
(async () => setResolvedChildren(typeof children === "function" ? await children() : children))();
|
|
6
|
-
}, [children]);
|
|
7
|
-
return resolvedChildren;
|
|
8
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ExtractByKeyValue, ExtractValues, LiteralKeys, SwitchProps } from "../types";
|
|
2
|
-
export declare function createSwitcher<T, K extends LiteralKeys<T>>(data: T): {
|
|
3
|
-
Switch: ({ children, when, fallback }: SwitchProps<T, K>) => string | number | boolean | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | null;
|
|
4
|
-
Match: <V extends ExtractValues<T, K>>({ children }: {
|
|
5
|
-
case: V;
|
|
6
|
-
children: (props: ExtractByKeyValue<T, K, V>) => React.ReactNode;
|
|
7
|
-
}) => import("react").ReactNode;
|
|
8
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export function createSwitcher(data) {
|
|
2
|
-
function Switch({ children, when, fallback = null }) {
|
|
3
|
-
children.reduce((acc, { type, props }) => {
|
|
4
|
-
if (type !== Match)
|
|
5
|
-
throw new Error("Match 컴포넌트만 사용할 수 있습니다.");
|
|
6
|
-
if (props.case) {
|
|
7
|
-
if (acc.includes(props.case))
|
|
8
|
-
throw new Error(`Duplicate Match key: ${props.case}`);
|
|
9
|
-
else
|
|
10
|
-
acc.push(props.case);
|
|
11
|
-
}
|
|
12
|
-
return acc;
|
|
13
|
-
}, []);
|
|
14
|
-
return children.find(({ props }) => props.case === data[when]) ?? fallback;
|
|
15
|
-
}
|
|
16
|
-
function Match({ children }) {
|
|
17
|
-
return children(data);
|
|
18
|
-
}
|
|
19
|
-
;
|
|
20
|
-
return { Switch, Match };
|
|
21
|
-
}
|
package/dist/experimental.d.ts
DELETED
package/dist/experimental.js
DELETED