sh-ui-cli 0.14.0 → 0.21.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.
Files changed (162) hide show
  1. package/bin/sh-ui.mjs +6 -0
  2. package/data/changelog/versions.json +354 -0
  3. package/data/registry/flutter/foundation/sh_ui_tokens.dart +385 -0
  4. package/data/registry/flutter/registry.json +336 -0
  5. package/data/registry/flutter/widgets/sh_ui_accordion.dart +255 -0
  6. package/data/registry/flutter/widgets/sh_ui_app_shell.dart +267 -0
  7. package/data/registry/flutter/widgets/sh_ui_avatar.dart +95 -0
  8. package/data/registry/flutter/widgets/sh_ui_badge.dart +82 -0
  9. package/data/registry/flutter/widgets/sh_ui_breadcrumb.dart +107 -0
  10. package/data/registry/flutter/widgets/sh_ui_button.dart +201 -0
  11. package/data/registry/flutter/widgets/sh_ui_card.dart +159 -0
  12. package/data/registry/flutter/widgets/sh_ui_carousel.dart +204 -0
  13. package/data/registry/flutter/widgets/sh_ui_checkbox.dart +154 -0
  14. package/data/registry/flutter/widgets/sh_ui_color_picker.dart +264 -0
  15. package/data/registry/flutter/widgets/sh_ui_combobox.dart +614 -0
  16. package/data/registry/flutter/widgets/sh_ui_context_menu.dart +71 -0
  17. package/data/registry/flutter/widgets/sh_ui_date_picker.dart +648 -0
  18. package/data/registry/flutter/widgets/sh_ui_dialog.dart +567 -0
  19. package/data/registry/flutter/widgets/sh_ui_dropdown_menu.dart +251 -0
  20. package/data/registry/flutter/widgets/sh_ui_file_upload.dart +200 -0
  21. package/data/registry/flutter/widgets/sh_ui_header.dart +488 -0
  22. package/data/registry/flutter/widgets/sh_ui_input.dart +664 -0
  23. package/data/registry/flutter/widgets/sh_ui_label.dart +145 -0
  24. package/data/registry/flutter/widgets/sh_ui_menubar.dart +98 -0
  25. package/data/registry/flutter/widgets/sh_ui_pagination.dart +276 -0
  26. package/data/registry/flutter/widgets/sh_ui_popover.dart +248 -0
  27. package/data/registry/flutter/widgets/sh_ui_progress.dart +47 -0
  28. package/data/registry/flutter/widgets/sh_ui_radio.dart +108 -0
  29. package/data/registry/flutter/widgets/sh_ui_select.dart +904 -0
  30. package/data/registry/flutter/widgets/sh_ui_separator.dart +42 -0
  31. package/data/registry/flutter/widgets/sh_ui_sidebar.dart +1116 -0
  32. package/data/registry/flutter/widgets/sh_ui_skeleton.dart +129 -0
  33. package/data/registry/flutter/widgets/sh_ui_slider.dart +147 -0
  34. package/data/registry/flutter/widgets/sh_ui_spinner.dart +56 -0
  35. package/data/registry/flutter/widgets/sh_ui_switch.dart +109 -0
  36. package/data/registry/flutter/widgets/sh_ui_tabs.dart +329 -0
  37. package/data/registry/flutter/widgets/sh_ui_textarea.dart +126 -0
  38. package/data/registry/flutter/widgets/sh_ui_toast.dart +362 -0
  39. package/data/registry/flutter/widgets/sh_ui_toggle.dart +229 -0
  40. package/data/registry/flutter/widgets/sh_ui_tooltip.dart +62 -0
  41. package/data/registry/react/components/accordion/index.tsx +85 -0
  42. package/data/registry/react/components/accordion/styles.css +94 -0
  43. package/data/registry/react/components/animations/animations.css +51 -0
  44. package/data/registry/react/components/avatar/index.tsx +75 -0
  45. package/data/registry/react/components/avatar/styles.css +36 -0
  46. package/data/registry/react/components/badge/index.tsx +42 -0
  47. package/data/registry/react/components/badge/styles.css +57 -0
  48. package/data/registry/react/components/base/base.css +102 -0
  49. package/data/registry/react/components/breadcrumb/index.tsx +154 -0
  50. package/data/registry/react/components/breadcrumb/styles.css +82 -0
  51. package/data/registry/react/components/breakpoints/breakpoints.css +17 -0
  52. package/data/registry/react/components/button/index.tsx +47 -0
  53. package/data/registry/react/components/button/styles.css +93 -0
  54. package/data/registry/react/components/card/index.tsx +86 -0
  55. package/data/registry/react/components/card/styles.css +73 -0
  56. package/data/registry/react/components/carousel/index.tsx +432 -0
  57. package/data/registry/react/components/carousel/styles.css +155 -0
  58. package/data/registry/react/components/checkbox/index.tsx +98 -0
  59. package/data/registry/react/components/checkbox/styles.css +75 -0
  60. package/data/registry/react/components/code-panel/copy.tsx +56 -0
  61. package/data/registry/react/components/code-panel/index.tsx +193 -0
  62. package/data/registry/react/components/code-panel/styles.css +124 -0
  63. package/data/registry/react/components/color-picker/index.tsx +466 -0
  64. package/data/registry/react/components/color-picker/styles.css +166 -0
  65. package/data/registry/react/components/combobox/index.tsx +167 -0
  66. package/data/registry/react/components/combobox/styles.css +151 -0
  67. package/data/registry/react/components/context-menu/index.tsx +253 -0
  68. package/data/registry/react/components/context-menu/styles.css +140 -0
  69. package/data/registry/react/components/date-picker/index.tsx +757 -0
  70. package/data/registry/react/components/date-picker/styles.css +279 -0
  71. package/data/registry/react/components/dialog/index.tsx +97 -0
  72. package/data/registry/react/components/dialog/styles.css +127 -0
  73. package/data/registry/react/components/dropdown-menu/index.tsx +257 -0
  74. package/data/registry/react/components/dropdown-menu/styles.css +150 -0
  75. package/data/registry/react/components/file-upload/index.tsx +489 -0
  76. package/data/registry/react/components/file-upload/styles.css +170 -0
  77. package/data/registry/react/components/focus-ring/focus-ring.css +23 -0
  78. package/data/registry/react/components/form/context.ts +92 -0
  79. package/data/registry/react/components/form/field.test.tsx +230 -0
  80. package/data/registry/react/components/form/field.tsx +236 -0
  81. package/data/registry/react/components/form/focus-first-error.ts +54 -0
  82. package/data/registry/react/components/form/form.section.test.tsx +58 -0
  83. package/data/registry/react/components/form/form.test.tsx +146 -0
  84. package/data/registry/react/components/form/form.tsx +180 -0
  85. package/data/registry/react/components/form/index.tsx +61 -0
  86. package/data/registry/react/components/form/steps.test.tsx +106 -0
  87. package/data/registry/react/components/form/steps.tsx +193 -0
  88. package/data/registry/react/components/form/store.test.ts +206 -0
  89. package/data/registry/react/components/form/store.ts +318 -0
  90. package/data/registry/react/components/form/styles.css +47 -0
  91. package/data/registry/react/components/form/types.ts +104 -0
  92. package/data/registry/react/components/form/use-sh-ui-form.ts +15 -0
  93. package/data/registry/react/components/form/utils.test.ts +44 -0
  94. package/data/registry/react/components/form/utils.ts +49 -0
  95. package/data/registry/react/components/form/validation.test.ts +67 -0
  96. package/data/registry/react/components/form/validation.ts +64 -0
  97. package/data/registry/react/components/form-rhf/README.md +27 -0
  98. package/data/registry/react/components/form-rhf/index.tsx +289 -0
  99. package/data/registry/react/components/form-rhf/rhf.test.tsx +42 -0
  100. package/data/registry/react/components/form-tanstack/README.md +27 -0
  101. package/data/registry/react/components/form-tanstack/index.tsx +352 -0
  102. package/data/registry/react/components/form-tanstack/tanstack.test.tsx +45 -0
  103. package/data/registry/react/components/form-yup/README.md +22 -0
  104. package/data/registry/react/components/form-yup/index.tsx +50 -0
  105. package/data/registry/react/components/form-yup/yup.test.ts +27 -0
  106. package/data/registry/react/components/header/index.tsx +257 -0
  107. package/data/registry/react/components/header/styles.css +190 -0
  108. package/data/registry/react/components/input/index.tsx +517 -0
  109. package/data/registry/react/components/input/styles.css +203 -0
  110. package/data/registry/react/components/label/index.tsx +54 -0
  111. package/data/registry/react/components/label/styles.css +90 -0
  112. package/data/registry/react/components/menubar/index.tsx +34 -0
  113. package/data/registry/react/components/menubar/styles.css +45 -0
  114. package/data/registry/react/components/pagination/index.tsx +271 -0
  115. package/data/registry/react/components/pagination/styles.css +105 -0
  116. package/data/registry/react/components/popover/index.tsx +115 -0
  117. package/data/registry/react/components/popover/styles.css +65 -0
  118. package/data/registry/react/components/progress/index.tsx +56 -0
  119. package/data/registry/react/components/progress/styles.css +41 -0
  120. package/data/registry/react/components/radio/index.tsx +67 -0
  121. package/data/registry/react/components/radio/styles.css +80 -0
  122. package/data/registry/react/components/select/index.tsx +236 -0
  123. package/data/registry/react/components/select/styles.css +193 -0
  124. package/data/registry/react/components/separator/index.tsx +48 -0
  125. package/data/registry/react/components/separator/styles.css +15 -0
  126. package/data/registry/react/components/sidebar/index.tsx +1084 -0
  127. package/data/registry/react/components/sidebar/styles.css +502 -0
  128. package/data/registry/react/components/skeleton/index.tsx +24 -0
  129. package/data/registry/react/components/skeleton/styles.css +24 -0
  130. package/data/registry/react/components/slider/index.tsx +300 -0
  131. package/data/registry/react/components/slider/styles.css +64 -0
  132. package/data/registry/react/components/spinner/index.tsx +40 -0
  133. package/data/registry/react/components/spinner/styles.css +37 -0
  134. package/data/registry/react/components/switch/index.tsx +41 -0
  135. package/data/registry/react/components/switch/styles.css +83 -0
  136. package/data/registry/react/components/tabs/index.tsx +93 -0
  137. package/data/registry/react/components/tabs/styles.css +148 -0
  138. package/data/registry/react/components/textarea/index.tsx +25 -0
  139. package/data/registry/react/components/textarea/styles.css +54 -0
  140. package/data/registry/react/components/theme/index.tsx +91 -0
  141. package/data/registry/react/components/toast/index.tsx +257 -0
  142. package/data/registry/react/components/toast/styles.css +290 -0
  143. package/data/registry/react/components/toggle/index.tsx +133 -0
  144. package/data/registry/react/components/toggle/styles.css +85 -0
  145. package/data/registry/react/components/tooltip/index.tsx +85 -0
  146. package/data/registry/react/components/tooltip/styles.css +44 -0
  147. package/data/registry/react/components/z-index/z-index.css +16 -0
  148. package/data/registry/react/hooks/use-active-section.ts +104 -0
  149. package/data/registry/react/hooks/use-media-query.ts +27 -0
  150. package/data/registry/react/lib/cn.ts +39 -0
  151. package/data/registry/react/registry.json +835 -0
  152. package/data/summaries/flutter.json +42 -0
  153. package/data/summaries/react.json +50 -0
  154. package/data/tokens/build.mjs +553 -0
  155. package/data/tokens/src/primitives.json +146 -0
  156. package/data/tokens/src/semantic.json +146 -0
  157. package/package.json +13 -4
  158. package/src/add.mjs +13 -12
  159. package/src/list.mjs +3 -11
  160. package/src/mcp.mjs +308 -0
  161. package/src/paths.mjs +52 -0
  162. package/src/remove.mjs +4 -11
