@designbasekorea/ui-wc 0.13.0 → 0.15.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 (168) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +45 -0
  4. package/README.md +13 -5
  5. package/THIRD-PARTY-NOTICES.md +5 -0
  6. package/dist/esm/components/db-ad-banner.d.ts +6 -0
  7. package/dist/esm/components/db-ad-banner.js +1 -1
  8. package/dist/esm/components/db-animation-background.d.ts +7 -0
  9. package/dist/esm/components/db-animation-background.js +1 -1
  10. package/dist/esm/components/db-avatar.d.ts +2 -0
  11. package/dist/esm/components/db-avatar.js +1 -1
  12. package/dist/esm/components/db-banner.d.ts +2 -0
  13. package/dist/esm/components/db-banner.js +1 -1
  14. package/dist/esm/components/db-bottom-navigation.d.ts +2 -0
  15. package/dist/esm/components/db-bottom-navigation.js +1 -1
  16. package/dist/esm/components/db-card.d.ts +2 -0
  17. package/dist/esm/components/db-card.js +1 -1
  18. package/dist/esm/components/db-carousel.d.ts +2 -0
  19. package/dist/esm/components/db-carousel.js +1 -1
  20. package/dist/esm/components/db-code-block.d.ts +3 -0
  21. package/dist/esm/components/db-code-block.js +1 -1
  22. package/dist/esm/components/db-color-picker.d.ts +5 -0
  23. package/dist/esm/components/db-color-picker.js +1 -1
  24. package/dist/esm/components/db-color-swatch.d.ts +2 -0
  25. package/dist/esm/components/db-color-swatch.js +1 -1
  26. package/dist/esm/components/db-confirm.d.ts +2 -0
  27. package/dist/esm/components/db-confirm.js +1 -1
  28. package/dist/esm/components/db-context-menu.d.ts +6 -2
  29. package/dist/esm/components/db-context-menu.js +1 -1
  30. package/dist/esm/components/db-cookie-banner.d.ts +2 -0
  31. package/dist/esm/components/db-cookie-banner.js +1 -1
  32. package/dist/esm/components/db-drawer.d.ts +2 -0
  33. package/dist/esm/components/db-drawer.js +1 -1
  34. package/dist/esm/components/db-dropdown.d.ts +2 -0
  35. package/dist/esm/components/db-dropdown.js +1 -1
  36. package/dist/esm/components/db-easing-editor.d.ts +5 -0
  37. package/dist/esm/components/db-empty-state.d.ts +2 -0
  38. package/dist/esm/components/db-empty-state.js +1 -1
  39. package/dist/esm/components/db-file-uploader.d.ts +4 -0
  40. package/dist/esm/components/db-file-uploader.js +1 -1
  41. package/dist/esm/components/db-footer.d.ts +2 -0
  42. package/dist/esm/components/db-footer.js +1 -1
  43. package/dist/esm/components/db-gantt.d.ts +2 -0
  44. package/dist/esm/components/db-gantt.js +1 -1
  45. package/dist/esm/components/db-image-list.d.ts +3 -0
  46. package/dist/esm/components/db-image-list.js +1 -1
  47. package/dist/esm/components/db-keyframe-editor.d.ts +5 -0
  48. package/dist/esm/components/db-layer-list.d.ts +71 -0
  49. package/dist/esm/components/db-layer-list.js +1 -0
  50. package/dist/esm/components/db-lightbox.d.ts +4 -0
  51. package/dist/esm/components/db-lightbox.js +1 -1
  52. package/dist/esm/components/db-list.d.ts +2 -0
  53. package/dist/esm/components/db-list.js +1 -1
  54. package/dist/esm/components/db-menu-item.d.ts +2 -0
  55. package/dist/esm/components/db-menu-item.js +1 -1
  56. package/dist/esm/components/db-modal.d.ts +3 -0
  57. package/dist/esm/components/db-modal.js +1 -1
  58. package/dist/esm/components/db-navbar.d.ts +5 -0
  59. package/dist/esm/components/db-navbar.js +1 -1
  60. package/dist/esm/components/db-onboarding-modal.d.ts +3 -0
  61. package/dist/esm/components/db-onboarding-modal.js +1 -1
  62. package/dist/esm/components/db-page-header.d.ts +3 -0
  63. package/dist/esm/components/db-page-header.js +1 -1
  64. package/dist/esm/components/db-pagination.d.ts +2 -0
  65. package/dist/esm/components/db-pagination.js +1 -1
  66. package/dist/esm/components/db-popover.d.ts +2 -0
  67. package/dist/esm/components/db-popover.js +1 -1
  68. package/dist/esm/components/db-search-bar.d.ts +3 -0
  69. package/dist/esm/components/db-search-bar.js +1 -1
  70. package/dist/esm/components/db-section-app-download.d.ts +2 -0
  71. package/dist/esm/components/db-section-app-download.js +1 -1
  72. package/dist/esm/components/db-section-contact.d.ts +2 -0
  73. package/dist/esm/components/db-section-contact.js +1 -1
  74. package/dist/esm/components/db-section-cta.d.ts +3 -0
  75. package/dist/esm/components/db-section-cta.js +1 -1
  76. package/dist/esm/components/db-section-faq.d.ts +2 -0
  77. package/dist/esm/components/db-section-faq.js +1 -1
  78. package/dist/esm/components/db-section-feature.d.ts +3 -0
  79. package/dist/esm/components/db-section-feature.js +1 -1
  80. package/dist/esm/components/db-section-hero.d.ts +2 -0
  81. package/dist/esm/components/db-section-hero.js +1 -1
  82. package/dist/esm/components/db-section-logo-cloud.d.ts +2 -0
  83. package/dist/esm/components/db-section-logo-cloud.js +1 -1
  84. package/dist/esm/components/db-section-pricing.d.ts +3 -0
  85. package/dist/esm/components/db-section-pricing.js +1 -1
  86. package/dist/esm/components/db-section-stats.d.ts +2 -0
  87. package/dist/esm/components/db-section-stats.js +1 -1
  88. package/dist/esm/components/db-section-testimonials.d.ts +4 -0
  89. package/dist/esm/components/db-section-testimonials.js +1 -1
  90. package/dist/esm/components/db-section.d.ts +2 -0
  91. package/dist/esm/components/db-section.js +1 -1
  92. package/dist/esm/components/db-share.d.ts +5 -0
  93. package/dist/esm/components/db-share.js +1 -1
  94. package/dist/esm/components/db-sidebar.d.ts +7 -0
  95. package/dist/esm/components/db-sidebar.js +1 -1
  96. package/dist/esm/components/db-stat.d.ts +2 -0
  97. package/dist/esm/components/db-stat.js +1 -1
  98. package/dist/esm/components/db-table.d.ts +5 -0
  99. package/dist/esm/components/db-table.js +1 -1
  100. package/dist/esm/components/db-testimonial.d.ts +3 -0
  101. package/dist/esm/components/db-testimonial.js +1 -1
  102. package/dist/esm/components/db-time-picker.d.ts +1 -0
  103. package/dist/esm/components/db-time-picker.js +1 -1
  104. package/dist/esm/components/db-top-banner.d.ts +3 -0
  105. package/dist/esm/components/db-top-banner.js +1 -1
  106. package/dist/esm/components/db-tutorial.d.ts +3 -0
  107. package/dist/esm/components/db-tutorial.js +1 -1
  108. package/dist/esm/components/db-video-timeline.d.ts +34 -2
  109. package/dist/esm/components/db-video-timeline.js +1 -1
  110. package/dist/esm/components/db-world-map.d.ts +5 -0
  111. package/dist/esm/components/media-editor-model.d.ts +10 -1
  112. package/dist/esm/core/i18n-en.js +1 -1
  113. package/dist/esm/core/i18n.d.ts +11 -0
  114. package/dist/esm/core/i18n.js +1 -1
  115. package/dist/esm/index.d.ts +2 -1
  116. package/dist/esm/index.js +1 -1
  117. package/dist/index.cjs +1 -1
  118. package/dist/index.css +1 -1
  119. package/dist/index.d.ts +619 -486
  120. package/dist/index.esm.js +1 -1
  121. package/dist/react/index.cjs +1 -1
  122. package/dist/react/index.d.ts +47 -3
  123. package/dist/react/index.esm.js +1 -1
  124. package/docs/ACCORDION.md +17 -0
  125. package/docs/ACHIEVEMENTS.md +15 -0
  126. package/docs/AI-ELEMENTS.md +86 -0
  127. package/docs/APP-UPDATE.md +60 -0
  128. package/docs/ATTACHMENTS.md +32 -0
  129. package/docs/BUTTON.md +17 -0
  130. package/docs/CDN-GUIDE.md +82 -0
  131. package/docs/COMPONENT-CHECKLIST.md +98 -0
  132. package/docs/CONTEXT-MENU.md +22 -0
  133. package/docs/CREDIT-AI.md +136 -0
  134. package/docs/CREDIT-CARD.md +52 -0
  135. package/docs/CROSS_PLATFORM_COMPONENT_STRATEGY.md +81 -0
  136. package/docs/EASING-EDITOR.md +42 -0
  137. package/docs/EFFECT-KEYFRAMES.md +60 -0
  138. package/docs/LAYER-LIST.md +31 -0
  139. package/docs/MEDIA-EDITORS.md +63 -0
  140. package/docs/MODULE-REUSE.md +43 -0
  141. package/docs/MULTI-PLATFORM-GUIDE.md +246 -0
  142. package/docs/NOTIFICATIONS.md +23 -0
  143. package/docs/PAPER-CARDS.md +61 -0
  144. package/docs/QUALITY-GUIDELINES.md +196 -0
  145. package/docs/RANGE-SLIDER.md +29 -0
  146. package/docs/REACT-WC-INTEGRATION.md +96 -0
  147. package/docs/RECENT-COMPONENTS-QUALITY.md +96 -0
  148. package/docs/SELECT.md +26 -0
  149. package/docs/SELECTION-CONTROLS.md +33 -0
  150. package/docs/SITE-SHELL.md +37 -0
  151. package/docs/STYLING.md +60 -0
  152. package/docs/SUPPORT.md +39 -0
  153. package/docs/TABS.md +19 -0
  154. package/docs/TEXT-FIELDS.md +28 -0
  155. package/docs/TIME-PICKER-DEVELOPMENT.md +115 -0
  156. package/docs/TOGGLE.md +40 -0
  157. package/docs/TRAVEL.md +30 -0
  158. package/docs/UI-NATIVE.md +90 -0
  159. package/docs/VIDEO-EXPORT.md +12 -0
  160. package/docs/VOICE-INPUT.md +24 -0
  161. package/docs/VUE-ANGULAR-INTEGRATION.md +197 -0
  162. package/docs/WORDPRESS-INTEGRATION.md +250 -0
  163. package/docs/WORKSPACE.md +27 -0
  164. package/docs/quality/AXE-REPORT.md +35 -0
  165. package/docs/quality/CREDIT-AI-RELEASE-2026-10-18.md +34 -0
  166. package/docs/quality/ENUM-MIGRATION-WORKSHEET.md +288 -0
  167. package/docs/quality/SCORECARD.md +389 -0
  168. package/package.json +136 -130
