@iyulab/components 1.22.0 → 1.24.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 (71) hide show
  1. package/CHANGELOG.md +242 -0
  2. package/LICENSE +1 -1
  3. package/README.md +33 -1
  4. package/dist/components/UOverlayElement.d.ts +18 -0
  5. package/dist/components/UOverlayElement.js +24 -0
  6. package/dist/components/badge/UBadge.d.ts +5 -0
  7. package/dist/components/badge/UBadge.js +9 -0
  8. package/dist/components/badge/UBadge.styles.js +6 -0
  9. package/dist/components/dialog/UDialog.styles.js +1 -1
  10. package/dist/components/drawer/UDrawer.styles.js +1 -1
  11. package/dist/components/expander/UExpander.d.ts +38 -0
  12. package/dist/components/expander/UExpander.js +78 -0
  13. package/dist/components/expander/UExpander.styles.d.ts +1 -0
  14. package/dist/components/expander/UExpander.styles.js +95 -0
  15. package/dist/components/field/UField.styles.js +15 -0
  16. package/dist/components/icon/UIcon.d.ts +17 -4
  17. package/dist/components/icon/UIcon.js +9 -6
  18. package/dist/components/panel/UPanel.d.ts +0 -2
  19. package/dist/components/panel/UPanel.js +0 -5
  20. package/dist/components/skeleton/USkeleton.d.ts +7 -0
  21. package/dist/components/skeleton/USkeleton.js +7 -1
  22. package/dist/components/skeleton/USkeleton.styles.js +64 -0
  23. package/dist/components/tab-panel/UTabPanel.d.ts +4 -2
  24. package/dist/components/tab-panel/UTabPanel.js +0 -5
  25. package/dist/components/tag/UTag.d.ts +7 -0
  26. package/dist/components/tag/UTag.js +10 -1
  27. package/dist/components/tag/UTag.styles.js +4 -0
  28. package/dist/components/text/UText.d.ts +38 -0
  29. package/dist/components/text/UText.js +45 -0
  30. package/dist/components/text/UText.styles.d.ts +1 -0
  31. package/dist/components/text/UText.styles.js +91 -0
  32. package/dist/components/tree/UTree.d.ts +4 -2
  33. package/dist/components/tree/UTree.js +0 -5
  34. package/dist/components/tree-item/UTreeItem.d.ts +4 -1
  35. package/dist/components/tree-item/UTreeItem.js +0 -5
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.js +3 -1
  38. package/dist/react/UExpander.d.ts +16 -0
  39. package/dist/react/UExpander.js +13 -0
  40. package/dist/react/UText.d.ts +12 -0
  41. package/dist/react/UText.js +10 -0
  42. package/dist/react/index.d.ts +2 -0
  43. package/dist/react/index.js +2 -0
  44. package/dist/utilities/Dialog.js +1 -1
  45. package/dist/utilities/Locale.d.ts +34 -0
  46. package/dist/utilities/Locale.js +43 -6
  47. package/dist/utilities/Theme.d.ts +37 -0
  48. package/dist/utilities/Theme.js +65 -0
  49. package/dist/utilities/accent.d.ts +52 -0
  50. package/dist/utilities/accent.js +127 -0
  51. package/dist/utilities/icons.js +1 -1
  52. package/dist/utilities/statusIcon.d.ts +31 -0
  53. package/dist/utilities/statusIcon.js +34 -0
  54. package/package.json +5 -3
  55. package/skills/iyulab-components/SKILL.md +4 -1
  56. package/skills/iyulab-components/references/components/badge.md +2 -1
  57. package/skills/iyulab-components/references/components/button.md +3 -1
  58. package/skills/iyulab-components/references/components/copy-button.md +80 -0
  59. package/skills/iyulab-components/references/components/drawer.md +30 -0
  60. package/skills/iyulab-components/references/components/expander.md +70 -0
  61. package/skills/iyulab-components/references/components/icon.md +12 -0
  62. package/skills/iyulab-components/references/components/input.md +6 -0
  63. package/skills/iyulab-components/references/components/panel.md +6 -4
  64. package/skills/iyulab-components/references/components/skeleton.md +12 -0
  65. package/skills/iyulab-components/references/components/tab-panel.md +4 -5
  66. package/skills/iyulab-components/references/components/tag.md +18 -1
  67. package/skills/iyulab-components/references/components/text.md +79 -0
  68. package/skills/iyulab-components/references/components/textarea.md +5 -0
  69. package/skills/iyulab-components/references/components/tree.md +2 -4
  70. package/skills/iyulab-components/references/usage.md +73 -2
  71. package/skills/iyulab-components/references/utilities/theme.md +23 -4