@@ -0,0 +1,104 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+
5
+ export interface UseActiveSectionOptions {
6
+ /** 감시할 섹션의 DOM id 목록. 순서는 문서에서의 등장 순서와 동일해야 한다. */
7
+ sectionIds: string[];
8
+ /** IntersectionObserver rootMargin. 기본값은 뷰포트 상단 20% 지점에서 활성 전환. */
9
+ rootMargin?: string;
10
+ /** 관측 대상이 될 스크롤 컨테이너. 기본은 viewport. */
11
+ root?: Element | Document | null;
12
+ /** 초기 활성 섹션. 지정하지 않으면 sectionIds[0]. */
13
+ defaultActiveId?: string;
14
+ }
15
+
16
+ /**
17
+ * 스크롤 위치에 따라 현재 활성 섹션 id를 반환한다.
18
+ * - 여러 섹션이 동시에 교차하면 가장 위에 있는 섹션을 선택한다.
19
+ * - 어떤 섹션도 교차하지 않으면 직전 활성 섹션을 유지한다.
20
+ */
21
+ export function useActiveSection({
22
+ sectionIds,
23
+ rootMargin = "-20% 0px -70% 0px",
24
+ root = null,
25
+ defaultActiveId,
26
+ }: UseActiveSectionOptions): string | undefined {
27
+ const [activeId, setActiveId] = React.useState<string | undefined>(
28
+ defaultActiveId ?? sectionIds[0]
29
+ );
30
+
31
+ const idsKey = sectionIds.join("|");
32
+
33
+ React.useEffect(() => {
34
+ if (typeof window === "undefined") return;
35
+ if (sectionIds.length === 0) return;
36
+
37
+ const visible = new Map<string, IntersectionObserverEntry>();
38
+
39
+ const observer = new IntersectionObserver(
40
+ (entries) => {
41
+ for (const entry of entries) {
42
+ const id = (entry.target as HTMLElement).id;
43
+ if (entry.isIntersecting) visible.set(id, entry);
44
+ else visible.delete(id);
45
+ }
46
+
47
+ if (visible.size === 0) return;
48
+
49
+ let topId: string | undefined;
50
+ let topY = Number.POSITIVE_INFINITY;
51
+ visible.forEach((entry, id) => {
52
+ const y = entry.boundingClientRect.top;
53
+ if (y < topY) {
54
+ topY = y;
55
+ topId = id;
56
+ }
57
+ });
58
+ if (topId) setActiveId(topId);
59
+ },
60
+ {
61
+ rootMargin,
62
+ root: root instanceof Document ? null : root ?? null,
63
+ threshold: 0,
64
+ }
65
+ );
66
+
67
+ const elements = sectionIds
68
+ .map((id) => document.getElementById(id))
69
+ .filter((el): el is HTMLElement => el !== null);
70
+
71
+ elements.forEach((el) => observer.observe(el));
72
+
73
+ // 스크롤 끝 보정: 마지막 섹션이 트리거 라인까지 못 올라오는 경우 강제 활성화.
74
+ const scrollTarget: Element | Window | null =
75
+ root instanceof Document ? window : (root as Element | null) ?? window;
76
+
77
+ const handleScroll = () => {
78
+ const lastId = sectionIds[sectionIds.length - 1];
79
+ if (!lastId) return;
80
+ const el =
81
+ (root instanceof Document ? null : (root as HTMLElement | null)) ??
82
+ (document.scrollingElement as HTMLElement | null) ??
83
+ document.documentElement;
84
+ const scrollTop = el.scrollTop;
85
+ const clientHeight = el.clientHeight;
86
+ const scrollHeight = el.scrollHeight;
87
+ if (scrollTop + clientHeight >= scrollHeight - 2) {
88
+ setActiveId(lastId);
89
+ }
90
+ };
91
+
92
+ scrollTarget.addEventListener("scroll", handleScroll, { passive: true });
93
+ handleScroll();
94
+
95
+ return () => {
96
+ observer.disconnect();
97
+ scrollTarget.removeEventListener("scroll", handleScroll);
98
+ };
99
+ // idsKey로 배열 내용 변경을 감지
100
+ // eslint-disable-next-line react-hooks/exhaustive-deps
101
+ }, [idsKey, rootMargin, root]);
102
+
103
+ return activeId;
104
+ }
@@ -0,0 +1,27 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+
5
+ /**
6
+ * 미디어 쿼리에 따른 boolean 상태를 반환한다. SSR 안전(초기값 false).
7
+ *
8
+ * const isWide = useMediaQuery("(min-width: 64rem)");
9
+ */
10
+ export function useMediaQuery(query: string): boolean {
11
+ const [matches, setMatches] = useState(false);
12
+
13
+ useEffect(() => {
14
+ const mql = window.matchMedia(query);
15
+ const onChange = () => setMatches(mql.matches);
16
+ onChange();
17
+ mql.addEventListener("change", onChange);
18
+ return () => mql.removeEventListener("change", onChange);
19
+ }, [query]);
20
+
21
+ return matches;
22
+ }
23
+
24
+ /** 모바일(< 768px) 여부. Sidebar 등에서 사용. */
25
+ export function useIsMobile(): boolean {
26
+ return useMediaQuery("(max-width: 47.99rem)");
27
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * className 합성 헬퍼.
3
+ * - falsy(null/false/undefined/"") 값은 자동 제외
4
+ * - 객체 형태 `{ "is-active": true }` 지원
5
+ *
6
+ * cn("base", isActive && "active", { "with-icon": hasIcon }, className)
7
+ */
8
+ export type ClassValue =
9
+ | string
10
+ | number
11
+ | boolean
12
+ | null
13
+ | undefined
14
+ | { [key: string]: boolean | null | undefined }
15
+ | ClassValue[];
16
+
17
+ export function cn(...inputs: ClassValue[]): string {
18
+ const out: string[] = [];
19
+
20
+ const push = (v: ClassValue) => {
21
+ if (!v && v !== 0) return;
22
+ if (typeof v === "string" || typeof v === "number") {
23
+ out.push(String(v));
24
+ return;
25
+ }
26
+ if (Array.isArray(v)) {
27
+ for (const item of v) push(item);
28
+ return;
29
+ }
30
+ if (typeof v === "object") {
31
+ for (const key in v) {
32
+ if (v[key]) out.push(key);
33
+ }
34
+ }
35
+ };
36
+
37
+ for (const input of inputs) push(input);
38
+ return out.join(" ");
39
+ }