@@ -0,0 +1,52 @@
1
+ # CreditCard
2
+
3
+ `db-credit-card` / React `CreditCard`는 미니멀한 카드 표시 컴포넌트입니다. 카드 면 전체를 눌러 앞뒷면을 전환합니다. 실제 결제나 카드 정보 수집 기능은 포함하지 않습니다.
4
+
5
+ ```tsx
6
+ import { useState } from 'react';
7
+ import { CreditCard } from '@designbasekorea/ui-wc/react';
8
+ // 앱 진입점에서 tokens/theme/ui-wc CSS를 로드합니다.
9
+
10
+ function SavedCard() {
11
+ const [flipped, setFlipped] = useState(false);
12
+ return <CreditCard issuer="Supernormal" holder="KIM SEOYEON"
13
+ lastFour="4242" expiry="12/28" network="VISA"
14
+ orientation="horizontal" variant="contrast"
15
+ flipped={flipped} onFlip={event => setFlipped(event.detail.flipped)} />;
16
+ }
17
+ ```
18
+
19
+ ```html
20
+ <db-credit-card issuer="Supernormal" holder="KIM SEOYEON" last-four="4242"
21
+ expiry="12/28" orientation="vertical" variant="metal"></db-credit-card>
22
+ <script>
23
+ const card = document.querySelector('db-credit-card');
24
+ card.addEventListener('db-flip', event => console.log(event.detail.flipped));
25
+ // 앱에서 직접 제어할 때도 동일한 상태를 반영합니다.
26
+ card.flipped = true;
27
+ </script>
28
+ ```
29
+
30
+ - `orientation`: `horizontal`(기본), `vertical`. 부모 폭에 맞춰 줄어들며 실제 카드 비율을 유지합니다. 기본 최대 폭은 가로 420px, 세로 264px입니다.
31
+ - `variant`: `default`(기본 표면), `contrast`(반전 표면), `metal`(얇은 금속 질감). `blue`, `sage`, `rose`는 시스템 색상 토큰을 섞은 컬러 표면입니다. `cobalt`, `coral`, `lime`은 선명한 브랜드 컬러와 그에 맞는 고정 텍스트 색상을 사용합니다. 모든 변형은 시스템 테마를 따릅니다.
32
+ - `issuer`, `holder`, `last-four`, `expiry`, `network`, `back-note`: 카드 표시 데이터. 문자열은 HTML로 해석하지 않습니다. `last-four`는 숫자 네 자리만 허용하고 나머지 번호는 항상 마스킹합니다.
33
+ - `security-code`는 선택 사항이며 기본 표시값은 `•••`입니다. 전달한 내용은 일반 DOM에 표시되는 데이터이므로 화면에 보여줄 수 있는 값만 전달합니다.
34
+ - `flipped`: boolean attribute 또는 property. 기본 false. 사용자 전환 시 `db-flip` / `onFlip`에 `{ flipped: boolean }`을 전달합니다. 앱의 외부 속성 변경은 이벤트를 발생시키지 않습니다.
35
+ - `disabled`: 클릭·키보드 전환을 막습니다. 앱은 비활성 상태에서도 `flipped` property로 표시 면을 정할 수 있습니다.
36
+ - 네이티브 버튼의 클릭·Enter·Space를 사용합니다. 버튼 포커스가 면 전환 중에도 유지되며 `aria-pressed`가 뒷면 표시 여부를 나타냅니다. 숨겨진 면은 `aria-hidden`과 `inert`로 접근성 트리에서 제외합니다. `label`로 버튼의 접근 가능한 이름을 바꿀 수 있습니다.
37
+ - `prefers-reduced-motion: reduce`일 때 회전 애니메이션 없이 면을 즉시 전환합니다. 인쇄 시에도 애니메이션을 제거합니다.
38
+ - 컴포넌트 안에 별도 인터랙티브 자식을 넣지 않습니다. 외부 액션은 카드 옆에 배치합니다.
39
+
40
+ 사용할 수 있는 CSS 변수는 `--db-credit-card-width`, `--db-credit-card-background`, `--db-credit-card-text`, `--db-credit-card-border`, `--db-credit-card-radius`입니다. 미지정 항목은 실제 `--db-*` 표면·텍스트·테두리 토큰을 따릅니다.
41
+
42
+ ## 결제 브랜드와 표면
43
+
44
+ `network="Visa"`, `Mastercard`, `Amex`(또는 `American Express`), `Discover`, `JCB`, `UnionPay`는 내장 SVG를 표시합니다. 대소문자·공백·하이픈은 무시합니다. 다른 이름은 안전한 일반 텍스트로 표시합니다. 그래픽은 번들에 포함되어 외부 이미지 요청이 없습니다. `PAYMENT_BRANDS`와 `getPaymentBrand`를 루트 또는 `helpers/payment-brands`에서 가져와 결제수단 목록에도 재사용할 수 있습니다.
45
+
46
+ 그래픽 출처: [Datatrans payment-logos](https://github.com/datatrans/payment-logos), CC BY-SA 4.0. 원본 파일은 `src/assets/payment/`에 모았으며, 카드 안의 Visa·Mastercard는 여백을 정리했습니다. Visa는 카드 텍스트 색상의 단색 실루엣으로 표시합니다. 저작자·라이선스 전문은 배포 패키지의 `LICENSE-PAYMENT-LOGOS.md`를 확인하세요.
47
+
48
+ 마우스 포인터 위치에 따라 최대 3.5도의 틸트와 표면 반사가 적용됩니다. 포인터가 벗어나거나 포커스를 잃으면 복귀합니다. 터치에서는 포인터 효과를 적용하지 않으며, 비활성·모션 감소·인쇄에서는 표면 모션을 끕니다. 뒤집기와 틸트를 별도 레이어에서 처리하여 두 동작이 충돌하지 않습니다. 세로형 뒷면은 마그네틱 띠를 왼쪽 세로 방향에 배치합니다.
49
+
50
+ 빛은 마우스를 뗄 때 마지막 위치에서 바깥 방향으로 이동하며 사라집니다. 유휴 상태에는 9초 주기로 두 차례 반사광이 지나가고 잠시 쉬며, 호버 중에는 이 반사광 대신 포인터 반사를 표시합니다. 비활성·모션 감소·인쇄에서는 유휴 반사광도 끕니다.
51
+
52
+ 카드 비율은 가로 1.586:1, 세로 0.6305:1이며 ID-1(85.60×53.98mm) 비율과 일치합니다. 모서리는 가로 폭의 약 3.7%, 세로 폭의 약 5.9%로 축소했습니다. 참고: [Entrust ID 카드 출력 가이드](https://www.entrust.com/sites/default/files/documentation/productsupport/sigma-dse-users-guide.pdf).
@@ -0,0 +1,81 @@
1
+ <!-- Generated from docs/CROSS_PLATFORM_COMPONENT_STRATEGY.md by scripts/sync-package-docs.mjs. -->
2
+ # 크로스플랫폼 컴포넌트 전략
3
+
4
+ Designbase Library의 웹 컴포넌트는 **하나의 원본 구현**을 기준으로 React, Vue, Angular, vanilla HTML에서 같은 디자인과 동작을 공유합니다.
5
+
6
+
7
+ ## 결론
8
+
9
+ 웹 플랫폼의 canonical component layer는 `@designbasekorea/ui-wc`입니다.
10
+
11
+ ```txt
12
+ @designbasekorea/tokens
13
+ @designbasekorea/theme
14
+ ↓
15
+ @designbasekorea/ui-wc ← 원본 (Custom Elements)
16
+ ↓
17
+ @designbasekorea/ui-wc/react ← React thin wrapper (빌드 산출물)
18
+ Vue / Angular / vanilla ← <db-*> 직접 사용
19
+
20
+ @designbasekorea/ui ← 레거시 full React (참고·Storybook 기준, 수정 금지)
21
+ ```
22
+
23
+ ## 공개 API 이름
24
+
25
+ | 패키지 | 공개 API | 역할 |
26
+ |--------|----------|------|
27
+ | `@designbasekorea/ui-wc` | `<db-button>` | 실제 구현 원본 |
28
+ | `@designbasekorea/ui-wc/react` | `<Button />` | WC 기반 React wrapper (thin bridge) |
29
+ | Vue / Angular / vanilla | `<db-button>` | Custom Element 직접 사용 |
30
+ | `@designbasekorea/ui` | `<Button />` | full React 구현 (디자인·Storybook 참고용) |
31
+
32
+ ## ui-wc로 이전 완료 (41개)
33
+
34
+ Batch 0~9에서 WC 원본(`db-*`)이 구현되었습니다.
35
+
36
+ `Accordion`, `Alert`, `Avatar`, `Backdrop`, `Badge`, `Breadcrumbs`, `Button`, `Card`, `Checkbox`, `Chip`, `Confirm`, `ContextMenu`, `Divider`, `Drawer`, `Dropdown`, `EmptyState`, `Indicator`, `Input`, `Label`, `List`, `MenuItem`, `Modal`, `Pagination`, `Popover`, `Progress`, `ProgressStep`, `Progressbar`, `Radio`, `RangeSlider`, `SearchBar`, `SegmentControl`, `Select`, `Skeleton`, `Spinner`, `Stepper`, `Table`, `Tabs`, `Textarea`, `Toast`, `Toggle`, `Tooltip`, `Form`, `Toolbar`, `Stack`, `Grid`, `Container`
37
+
38
+ ## Migration 원칙
39
+
40
+ 1. **React (`@designbasekorea/ui`)**: 기존 full React + `*.scss` 구현을 **유지·보호**합니다. Storybook·디자인의 기준(source of truth)이며 직접 수정하지 않습니다.
41
+ 2. **ui-wc (`@designbasekorea/ui-wc`)**: Vue/Angular/Vanilla/React 공통 원본. SCSS는 `packages/ui-wc/src/components/db-*.scss`에서 **직접 관리**합니다 (독립 canonical, `.designbase-wc-*` 프리픽스). `packages/ui`와 자동 동기화하지 않습니다.
42
+ 3. **React 소비자 (`@designbasekorea/ui-wc/react`)**: WC를 감싸는 thin wrapper. `ui-wc` 빌드 시 `dist/react/*`가 함께 산출됩니다.
43
+ 4. React Native는 `ui-wc`를 공유하지 않습니다. `ui-native`에서 별도 구현합니다.
44
+
45
+ ### CSS 로드 규칙
46
+
47
+ | 소비자 | 필수 CSS |
48
+ |--------|----------|
49
+ | React (`@designbasekorea/ui-wc/react`) | `tokens` + `theme` + **`ui-wc/dist/index.css`** |
50
+ | Vue/Angular/Vanilla (`db-*`) | `tokens` + `theme` + **`ui-wc/dist/index.css`** |
51
+ | 레거시 React (`@designbasekorea/ui`) | `tokens` + `theme` + **`ui/dist/index.css`** |
52
+ | React 예제 앱 (layout) | 위 + `ui/dist/index.css` (DocLayout 등 셸 UI만) |
53
+
54
+ ### SCSS 관리
55
+
56
+ `ui-wc`의 SCSS는 `packages/ui-wc/src/components/db-*.scss`에서 직접 수정합니다 (독립 관리). 수정 후 빌드만 하면 됩니다.
57
+
58
+ ```bash
59
+ cd packages/ui-wc && npm run build
60
+ ```
61
+
62
+ ## React 사용 예 (권장)
63
+
64
+ ```tsx
65
+ import '@designbasekorea/ui-wc/dist/index.css';
66
+ import { Button } from '@designbasekorea/ui-wc/react';
67
+
68
+ <Button variant="primary" size="m" onPress={handleSave}>
69
+ 저장
70
+ </Button>
71
+ ```
72
+
73
+ 내부에서는 `<db-button>`을 렌더링하고 `db-click`을 `onPress`에 연결합니다.
74
+
75
+ ## Vue / Angular / vanilla 사용 예
76
+
77
+ ```html
78
+ <db-button variant="primary" size="m">저장</db-button>
79
+ ```
80
+
81
+ 각 컴포넌트는 ui-wc 원본 → React wrapper → 4개 예제 → Batch QA 문서 순으로 맞춥니다.
@@ -0,0 +1,42 @@
1
+ <!-- Generated from docs/EASING-EDITOR.md by scripts/sync-package-docs.mjs. -->
2
+ # Easing, velocity and clip affordances · 2026-11-05
3
+
4
+ ## EasingEditor (Tools)
5
+
6
+ Canonical sources: `packages/ui-wc/src/components/db-easing-editor.ts`, `db-easing-editor.scss` and the pure `easing-model.ts`. React `EasingEditor` is exported with `EasingCurve`, `EasingChangeDetail` and `EasingPreset` types. Direct import `@designbasekorea/ui-wc/components/db-easing-editor` works without the all-component bundle. Load theme and UI CSS as usual.
7
+
8
+ `value` is `[x1,y1,x2,y2]` with each coordinate in 0–1. The JSON HTML attribute and native/React array property are both supported. This editor deliberately uses bounded, non-overshooting CSS cubic Beziers; elastic/bounce and overshoot are not simulated. `easingCss(value)` returns a usable `cubic-bezier(...)` string.
9
+
10
+ `mode=value` displays normalized progress against normalized time. `mode=speed` displays the analytical derivative dY/dX of **the same curve**; it does not replace the value curve with a different interpolation. Endpoint/influence handles change the original Bezier coordinates. Horizontal dashed influences connect the endpoint speed to its handle. They are tangent controls, not arbitrary samples on the speed curve.
11
+
12
+ Speed is normalized: `evaluateEasingVelocity(curve,t) * (endValue-startValue) / segmentDuration` gives real units per second. One times speed means uniform progress. The graph display scale is capped at 12× for near-vertical tangents; output/helper values are not display-clamped. The domain is frozen during a pointer drag to avoid rescaling feedback. Degenerate zero-length tangents, including linear (1×), use the sampled derivative near the endpoint rather than a false 0/0 display.
13
+
14
+ The ten exported `EASING_PRESETS` are Linear, Ease, Ease in, Ease out, Ease in/out, Smooth, Snappy, Swift out, Gentle and Emphasized. Preset labels use the native EN/KO tables; identifiers and coordinate arrays remain stable. `variant=compact` reduces insets. `hidePresets` provides an inspector-only form without duplicating logic.
15
+
16
+ All controls are real Button/Input components. Graph handles have larger transparent hit areas, are focusable sliders and support .01 arrow nudges / .1 with Shift. Escape, pointercancel and lost capture restore the gesture's original curve. Disabled controls reject pointer/keyboard edits. Input field events are consumed internally; clients receive only editor-shaped transactions. The editor owns a stable focus target during pointer updates, so replacing graph DOM cannot lose Escape handling.
17
+
18
+ `db-input` / `onInput` sends live `{value,css,preset,source,cancelled?}`; `db-change` / `onChange` commits one transaction. `db-mode-change` changes the view only. A user-triggered, finite preview follows the same mathematical curve; reduced-motion preference jumps to its final position. Duration is .1–30 seconds.
19
+
20
+ ## Clip anatomy and editing
21
+
22
+ VideoTimeline's left/right bars already trimmed the source range. They now have explicit grip marks, thin selected edge accents, touch targets, aria labels and keyboard editing: Left/Right is one frame, Shift ten. The clip body remains the move target. At very low zoom, very short clips should be enlarged before fine pointer edits; the selected handles remain keyboard reachable.
23
+
24
+ Top diamonds edit `fadeIn` / `fadeOut` in seconds. Fades are clamped to the clip length and cannot overlap. Trimming clamps envelopes; splitting clears the new inner fades and retains the original outer fades. Pointer and keyboard transactions use `action='fade-in'|'fade-out'`. The transient timecode readout is removed after a commit or cancellation and does not add layout height.
25
+
26
+ `VideoClip` also accepts:
27
+
28
+ - `effects?: {id,label,kind:'color'|'blur'|'transform'|'opacity'|'speed',enabled?}[]`: enabled/disabled FX badges. Data is copied; the timeline never executes filters itself.
29
+ - `appearance?: 'standard'|'filmstrip'|'waveform'|'compact'` and `thumbnail?: string`: a standard clip, repeated real thumbnail, waveform sample or compact title/layer. The filmstrip uses the provided image URL without changing clip data.
30
+ - `fadeIn?: number`, `fadeOut?: number`: source-relative clip envelopes in seconds.
31
+
32
+ Video block's selected clip Blur/Mono controls drive real CSS filters on the current clip preview and use its existing undo history. Fade data drives the video's visual opacity envelope; audio mixing remains the application's engine responsibility. Thumbnail art matches the generated sample composition and is labeled demo media. Live video metadata clamps both source ranges and envelopes.
33
+
34
+ The Video and Motion blocks map EasingEditor to the selected keyframe's outgoing Bezier segment. Last keys and Hold segments disable the editor; switch interpolation in KeyframeEditor before editing a Hold. Video's timing panel can be collapsed. Motion's editor is exposed directly. Preset/coordinate edits propagate to value curves, evaluated animation and exported JSON.
35
+
36
+ ## Verification
37
+
38
+ - `scripts/test-easing-model.mjs`: all ten presets, actual derivative vs finite difference, unit velocity integral, endpoints, bounds and CSS.
39
+ - `scripts/test-easing-editor.mjs`: native coordinate/speed fields, one event per commit, drag/keyboard/cancellation, disabled/reduced motion, trim/fade/FX and block integration, EN/light + KO/dark and viewport boundaries.
40
+ - Existing media component/model and standalone delivery checks cover regression and translated-source removal.
41
+
42
+ These changes are local library/source additions. No npm publication or production deployment is implied.
@@ -0,0 +1,60 @@
1
+ <!-- Generated from docs/EFFECT-KEYFRAMES.md by scripts/sync-package-docs.mjs. -->
2
+ # Effect keyframes: host integration
3
+
4
+ Updated 2026-11-07. This guide describes the implemented VideoTimeline contract, not an encoding engine.
5
+
6
+ ## Model and time coordinates
7
+
8
+ Effects belong to a `VideoClip`. Each effect exposes scalar `VideoEffectProperty` channels. Use stable unique IDs for clips, effects, properties and keys. Key times are **clip-local seconds**, not sequence timestamps. Moving or copying a clip preserves its channels. Evaluate using `evaluateKeyframes(property.keyframes, sequenceTime - clip.start)`; skip effects with enabled=false and clamp/apply values as required by your renderer.
9
+
10
+ ```tsx
11
+ const clips: VideoClip[] = [{
12
+ id: 'hero', trackId: 'visual', kind: 'video', label: 'Hero',
13
+ start: 2, duration: 6, sourceDuration: 20,
14
+ effects: [{ id: 'transform', label: 'Transform', kind: 'transform', enabled: true,
15
+ properties: [
16
+ { id: 'x', label: 'X', min: -500, max: 500,
17
+ keyframes: [{ id: 'x-a', time: 0, value: 0, easing: 'ease-out' },
18
+ { id: 'x-b', time: 6, value: 200 }] },
19
+ { id: 'scale', label: 'Scale', min: 0, max: 200,
20
+ keyframes: [{ id: 's-a', time: 0, value: 100 },
21
+ { id: 's-b', time: 6, value: 120 }] },
22
+ ],
23
+ }],
24
+ }];
25
+ ```
26
+
27
+ X/Y are caller-defined units; scale/opacity percent conversion is also owned by the host. Blur, rotation, gain or other scalar channels use the same structure. Actual video processing and GPU effects are not supplied by these controls.
28
+
29
+ ## Controlled React updates and persistence
30
+
31
+ Assign `tracks`, `clips`, `currentTime`, `duration` and integer `fps` through native properties or the React wrapper. Keep one canonical project state. `db-input`/`onInput` provides optimistic complete clips; `cancelled` restores the gesture-start snapshot. `db-change`/`onChange` commits one complete array. Effect edits use action=keyframe and may include effectId/propertyId. Bulk actions can span channels, so persist the returned clips rather than reconstructing one key from those optional IDs.
32
+
33
+ Do not persist every pointer move or create undo entries from db-input. Save/project-export the nested effects/properties/keyframes along with clip data. The renderer should read the same state used for preview. Keep visibility/lock state, selection, expansion and project data responsibilities explicit.
34
+
35
+ ```tsx
36
+ <VideoTimeline tracks={tracks} clips={clips} duration={12} fps={30}
37
+ currentTime={time} selectedClipId={selected}
38
+ onSeek={e => setTime(e.detail.time)}
39
+ onSelectionChange={e => setSelected(e.detail.clipId)}
40
+ onInput={e => setClips(e.detail.clips)}
41
+ onChange={e => { setClips(e.detail.clips); queueProjectSave(e.detail.clips); }} />
42
+ ```
43
+
44
+ A controlled commit echo does not reset native history. A genuinely different programmatic clip replacement does. Native Cmd/Ctrl+Z and Shift+Cmd/Ctrl+Z store up to 100 committed clip snapshots and emit actions undo/redo. A host with its own history must treat those actions as history traversal rather than creating another independent history entry.
45
+
46
+ ## Interaction
47
+
48
+ - U expands/collapses properties for the selected effect-bearing clip. Text inputs retain normal typing.
49
+ - Drag blank effect content to marquee-select; Shift adds/toggles keys. Selection is scoped to a clip's channels.
50
+ - Drag selected diamonds to move the group by one shared frame delta. Unselected neighbors and clip bounds prevent overwrites.
51
+ - Alt/Option drag duplicates the group with new IDs, preserving source keys and curve data. Copies need valid free landing frames inside the clip. Escape cancels the provisional copies.
52
+ - Right-click selected keys for Duplicate, Delete, Easing submenu or Undo. Delete/Backspace also removes selection. The former inline easing bar is no longer rendered.
53
+ - Open a property for exact time/value edits, add/delete, interpolation and Bezier tangents. Normal tangent drag is symmetric; Cmd/Ctrl edits a side independently; H restores collapsed handles.
54
+ - Locked tracks and disabled effects reject edits. Readouts and toolbar text are nonselectable; real text fields remain selectable.
55
+
56
+ ## Event and lifecycle rules
57
+
58
+ Pointer ownership is scoped to the active pointer. Nested-editor or unrelated cancellation events must not cancel another gesture. A delayed lostpointercapture event is ignored while a newer capture is still held. Do not recreate the custom element or change its React key during a gesture; stable controlled properties allow the native editor to preserve its draft. Locale/theme changes should be applied through the existing providers.
59
+
60
+ Tests: test-timeline-effects.mjs, test-timeline-key-selection.mjs, test-timeline-key-context.mjs and test-media-precision.mjs cover the actual native/React paths. The Tools gallery's Effects/property-keyframes example applies X/Y/scale/opacity to a live sample object.
@@ -0,0 +1,31 @@
1
+ <!-- Generated from docs/LAYER-LIST.md by scripts/sync-package-docs.mjs. -->
2
+ # Layer List
3
+
4
+ `db-layer-list` / React `LayerList` is a compact list for editor layers and effect stacks. It composes native Designbase ghost buttons and outline icons. Default labels follow `dbSetLocale`; item labels and custom action labels belong to the host document.
5
+
6
+ ```tsx
7
+ import { useState } from 'react';
8
+ import { LayerList, type LayerListItem } from '@designbasekorea/ui-wc/react';
9
+ const initial: LayerListItem[] = [
10
+ { id:'color', label:'Color grade', visible:true },
11
+ { id:'grain', label:'Film grain', locked:true },
12
+ ];
13
+ export function Effects() {
14
+ const [items,setItems] = useState(initial);
15
+ return <LayerList items={items} dragMode="handle"
16
+ onChange={e => { setItems(e.detail.items); /* persist complete document state */ }} />;
17
+ }
18
+ ```
19
+
20
+ - `items`: array or JSON string, unique stable `id`, `label`, optional `description`, official `icon`, `visible` (default true), `locked`, `removable` (default true), `actions: {id,label,icon,disabled?}[]`.
21
+ - `drag-mode`: `handle` (default) or `row`. Row mode omits the grip; mouse/touch can drag anywhere except action buttons. Use handle mode when touch users need to scroll by swiping rows.
22
+ - `selected-id` / `selectedId`: selected item. Selection does not change visibility or lock.
23
+ - `actions-visibility` / `actionsVisibility`: `always` (default) or `hover`. Hover mode reveals controls on row hover or keyboard focus, keeps label space stable, and always displays actions on touch devices.
24
+ - `disabled`, `hide-visibility`, `hide-lock`, `hide-delete` are boolean options.
25
+ - `--db-layer-list-max-height`: opt-in scrolling height, e.g. `240px`. Dragging at an overflowing ancestor's top/bottom scrolls it. Width always stays inside the parent.
26
+
27
+ `db-change` delivers `{items,itemId,action,fromIndex?,toIndex?}`, where action is `reorder`, `visibility`, `lock`, or `delete`. `db-reorder` also reports reorder only. `db-selection-change` reports `{itemId}`. `db-action` reports custom `{itemId,actionId}`; the owner implements duplication, settings, etc. React maps these to `onChange`, `onReorder`, `onSelectionChange`, `onAction`. Persist only once through `onChange`; subscribing to both change and reorder must not produce two history entries.
28
+
29
+ A locked item cannot initiate drag or be deleted, but can be unlocked or hidden. Other items may reorder around it. `removable:false` removes delete entirely. No network or project deletion occurs automatically; the component only changes its local list and emits the result. Supply saved items on remount.
30
+
31
+ Keyboard on a focused row: arrows focus previous/next, Enter/Space select, Alt+Up/Down reorder, Delete/Backspace delete when allowed, Escape cancels an active drag. Buttons retain their own normal keyboard behavior. Pointer cancellation and disconnection cancel uncommitted reorder. One drop produces one change; clicking an action never initiates row drag.
@@ -0,0 +1,63 @@
1
+ <!-- Generated from docs/MEDIA-EDITORS.md by scripts/sync-package-docs.mjs. -->
2
+ # Media editing components
3
+
4
+ Canonical implementations: `packages/ui-wc/src/components/db-video-timeline.ts`, `db-keyframe-editor.ts`, and pure model helpers in `media-editor-model.ts`. Blocks: `packages/blocks/src/blocks/video-editor.tsx` and `motion-editor.tsx`. The existing activity Timeline is unchanged.
5
+
6
+ ## Data and integration
7
+
8
+ Time is seconds, quantized to integral frames at an integer FPS (1–120). `duration`, `fps`, `zoom`, `currentTime` and `disabled` are shared between both editors. Assign duration/FPS before assigning data. Arrays are **properties**, not JSON HTML attributes; React wrappers assign them as properties. No caller-owned objects are mutated.
9
+
10
+ - `VideoTrack`: `{id, label, kind: 'video'|'audio'|'title', locked?, muted?, height?}`.
11
+ - `VideoClip`: `{id, trackId, label, start, duration, sourceOffset?, sourceDuration?}`. Provide available source bounds for accurate trimming. Track IDs must exist, IDs must be unique, and initial clips on one track must not overlap. Moves cannot introduce overlaps. Cross-track movement only targets unlocked tracks of the same kind.
12
+ - `TimelineMarker`: `{id, time, label}`. Click to seek; also a snap target.
13
+ - `EditorKeyframe`: `{id, time, value, easing?, bezier?, inTangent?, outTangent?, tangentMode?}`. Keys sort by time and deduplicate by frame. Values stay in min/max. `easing` applies to the **outgoing** segment: linear, hold, ease-in, ease-out, ease-in-out, bezier. `bezier` is normalized `[x1,y1,x2,y2]` in 0–1. Last keys have no outgoing segment. Vertex-owned `inTangent` and `outTangent` are relative `{time,value}` vectors; incoming time is negative, outgoing positive. `tangentMode` is aligned or free. Physical tangents support value overshoot, including flat endpoint segments. `applyKeyframeEasing(keys,id,easing,bezier?)` resets only the two tangent endpoints of the affected segment; `keyframeEasingCurve` derives its normalized curve when representable.
14
+
15
+ `db-input` / React `onInput` sends optimistic drag data; use it for preview, without making history entries. `db-change` / `onChange` commits one transaction on release or keyboard/input operation. Escape or pointer cancellation restores the pre-drag snapshot with `db-input {cancelled:true}`. The app owns persistence/history and should commit returned arrays. `db-seek {time}` links transport, preview and both editors. `db-selection-change` connects the inspector. Timeline `db-track-change {tracks}` connects locking and muting; actual audio mixing is external. `db-track-input` streams row-height updates, while `db-track-change` commits them. `db-resize-input`/`db-resize` stream/commit viewport `{height}`. `db-zoom-change {value,previousValue,anchorTime,source}` synchronizes zoom controls.
16
+
17
+ `evaluateKeyframes(keys,time)` uses the same cubic interpolation as the drawn curve, including hold. `editorTimecode(time,fps)` produces non-drop-frame HH:MM:SS:FF. Fractional and drop-frame timecode are not supported.
18
+
19
+ ## Interaction
20
+
21
+ Timeline: ruler/playhead dragging scrubs; clip body moves; edges trim without changing source alignment. Snap targets are other clip edges, markers, sequence start and playhead within 8 screen pixels. Shift bypasses snap. Drag to a viewport edge to scroll continuously, including on mobile. Empty lanes pan natively on touch. Track labels remain sticky. A right-edge button advertises hidden horizontal content; scrolling never expands the page.
22
+
23
+ With timeline focus: arrows seek one frame (Shift ten), Home/End sequence bounds, S split the selected unlocked clip, Delete/Backspace remove it. Selection is also keyboard accessible. Escape cancels active drags. Field editing is ignored. Cmd/Ctrl+wheel zooms around the pointer and prevents page zoom; +/− zoom and 0 fits the sequence. `shortcuts=false` disables these bindings. `minClipDuration` defaults to 0.5 seconds (frame-rounded); source bounds may allow less. Clips keep a minimum 24px target at low zoom. Selection changes border/grip colors without changing fill, shape or height. Each edge has one grip line. `rowHeight` defaults to 42px (32–120); per-track height overrides it. Resize each row at its lower edge. Resize the entire viewport at the footer (120–720px); Home or double-click restores auto height. Escape restores the previous size.
24
+
25
+ Keyframe editor: drag a diamond in time/value; select it to edit values/interpolation or its incoming/outgoing Bezier handles. Normal dragging mirrors both vectors; Cmd/Ctrl dragging edits one side independently. Collapsed handles have dashed 24px proxies; H or Restore handles resets a usable tangent. Visible diamonds are 6px and handle dots 6px, with larger invisible hit targets. Double-click the plot or K adds at the playhead; Delete removes the selected key. Arrow keys nudge selected time/value (Shift ten); handles nudge by a frame horizontally or one value unit vertically (Shift ten). Previous/next buttons seek to adjacent keys. Touch can pan empty chart areas. Input fields are real Input/Select components; toolbar controls are real Button components.
26
+
27
+ ## Blocks
28
+
29
+ Video editing workspace joins timeline, opacity/position keyframe channels, live title preview, 30fps transport, clip selection, 100-entry undo/redo and JSON project export. Space toggles playback, Cmd/Ctrl+Z undoes, Shift+Cmd/Ctrl+Z redoes, scoped to the workspace outside fields. Local MP4/WebM files stay in the browser and feed a seek-based video preview; URLs are revoked on replacement/unmount. Generated stage and audio waveform are labeled sample content. The title clip's mute flag controls title visibility. The animation channels are sequence-level, not per-clip effect stacks.
30
+
31
+ Motion curve studio maps evaluated keys to position, rotation, scale or opacity of a composition object, with transport/reset and JSON export. Neither block includes video encoding, audio decoding/mixing, ripple/roll/slip tools, media relinking, multi-key selection, GPU compositing, server storage or native Premiere/After Effects integration. These are composable UI primitives and runnable state integration examples, not complete NLE engines.
32
+
33
+ Preview copy follows the existing English/Korean locale. Native strings use dbUseLocale/dbSetLocale. All surfaces use semantic theme tokens. Delivery sources are generated through `generate-registry-json.mjs --only=video-editor,motion-editor`; preview locale branches/dictionaries are removed from download sources.
34
+
35
+ ## Validation
36
+
37
+ `node scripts/test-media-editors.mjs` tests real pointer/keyboard edits, source trims, lock, undo/cancel behavior, autoscroll, interpolation handles, inspector input, transport and JSON export. Screen checks cover desktop/tablet/mobile boundaries and English/light + Korean/dark. A separate temporary consumer verifies the generated source and packaged UI with a clean installation and production build. Waveforms remain explicitly labeled sample data.
38
+
39
+ ## Timing / effect additions
40
+
41
+ See `EASING-EDITOR.md` for the shared easing/value-speed editor, ten presets and derivative helpers, explicit trim/fade handles, per-clip FX badges and live block integrations. Clip filters now demonstrate per-clip Blur/Mono; animation channels remain sequence-level. Existing engine limitations remain unchanged.
42
+
43
+ Precision regression: `node scripts/test-media-tangents.mjs` checks physical interpolation and preset scope. `node scripts/test-media-precision.mjs` verifies linked/independent handle drags, recovery, minimum trim, selection geometry, row/panel resize, pointer-anchored zoom and responsive theme surfaces.
44
+
45
+ Track controls use ghost Buttons with outline icons reflecting current lock/audio state (unlock/lock, volume-up/mute). Accessible names describe the current state; aria-pressed preserves toggle semantics. Timeline markers use labeled flags and seek on click. The playhead has a circular head; its cursor and markers hide behind the sticky track-label area when scrolled. Clip edge grips and the panel resize grip are 3px thick.
46
+
47
+ Mixed lanes: `VideoTrack.kind="mixed"` accepts any clip kind; set `VideoClip.kind` to video/audio/title so presentation survives vertical drops. Typed lanes continue accepting matching media only. Cmd/Ctrl + either trim edge performs a track-local ripple: following clips shift by the duration delta with gaps intact; start trim keeps sequence placement and updates source offset. Sequence/source bounds and minimum durations apply. Escape cancels the entire multi-clip transaction; one db-change commits all clips. Other tracks remain unchanged.
48
+
49
+ Modifier contract: Cmd on macOS / Ctrl elsewhere enables ripple trims and insert moves. An insert inside an occupied clip resolves to its start boundary, keeping that clip intact and pushing colliding followers. Alt/Option + body drag creates a new ID while retaining the source; dropping into an ordinary collision is rejected. Modifier edits remain one transaction. Escape cancels even while modifiers are held.
50
+
51
+ ## Clip effect keyframes
52
+
53
+ `VideoClipEffect.properties?: VideoEffectProperty[]` supplies any number of named scalar channels (`id`, `label`, `min`, `max`, `keyframes`). Keys use clip-local seconds; moving/duplicating a clip retains its effect channels. There is no fixed property enum: X, Y, scale, opacity, blur intensity and other numeric controls share the same contract.
54
+
55
+ Expand clip effects, then an effect to see time-aligned property key rows. Drag a diamond horizontally to adjust its time, or select the property/key to open the native KeyframeEditor for value/time fields, add/delete and tangent/easing controls. Changes send complete `clips` through db-input/db-change with action=keyframe and effectId/propertyId. Cancellation restores the gesture snapshot. Track lock and effect enabled state disable key edits. Expansion is view state; editing is data state owned by the consumer, so existing project persistence/history can store one transaction per edit. Playback engines should evaluate enabled channels at sequenceTime - clip.start with evaluateKeyframes and apply the resulting transform/effect values.
56
+
57
+ The Effects/property-keyframes demo drives a live X/Y/scale/opacity sample. It uses the same controlled React property path as an app; graph editing keeps its pointer interaction alive during optimistic rerenders. Expanding rows is accounted for in vertical clip drop hit-testing. Arbitrary shader/GPU effects remain the application's responsibility.
58
+
59
+ ### Effect-key selection
60
+
61
+ U, while the timeline is focused outside text inputs, expands/collapses the selected clip's effect properties. Click a key to select it; Shift toggles additive selection. Drag empty property-lane space to box-select visible keys across rows (Shift adds). Selected diamonds are filled and outlined. Drag a selected key to move the selection by one shared frame-quantized delta, bounded by clip edges and unselected neighbors. Delete/Backspace removes selected keys; the two-level Context Menu applies easing presets to their outgoing segments. Detailed property graphs still expose exact values and Bezier tangents. Escape rolls back timing drags or box selection. Timeline tool text is nonselectable; actual text-entry controls remain selectable. Value readouts target a dedicated class and never replace Button icon nodes.
62
+
63
+ Alt/Option + key drag duplicates the entire selected key group, preserving original IDs, values and tangent data. Copies receive new IDs and a shared frame offset; landing on an existing key frame is rejected. Duplicate, delete and easing actions are available from the real ContextMenu with an Easing submenu. Plain dragging anywhere in blank effect content starts a marquee. Cmd/Ctrl+Z undoes committed timeline edits and Shift+Cmd/Ctrl+Z redoes them (up to 100 snapshots); optimistic moves and selection changes do not create history. External clip replacements reset native history; own controlled commit echoes do not. Undo/redo emits db-change actions undo/redo for consumers with their own history integration.
@@ -0,0 +1,43 @@
1
+ # Module consumption — local audit 2026-10-19
2
+
3
+ The current development tarball was tested in a separate offline-installed React 19 consumer and individually bundled Vanilla consumers, without source aliases. Public signatures and runtime dependencies are unchanged. No registry release or starter snapshot update occurred.
4
+
5
+ ## Browser React
6
+
7
+ ```tsx
8
+ import '@designbasekorea/theme/dist/css/theme.css';
9
+ import '@designbasekorea/ui-wc/dist/index.css';
10
+ import { AttachmentList } from '@designbasekorea/ui-wc/react';
11
+
12
+ <AttachmentList attachments={snapshot.attachments}
13
+ onDbRetry={event => retryThroughProductServer(event.detail.id)} />;
14
+ ```
15
+
16
+ Use the actual props/types in ATTACHMENTS.md, WORKSPACE.md, NOTIFICATIONS.md and CREDIT-AI.md. These are controlled presentation modules. The host owns data fetching, identity changes, asynchronous locks and confirmed state updates. Roles, displayed credits and client validation are not authorization. No billing, email, remote upload or agent execution is performed by rendering these elements.
17
+
18
+ ## Individual Vanilla module
19
+
20
+ ```ts
21
+ import '@designbasekorea/theme/dist/css/theme.css';
22
+ import '@designbasekorea/ui-wc/dist/index.css';
23
+ import '@designbasekorea/ui-wc/components/db-attachment-list';
24
+
25
+ const attachments = document.createElement('db-attachment-list');
26
+ attachments.attachments = serverSnapshot.attachments;
27
+ attachments.addEventListener('db-retry', event => retryThroughProductServer(event.detail.id));
28
+ container.append(attachments);
29
+ ```
30
+
31
+ Arrays are properties. Do not pass a JSON attribute where the public API only exposes a property. Use registered tags when mixing root and component entries. The bundled root and per-component ESM can contain different class copies; directly constructing an exported class from a second entry with `new` is not supported. Composition modules resolve children through the custom element registry so root-first and subpath-first orders both work.
32
+
33
+ The package marks component registration as a side effect. Do not override that metadata as `sideEffects:false` in the consumer. CSS is loaded separately. Root React currently registers the whole WC catalog; named wrapper imports do not promise small per-component bundles.
34
+
35
+ ## Boundaries
36
+
37
+ - Browser React 19 and Vanilla tags were tested. React 18, Vue, Angular and Native were not tested by this audit.
38
+ - Direct server import of the current React entry throws `HTMLElement is not defined`. This is not an SSR-safe package. Next.js needs an explicit client-only dynamic loading boundary and its own build/hydration acceptance.
39
+ - The standalone UI examples are not real backend integration, real product adoption or production readiness.
40
+ - The starter's fixed r2 vendor tarball remains unchanged and lacks the later API additions. Upgrade a real consumer's manifest/lockfile and validate it separately.
41
+ - Main gallery navigation/category routes are undergoing a separate migration; standalone installed-package AI Elements validation does not certify those routes. Lottie is explicitly unavailable in ui-wc and no placeholder renderer is treated as implemented playback.
42
+
43
+ Audit tooling: `scripts/audit-module-consumers.mjs` expects `DB_AUDIT_ROOT` to point to an independently prepared offline consumer. `scripts/test-module-mixed-imports.mjs` checks both import orders. `scripts/test-module-instance-isolation.mjs` uses DB_UI_EXAMPLE_URL. Package/lock/provenance and initial failure evidence are retained in the starter's reports/module-audit/2026-10-19/ directory.
@@ -0,0 +1,246 @@
1
+ <!-- Generated from docs/MULTI-PLATFORM-GUIDE.md by scripts/sync-package-docs.mjs. -->
2
+ # 멀티플랫폼 사용 가이드
3
+
4
+ Designbase Library를 **React**, **Vue 3**, **Angular**, **vanilla HTML**에서 사용하는 방법입니다.
5
+
6
+ > 핵심 전략은 `@designbasekorea/ui-wc`를 웹 컴포넌트 원본으로 두고, React/Vue/Angular가 같은 원본을 사용하는 것입니다. 자세한 결정은 [CROSS_PLATFORM_COMPONENT_STRATEGY.md](./CROSS_PLATFORM_COMPONENT_STRATEGY.md)를 참고하세요.
7
+
8
+ ## 패키지별 지원 범위
9
+
10
+ | 패키지 | Vue / Angular / vanilla | React | React Native |
11
+ |--------|-------------------------|-------|--------------|
12
+ | `@designbasekorea/tokens` | ✅ CSS, SCSS, JSON | ✅ | ✅ native JSON |
13
+ | `@designbasekorea/theme` | ✅ CSS + `setTheme()` | ✅ | ❌ (ui-native ThemeProvider) |
14
+ | `@designbasekorea/icons-webfont` | ✅ | ✅ | ❌ |
15
+ | `@designbasekorea/ui-wc` | ✅ Custom Elements | ✅ `./react` thin wrapper | ❌ |
16
+ | `@designbasekorea/ui-wc/react` | ❌ | ✅ `Button`, `Input` … (WC 기반) | ❌ |
17
+ | `@designbasekorea/ui` | ❌ | ✅ full React (레거시·참고용) | ❌ |
18
+ | `@designbasekorea/ui-native` | ❌ | ❌ | ✅ |
19
+
20
+ 컴포넌트가 필요 없고 **색·간격·타이포만** 맞추면 tokens + theme만 연결하면 됩니다.
21
+ 컴포넌트 API가 필요하면 `@designbasekorea/ui-wc`를 원본으로 사용하세요. React에서는 `@designbasekorea/ui-wc/react`의 `Button`, `Input`, `Tabs` 이름을 사용합니다.
22
+
23
+ ---
24
+
25
+ ## 1. 공통: 토큰 & 테마 연결
26
+
27
+ ### npm
28
+
29
+ ```bash
30
+ npm install @designbasekorea/tokens @designbasekorea/theme
31
+ ```
32
+
33
+ **진입점 (앱 루트 1회):**
34
+
35
+ ```ts
36
+ import '@designbasekorea/tokens/dist/css/tokens.css';
37
+ import '@designbasekorea/theme/dist/css/theme.css';
38
+ ```
39
+
40
+ ### CDN
41
+
42
+ [`CDN-GUIDE.md`](./CDN-GUIDE.md)와 동일합니다.
43
+
44
+ ```html
45
+ <link rel="stylesheet" href="https://unpkg.com/@designbasekorea/tokens@latest/dist/css/tokens.css">
46
+ <link rel="stylesheet" href="https://unpkg.com/@designbasekorea/theme@latest/dist/css/theme.css">
47
+ ```
48
+
49
+ ### 다크 모드
50
+
51
+ ```html
52
+ <html lang="ko" data-theme="light">
53
+ ```
54
+
55
+ ```js
56
+ import { setTheme, toggleTheme } from '@designbasekorea/theme';
57
+ setTheme('dark');
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 2. React
63
+
64
+ ### Web Components + React wrapper (`ui-wc/react`)
65
+
66
+ ```bash
67
+ npm install @designbasekorea/ui-wc @designbasekorea/tokens @designbasekorea/theme
68
+ ```
69
+
70
+ ```tsx
71
+ // main.tsx
72
+ import '@designbasekorea/tokens/dist/css/tokens.css';
73
+ import '@designbasekorea/theme/dist/css/theme.css';
74
+ import '@designbasekorea/ui-wc/dist/index.css';
75
+ import { Button } from '@designbasekorea/ui-wc/react';
76
+
77
+ function App() {
78
+ return (
79
+ <Button variant="primary" onPress={() => console.log('saved')}>
80
+ 저장
81
+ </Button>
82
+ );
83
+ }
84
+ ```
85
+
86
+ `@designbasekorea/ui-wc/react`는 WC(`db-*`)를 감싼 thin wrapper입니다. Vue/Angular와 동일한 원본을 공유합니다.
87
+
88
+ > `@designbasekorea/ui`는 full React 구현(Storybook·디자인 참고용)으로 별도 유지됩니다. 신규 크로스플랫폼 프로젝트는 `ui-wc/react`를 사용하세요.
89
+
90
+ ---
91
+
92
+ ## 3. Vue 3
93
+
94
+ ### 토큰만 (컴포넌트 직접 구현)
95
+
96
+ ```ts
97
+ // main.ts
98
+ import { createApp } from 'vue';
99
+ import App from './App.vue';
100
+ import '@designbasekorea/tokens/dist/css/tokens.css';
101
+ import '@designbasekorea/theme/dist/css/theme.css';
102
+
103
+ createApp(App).mount('#app');
104
+ ```
105
+
106
+ ```vue
107
+ <!-- App.vue -->
108
+ <template>
109
+ <button class="my-btn">저장</button>
110
+ </template>
111
+
112
+ <style scoped>
113
+ .my-btn {
114
+ padding: var(--db-padding-s) var(--db-padding-m);
115
+ background: var(--db-btn-primary-bg);
116
+ color: var(--db-btn-primary-text);
117
+ border-radius: var(--db-radius-button);
118
+ font-weight: var(--db-weight-medium);
119
+ }
120
+ </style>
121
+ ```
122
+
123
+ ### Web Components (`ui-wc`)
124
+
125
+ ```ts
126
+ // main.ts
127
+ import '@designbasekorea/tokens/dist/css/tokens.css';
128
+ import '@designbasekorea/theme/dist/css/theme.css';
129
+ import '@designbasekorea/ui-wc/dist/index.css';
130
+ import '@designbasekorea/ui-wc';
131
+ ```
132
+
133
+ ```vue
134
+ <template>
135
+ <db-button variant="primary" @db-click="onSave">저장</db-button>
136
+ </template>
137
+
138
+ <script setup lang="ts">
139
+ function onSave() {
140
+ console.log('saved');
141
+ }
142
+ </script>
143
+ ```
144
+
145
+ `compilerOptions.isCustomElement` 설정은 [VUE-ANGULAR-INTEGRATION.md](./VUE-ANGULAR-INTEGRATION.md)를 참고하세요.
146
+
147
+ ---
148
+
149
+ ## 4. Angular
150
+
151
+ ### 토큰만
152
+
153
+ `angular.json` → `styles`:
154
+
155
+ ```json
156
+ [
157
+ "node_modules/@designbasekorea/tokens/dist/css/tokens.css",
158
+ "node_modules/@designbasekorea/theme/dist/css/theme.css"
159
+ ]
160
+ ```
161
+
162
+ ### Web Components
163
+
164
+ `angular.json` styles에 추가:
165
+
166
+ ```json
167
+ "node_modules/@designbasekorea/ui-wc/dist/index.css"
168
+ ```
169
+
170
+ `main.ts`:
171
+
172
+ ```ts
173
+ import '@designbasekorea/ui-wc';
174
+ ```
175
+
176
+ 컴포넌트 모듈:
177
+
178
+ ```ts
179
+ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
180
+
181
+ @Component({
182
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
183
+ template: `<db-button variant="primary">저장</db-button>`,
184
+ })
185
+ export class AppComponent {}
186
+ ```
187
+
188
+ ---
189
+
190
+ ## 5. Vanilla HTML
191
+
192
+ ```html
193
+ <!DOCTYPE html>
194
+ <html lang="ko" data-theme="light">
195
+ <head>
196
+ <link rel="stylesheet" href="https://unpkg.com/@designbasekorea/tokens@latest/dist/css/tokens.css">
197
+ <link rel="stylesheet" href="https://unpkg.com/@designbasekorea/theme@latest/dist/css/theme.css">
198
+ <link rel="stylesheet" href="https://unpkg.com/@designbasekorea/ui-wc@latest/dist/index.css">
199
+ </head>
200
+ <body>
201
+ <db-button id="save" variant="primary">저장</db-button>
202
+ <script type="module">
203
+ import 'https://unpkg.com/@designbasekorea/ui-wc@latest/dist/index.esm.js';
204
+ document.getElementById('save').addEventListener('db-click', () => alert('saved'));
205
+ </script>
206
+ </body>
207
+ </html>
208
+ ```
209
+
210
+ ---
211
+
212
+ ## 6. 아이콘
213
+
214
+ React SVG 컴포넌트(`@designbasekorea/icons`) 대신 웹폰트를 사용하세요.
215
+
216
+ ```bash
217
+ npm install @designbasekorea/icons-webfont
218
+ ```
219
+
220
+ ```html
221
+ <link rel="stylesheet" href="node_modules/@designbasekorea/icons-webfont/dist/css/designbase-icons.css">
222
+ <i class="icon-home"></i>
223
+ ```
224
+
225
+ ---
226
+
227
+ ## 7. React Native
228
+
229
+ Web Components는 DOM이 없어 사용할 수 없습니다.
230
+
231
+ ```bash
232
+ npm install @designbasekorea/ui-native
233
+ ```
234
+
235
+ [`packages/ui-native/README.md`](./UI-NATIVE.md)를 참고하세요.
236
+
237
+ ---
238
+
239
+ ## 관련 문서
240
+
241
+ - [CDN-GUIDE.md](./CDN-GUIDE.md) — CDN 빠른 시작
242
+ - [CROSS_PLATFORM_COMPONENT_STRATEGY.md](./CROSS_PLATFORM_COMPONENT_STRATEGY.md) — 원본/Wrappers 전략
243
+ - [REACT-WC-INTEGRATION.md](./REACT-WC-INTEGRATION.md) — React + ui-wc 공존 전략
244
+ - [VUE-ANGULAR-INTEGRATION.md](./VUE-ANGULAR-INTEGRATION.md) — Vue / Angular 상세 설정
245
+ - [WORDPRESS-INTEGRATION.md](./WORDPRESS-INTEGRATION.md) — WordPress wp-admin 플러그인 연동
246
+ - [packages/ui-wc/docs/STYLING.md](./STYLING.md) — WC 스타일 전략