@ilokesto/utilinent 1.0.12 → 1.0.13

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,6 +1,7 @@
1
1
  import { Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createElement, forwardRef } from "react";
3
3
  import { htmlTags } from "../constants/htmlTags";
4
+ import { PluginManager } from "../core/PluginManager";
4
5
  function BaseFor({ each, children, fallback = null, before, after, }) {
5
6
  const content = each && each.length > 0 ? each.map(children) : fallback;
6
7
  return (_jsxs(_Fragment, { children: [before, content, after] }));
@@ -11,8 +12,31 @@ forwardRef(({ each, children, fallback = null, before, after, ...props }, ref) =
11
12
  const content = each && each.length > 0 ? each.map(children) : fallback;
12
13
  return createElement(tag, { ...props, ref }, before, content, after);
13
14
  });
15
+ // HTML 태그들을 등록
14
16
  const tagEntries = htmlTags.reduce((acc, tag) => {
15
17
  acc[tag] = renderForTag(tag);
16
18
  return acc;
17
19
  }, {});
18
- export const For = Object.assign(BaseFor, tagEntries);
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
+ return renderForTag(component);
33
+ }
34
+ // 'base' 카테고리에서 찾기
35
+ if (PluginManager.has('base', propName)) {
36
+ const component = PluginManager.get('base', propName);
37
+ return renderForTag(component);
38
+ }
39
+ // 찾지 못하면 undefined 반환
40
+ return undefined;
41
+ }
42
+ });
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createElement, forwardRef } from "react";
3
3
  import { htmlTags } from "../constants/htmlTags";
4
+ import { PluginManager } from "../core/PluginManager";
4
5
  import { For } from "./For";
5
6
  function BaseRepeat({ times, children, fallback = null }) {
6
7
  if (!times || times <= 0 || !Number.isInteger(times)) {
@@ -16,8 +17,30 @@ forwardRef(({ times, children, fallback = null, ...props }, ref) => {
16
17
  : fallback ?? null;
17
18
  return createElement(tag, { ...props, ref }, content);
18
19
  });
20
+ // HTML 태그들을 등록
19
21
  const tagEntries = htmlTags.reduce((acc, tag) => {
20
22
  acc[tag] = renderForTag(tag);
21
23
  return acc;
22
24
  }, {});
23
- export const Repeat = Object.assign(BaseRepeat, tagEntries);
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
+ return renderForTag(component);
37
+ }
38
+ // 'base' 카테고리에서 찾기
39
+ if (PluginManager.has('base', propName)) {
40
+ const component = PluginManager.get('base', propName);
41
+ return renderForTag(component);
42
+ }
43
+ // 찾지 못하면 undefined 반환
44
+ return undefined;
45
+ }
46
+ });
@@ -1,5 +1,6 @@
1
1
  import { createElement, forwardRef } from "react";
2
2
  import { htmlTags } from "../constants/htmlTags";
