sh-ui-cli 0.116.0 → 0.118.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/data/changelog/versions.json +24 -0
- package/data/registry/flutter/registry.json +9 -0
- package/data/registry/flutter/widgets/sh_ui_tree.dart +428 -0
- package/data/registry/react/components/rich-text-editor/index.module.tsx +98 -8
- package/data/registry/react/components/rich-text-editor/index.tailwind.tsx +87 -4
- package/data/registry/react/components/rich-text-editor/index.tsx +98 -8
- package/data/registry/react/components/rich-text-editor/rich-text-editor.test.tsx +283 -0
- package/data/registry/react/components/table/index.module.tsx +69 -0
- package/data/registry/react/components/table/index.tailwind.tsx +68 -0
- package/data/registry/react/components/table/index.tsx +69 -0
- package/data/registry/react/components/table/styles.css +57 -0
- package/data/registry/react/components/table/styles.module.css +57 -0
- package/data/registry/react/components/table/table.test.tsx +59 -0
- package/data/registry/react/components/tree/flatten.test.ts +72 -0
- package/data/registry/react/components/tree/flatten.ts +69 -0
- package/data/registry/react/components/tree/index.module.tsx +215 -0
- package/data/registry/react/components/tree/index.tailwind.tsx +224 -0
- package/data/registry/react/components/tree/index.tsx +215 -0
- package/data/registry/react/components/tree/styles.css +69 -0
- package/data/registry/react/components/tree/styles.module.css +69 -0
- package/data/registry/react/components/tree/tree.test.tsx +110 -0
- package/data/registry/react/components/tree/types.ts +36 -0
- package/data/registry/react/peer-versions.json +9 -1
- package/data/registry/react/registry.json +78 -0
- package/data/registry/react/tokens-used.json +76 -1
- package/data/summaries/flutter.json +2 -1
- package/data/summaries/react.json +3 -1
- package/package.json +3 -3
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.sh-ui-tree {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
width: 100%;
|
|
5
|
+
color: var(--foreground);
|
|
6
|
+
font-size: 0.9375rem;
|
|
7
|
+
}
|
|
8
|
+
.sh-ui-tree[data-size="sm"] {
|
|
9
|
+
font-size: var(--text-xs);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.sh-ui-tree__group {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.sh-ui-tree__item {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: var(--space-2);
|
|
21
|
+
padding: var(--space-2) var(--space-2);
|
|
22
|
+
border-radius: calc(var(--radius) - 2px);
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
user-select: none;
|
|
25
|
+
transition: background-color var(--duration-fast) var(--ease-standard);
|
|
26
|
+
}
|
|
27
|
+
.sh-ui-tree__item:not([data-disabled]):hover {
|
|
28
|
+
background: var(--background-muted);
|
|
29
|
+
}
|
|
30
|
+
.sh-ui-tree__item:focus-visible {
|
|
31
|
+
outline: var(--border-width-strong) solid var(--ring);
|
|
32
|
+
outline-offset: -2px;
|
|
33
|
+
}
|
|
34
|
+
.sh-ui-tree__item--selected {
|
|
35
|
+
background: var(--background-muted);
|
|
36
|
+
font-weight: var(--weight-medium);
|
|
37
|
+
}
|
|
38
|
+
.sh-ui-tree__item[data-disabled] {
|
|
39
|
+
color: var(--foreground-muted);
|
|
40
|
+
cursor: not-allowed;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.sh-ui-tree__chevron {
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
width: var(--space-4);
|
|
46
|
+
justify-content: center;
|
|
47
|
+
transition: transform var(--duration-fast) var(--ease-standard);
|
|
48
|
+
}
|
|
49
|
+
.sh-ui-tree__chevron[data-expanded] {
|
|
50
|
+
transform: rotate(90deg);
|
|
51
|
+
}
|
|
52
|
+
.sh-ui-tree__chevron--leaf {
|
|
53
|
+
visibility: hidden;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.sh-ui-tree__icon {
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
}
|
|
59
|
+
.sh-ui-tree__label {
|
|
60
|
+
min-width: 0;
|
|
61
|
+
overflow-wrap: anywhere;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@media (prefers-reduced-motion: reduce) {
|
|
65
|
+
.sh-ui-tree__item,
|
|
66
|
+
.sh-ui-tree__chevron {
|
|
67
|
+
transition: none;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.tree {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
width: 100%;
|
|
5
|
+
color: var(--foreground);
|
|
6
|
+
font-size: 0.9375rem;
|
|
7
|
+
}
|
|
8
|
+
.tree[data-size="sm"] {
|
|
9
|
+
font-size: var(--text-xs);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.tree__group {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.tree__item {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: var(--space-2);
|
|
21
|
+
padding: var(--space-2) var(--space-2);
|
|
22
|
+
border-radius: calc(var(--radius) - 2px);
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
user-select: none;
|
|
25
|
+
transition: background-color var(--duration-fast) var(--ease-standard);
|
|
26
|
+
}
|
|
27
|
+
.tree__item:not([data-disabled]):hover {
|
|
28
|
+
background: var(--background-muted);
|
|
29
|
+
}
|
|
30
|
+
.tree__item:focus-visible {
|
|
31
|
+
outline: var(--border-width-strong) solid var(--ring);
|
|
32
|
+
outline-offset: -2px;
|
|
33
|
+
}
|
|
34
|
+
.tree__item--selected {
|
|
35
|
+
background: var(--background-muted);
|
|
36
|
+
font-weight: var(--weight-medium);
|
|
37
|
+
}
|
|
38
|
+
.tree__item[data-disabled] {
|
|
39
|
+
color: var(--foreground-muted);
|
|
40
|
+
cursor: not-allowed;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.tree__chevron {
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
width: var(--space-4);
|
|
46
|
+
justify-content: center;
|
|
47
|
+
transition: transform var(--duration-fast) var(--ease-standard);
|
|
48
|
+
}
|
|
49
|
+
.tree__chevron[data-expanded] {
|
|
50
|
+
transform: rotate(90deg);
|
|
51
|
+
}
|
|
52
|
+
.tree__chevron--leaf {
|
|
53
|
+
visibility: hidden;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.tree__icon {
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
}
|
|
59
|
+
.tree__label {
|
|
60
|
+
min-width: 0;
|
|
61
|
+
overflow-wrap: anywhere;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@media (prefers-reduced-motion: reduce) {
|
|
65
|
+
.tree__item,
|
|
66
|
+
.tree__chevron {
|
|
67
|
+
transition: none;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { render, screen, fireEvent } from "@testing-library/react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Tree } from "./index";
|
|
5
|
+
import type { TreeNode } from "./types";
|
|
6
|
+
|
|
7
|
+
const nodes: TreeNode[] = [
|
|
8
|
+
{ id: "a", label: "Apple", children: [{ id: "a1", label: "Ant" }] },
|
|
9
|
+
{ id: "b", label: "Banana" },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
describe("Tree 렌더 + 상태", () => {
|
|
13
|
+
it("role=tree 와 최상위 treeitem 을 렌더", () => {
|
|
14
|
+
render(<Tree nodes={nodes} />);
|
|
15
|
+
expect(screen.getByRole("tree")).toBeTruthy();
|
|
16
|
+
const items = screen.getAllByRole("treeitem");
|
|
17
|
+
expect(items.length).toBe(2);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("부모 toggle 클릭으로 비제어 확장 → 자식 노출", () => {
|
|
21
|
+
render(<Tree nodes={nodes} />);
|
|
22
|
+
fireEvent.click(screen.getByText("Apple"));
|
|
23
|
+
expect(screen.getByText("Ant")).toBeTruthy();
|
|
24
|
+
expect(screen.getByRole("treeitem", { name: /Apple/ }).getAttribute("aria-expanded")).toBe("true");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("제어 selectedId 가 aria-selected 로 반영", () => {
|
|
28
|
+
render(<Tree nodes={nodes} selectedId="b" />);
|
|
29
|
+
expect(screen.getByRole("treeitem", { name: /Banana/ }).getAttribute("aria-selected")).toBe("true");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("노드 클릭이 onSelect 를 호출", () => {
|
|
33
|
+
const onSelect = vi.fn();
|
|
34
|
+
render(<Tree nodes={nodes} onSelect={onSelect} />);
|
|
35
|
+
fireEvent.click(screen.getByText("Banana"));
|
|
36
|
+
expect(onSelect).toHaveBeenCalledWith("b");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("aria-level 이 깊이를 반영", () => {
|
|
40
|
+
render(<Tree nodes={nodes} defaultExpandedIds={["a"]} />);
|
|
41
|
+
expect(screen.getByRole("treeitem", { name: /Ant/ }).getAttribute("aria-level")).toBe("2");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("aria-setsize / aria-posinset 가 형제 집합을 반영", () => {
|
|
45
|
+
render(<Tree nodes={nodes} />);
|
|
46
|
+
const apple = screen.getByRole("treeitem", { name: /Apple/ });
|
|
47
|
+
const banana = screen.getByRole("treeitem", { name: /Banana/ });
|
|
48
|
+
expect(apple.getAttribute("aria-setsize")).toBe("2");
|
|
49
|
+
expect(apple.getAttribute("aria-posinset")).toBe("1");
|
|
50
|
+
expect(banana.getAttribute("aria-posinset")).toBe("2");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("제어 expandedIds 는 외부 값이 우선 (클릭 무관)", () => {
|
|
54
|
+
const { rerender } = render(<Tree nodes={nodes} expandedIds={["a"]} />);
|
|
55
|
+
expect(screen.getByText("Ant")).toBeTruthy();
|
|
56
|
+
rerender(<Tree nodes={nodes} expandedIds={[]} />);
|
|
57
|
+
expect(screen.queryByText("Ant")).toBeNull();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("disabled 노드 클릭은 onSelect 를 호출하지 않는다", () => {
|
|
61
|
+
const onSelect = vi.fn();
|
|
62
|
+
const dnodes = [
|
|
63
|
+
{ id: "x", label: "Xenon", disabled: true },
|
|
64
|
+
{ id: "y", label: "Yttrium" },
|
|
65
|
+
];
|
|
66
|
+
render(<Tree nodes={dnodes} onSelect={onSelect} />);
|
|
67
|
+
fireEvent.click(screen.getByText("Xenon"));
|
|
68
|
+
expect(onSelect).not.toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("Tree 키보드", () => {
|
|
73
|
+
function setup() {
|
|
74
|
+
render(<Tree nodes={nodes} defaultExpandedIds={["a"]} defaultSelectedId="a" />);
|
|
75
|
+
return screen.getByRole("tree");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
it("ArrowDown 이 다음 가시 노드로 포커스 이동", () => {
|
|
79
|
+
setup();
|
|
80
|
+
const a = screen.getByRole("treeitem", { name: /Apple/ });
|
|
81
|
+
a.focus();
|
|
82
|
+
fireEvent.keyDown(a, { key: "ArrowDown" });
|
|
83
|
+
expect(screen.getByRole("treeitem", { name: /Ant/ }).getAttribute("tabindex")).toBe("0");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("ArrowLeft 가 열린 부모를 축소", () => {
|
|
87
|
+
setup();
|
|
88
|
+
const a = screen.getByRole("treeitem", { name: /Apple/ });
|
|
89
|
+
a.focus();
|
|
90
|
+
fireEvent.keyDown(a, { key: "ArrowLeft" });
|
|
91
|
+
expect(a.getAttribute("aria-expanded")).toBe("false");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("ArrowRight 가 닫힌 부모를 확장", () => {
|
|
95
|
+
render(<Tree nodes={nodes} />);
|
|
96
|
+
const a = screen.getByRole("treeitem", { name: /Apple/ });
|
|
97
|
+
a.focus();
|
|
98
|
+
fireEvent.keyDown(a, { key: "ArrowRight" });
|
|
99
|
+
expect(a.getAttribute("aria-expanded")).toBe("true");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("Enter 가 포커스 노드를 선택", () => {
|
|
103
|
+
const onSelect = vi.fn();
|
|
104
|
+
render(<Tree nodes={nodes} onSelect={onSelect} />);
|
|
105
|
+
const b = screen.getByRole("treeitem", { name: /Banana/ });
|
|
106
|
+
b.focus();
|
|
107
|
+
fireEvent.keyDown(b, { key: "Enter" });
|
|
108
|
+
expect(onSelect).toHaveBeenCalledWith("b");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface TreeNode {
|
|
4
|
+
id: string;
|
|
5
|
+
label: React.ReactNode;
|
|
6
|
+
children?: TreeNode[];
|
|
7
|
+
icon?: React.ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type TreeSize = "sm" | "md";
|
|
12
|
+
|
|
13
|
+
export interface TreeProps {
|
|
14
|
+
nodes: TreeNode[];
|
|
15
|
+
expandedIds?: string[];
|
|
16
|
+
defaultExpandedIds?: string[];
|
|
17
|
+
onExpandedChange?: (ids: string[]) => void;
|
|
18
|
+
selectedId?: string | null;
|
|
19
|
+
defaultSelectedId?: string | null;
|
|
20
|
+
onSelect?: (id: string | null) => void;
|
|
21
|
+
renderLabel?: (node: TreeNode) => React.ReactNode;
|
|
22
|
+
size?: TreeSize;
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface VisibleNode {
|
|
27
|
+
id: string;
|
|
28
|
+
node: TreeNode;
|
|
29
|
+
level: number;
|
|
30
|
+
parentId: string | null;
|
|
31
|
+
hasChildren: boolean;
|
|
32
|
+
expanded: boolean;
|
|
33
|
+
disabled: boolean;
|
|
34
|
+
setSize: number;
|
|
35
|
+
posInSet: number;
|
|
36
|
+
}
|
|
@@ -3,12 +3,20 @@
|
|
|
3
3
|
"versions": {
|
|
4
4
|
"@base-ui/react": "^1.4.1",
|
|
5
5
|
"@tanstack/react-form": "^1.29.1",
|
|
6
|
+
"@tiptap/core": "^3.26.0",
|
|
7
|
+
"@tiptap/extension-link": "^3.26.0",
|
|
8
|
+
"@tiptap/extension-placeholder": "^3.26.0",
|
|
9
|
+
"@tiptap/extension-text-style": "^3.26.0",
|
|
10
|
+
"@tiptap/pm": "^3.26.0",
|
|
11
|
+
"@tiptap/react": "^3.26.0",
|
|
12
|
+
"@tiptap/starter-kit": "^3.26.0",
|
|
6
13
|
"@vanilla-extract/css": "^1.16.0",
|
|
7
14
|
"class-variance-authority": "^0.7.1",
|
|
8
15
|
"clsx": "^2.1.1",
|
|
9
16
|
"lucide-react": "^1.11.0",
|
|
10
17
|
"react-hook-form": "^7.74.0",
|
|
11
18
|
"shiki": "^4.0.2",
|
|
12
|
-
"tailwind-merge": "^3.5.0"
|
|
19
|
+
"tailwind-merge": "^3.5.0",
|
|
20
|
+
"tiptap-markdown": "^0.9.0"
|
|
13
21
|
}
|
|
14
22
|
}
|
|
@@ -504,10 +504,12 @@
|
|
|
504
504
|
"dependencies": [
|
|
505
505
|
"@tiptap/react",
|
|
506
506
|
"@tiptap/pm",
|
|
507
|
+
"@tiptap/core",
|
|
507
508
|
"@tiptap/starter-kit",
|
|
508
509
|
"@tiptap/extension-placeholder",
|
|
509
510
|
"@tiptap/extension-link",
|
|
510
511
|
"@tiptap/extension-text-style",
|
|
512
|
+
"tiptap-markdown",
|
|
511
513
|
"lucide-react"
|
|
512
514
|
],
|
|
513
515
|
"registryDependencies": ["utils"]
|
|
@@ -1659,6 +1661,82 @@
|
|
|
1659
1661
|
"dependencies": ["@base-ui/react"],
|
|
1660
1662
|
"registryDependencies": ["utils"]
|
|
1661
1663
|
},
|
|
1664
|
+
"tree": {
|
|
1665
|
+
"name": "tree",
|
|
1666
|
+
"type": "component",
|
|
1667
|
+
"files": [
|
|
1668
|
+
{
|
|
1669
|
+
"src": "components/tree/index.tsx",
|
|
1670
|
+
"dest": "{components}/tree/index.tsx",
|
|
1671
|
+
"frameworks": ["plain"]
|
|
1672
|
+
},
|
|
1673
|
+
{
|
|
1674
|
+
"src": "components/tree/types.ts",
|
|
1675
|
+
"dest": "{components}/tree/types.ts",
|
|
1676
|
+
"frameworks": ["plain", "tailwind", "css-modules"]
|
|
1677
|
+
},
|
|
1678
|
+
{
|
|
1679
|
+
"src": "components/tree/flatten.ts",
|
|
1680
|
+
"dest": "{components}/tree/flatten.ts",
|
|
1681
|
+
"frameworks": ["plain", "tailwind", "css-modules"]
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
"src": "components/tree/styles.css",
|
|
1685
|
+
"dest": "{components}/tree/styles.css",
|
|
1686
|
+
"frameworks": ["plain"]
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
"src": "components/tree/index.tailwind.tsx",
|
|
1690
|
+
"dest": "{components}/tree/index.tsx",
|
|
1691
|
+
"frameworks": ["tailwind"]
|
|
1692
|
+
},
|
|
1693
|
+
{
|
|
1694
|
+
"src": "components/tree/index.module.tsx",
|
|
1695
|
+
"dest": "{components}/tree/index.tsx",
|
|
1696
|
+
"frameworks": ["css-modules"]
|
|
1697
|
+
},
|
|
1698
|
+
{
|
|
1699
|
+
"src": "components/tree/styles.module.css",
|
|
1700
|
+
"dest": "{components}/tree/styles.module.css",
|
|
1701
|
+
"frameworks": ["css-modules"]
|
|
1702
|
+
}
|
|
1703
|
+
],
|
|
1704
|
+
"dependencies": [],
|
|
1705
|
+
"registryDependencies": ["utils"]
|
|
1706
|
+
},
|
|
1707
|
+
"table": {
|
|
1708
|
+
"name": "table",
|
|
1709
|
+
"type": "component",
|
|
1710
|
+
"files": [
|
|
1711
|
+
{
|
|
1712
|
+
"src": "components/table/index.tsx",
|
|
1713
|
+
"dest": "{components}/table/index.tsx",
|
|
1714
|
+
"frameworks": ["plain"]
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
"src": "components/table/styles.css",
|
|
1718
|
+
"dest": "{components}/table/styles.css",
|
|
1719
|
+
"frameworks": ["plain"]
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
"src": "components/table/index.tailwind.tsx",
|
|
1723
|
+
"dest": "{components}/table/index.tsx",
|
|
1724
|
+
"frameworks": ["tailwind"]
|
|
1725
|
+
},
|
|
1726
|
+
{
|
|
1727
|
+
"src": "components/table/index.module.tsx",
|
|
1728
|
+
"dest": "{components}/table/index.tsx",
|
|
1729
|
+
"frameworks": ["css-modules"]
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
"src": "components/table/styles.module.css",
|
|
1733
|
+
"dest": "{components}/table/styles.module.css",
|
|
1734
|
+
"frameworks": ["css-modules"]
|
|
1735
|
+
}
|
|
1736
|
+
],
|
|
1737
|
+
"dependencies": [],
|
|
1738
|
+
"registryDependencies": ["utils"]
|
|
1739
|
+
},
|
|
1662
1740
|
"carousel": {
|
|
1663
1741
|
"name": "carousel",
|
|
1664
1742
|
"type": "component",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$description": "컴포넌트별 토큰 의존성 (var(--*) 추출). build-registry-tokens.mjs 가 자동 생성.",
|
|
3
|
-
"$generated": "2026-06-
|
|
3
|
+
"$generated": "2026-06-19T00:56:42.605Z",
|
|
4
4
|
"components": {
|
|
5
5
|
"button": {
|
|
6
6
|
"plain": [
|
|
@@ -1931,6 +1931,81 @@
|
|
|
1931
1931
|
],
|
|
1932
1932
|
"vanilla-extract": []
|
|
1933
1933
|
},
|
|
1934
|
+
"tree": {
|
|
1935
|
+
"plain": [
|
|
1936
|
+
"--background-muted",
|
|
1937
|
+
"--border-width-strong",
|
|
1938
|
+
"--duration-fast",
|
|
1939
|
+
"--ease-standard",
|
|
1940
|
+
"--foreground",
|
|
1941
|
+
"--foreground-muted",
|
|
1942
|
+
"--radius",
|
|
1943
|
+
"--ring",
|
|
1944
|
+
"--space-2",
|
|
1945
|
+
"--space-4",
|
|
1946
|
+
"--text-xs",
|
|
1947
|
+
"--weight-medium"
|
|
1948
|
+
],
|
|
1949
|
+
"tailwind": [
|
|
1950
|
+
"--border-width-strong",
|
|
1951
|
+
"--duration-fast",
|
|
1952
|
+
"--radius",
|
|
1953
|
+
"--space-2",
|
|
1954
|
+
"--space-4",
|
|
1955
|
+
"--text-xs"
|
|
1956
|
+
],
|
|
1957
|
+
"css-modules": [
|
|
1958
|
+
"--background-muted",
|
|
1959
|
+
"--border-width-strong",
|
|
1960
|
+
"--duration-fast",
|
|
1961
|
+
"--ease-standard",
|
|
1962
|
+
"--foreground",
|
|
1963
|
+
"--foreground-muted",
|
|
1964
|
+
"--radius",
|
|
1965
|
+
"--ring",
|
|
1966
|
+
"--space-2",
|
|
1967
|
+
"--space-4",
|
|
1968
|
+
"--text-xs",
|
|
1969
|
+
"--weight-medium"
|
|
1970
|
+
],
|
|
1971
|
+
"vanilla-extract": []
|
|
1972
|
+
},
|
|
1973
|
+
"table": {
|
|
1974
|
+
"plain": [
|
|
1975
|
+
"--background-muted",
|
|
1976
|
+
"--border",
|
|
1977
|
+
"--control-md",
|
|
1978
|
+
"--duration-fast",
|
|
1979
|
+
"--ease-standard",
|
|
1980
|
+
"--foreground",
|
|
1981
|
+
"--foreground-muted",
|
|
1982
|
+
"--space-3",
|
|
1983
|
+
"--text-sm",
|
|
1984
|
+
"--text-xs",
|
|
1985
|
+
"--weight-medium"
|
|
1986
|
+
],
|
|
1987
|
+
"tailwind": [
|
|
1988
|
+
"--control-md",
|
|
1989
|
+
"--duration-fast",
|
|
1990
|
+
"--space-3",
|
|
1991
|
+
"--text-sm",
|
|
1992
|
+
"--text-xs"
|
|
1993
|
+
],
|
|
1994
|
+
"css-modules": [
|
|
1995
|
+
"--background-muted",
|
|
1996
|
+
"--border",
|
|
1997
|
+
"--control-md",
|
|
1998
|
+
"--duration-fast",
|
|
1999
|
+
"--ease-standard",
|
|
2000
|
+
"--foreground",
|
|
2001
|
+
"--foreground-muted",
|
|
2002
|
+
"--space-3",
|
|
2003
|
+
"--text-sm",
|
|
2004
|
+
"--text-xs",
|
|
2005
|
+
"--weight-medium"
|
|
2006
|
+
],
|
|
2007
|
+
"vanilla-extract": []
|
|
2008
|
+
},
|
|
1934
2009
|
"carousel": {
|
|
1935
2010
|
"plain": [
|
|
1936
2011
|
"--background",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"progress": "ShUiProgress — 선형 진행률, indeterminate.",
|
|
38
38
|
"spinner": "ShUiSpinner — 원형 로딩.",
|
|
39
39
|
"separator": "ShUiSeparator — 구분선 (horizontal/vertical).",
|
|
40
|
-
"skeleton": "ShUiSkeleton — 로딩 플레이스홀더."
|
|
40
|
+
"skeleton": "ShUiSkeleton — 로딩 플레이스홀더.",
|
|
41
|
+
"tree": "ShUiTree — 계층 데이터 트리. 확장/축소 + 단일 선택(제어·비제어). ShUiTreeNode(id/label/children/icon/disabled) 재귀. 키보드(화살표·Home/End·Enter/Space)·Semantics. ShUiTreeSize sm/md."
|
|
41
42
|
}
|
|
42
43
|
}
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"page-toc": "페이지 자동 목차 — 헤딩 스캔 · slugify · IntersectionObserver active 추적 · smooth scroll. routeKey 로 라우트 변경 자동 재스캔, levels/excludeSelector 커스터마이즈.",
|
|
43
43
|
"code-editor": "CodeMirror 6 기반 코드 에디터 — js/ts/jsx/tsx/json/css/html/markdown, sh-ui 토큰 테마, readOnly·placeholder·minHeight/maxHeight. controlled(value/onChange) · uncontrolled(defaultValue) 모두 지원.",
|
|
44
44
|
"markdown-editor": "마크다운 에디터 — CodeEditor + react-markdown 라이브 프리뷰 합성, GFM 지원, raw HTML 차단으로 XSS 방어. controlled(value/onChange) · uncontrolled(defaultValue) 모두 지원.",
|
|
45
|
-
"rich-text-editor": "Tiptap 3 기반 WYSIWYG 에디터 —
|
|
45
|
+
"rich-text-editor": "Tiptap 3 기반 WYSIWYG 에디터 — format='html'(기본) 또는 format='markdown'(tiptap-markdown 직렬화) I/O, 기본 toolbar(헤딩·리스트·인용·코드·링크·강조), readOnly·placeholder. submitOnEnter+onSubmit(Enter 전송·Shift+Enter 줄바꿈), extensions(추가 확장 주입)·onCreate(에디터 인스턴스 접근). controlled(value/onChange) · uncontrolled(defaultValue) 모두 지원.",
|
|
46
46
|
"base": "CSS 리셋 — base.css.",
|
|
47
47
|
"breakpoints": "반응형 미디어 쿼리 토큰 — breakpoints.css.",
|
|
48
48
|
"focus-ring": "공용 포커스 링 스타일 — focus-ring.css.",
|
|
@@ -57,6 +57,8 @@
|
|
|
57
57
|
"form-tanstack": "TanStack Form 인스턴스 → sh-ui FormStore 어댑터. `adaptTanstackForm(tanstackInstance, config)` — TanStack Form 이 state owner. @tanstack/react-form 은 peerDependency.",
|
|
58
58
|
"calendar": "내부 캘린더 위젯 (DatePicker 가 사용). single / multiple / range 모드. CalendarMessages 로 a11y 텍스트 override. 일반적으로 직접 사용보다 DatePicker / DateRangePicker 권장.",
|
|
59
59
|
"scroll-area": "커스텀 스크롤 컨테이너 — composite export ScrollArea (Base UI). 내부에서 viewport + scrollbar + thumb + corner 를 자동 구성하며 OS-native 스크롤바를 대체한다. orientation: \"vertical\" | \"horizontal\" | \"both\" (기본 vertical). 외부 height/width 가 정해진 컨테이너 안에서 사용. viewportClassName 으로 viewport 의 패딩/레이아웃 분리 적용. 스크롤바는 hover/scrolling 시 fade in, prefers-reduced-motion 존중.",
|
|
60
|
+
"tree": "계층 데이터 트리 뷰 — Tree 단일 export + TreeNode 타입(`@/components/ui/tree/types`). nodes(TreeNode[]: id/label/children/icon/disabled) 를 평탄화해 role=tree 로 렌더. 확장: expandedIds/onExpandedChange(controlled) 또는 defaultExpandedIds(uncontrolled). 선택: selectedId/onSelect(controlled) 또는 defaultSelectedId(uncontrolled). 키보드 네비(화살표·Home/End·Enter·typeahead), renderLabel 커스텀 렌더러, size(sm/md). Base UI 비의존 자체 구현.",
|
|
61
|
+
"table": "데이터 테이블 프리미티브 — Table / TableHeader / TableBody / TableFooter / TableRow / TableHead / TableCell / TableCaption 8종 presentational (네이티브 <table> + sh-ui 토큰, 의존성 0). 정렬·행선택·페이지네이션은 TanStack Table v8 로 조립 — docs 의 data-table 예제 참고. shadcn 모델(headless 엔진 + presentational 레이어).",
|
|
60
62
|
"sheet": "화면 가장자리에서 슬라이드 인 하는 side drawer — separate exports: Sheet / SheetTrigger / SheetClose / SheetContent / SheetTitle / SheetDescription / SheetHeader / SheetFooter / SheetCloseX (Base UI Drawer 래핑, 포커스 트랩). 글로벌 알림함 · 작업 큐 · 보조 패널 같은 사이드바 무관 모달 시트용. 사이드바 인근 detail 패널은 SidebarPanel, 중앙 강제 모달은 Dialog 권장. SheetContent 의 side: \"right\" | \"left\" | \"top\" | \"bottom\" (기본 right) 으로 진입 방향 지정. SheetTrigger·SheetClose 는 자체 button — 다른 엘리먼트 슬롯은 `render` prop. ESC/바깥 클릭/포커스 복귀 자동, prefers-reduced-motion 시 transform 트랜지션 제거."
|
|
61
63
|
}
|
|
62
64
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sh-ui-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.118.0",
|
|
4
4
|
"description": "sh-ui CLI — 프로젝트 스캐폴드(create) + 컴포넌트 추가(add/list/remove) + IDE-내 AI용 MCP 서버",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
"components"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@inquirer/prompts": "^8.
|
|
28
|
+
"@inquirer/prompts": "^8.5.2",
|
|
29
29
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
30
30
|
"zod": "^4.4.3"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"fs-extra": "^11.3.5",
|
|
34
|
-
"vitest": "^
|
|
34
|
+
"vitest": "^4.1.8"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|