@@ -0,0 +1,34 @@
1
+ //#region src/utilities/statusIcon.ts
2
+ /**
3
+ * 역할 축(의미)의 상태 → 내장 아이콘 이름.
4
+ *
5
+ * ## 왜 있나
6
+ *
7
+ * `u-tag`·`u-badge` 의 상태는 **색으로만** 전달돼 왔다. 색각 이상(남성 약 8%)이나 흑백
8
+ * 인쇄에서는 *"성공"* 과 *"실패"* 가 같은 회색 알약이 된다. 대비 계약(1.20.0)은
9
+ * *읽히는가* 를 지키지 *구별되는가* 를 지키지 않는다 — 역할 색 충돌 검사(ΔE)가
10
+ * **색 공간에서** 세운 그 구분을, 이 표는 **모양 공간에서** 세운다.
11
+ *
12
+ * ## 매핑하지 않는 것
13
+ *
14
+ * - **장식 축**(`blue`·`purple` …)은 *색 자체*를 뜻하지 의미를 뜻하지 않는다.
15
+ * - **`neutral`·`primary`** 는 상태가 아니다(`primary` 는 브랜드 강조이지 «좋음»이 아니다).
16
+ *
17
+ * ⇒ 그 자리에 `icon` 을 줘도 **아무것도 그리지 않는다.** 없는 의미를 아이콘으로 지어내면
18
+ * 그 아이콘이 잘못된 정보를 나른다.
19
+ *
20
+ * ⚠**`u-alert` 의 `status` 축(`error`·`notice` …)은 다른 어휘다** — 이름이 겹치지 않으므로
21
+ * 한 표로 합치지 않았다. 합치려면 두 축의 이름을 먼저 통일해야 하고, 그것은 파괴적 변경이다.
22
+ */
23
+ var STATUS_ICON = {
24
+ info: "info-circle-fill",
25
+ success: "circle-check-fill",
26
+ warning: "alert-triangle-fill",
27
+ danger: "alert-circle-fill"
28
+ };
29
+ /** 역할 값이면 아이콘 이름을, 아니면 `undefined` 를 돌려준다. */
30
+ function statusIcon(color) {
31
+ return color && color in STATUS_ICON ? STATUS_ICON[color] : void 0;
32
+ }
33
+ //#endregion
34
+ export { STATUS_ICON, statusIcon };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iyulab/components",
3
3
  "description": "web-components library based on lit-element made by iyulab",
4
- "version": "1.22.0",
4
+ "version": "1.24.0",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "components",
@@ -42,13 +42,15 @@
42
42
  "test:browser": "vitest run --project=browser",
43
43
  "lint": "eslint src/",
44
44
  "lint:fix": "eslint src/ --fix",
45
- "build": "eslint && npm run typecheck:plugins && vite build && npm run build:plugins && npm run test:react-types",
45
+ "build": "npm run typecheck && eslint && npm run typecheck:plugins && vite build && npm run build:plugins && npm run test:react-types",
46
46
  "test:react-types": "tsc -p tsconfig.react-smoke.json",
47
47
  "typecheck:plugins": "tsc -p plugins/tsconfig.json",
48
48
  "docs:cssprops": "node scripts/cssprops-doc.mjs --write",
49
49
  "docs:react-events": "node scripts/react-events-doc.mjs --write",
50
50
  "docs:tokens": "node scripts/design-tokens-doc.mjs --write",
51
- "build:plugins": "tsc -p plugins/tsconfig.build.json"
51
+ "build:plugins": "tsc -p plugins/tsconfig.build.json",
52
+ "probe:seed-ramp": "node scripts/seed-ramp.mjs",
53
+ "typecheck": "tsc --noEmit"
52
54
  },