3
+ import { PluginManager } from "../core/PluginManager";
3
4
  const BaseShow = ({ when, children, fallback = null }) => {
4
5
  const shouldRender = Array.isArray(when) ? when.every(Boolean) : !!when;
5
6
  return shouldRender
@@ -19,8 +20,30 @@ forwardRef(function Render({ when, children, fallback = null, ...props }, ref) {
19
20
  : fallback;
20
21
  return createElement(tag, { ...props, ref }, content);
21
22
  });
23
+ // HTML 태그들을 등록
22
24
  const tagEntries = htmlTags.reduce((acc, tag) => {
23
25
  acc[tag] = renderForTag(tag);
24
26
  return acc;
25
27
  }, {});
26
- export const Show = Object.assign(BaseShow, tagEntries);
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
+ return renderForTag(component);
40
+ }
41
+ // 'base' 카테고리에서 찾기
42
+ if (PluginManager.has('base', propName)) {
43
+ const component = PluginManager.get('base', propName);
44
+ return renderForTag(component);
45
+ }
46
+ // 찾지 못하면 undefined 반환
47
+ return undefined;
48
+ }
49
+ });
@@ -0,0 +1,88 @@
1
+ /**
2
+ * 플러그인 등록을 위한 타입
3
+ * Register 인터페이스의 각 카테고리에 대해 부분적으로 등록 가능
4
+ */
5
+ type PluginRegistration = {
6
+ [K in "show" | "for" | "repeat" | "base"]?: Record<string, any>;
7
+ };
8
+ /**
9
+ * 플러그인 컴포넌트를 등록하고 관리하는 싱글턴 클래스
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { UtilinentPluginManager } from '@ilokesto/utilinent';
14
+ * import Link from 'next/link';
15
+ * import { motion } from 'framer-motion';
16
+ *
17
+ * // 컴포넌트 등록
18
+ * UtilinentPluginManager.register({
19
+ * show: {
20
+ * Link: Link,
21
+ * },
22
+ * base: {
23
+ * motionButton: motion.button,
24
+ * }
25
+ * });
26
+ *
27
+ * // 타입 등록 (별도 파일에서)
28
+ * declare module '@ilokesto/utilinent' {
29
+ * interface Register {
30
+ * show: {
31
+ * Link: typeof Link;
32
+ * };
33
+ * base: {
34
+ * motionButton: typeof motion.button;
35
+ * };
36
+ * }
37
+ * }
38
+ * ```
39
+ */
40
+ export declare class PluginManager {
41
+ private static instance;
42
+ private plugins;
43
+ private constructor();
44
+ /**
45
+ * PluginManager 인스턴스를 가져옵니다
46
+ */
47
+ private static getInstance;
48
+ /**
49
+ * 플러그인 컴포넌트들을 객체 형태로 등록합니다
50
+ *
51
+ * @param plugins - 카테고리별 컴포넌트 객체
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * UtilinentPluginManager.register({
56
+ * show: {
57
+ * Link: Link,
58
+ * Button: CustomButton,
59
+ * },
60
+ * base: {
61
+ * motionDiv: motion.div,
62
+ * }
63
+ * });
64
+ * ```
65
+ */
66
+ static register(plugins: PluginRegistration): void;
67
+ /**
68
+ * 단일 플러그인 컴포넌트를 등록합니다 (내부용)
69
+ */
70
+ private registerOne;
71
+ /**
72
+ * 등록된 플러그인 컴포넌트를 가져옵니다 (내부용)
73
+ */
74
+ static get<K extends "show" | "for" | "repeat" | "base">(category: K, name: string): any;
75
+ /**
76
+ * 특정 카테고리의 모든 플러그인을 가져옵니다 (내부용)
77
+ */
78
+ static getAll<K extends "show" | "for" | "repeat" | "base">(category: K): Map<string, any>;
79
+ /**
80
+ * 플러그인이 등록되어 있는지 확인합니다
81
+ */
82
+ static has<K extends "show" | "for" | "repeat" | "base">(category: K, name: string): boolean;
83
+ /**
84
+ * 플러그인을 제거합니다
85
+ */
86
+ static unregister<K extends "show" | "for" | "repeat" | "base">(category: K, name: string): boolean;
87
+ }
88
+ export {};
@@ -0,0 +1,116 @@
1
+ /**
2
+ * 플러그인 컴포넌트를 등록하고 관리하는 싱글턴 클래스
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { UtilinentPluginManager } from '@ilokesto/utilinent';
7
+ * import Link from 'next/link';
8
+ * import { motion } from 'framer-motion';
9
+ *
10
+ * // 컴포넌트 등록
11
+ * UtilinentPluginManager.register({
12
+ * show: {
13
+ * Link: Link,
14
+ * },
15
+ * base: {
16
+ * motionButton: motion.button,
17
+ * }
18
+ * });
19
+ *
20
+ * // 타입 등록 (별도 파일에서)
21
+ * declare module '@ilokesto/utilinent' {
22
+ * interface Register {
23
+ * show: {
24
+ * Link: typeof Link;
25
+ * };
26
+ * base: {
27
+ * motionButton: typeof motion.button;
28
+ * };
29
+ * }
30
+ * }
31
+ * ```
32
+ */
33
+ export class PluginManager {
34
+ static instance;
35
+ plugins = {
36
+ show: new Map(),
37
+ for: new Map(),
38
+ repeat: new Map(),
39
+ base: new Map(),
40
+ };
41
+ constructor() {
42
+ // 싱글턴 패턴: private constructor
43
+ }
44
+ /**
45
+ * PluginManager 인스턴스를 가져옵니다
46
+ */
47
+ static getInstance() {
48
+ if (!PluginManager.instance) {
49
+ PluginManager.instance = new PluginManager();
50
+ }
51
+ return PluginManager.instance;
52
+ }
53
+ /**
54
+ * 플러그인 컴포넌트들을 객체 형태로 등록합니다
55
+ *
56
+ * @param plugins - 카테고리별 컴포넌트 객체
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * UtilinentPluginManager.register({
61
+ * show: {
62
+ * Link: Link,
63
+ * Button: CustomButton,
64
+ * },
65
+ * base: {
66
+ * motionDiv: motion.div,
67
+ * }
68
+ * });
69
+ * ```
70
+ */
71
+ static register(plugins) {
72
+ const instance = PluginManager.getInstance();
73
+ Object.keys(plugins).forEach((category) => {
74
+ const components = plugins[category];
75
+ if (components) {
76
+ Object.entries(components).forEach(([name, component]) => {
77
+ instance.registerOne(category, name, component);
78
+ });
79
+ }
80
+ });
81
+ }
82
+ /**
83
+ * 단일 플러그인 컴포넌트를 등록합니다 (내부용)
84
+ */
85
+ registerOne(category, name, component) {
86
+ this.plugins[category].set(name, component);
87
+ }
88
+ /**
89
+ * 등록된 플러그인 컴포넌트를 가져옵니다 (내부용)
90
+ */
91
+ static get(category, name) {
92
+ const instance = PluginManager.getInstance();
93
+ return instance.plugins[category].get(name);
94
+ }
95
+ /**
96
+ * 특정 카테고리의 모든 플러그인을 가져옵니다 (내부용)
97
+ */
98
+ static getAll(category) {
99
+ const instance = PluginManager.getInstance();
100
+ return instance.plugins[category];
101
+ }
102
+ /**
103
+ * 플러그인이 등록되어 있는지 확인합니다
104
+ */
105
+ static has(category, name) {
106
+ const instance = PluginManager.getInstance();
107
+ return instance.plugins[category].has(name);
108
+ }
109
+ /**
110
+ * 플러그인을 제거합니다
111
+ */
112
+ static unregister(category, name) {
113
+ const instance = PluginManager.getInstance();
114
+ return instance.plugins[category].delete(name);
115
+ }
116
+ }
package/dist/index.d.ts CHANGED
@@ -6,3 +6,5 @@ export * from './components/Show';
6
6
  export * from './components/Slacker';