53
55
  "dependencies": {
54
56
  "@floating-ui/dom": "^1.8.0",
@@ -59,6 +59,7 @@ import { UButton, UInput } from '@iyulab/components/react';
59
59
 
60
60
  - [`u-button`](./references/components/button.md) — Versatile button with multiple variants; renders as `<a>` when `href` is set
61
61
  - [`u-icon-button`](./references/components/icon-button.md) — Square icon-only button with built-in tooltip
62
+ - [`u-copy-button`](./references/components/copy-button.md) — Copies text to the clipboard with a transient confirmation
62
63
  - [`u-button-group`](./references/components/button-group.md) — Groups buttons with shared variant and disabled state
63
64
 
64
65
  ### Form Controls
@@ -98,7 +99,8 @@ import { UButton, UInput } from '@iyulab/components/react';
98
99
  - [`u-card`](./references/components/card.md) — Content card with media, header, and footer slots
99
100
  - [`u-carousel`](./references/components/carousel.md) — Slide carousel with autoplay, navigation, and pagination
100
101
  - [`u-split-panel`](./references/components/split-panel.md) — Resizable two-panel layout
101
- - [`u-panel`](./references/components/panel.md) — General-purpose content panel with optional collapsing
102
+ - [`u-panel`](./references/components/panel.md) — General-purpose content panel
103
+ - [`u-expander`](./references/components/expander.md) — Disclosure section; header toggles the body open/closed
102
104
  - [`u-divider`](./references/components/divider.md) — Horizontal or vertical separator line
103
105
 
104
106
  ### Data Display
@@ -108,6 +110,7 @@ import { UButton, UInput } from '@iyulab/components/react';
108
110
  - [`u-chip`](./references/components/chip.md) — Selectable/removable chip tag
109
111
  - [`u-tag`](./references/components/tag.md) — Non-interactive label tag
110
112
  - [`u-icon`](./references/components/icon.md) — SVG icon from built-in or external icon library
113
+ - [`u-text`](./references/components/text.md) — Semantic typography step; optional heading level
111
114
 
112
115
  ---
113
116
 
@@ -34,5 +34,6 @@ Status badge for numbers, labels, or dot indicators. Use `anchor` to position it
34
34
  | Property | Type | Default | Reflect | Description |
35
35
  |----------|------|---------|---------|-------------|
36
36
  | `variant` | `'pill'\|'dot'\|'square'` | `'pill'` | ✓ | Shape variant; `dot` renders no content |
37
- | `color` | `'neutral'\|'blue'\|'green'\|'yellow'\|'red'\|'orange'\|'teal'\|'cyan'\|'purple'\|'pink'` | `'neutral'` | ✓ | Badge color |
37
+ | `color` | `'neutral'\|'primary'\|'info'\|'success'\|'warning'\|'danger'\|'blue'\|'green'\|'yellow'\|'red'\|'orange'\|'teal'\|'cyan'\|'purple'\|'pink'` | `'blue'` | ✓ | Badge color (role axis = semantics, decorative axis = the color itself) |
38
38
  | `anchor` | `'top-right'\|'top-left'\|'bottom-right'\|'bottom-left'` | — | ✓ | Absolute anchor position relative to parent |
39
+ | `icon` | `boolean` | `false` | ✓ | Adds a status icon so the meaning survives without color (`info`/`success`/`warning`/`danger`; not drawn for `variant="dot"`) |
@@ -45,12 +45,14 @@ Versatile button with multiple visual variants. Renders as an `<a>` element when
45
45
  | Property | Type | Default | Reflect | Description |
46
46
  |----------|------|---------|---------|-------------|
47
47
  | `variant` | `'solid'\|'surface'\|'filled'\|'outlined'\|'ghost'\|'link'` | `'solid'` | ✓ | Visual style |
48
- | `color` | `'neutral'\|'blue'\|'green'\|'red'\|'orange'\|'teal'\|'cyan'\|'purple'\|'pink'` | `'neutral'` | ✓ | Semantic color, independent of `variant`. `ghost` is unaffected (see notes below). |
48
+ | `color` | `'neutral'\|'primary'\|'info'\|'success'\|'warning'\|'danger'\|'blue'\|'green'\|'red'\|'orange'\|'teal'\|'cyan'\|'purple'\|'pink'` | `'neutral'` | ✓ | Semantic color, independent of `variant`. `ghost` is unaffected (see notes below). |
49
49
  | `size` | `'sm'\|'md'\|'lg'` | `'md'` | ✓ | Button size (12px/14px/16px font-size; padding, spinner, and icon slots scale proportionally). |
50
50
  | `rounded` | `boolean` | `false` | ✓ | Pill-shaped border radius |
51
51
  | `disabled` | `boolean` | `false` | ✓ | Disable the button |
52
52
  | `loading` | `boolean` | `false` | ✓ | Show loading spinner; disables interaction |
53
53
  | `type` | `'button'\|'submit'\|'reset'` | `'button'` | — | Button `type` attribute |
54
+ | `name` | `string` | — | ✓ | Form field name — submitted with the form |
55
+ | `value` | `string` | — | ✓ | Form field value — submitted with the form |
54
56
  | `href` | `string` | — | — | Link URL (renders as `<a>`) |
55
57
  | `target` | `string` | — | — | Link `target` |
56
58
  | `rel` | `string` | — | — | Link `rel` |
@@ -0,0 +1,80 @@
1
+ # u-copy-button
2
+
3
+ ```ts
4
+ import '@iyulab/components/dist/components/copy-button/UCopyButton.js';
5
+ ```
6
+
7
+ **Tag:** `u-copy-button`
8
+
9
+ Copies text to the clipboard and shows a transient confirmation by swapping its icon.
10
+
11
+ Two shapes:
12
+
13
+ - **Icon only** (default) — the default slot becomes the tooltip.
14
+ - **Icon + label** — set `label` to render visible text beside the icon.
15
+
16
+ The clipboard logic is identical in both.
17
+
18
+ ```html
19
+ <!-- Icon only; slot content is the tooltip -->
20
+ <u-copy-button value="npm i @iyulab/components">Copy install command</u-copy-button>
21
+
22
+ <!-- Icon + label -->
23
+ <u-copy-button value="RESULT-1024" label="Copy result"></u-copy-button>
24
+
25
+ <!-- Stays in the copied state until reset explicitly -->
26
+ <u-copy-button value="token" .delay=${0}></u-copy-button>
27
+ ```
28
+
29
+ ## Changing or cancelling what gets copied
30
+
31
+ The `copy` event fires **before** the write, so a handler can rewrite the payload or cancel:
32
+
33
+ ```ts
34
+ button.addEventListener('copy', (e: ClipboardEvent) => {
35
+ e.clipboardData?.setData('text/plain', transform(button.value));
36
+ e.preventDefault(); // cancel the built-in write
37
+ });
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Slots
43
+
44
+ | Name | Description |
45
+ |------|-------------|
46
+ | *(default)* | Tooltip content, icon-only shape. Unused when `label` is set |
47
+
48
+ ## Properties
49
+
50
+ | Property | Type | Default | Reflect | Description |
51
+ |----------|------|---------|---------|-------------|
52
+ | `variant` | `'solid'\|'outline'\|'ghost'\|'link'` | `'ghost'` | ✓ | Button style |
53
+ | `rounded` | `boolean` | `false` | ✓ | Circular shape |
54
+ | `disabled` | `boolean` | `false` | ✓ | Disabled state |
55
+ | `copied` | `boolean` | `false` | ✓ | Currently showing the copied state |
56
+ | `tooltipPlacement` | `Placement` | `"top"` | | Tooltip placement (`tooltip-placement`) |
57
+ | `tooltipOffset` | `OffsetOptions` | `4` | | Tooltip distance (`tooltip-offset`) |
58
+ | `delay` | `number` | `1_000` | | Milliseconds before leaving the copied state; `0` or less keeps it |
59
+ | `value` | `string` | — | | Text to copy |
60
+ | `label` | `string` | — | | Inline label; switches to the icon + label shape |
61
+
62
+ ## Events
63
+
64
+ | Event | Detail | Description |
65
+ |-------|--------|-------------|
66
+ | `copy` | native `ClipboardEvent` | Fires before the write. `preventDefault()` cancels it; `clipboardData.setData` replaces the payload |
67
+
68
+ ## CSS Parts
69
+
70
+ | Part | Description |
71
+ |------|-------------|
72
+ | `button` | Inner button element |
73
+ | `icon` | Icon element |
74
+ | `tooltip` | Tooltip element (icon-only shape) |
75
+
76
+ ## Sizing
77
+
78
+ This component keeps a **fixed** font size (18px) rather than inheriting the surrounding
79
+ typography — it reads as an affordance next to text of any size. See
80
+ [design-tokens.md](../../../../docs/design-tokens.md) for the four components that do this.
@@ -61,3 +61,33 @@ Side panel that slides in from any screen edge. Extends `UOverlayElement` (focus
61
61
  | `header` | Header area |
62
62
  | `body` | Body area |
63
63
  | `close-btn` | Close button |
64
+
65
+ ---
66
+
67
+ ## Edit-panel pattern
68
+
69
+ A side panel for editing a record needs no extra component — `u-drawer` already provides the
70
+ whole contract. Measured in a real browser
71
+ (`tests/browser/drawer-edit-panel-pattern.browser.test.ts`):
72
+
73
+ ```html
74
+ <u-drawer id="edit" placement="right" closable>
75
+ <span slot="header">Edit order</span>
76
+
77
+ <u-input label="Quantity" autofocus></u-input>
78
+ <u-textarea label="Note"></u-textarea>
79
+
80
+ <div slot="footer">
81
+ <u-button variant="ghost" @click=${() => edit.hide()}>Cancel</u-button>
82
+ <u-button color="primary" @click=${save}>Save</u-button>
83
+ </div>
84
+ </u-drawer>
85
+ ```
86
+
87
+ | Requirement | How it is met |
88
+ |---|---|
89
+ | Focus the first input on open, restore the trigger on close | `[autofocus]` → first input control → first tabbable; focus is returned by the trap |
90
+ | Body scrolls, footer stays visible | `part="body"` is `flex: 1; overflow: auto`; the `footer` slot is `flex-shrink: 0` |
91
+ | Focus cannot leave the panel | `mode="modal"` (default) activates the focus trap |
92
+ | `Esc` closes, background scroll is locked | `closeOn` defaults to `['escape','backdrop','button']` |
93
+ | Nothing pops open by itself | Selects/comboboxes open only on user interaction |
@@ -0,0 +1,70 @@
1
+ # u-expander
2
+
3
+ ```ts
4
+ import '@iyulab/components/dist/components/expander/UExpander.js';
5
+ ```
6
+
7
+ **Tag:** `u-expander`
8
+
9
+ Disclosure section — the header toggles the body open and closed. The header is a native
10
+ `<button>`, so keyboard operation (Enter / Space) and focus order come for free, and the
11
+ collapsed body is removed from both the accessibility tree and the tab order.
12
+
13
+ ```html
14
+ <u-expander label="Shipping details" open>
15
+ <p>Body content.</p>
16
+ </u-expander>
17
+
18
+ <!-- Custom header + trailing slot -->
19
+ <u-expander>
20
+ <span slot="header">Order 1042</span>
21
+ <u-tag slot="suffix" color="success">Paid</u-tag>
22
+ <p>Body content.</p>
23
+ </u-expander>
24
+ ```
25
+
26
+ The open/close transition runs on the motion tokens (`--u-duration-normal` /
27
+ `--u-ease-standard`) and is suppressed under `prefers-reduced-motion: reduce` — the
28
+ transition is decoration here, since the collapsed/expanded result reads the same when static.
29
+
30
+ ---
31
+
32
+ ## Slots
33
+
34
+ | Name | Description |
35
+ |------|-------------|
36
+ | `header` | Replaces the header text (wins over `label`) |
37
+ | *(default)* | Body content, shown while open |
38
+ | `suffix` | Content placed at the end of the header row |
39
+
40
+ ## Properties
41
+
42
+ | Property | Type | Default | Reflect | Description |
43
+ |----------|------|---------|---------|-------------|
44
+ | `open` | `boolean` | `false` | ✓ | Expanded state |
45
+ | `disabled` | `boolean` | `false` | ✓ | Disable the header button |
46
+ | `label` | `string` | `''` | | Header text |
47
+
48
+ ## Events
49
+
50
+ | Event | Cancelable | Description |
51
+ |-------|------------|-------------|
52
+ | `expand` | ✓ | Before the body expands |
53
+ | `collapse` | ✓ | Before the body collapses |
54
+
55
+ ## Methods
56
+
57
+ | Method | Description |
58
+ |--------|-------------|
59
+ | `expand()` | Expand; returns `false` if cancelled or already open |
60
+ | `collapse()` | Collapse; returns `false` if cancelled or already closed |
61
+ | `toggle()` | Switch to the opposite state |
62
+
63
+ ## CSS Parts
64
+
65
+ | Part | Description |
66
+ |------|-------------|
67
+ | `header` | Header button |
68
+ | `icon` | Disclosure chevron |
69
+ | `label` | Header text area |
70
+ | `content` | Body wrapper |
@@ -30,8 +30,19 @@ Renders an SVG icon by name from a registered icon library. Inline `src` also ac
30
30
  <u-icon src='<svg ...>...</svg>'></u-icon>
31
31
  ```
32
32
 
33
+ ```html
34
+ <!-- Fallback: drawn when the name does not resolve -->
35
+ <u-icon name="might-not-exist" fallback='<svg viewBox="0 0 16 16">...</svg>'></u-icon>
36
+ ```
37
+
33
38
  For registering custom libraries, see [icons.md](../utilities/icons.md).
34
39
 
40
+ > **When you need `fallback`.** An icon that fails to resolve renders nothing. That is usually
41
+ > harmless — but not where the icon is the only hit target. A collapsed sidebar hides labels, so
42
+ > a nav item with no visible icon becomes an **empty row the user cannot click**: the screen
43
+ > becomes unreachable. `fallback` covers all three failure modes (no `name`, 404, unparseable SVG).
44
+ > Keep the fallback **inline**; a fallback that fetches reproduces the very failure it covers.
45
+
35
46
  ---
36
47
 
37
48
  ## Properties
@@ -41,6 +52,7 @@ For registering custom libraries, see [icons.md](../utilities/icons.md).
41
52
  | `lib` | `'internal'\|'tabler'\|'heroicons'\|'lucide'\|'bootstrap'\|string` | — | Icon library identifier |
42
53
  | `name` | `string` | — | Icon name (library-specific; append `:filled` / `:solid` for filled variants) |
43
54
  | `src` | `string` | — | Raw SVG string (overrides `lib`/`name`) |
55
+ | `fallback` | `string` | — | Raw SVG drawn when `name`/`src` cannot be resolved (missing, 404, or unparseable) |
44
56
 
45
57
  ## CSS Parts
46
58
 
@@ -50,6 +50,12 @@ Text input field with prefix/suffix slots and label. Add `u-option` children for
50
50
  | `autofocus` | `boolean` | `false` | — | Auto-focus on render |
51
51
  | `autocomplete` | `AutoFill` | — | — | Browser autocomplete |
52
52
  | `spellcheck` | `boolean` | `false` | — | Spellcheck |
53
+ | `dirname` | `string` | — | — | Native `dirname` — submits the text direction with the form |
54
+ | `inputmode` | `'none'\|'text'\|'decimal'\|'numeric'\|'tel'\|'search'\|'email'\|'url'` | — | — | Virtual keyboard hint |
55
+ | `enterkeyhint` | `'enter'\|'done'\|'go'\|'next'\|'previous'\|'search'\|'send'` | — | — | Enter-key label hint |
56
+ | `autocorrect` | `boolean` | `false` | — | Native autocorrect (Safari/iOS) |
57
+ | `autocapitalize` | `'off'\|'none'\|'on'\|'sentences'\|'words'\|'characters'` | `'off'` | — | Auto-capitalization behavior |
58
+ | `size` | `number` | — | — | Native `size` — visible width in characters |
53
59
  | `disabled` | `boolean` | `false` | ✓ | Disabled |
54
60
  | `readonly` | `boolean` | `false` | ✓ | Read-only |
55
61
  | `required` | `boolean` | `false` | ✓ | Required |
@@ -6,11 +6,14 @@ import '@iyulab/components/dist/components/panel/UPanel.js';
6
6
 
7
7
  **Tag:** `u-panel`
8
8
 
9
- General-purpose content panel. Matches a tab or tree node when using `value`. Supports optional collapsing.
9
+ General-purpose content panel. Matches a tab or tree node when using `value`.
10
+
11
+ > Looking for a collapsible section? Use [`u-expander`](expander.md). `u-panel` previously
12
+ > declared a `collapsible` property that was never implemented — it has been removed.
10
13
 
11
14
  ```html
12
- <!-- Standalone collapsible panel -->
13
- <u-panel collapsible>Content inside panel</u-panel>
15
+ <!-- Standalone panel -->
16
+ <u-panel>Content inside panel</u-panel>
14
17
 
15
18
  <!-- Inside u-tab-panel (matched by value) -->
16
19
  <u-tab-panel>
@@ -35,4 +38,3 @@ General-purpose content panel. Matches a tab or tree node when using `value`. Su
35
38
  |----------|------|---------|---------|-------------|
36
39
  | `value` | `string` | `''` | ✓ | Identifier used for tab/tree matching |
37
40
  | `disabled` | `boolean` | `false` | ✓ | Disable the panel |
38
- | `collapsible` | `boolean` | `false` | ✓ | Allow the panel to collapse |
@@ -17,6 +17,9 @@ Placeholder shape displayed while content is loading.
17
17
 
18
18
  <!-- Card placeholder -->
19
19
  <u-skeleton shape="rounded" width="100%" height="120px" effect="shimmer"></u-skeleton>
20
+
21
+ <!-- Paragraph / list-row placeholder: 3 stacked bars, last one shortened -->
22
+ <u-skeleton lines="3" height="1em"></u-skeleton>
20
23
  ```
21
24
 
22
25
  ---
@@ -35,6 +38,7 @@ Placeholder shape displayed while content is loading.
35
38
  | `effect` | `'none'\|'pulse'\|'shimmer'` | `'shimmer'` | ✓ | Animation style |
36
39
  | `width` | `string` | — | — | CSS width value |
37
40
  | `height` | `string` | — | — | CSS height value |
41
+ | `lines` | `number` | — | ✓ | Draw N stacked bars instead of one (takes effect at 2+); the last bar is shortened |
38
42
 
39
43
  ## CSS Custom Properties
40
44
 
@@ -44,3 +48,11 @@ Placeholder shape displayed while content is loading.
44
48
  | `--skeleton-height` | Override height |
45
49
  | `--skeleton-color` | Base placeholder color |
46
50
  | `--skeleton-shimmer-color` | Shimmer highlight color |
51
+ | `--skeleton-line-gap` | Gap between bars when `lines` is set (default `0.5em`) |
52
+ | `--skeleton-last-line-width` | Width of the last bar when `lines` is set (default `60%`) |
53
+
54
+ ## CSS Parts
55
+
56
+ | Part | Description |
57
+ |------|-------------|
58
+ | `line` | One bar of a multi-line placeholder (only rendered when `lines` is set) |
@@ -21,8 +21,8 @@ Tab-based content switcher. Pair each `u-tab` with a `u-panel` of the same `valu
21
21
  <u-panel value="settings">Settings content</u-panel>
22
22
  </u-tab-panel>
23
23
 
24
- <!-- Card variant, right placement, editable -->
25
- <u-tab-panel variant="card" placement="left" editable draggable>
24
+ <!-- Card variant, left placement -->
25
+ <u-tab-panel variant="card" placement="left">
26
26
  <u-tab value="a" removable>Tab A</u-tab>
27
27
  <u-panel value="a">Panel A</u-panel>
28
28
  </u-tab-panel>
@@ -46,8 +46,7 @@ Tab-based content switcher. Pair each `u-tab` with a `u-panel` of the same `valu
46
46
  | `value` | `string` | `''` | ✓ | Currently active tab value |
47
47
  | `variant` | `'line'\|'card'\|'pill'\|'plain'` | `'line'` | ✓ | Tab bar style |
48
48
  | `placement` | `'top'\|'bottom'\|'left'\|'right'` | `'top'` | ✓ | Tab bar position |
49
- | `editable` | `boolean` | `false` | ✓ | Allow adding/removing tabs |
50
- | `draggable` | `boolean` | `false` | ✓ | Allow reordering tabs by drag |
49
+ | `draggable` | `boolean` | `false` | ✓ | Native drag attribute — **no built-in reordering** |
51
50
  | `disabled` | `boolean` | `false` | ✓ | Disable all tabs |
52
51
 
53
52
  ### Events
@@ -84,7 +83,7 @@ Tab-based content switcher. Pair each `u-tab` with a `u-panel` of the same `valu
84
83
  | `value` | `string` | `''` | ✓ | Matches a `u-panel` with the same `value` |
85
84
  | `disabled` | `boolean` | `false` | ✓ | Disable the tab |
86
85
  | `removable` | `boolean` | `false` | ✓ | Show close/remove button |
87
- | `draggable` | `boolean` | `false` | ✓ | Allow dragging to reorder |
86
+ | `draggable` | `boolean` | `false` | ✓ | Native drag attribute **no built-in reordering** |
88
87
 
89
88
  ### Events
90
89
 
@@ -37,14 +37,31 @@ For interactive chips (selectable/removable), use [`u-chip`](./chip.md) instead.
37
37
  | Property | Type | Default | Reflect | Description |
38
38
  |----------|------|---------|---------|-------------|
39
39
  | `variant` | `'solid'\|'surface'\|'filled'\|'outlined'` | `'filled'` | ✓ | Visual style |
40
- | `color` | `'neutral'\|'blue'\|'green'\|'yellow'\|'red'\|'orange'\|'teal'\|'cyan'\|'purple'\|'pink'` | `'neutral'` | ✓ | Color |
40
+ | `color` | `'neutral'\|'primary'\|'info'\|'success'\|'warning'\|'danger'\|'blue'\|'green'\|'yellow'\|'red'\|'orange'\|'teal'\|'cyan'\|'purple'\|'pink'` | `'neutral'` | ✓ | Color |
41
41
  | `rounded` | `boolean` | `false` | ✓ | Pill shape |
42
+ | `icon` | `boolean` | `false` | ✓ | Adds a status icon so the meaning survives without color (`info`/`success`/`warning`/`danger` only) |
42
43
 
43
44
  ## CSS Parts
44
45
 
45
46
  | Part | Description |
46
47
  |------|-------------|
47
48
  | `content` | Inner content wrapper |
49
+ | `icon` | Status icon (rendered only with `icon` + a semantic `color`) |
50
+
51
+ ## Color axes
52
+
53
+ `color` carries **two** axes. The **role** axis (`primary`·`info`·`success`·`warning`·`danger`)
54
+ means *semantics* — it follows re-branding and inherits the contrast contract. The **decorative**
55
+ axis (`blue`·`purple` …) means *the color itself* and is deliberately immune to re-branding.
56
+
57
+ `icon` only applies to the four **status** roles — `neutral` and `primary` are not states, and the
58
+ decorative axis carries no meaning, so no icon is drawn there.
59
+
60
+ ```html
61
+ <!-- distinguishable in grayscale / for color-vision deficiency -->
62
+ <u-tag color="danger" icon>Failed</u-tag>
63
+ <u-tag color="success" icon>Done</u-tag>
64
+ ```
48
65
 
49
66
  ## CSS Custom Properties
50
67
 
@@ -0,0 +1,79 @@
1
+ # u-text
2
+
3
+ ```ts
4
+ import '@iyulab/components/dist/components/text/UText.js';
5
+ ```
6
+
7
+ **Tag:** `u-text`
8
+
9
+ Semantic typography. Applies one of the seven design-token type steps
10
+ (`display` → `overline`) so markup can use the scale without any consumer CSS.
11
+ The component reads the token sheet — it never defines its own type values.
12
+
13
+ ```html
14
+ <u-text level="1" variant="display">Document title</u-text>
15
+ <u-text variant="subtitle" tone="weak">One-line description</u-text>
16
+
17
+ <u-text>Body copy is the default step.</u-text>
18
+ <u-text variant="caption" tone="weak">Helper text</u-text>
19
+
20
+ <u-text variant="overline">Section</u-text>
21
+ ```
22
+
23
+ ## Visual step and heading level are independent
24
+
25
+ `variant` chooses how the text *looks*; `level` chooses what it *is*. When
26
+ `level` is set the component renders a real `<h1>`–`<h6>` in its shadow root, so
27
+ assistive technology reads it as a heading whose accessible name is the slotted
28
+ text. Without `level` it renders a `<p>`.
29
+
30
+ ```html
31
+ <!-- Second-level heading that is visually the largest thing on the page -->
32
+ <u-text level="2" variant="display">Overview</u-text>
33
+ ```
34
+
35
+ This keeps the document outline honest while leaving the visual hierarchy free.
36
+
37
+ > **Do not nest a heading inside the slot** — `<u-text><h2>…</h2></u-text>` makes
38
+ > the UA rule `h2 { font-size: 1.5em }` multiply the step's font size. Use
39
+ > `level` instead. Wrapping the other way (`<h2><u-text>…</u-text></h2>`) is safe
40
+ > because the steps are absolute sizes, but the outer heading keeps its UA
41
+ > margin, so `level` is still the simpler choice.
42
+
43
+ ## Colour
44
+
45
+ `tone` is a **neutral emphasis axis**, not a role-colour axis. Semantic status
46
+ colour belongs to the component that owns the status (`u-alert`, `u-tag`,
47
+ `u-badge`), and link colour belongs to the link.
48
+
49
+ ---
50
+
51
+ ## Slots
52
+
53
+ | Name | Description |
54
+ |------|-------------|
55
+ | *(default)* | Text content |
56
+
57
+ ## Properties
58
+
59
+ | Property | Type | Default | Reflect | Description |
60
+ |----------|------|---------|---------|-------------|
61
+ | `variant` | `'display'\|'title'\|'subtitle'\|'body'\|'label'\|'caption'\|'overline'` | `'body'` | ✓ | Semantic type step |
62
+ | `tone` | `'default'\|'weak'\|'strong'\|'inverse'` | `'default'` | ✓ | Neutral emphasis axis |
63
+ | `level` | `1\|2\|3\|4\|5\|6` | — | ✓ | Heading level; renders `<h1>`–`<h6>` |
64
+
65
+ ## CSS Parts
66
+
67
+ | Part | Description |
68
+ |------|-------------|
69
+ | `base` | The rendered `<p>` or `<h1>`–`<h6>` element |
70
+
71
+ ## Design tokens read
72
+
73
+ | Step | Tokens |
74
+ |------|--------|
75
+ | `display` · `title` · `subtitle` · `body` · `label` · `caption` · `overline` | `--u-text-{step}-size`, `--u-text-{step}-weight`, `--u-text-{step}-leading`, `--u-text-{step}-tracking` |
76
+ | `tone` | `--u-txt-color`, `--u-txt-color-weak`, `--u-txt-color-strong`, `--u-txt-color-inverse` |
77
+
78
+ Spacing between blocks is **not** this component's concern — it has no margin.
79
+ The surrounding layout decides rhythm (`u-group-box`, `u-card`, a flex column).
@@ -34,6 +34,11 @@ Multi-line text input with auto-resize and optional character counter. Form-asso
34
34
  | `autofocus` | `boolean` | `false` | — | Auto-focus on render |
35
35
  | `autocomplete` | `AutoFill` | — | — | Browser autocomplete |
36
36
  | `spellcheck` | `boolean` | `false` | — | Spellcheck |
37
+ | `dirname` | `string` | — | — | Native `dirname` — submits the text direction with the form |
38
+ | `inputmode` | `'none'\|'text'\|'decimal'\|'numeric'\|'tel'\|'search'\|'email'\|'url'` | — | — | Virtual keyboard hint |
39
+ | `enterkeyhint` | `'enter'\|'done'\|'go'\|'next'\|'previous'\|'search'\|'send'` | — | — | Enter-key label hint |
40
+ | `autocorrect` | `boolean` | `false` | — | Native autocorrect (Safari/iOS) |
41
+ | `autocapitalize` | `'off'\|'none'\|'on'\|'sentences'\|'words'\|'characters'` | `'off'` | — | Auto-capitalization behavior |
37
42
  | `disabled` | `boolean` | `false` | ✓ | Disable |
38
43
  | `readonly` | `boolean` | `false` | ✓ | Read-only |
39
44
  | `required` | `boolean` | `false` | ✓ | Required |
@@ -43,8 +43,7 @@ Hierarchical tree with support for selection, checkboxes, cascade check, and dra
43
43
  | `selectLeaf` | `boolean` | `false` | ✓ | Only leaf nodes are selectable |
44
44
  | `checkable` | `boolean` | `false` | ✓ | Show checkboxes |
45
45
  | `checkCascade` | `boolean` | `false` | ✓ | Parent/child checkbox cascade |
46
- | `draggable` | `boolean` | `false` | ✓ | Enable drag |
47
- | `droppable` | `boolean` | `false` | ✓ | Enable drop |
46
+ | `draggable` | `boolean` | `false` | ✓ | Native drag attribute — **no built-in drag & drop** |
48
47
  | `trigger` | `'item'\|'icon'` | `'item'` | — | Click target to expand/collapse |
49
48
 
50
49
  ### Events
@@ -98,8 +97,7 @@ Hierarchical tree with support for selection, checkboxes, cascade check, and dra
98
97
  | `selectable` | `boolean` | `false` | ✓ | This item can be selected |
99
98
  | `checkable` | `boolean` | `false` | ✓ | Show checkbox |
100
99
  | `loading` | `boolean` | `false` | ✓ | Loading state (async children) |
101
- | `draggable` | `boolean` | `false` | ✓ | Draggable |
102
- | `droppable` | `boolean` | `false` | ✓ | Accepts drops |
100
+ | `draggable` | `boolean` | `false` | ✓ | Native drag attribute — **no built-in drag & drop** |
103
101
  | `trigger` | `'item'\|'icon'` | `'item'` | — | Expand trigger target |
104
102
 
105
103
  ### Events