7
7
  export * from './components/Slot';
8
8
  export * from './hooks/useIntersectionObserver';
9
+ export { PluginManager } from './core/PluginManager';
10
+ export { UtilinentRegister } from './types/register';
package/dist/index.js CHANGED
@@ -6,3 +6,4 @@ export * from './components/Show';
6
6
  export * from './components/Slacker';
7
7
  export * from './components/Slot';
8
8
  export * from './hooks/useIntersectionObserver';
9
+ export { PluginManager } from './core/PluginManager';
@@ -1,5 +1,6 @@
1
1
  import { Fallback } from ".";
2
2
  import { HtmlTag } from "../constants/htmlTags";
3
+ import { UtilinentRegisterBase, UtilinentRegisterFor } from "./register";
3
4
  export interface ForProps<T extends Array<unknown>> extends Fallback {
4
5
  each: T | null | undefined;
5
6
  children: (item: T[number], index: number) => React.ReactNode;
@@ -9,9 +10,16 @@ export interface ForProps<T extends Array<unknown>> extends Fallback {
9
10
  type ForTagHelper<K extends HtmlTag> = {
10
11
  <const T extends Array<unknown>>(props: ForProps<T> & Omit<React.ComponentPropsWithRef<K>, 'children'>): React.ReactNode;
11
12
  };
13
+ type ForRegisterHelper<C> = C extends React.ComponentType<infer P> ? {
14
+ <const T extends Array<unknown>>(props: Omit<P, "children"> & ForProps<T>): React.ReactNode;
15
+ } : C;
12
16
  export type ForType = {
13
17
  <const T extends Array<unknown>>(props: ForProps<T>): React.ReactNode;
14
18
  } & {
15
19
  [K in HtmlTag]: ForTagHelper<K>;
20
+ } & {
21
+ [K in keyof UtilinentRegisterFor]: ForRegisterHelper<UtilinentRegisterFor[K]>;
22
+ } & {
23
+ [K in keyof UtilinentRegisterBase]: ForRegisterHelper<UtilinentRegisterBase[K]>;
16
24
  };
17
25
  export {};
@@ -1,4 +1,5 @@
1
1
  import type { ReactElement } from "react";
2
+ export type { UtilinentRegister } from "./register";
2
3
  export interface Fallback {
3
4
  fallback?: React.ReactNode;
4
5
  }
@@ -48,4 +49,3 @@ export type SlackerProps<T = any> = {
48
49
  maxRetries?: number;
49
50
  retryDelay?: number;
50
51
  };
51
- export {};
@@ -0,0 +1,14 @@
1
+ export interface UtilinentRegister {
2
+ }
3
+ export type UtilinentRegisterShow = UtilinentRegister extends {
4
+ show: infer Show;
5
+ } ? Show : never;
6
+ export type UtilinentRegisterBase = UtilinentRegister extends {
7
+ base: infer Base;
8
+ } ? Base : never;
9
+ export type UtilinentRegisterFor = UtilinentRegister extends {
10
+ for: infer For;
11
+ } ? For : never;
12
+ export type UtilinentRegisterRepeat = UtilinentRegister extends {
13
+ repeat: infer Repeat;
14
+ } ? Repeat : never;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  import { ComponentPropsWithRef } from "react";
2
2
  import { Fallback } from ".";
3
3
  import { HtmlTag } from "../constants/htmlTags";
4
+ import { UtilinentRegisterBase, UtilinentRegisterRepeat } from "./register";
4
5
  export interface RepeatProps extends Fallback {
5
6
  times: number;
6
7
  children: (index: number) => React.ReactNode;
@@ -8,9 +9,16 @@ export interface RepeatProps extends Fallback {
8
9
  type RepeatTagHelper<K extends HtmlTag> = {
9
10
  (props: RepeatProps & Omit<ComponentPropsWithRef<K>, "children">): React.ReactNode;
10
11
  };
12
+ type RepeatRegisterHelper<C> = C extends React.ComponentType<infer P> ? {
13
+ (props: Omit<P, "children"> & RepeatProps): React.ReactNode;
14
+ } : C;
11
15
  export type RepeatType = {
12
16
  (props: RepeatProps): React.ReactNode;
13
17
  } & {
14
18
  [K in HtmlTag]: RepeatTagHelper<K>;
19
+ } & {
20
+ [K in keyof UtilinentRegisterRepeat]: RepeatRegisterHelper<UtilinentRegisterRepeat[K]>;
21
+ } & {
22
+ [K in keyof UtilinentRegisterBase]: RepeatRegisterHelper<UtilinentRegisterBase[K]>;
15
23
  };
16
24
  export {};
@@ -1,6 +1,7 @@
1
1
  import { ComponentPropsWithRef } from "react";
2
2
  import { HtmlTag } from "../constants/htmlTags";
3
3
  import { Fallback, NonNullableElements } from "./";
4
+ import { UtilinentRegisterBase, UtilinentRegisterShow } from "./register";
4
5
  export interface ShowPropsArray<T extends unknown[]> extends Fallback {
5
6
  when: T;
6
7
  children: React.ReactNode | ((item: NonNullableElements<T>) => React.ReactNode);
@@ -13,10 +14,18 @@ type ShowTagHelper<K extends HtmlTag> = {
13
14
  <const T extends unknown[]>(props: Omit<ComponentPropsWithRef<K>, "children"> & ShowPropsArray<T>): React.ReactNode;
14
15
  <const T extends unknown>(props: Omit<ComponentPropsWithRef<K>, "children"> & ShowProps<T>): React.ReactNode;
15
16
  };
17
+ type ShowRegisterHelper<C> = C extends React.ComponentType<infer P> ? {
18
+ <const T extends unknown[]>(props: Omit<P, "children"> & ShowPropsArray<T>): React.ReactNode;
19
+ <const T extends unknown>(props: Omit<P, "children"> & ShowProps<T>): React.ReactNode;
20
+ } : C;
16
21
  export type ShowType = {
17
22
  <const T extends unknown[]>(props: ShowPropsArray<T>): React.ReactNode;
18
23
  <const T extends unknown>(props: ShowProps<T>): React.ReactNode;
19
24
  } & {
20
25
  [K in HtmlTag]: ShowTagHelper<K>;
26
+ } & {
27
+ [K in keyof UtilinentRegisterShow]: ShowRegisterHelper<UtilinentRegisterShow[K]>;
28
+ } & {
29
+ [K in keyof UtilinentRegisterBase]: ShowRegisterHelper<UtilinentRegisterBase[K]>;
21
30
  };
22
31
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ilokesto/utilinent",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ilokesto/utilinent.git"