@haiyue/ui 0.1.2 → 0.2.2

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 (110) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/LICENSE +27 -0
  3. package/README.md +643 -2
  4. package/dist/adapters/web/controls.d.ts +19 -0
  5. package/dist/adapters/web/controls.js +307 -0
  6. package/dist/adapters/web/dom.d.ts +10 -0
  7. package/dist/adapters/web/dom.js +98 -0
  8. package/dist/adapters/web/index.d.ts +3 -0
  9. package/dist/adapters/web/index.js +3 -0
  10. package/dist/adapters/web/renderer.d.ts +18 -0
  11. package/dist/adapters/web/renderer.js +553 -0
  12. package/dist/adapters/web/styles.d.ts +3 -0
  13. package/dist/adapters/web/styles.js +83 -0
  14. package/dist/adapters/web/types.d.ts +46 -0
  15. package/dist/adapters/web/types.js +2 -0
  16. package/dist/affix.d.ts +35 -0
  17. package/dist/affix.js +137 -0
  18. package/dist/badge.d.ts +45 -0
  19. package/dist/badge.js +168 -0
  20. package/dist/breadcrumb.d.ts +37 -0
  21. package/dist/breadcrumb.js +210 -0
  22. package/dist/button-group.d.ts +12 -0
  23. package/dist/button-group.js +72 -0
  24. package/dist/button.d.ts +15 -1
  25. package/dist/button.js +101 -12
  26. package/dist/carousel.d.ts +92 -0
  27. package/dist/carousel.js +509 -0
  28. package/dist/cascader.d.ts +65 -0
  29. package/dist/cascader.js +479 -0
  30. package/dist/collapse.d.ts +68 -0
  31. package/dist/collapse.js +348 -0
  32. package/dist/core/actions.d.ts +32 -0
  33. package/dist/core/actions.js +145 -0
  34. package/dist/core/data.d.ts +4 -0
  35. package/dist/core/data.js +27 -0
  36. package/dist/core/index.d.ts +7 -0
  37. package/dist/core/index.js +6 -0
  38. package/dist/core/platform-view.d.ts +17 -0
  39. package/dist/core/platform-view.js +84 -0
  40. package/dist/core/selection.d.ts +14 -0
  41. package/dist/core/selection.js +93 -0
  42. package/dist/core/text.d.ts +31 -0
  43. package/dist/core/text.js +154 -0
  44. package/dist/core/types.d.ts +269 -0
  45. package/dist/core/types.js +2 -0
  46. package/dist/core/validation.d.ts +24 -0
  47. package/dist/core/validation.js +243 -0
  48. package/dist/date-picker.d.ts +60 -0
  49. package/dist/date-picker.js +355 -0
  50. package/dist/dialog.d.ts +4 -0
  51. package/dist/dialog.js +23 -5
  52. package/dist/divider.d.ts +33 -0
  53. package/dist/divider.js +113 -0
  54. package/dist/draggable.d.ts +78 -0
  55. package/dist/draggable.js +255 -0
  56. package/dist/index.d.ts +53 -1
  57. package/dist/index.js +78 -0
  58. package/dist/input.d.ts +30 -1
  59. package/dist/input.js +166 -54
  60. package/dist/internal/qrcodegen.d.ts +94 -0
  61. package/dist/internal/qrcodegen.js +856 -0
  62. package/dist/masonry.d.ts +36 -0
  63. package/dist/masonry.js +171 -0
  64. package/dist/modal.d.ts +73 -0
  65. package/dist/modal.js +361 -0
  66. package/dist/portable/icons.d.ts +5 -0
  67. package/dist/portable/icons.js +24 -0
  68. package/dist/portable/index.d.ts +7 -0
  69. package/dist/portable/index.js +5 -0
  70. package/dist/portable/page.d.ts +38 -0
  71. package/dist/portable/page.js +361 -0
  72. package/dist/portable/responsive.d.ts +20 -0
  73. package/dist/portable/responsive.js +15 -0
  74. package/dist/portable/theme.d.ts +24 -0
  75. package/dist/portable/theme.js +60 -0
  76. package/dist/portable/tree.d.ts +10 -0
  77. package/dist/portable/tree.js +96 -0
  78. package/dist/qr-code.d.ts +62 -0
  79. package/dist/qr-code.js +224 -0
  80. package/dist/range.d.ts +3 -0
  81. package/dist/range.js +16 -5
  82. package/dist/rate.d.ts +46 -0
  83. package/dist/rate.js +193 -0
  84. package/dist/resizable.d.ts +97 -0
  85. package/dist/resizable.js +426 -0
  86. package/dist/skeleton.d.ts +41 -0
  87. package/dist/skeleton.js +141 -0
  88. package/dist/steps.d.ts +45 -0
  89. package/dist/steps.js +203 -0
  90. package/dist/table.d.ts +106 -0
  91. package/dist/table.js +689 -0
  92. package/dist/tabs.d.ts +3 -0
  93. package/dist/tabs.js +11 -1
  94. package/dist/tag.d.ts +55 -0
  95. package/dist/tag.js +225 -0
  96. package/dist/time-picker.d.ts +62 -0
  97. package/dist/time-picker.js +298 -0
  98. package/dist/timeline.d.ts +48 -0
  99. package/dist/timeline.js +201 -0
  100. package/dist/toast.d.ts +55 -0
  101. package/dist/toast.js +224 -0
  102. package/dist/tour.d.ts +89 -0
  103. package/dist/tour.js +306 -0
  104. package/dist/virtual-keyboard.d.ts +95 -0
  105. package/dist/virtual-keyboard.js +432 -0
  106. package/dist/virtual-mouse.d.ts +82 -0
  107. package/dist/virtual-mouse.js +358 -0
  108. package/dist/watermark.d.ts +44 -0
  109. package/dist/watermark.js +148 -0
  110. package/package.json +132 -4
package/README.md CHANGED
@@ -23,10 +23,12 @@ helpers, and registration stays explicit:
23
23
 
24
24
  ```ts
25
25
  import { defineButtonComponents } from '@haiyue/ui/button';
26
+ import { defineButtonGroupComponents } from '@haiyue/ui/button-group';
26
27
  import { defineTreeComponents } from '@haiyue/ui/tree';
27
28
  import { defineVirtualListComponents } from '@haiyue/ui/virtual-list';
28
29
 
29
30
  defineButtonComponents();
31
+ defineButtonGroupComponents();
30
32
  defineTreeComponents();
31
33
  defineVirtualListComponents();
32
34
  ```
@@ -46,6 +48,275 @@ defineHaiyueUI();
46
48
  Because `defineHaiyueUI()` references the complete component set, prefer focused subpaths in bundle-sensitive
47
49
  product entry points.
48
50
 
51
+ ## Modal
52
+
53
+ Import `defineModalComponents` from `@haiyue/ui/modal` and register once. `HYModal` is also exported by the root
54
+ and included in `defineHaiyueUI()`. It provides default confirmation/cancel actions around a native modal
55
+ `<dialog>`, with top-layer rendering, background inertness, focus containment and return focus through shadow roots.
56
+ The existing Dialog entry remains available for surfaces with application-supplied footer actions.
57
+
58
+ ```html
59
+ <hy-modal id="publish" heading="Publish project" width="560" ok-text="Publish">
60
+ <p>Review the project before publishing.</p>
61
+ </hy-modal>
62
+ ```
63
+
64
+ Call `showModal()` / `close(reason?)`, or set the reflected boolean `open` property/attribute.
65
+ `heading` defaults to “Modal”; the `heading` slot overrides its content and the default slot supplies the body.
66
+ `width` defaults to 520 CSS pixels (240–2000), constrained to the viewport. `centered`, `closable`,
67
+ `mask-closable` / `maskClosable`, `keyboard` (Escape), and `show-footer` / `showFooter` all default to true;
68
+ set their attributes to `"false"` or properties to false to disable them independently.
69
+ `ok-text` / `okText` and `cancel-text` / `cancelText` default to “OK” and “Cancel”.
70
+ Use the `footer` slot for application-owned custom actions, replacing both default buttons.
71
+
72
+ Bubbling/composed events are `modal-open`, `modal-ok`, `modal-cancel` and `modal-close`.
73
+ The cancelable `modal-ok` and `modal-cancel` events carry `{ reason }`. Preventing either event keeps the modal open.
74
+ Close reasons are `ok`, `cancel`, `close-button`, `mask`, `escape` and `programmatic`; `close(reason)` also accepts
75
+ an application-specific string. `modal-close` fires once after an actual close, with `{ reason }`.
76
+ With `controlled`, default user actions only emit requests; the application updates `open` or calls `close()`.
77
+
78
+ ```js
79
+ publish.addEventListener('modal-ok', async event => {
80
+ event.preventDefault();
81
+ publish.confirmLoading = true;
82
+ try {
83
+ await saveProject();
84
+ publish.close('ok');
85
+ } finally {
86
+ publish.confirmLoading = false;
87
+ }
88
+ });
89
+ publish.showModal();
90
+ ```
91
+
92
+ `confirm-loading` / `confirmLoading` disables the default actions and user dismissal, shows a spinner and marks the
93
+ surface busy; application `close()` remains available. `confirm-disabled` / `confirmDisabled` only disables confirmation.
94
+ `destroy-on-hidden` / `destroyOnHidden` unmounts light DOM content while closed, retaining the same nodes, values and
95
+ listeners for reopening. It defaults to false. Disconnecting removes modality and scroll locks without emitting a
96
+ close event; a retained `open` attribute reopens on reconnection. Nested modals retain scroll locking until the last closes.
97
+
98
+ Style parts `panel`, `header`, `heading`, `body`, `footer`, `actions`, `ok-button`, `cancel-button`,
99
+ `close-button`, `spinner`. Tokens include `--hy-modal-width`, `--hy-modal-radius`, `--hy-modal-body-padding`,
100
+ `--hy-modal-duration`, `--hy-modal-bg-color`, `--hy-modal-mask-color`, `--hy-modal-mask-blur`, `--hy-modal-shadow-color`,
101
+ `--hy-modal-footer-bg-color` and `--hy-modal-button-radius`; colors inherit semantic theme tokens. Reduced-motion
102
+ preferences suppress the entrance and spinner animations. No sibling component import or automatic registration is needed.
103
+
104
+ ## QR Code
105
+
106
+ Import `defineQRCodeComponents` from `@haiyue/ui/qr-code` and call it once. The root registration path also includes
107
+ `<hy-qr-code>`. Values are encoded locally into SVG; no runtime dependency or remote QR generation service is used.
108
+
109
+ ```html
110
+ <hy-qr-code value="https://haiyuestudio.github.io/UI/" size="220"
111
+ icon="/brand.svg" icon-size="32" icon-margin="2" aria-label="Open Haiyue UI"></hy-qr-code>
112
+
113
+ <hy-qr-code value="https://haiyuestudio.github.io/UI/">
114
+ <img slot="icon" src="/brand.svg" alt="" />
115
+ </hy-qr-code>
116
+ ```
117
+
118
+ Set `value` to a URL or text (including UTF-8/Chinese/emoji). `size` defaults to 200 CSS pixels (64–2048).
119
+ `margin` is the quiet zone in modules (default/minimum 4, maximum 16).
120
+ `error-correction-level` / `errorCorrectionLevel` accepts `L`, `M`, `Q`, or `H`. Without an explicit level,
121
+ it defaults to `H` with an icon and `M` otherwise. An explicit level applies with or without an icon.
122
+ An `icon` image URL or content in the `icon` slot adds a center icon; the slot takes precedence over the URL.
123
+ `icon-size` / `iconSize` requests the content size in pixels (default 32), while `icon-margin` / `iconMargin`
124
+ sets its backing padding (default 2). The complete overlay is capped at 20% of the QR matrix width, including padding,
125
+ and scales with responsive sizing. Icon content is decorative and inert. A failed image leaves the plain QR visible.
126
+
127
+ `color` and `background-color` / `backgroundColor` customize the QR colors. The inherited tokens
128
+ `--hy-qr-code-color` and `--hy-qr-code-background-color` default to dark modules on white for both themes.
129
+ Other styling hooks are `--hy-qr-code-icon-radius`, `--hy-qr-code-radius` and parts `frame`, `code`,
130
+ `background`, `modules`, `icon`, `icon-image`, `message`. Keep sufficient contrast and verify your final payload,
131
+ size, colors and icon with the intended scanner; arbitrary custom styling can affect readability.
132
+
133
+ The read-only `status` is `empty`, `ready`, or `error`. Empty values and over-capacity payloads clear the previous code.
134
+ Bubbling, composed events are `qr-render` with `{ value, version, moduleCount, errorCorrectionLevel }` after encoding,
135
+ `qr-error` with `{ message }` on encoding failure, and `qr-icon-error` with `{ src }` on image failure.
136
+ SVG is decorative beneath a labelled image role; set `aria-label` to describe the QR's purpose.
137
+
138
+ The internal encoder is vendored from [Project Nayuki](https://www.nayuki.io/page/qr-code-generator-library),
139
+ upstream Git blob `c4191ac0b5f8a24d87fd9340ceaa2d3b07d0231a`, with its MIT notice retained in source and `LICENSE`.
140
+ Local edits only add an ES module export, strict indexed-access assertions and formatting. Independent decoding tests
141
+ use `jsqr` as a development-only dependency. Internal encoder symbols are excluded from the public component API.
142
+
143
+ ## Carousel
144
+
145
+ `@haiyue/ui/carousel` exports `HYCarousel`, `defineCarouselComponents()` and the associated `HYCarousel*` types.
146
+ Registration is explicit; panels are HTML elements in the default slot and stay mounted between changes.
147
+
148
+ ```html
149
+ <hy-carousel direction="horizontal" indicator-style="line" indicator-position="bottom"
150
+ autoplay interval="4000" draggable="true" loop="true" aria-label="Featured projects">
151
+ <article>First panel</article>
152
+ <article>Second panel</article>
153
+ <article>Third panel</article>
154
+ </hy-carousel>
155
+ ```
156
+
157
+ | Attribute / property | Default | Behavior |
158
+ | --- | --- | --- |
159
+ | `index` | `0` | Active panel, zero based |
160
+ | `direction` | `horizontal` | `horizontal` or `vertical`; horizontal supports RTL |
161
+ | `indicator-style` / `indicatorStyle` | `dot` | `dot`, `line`, `number` |
162
+ | `indicator-position` / `indicatorPosition` | `bottom` | `top`, `right`, `bottom`, `left` |
163
+ | `show-indicators` / `showIndicators` | `true` | Set `false` to hide indicators |
164
+ | `show-arrows` / `showArrows` | `true` | Set `false` to hide previous/next buttons |
165
+ | `autoplay` | `false` | Opt-in automatic rotation with a pause/start button |
166
+ | `interval` | `3000` | Milliseconds, normalized to 100–86,400,000 |
167
+ | `draggable` | `true` | Mouse/touch swipe; set `false` to disable |
168
+ | `loop` | `true` | Wrap at the ends; `false` clamps and stops autoplay at the last panel |
169
+
170
+ Use `next()`, `previous()`, `goTo(index)`, `play()` and `pause()` for imperative control.
171
+ The bubbling, composed `change` event includes `{ index, previousIndex, source }`, with sources
172
+ `api`, `indicator`, `arrow`, `keyboard`, `drag`, `autoplay` and `content`.
173
+ Inactive panels are inert and hidden from assistive technology. Arrow keys (matching direction), Home and End
174
+ navigate the focused viewport or indicators; input fields keep their editing keys. Hover temporarily pauses rotation;
175
+ keyboard focus pauses until explicitly resumed. Reduced-motion preferences suppress transitions and initial automatic
176
+ rotation; `play()` permits explicit rotation. Disconnecting releases timers, pointer listeners and animations and restores panel attributes/styles.
177
+
178
+ Customize `::part(indicators)`, `::part(indicator)`, `::part(indicator-active)`, `::part(indicator-content)`,
179
+ `::part(previous)`, `::part(next)`, `::part(playback)` and `::part(viewport)`.
180
+ Tokens include `--hy-carousel-height` (240px), `--hy-carousel-duration` (320ms), `--hy-carousel-indicator-size`,
181
+ `--hy-carousel-indicator-gap`, `--hy-carousel-indicator-offset`, `--hy-carousel-indicator-radius`,
182
+ `--hy-carousel-indicator-color` and `--hy-carousel-indicator-active-color`; other colors inherit semantic theme tokens.
183
+ For arbitrary content, set `indicatorRenderer = (index, active) => Node | string | null` (strings are plain text).
184
+ The component retains the native accessible indicator buttons and click/keyboard behavior around your content.
185
+ Panels should not override the component's positioning, dimensions, visibility or transform.
186
+
187
+ ## Masonry layout
188
+
189
+ Import `defineMasonryComponents` from `@haiyue/ui/masonry` and call it once to register `<hy-masonry>`.
190
+ Place HTML elements of varying heights in the default slot:
191
+
192
+ ```html
193
+ <hy-masonry min-column-width="240" gap="16" aria-label="Project gallery">
194
+ <article>First card…</article>
195
+ <article>Another card with more content…</article>
196
+ <article><img src="preview.jpg" alt="Project preview" style="width: 100%" /></article>
197
+ </hy-masonry>
198
+ ```
199
+
200
+ `columns` defaults to `0` (automatic); positive values request a fixed number of columns.
201
+ `min-column-width` (default `240`) controls automatic sizing; `gap` (default `16`) sets both gaps in CSS pixels.
202
+ Columns shrink to fit narrow containers. Each item goes into the shortest column, starting at the inline start,
203
+ including RTL layouts. DOM, screen-reader and keyboard order remain the original slot order.
204
+ Items keep their own content, theme and semantics; the component supplies positioning, border-box width and zero outer margins.
205
+ Use padding inside cards and avoid overriding item positioning/width. Text nodes and named slots are not layout items.
206
+
207
+ Container resizing, item resizing (including image loads), adding/removing items and toggling `hidden` automatically
208
+ schedule a layout. Call `refresh()` after changes outside those observations (for example, a stylesheet rule that
209
+ reveals a previously hidden item). `layout-change` bubbles across shadow roots with `{ columns, itemCount, height }`
210
+ after geometry changes; `itemCount` excludes hidden items. Style the transparent container with `::part(layout)`.
211
+ Observers and queued frames are released on disconnect, and internal item CSS properties are restored.
212
+
213
+ ## Tag and toast
214
+
215
+ Tags provide compact semantic labels with optional checked and close interactions. Toasts are an imperative,
216
+ lightweight feedback surface for short-lived messages; use Notification when a message also needs a description
217
+ or richer stacked content.
218
+
219
+ ```ts
220
+ import { defineTagComponents } from '@haiyue/ui/tag';
221
+ import { defineToastComponents } from '@haiyue/ui/toast';
222
+
223
+ defineTagComponents();
224
+ defineToastComponents();
225
+ ```
226
+
227
+ ```html
228
+ <hy-tag variant="success" icon="✓" closable>Synced</hy-tag>
229
+ <hy-tag variant="primary" checkable value="featured">Featured</hy-tag>
230
+ <hy-toast id="feedback" placement="top" duration="3" closable></hy-toast>
231
+ <script type="module">
232
+ feedback.success('Saved successfully');
233
+ const key = feedback.loading('Exporting…');
234
+ // Reusing a key replaces the persistent loading toast.
235
+ feedback.success({ key, message: 'Export complete' });
236
+ </script>
237
+ ```
238
+
239
+ ## Button icons, loading, and groups
240
+
241
+ Buttons accept a text `icon` or a richer `icon` slot. Set `icon-position="end"` to place it after the label.
242
+ The boolean `loading` attribute replaces the configured icon with a spinner, marks the native button busy, and
243
+ temporarily disables activation so an asynchronous request cannot be submitted twice.
244
+
245
+ ```html
246
+ <hy-button label="Publish" icon="↥"></hy-button>
247
+ <hy-button label="Continue" icon="→" icon-position="end"></hy-button>
248
+ <hy-button loading label="Syncing"></hy-button>
249
+ <hy-button label="Upload"><svg slot="icon" aria-hidden="true">…</svg></hy-button>
250
+
251
+ <hy-button-group aria-label="History actions">
252
+ <hy-button label="Undo" icon="↶"></hy-button>
253
+ <hy-button label="Redo" icon="↷"></hy-button>
254
+ </hy-button-group>
255
+ ```
256
+
257
+ Use `orientation="vertical"` for a stacked group. Button styling is exposed through the `button`, `content`,
258
+ `icon`, and `spinner` parts; the group exposes its container as the `group` part.
259
+
260
+ ## Input and search
261
+
262
+ `HYInput` supports plain-text `prefix` and `suffix` attributes as well as named slots for icons or richer
263
+ content. Use `type="search"` to add an accessible search action button:
264
+
265
+ ```html
266
+ <hy-input type="search" prefix="⌕" suffix="assets"
267
+ placeholder="Search…" search-label="Search assets"></hy-input>
268
+
269
+ <hy-input placeholder="Amount">
270
+ <span slot="prefix">¥</span>
271
+ <span slot="suffix">CNY</span>
272
+ </hy-input>
273
+ ```
274
+
275
+ Search inputs emit a composed, cancelable `search` event when the user presses Enter, activates the search
276
+ button, or the application calls `search()`. Its detail contains `{ value, valid, source }`, where `source` is
277
+ `enter`, `button`, or `api`. Existing `value-change`, validation, number, and color input behavior remains
278
+ available. Style the `control`, `input`, `prefix`, `suffix`, and `search-button` parts or the
279
+ `--hy-input-affix-*` and `--hy-input-search-*` tokens.
280
+
281
+ ## Portable component semantics (M24 G03/G05)
282
+
283
+ `@haiyue/ui/core` provides platform-independent component types, validation, selection/input/action
284
+ controllers and the `PlatformView` lifetime contract. `@haiyue/ui/portable` provides `HYPage`, selector
285
+ bindings, keyed updates, transactions, focus/modal policy and semantic theme conversion. Both entries
286
+ can be imported without DOM, NativeScript or Engine. They do not register existing Web Components.
287
+
288
+ ```ts
289
+ import { hyNode, hyKey, type HYRenderer } from '@haiyue/ui/core';
290
+ import { HYPage } from '@haiyue/ui/portable';
291
+
292
+ export function mountPage(renderer: HYRenderer) {
293
+ const page = new HYPage(renderer);
294
+ page.mount(hyNode('Column', 'settings', { layout: { gap: 8 } }, {
295
+ children: [hyNode('Text', 'title', { text: 'Settings' })],
296
+ }));
297
+ page.setProps(hyKey('settings', 'title'), 'Text', { text: 'Preview settings' });
298
+ return page; // The shell forwards suspend/resume and calls dispose on exit.
299
+ }
300
+ ```
301
+
302
+ Author keys are stable and unique within each parent, including its named slots. `hyKey()` builds
303
+ scoped keys for bindings, events and focus. `setProps()` completely replaces a node's props; use
304
+ `transaction()` for one synchronous batch. Group all selectors for a given store in one `bind(store,
305
+ bindings)` call so an application transaction produces one renderer commit. Identical props produce
306
+ no writes; reordering preserves instances. Applications persist values on `commit`, not `valueChange`.
307
+
308
+ The Web backend is available from `@haiyue/ui/adapters/web`: explicitly call
309
+ `definePortableWebComponents()`, construct `new HYWebRenderer(connectedElement, options)`, then pass it
310
+ to `HYPage`. It reuses seven existing Web Components and maps the other semantic kinds to browser
311
+ elements. It introduces no runtime package dependencies or automatic registration. See the
312
+ [Web adapter guide](docs/web-adapter.md) and [interactive example](examples/portable-ui/index.html).
313
+ Run `npm run test:web-adapter` for Chromium/WebKit regression coverage.
314
+
315
+ These APIs are included in the package and remain under development. Mobile mapping is G06, desktop mapping
316
+ G08, and ShaderLab shared-page migration G07. Existing Web component APIs below remain independent. See the
317
+ [portable UI guide](docs/portable-ui.md) and [typed composition example](test/portable/fixtures/settings-page.ts).
318
+ Run `npm run verify:portable` for semantics, no-DOM types, and an isolated offline tarball consumer.
319
+
49
320
  ## Tabs
50
321
 
51
322
  `@haiyue/ui/tabs` retains its existing `HYTabs`, `HYTabOption`, `HYTabChangeDetail`, and
@@ -82,6 +353,238 @@ Use the `height` property (or `height` attribute) for the internal viewport. `vi
82
353
  exclusive `endIndex` / `visibleEndIndex` values, and `item-click` reports the source item and absolute index.
83
354
  The scrollbar can be themed with inherited semantic tokens and `--hy-virtual-list-scrollbar-size`.
84
355
 
356
+ ## Breadcrumb
357
+
358
+ Import and register breadcrumb navigation independently:
359
+
360
+ ```ts
361
+ import { defineBreadcrumbComponents } from '@haiyue/ui/breadcrumb';
362
+
363
+ defineBreadcrumbComponents();
364
+ const breadcrumb = document.querySelector('hy-breadcrumb');
365
+ breadcrumb.items = [
366
+ { key: 'projects', title: 'Projects', href: '/projects' },
367
+ { key: 'scene', title: 'Ocean World' },
368
+ { key: 'lighting', title: 'Lighting' },
369
+ ];
370
+ breadcrumb.separator = '›';
371
+ ```
372
+
373
+ Item text may use the Ant Design-compatible `title` field or its `label` alias. The final item is exposed as
374
+ the current page with `aria-current="page"`. Earlier items render as links when
375
+ they provide `href`, or as action buttons otherwise; disabled items remain readable but cannot be activated.
376
+ Listen for the composed, cancelable `breadcrumb-click` event to handle actions or prevent link navigation.
377
+ Use `renderItem` for custom item content, and `ariaLabel` when rendered content needs an explicit accessible
378
+ name. Styling hooks include the `nav`, `list`, `item`, `link`, `button`, `current`, `disabled`, and `separator`
379
+ shadow parts plus the `--hy-breadcrumb-*` CSS variables.
380
+
381
+ ## Cascader
382
+
383
+ Use the focused `@haiyue/ui/cascader` entry for hierarchical selection:
384
+
385
+ ```ts
386
+ import { defineCascaderComponents } from '@haiyue/ui/cascader';
387
+
388
+ defineCascaderComponents();
389
+ const cascader = document.querySelector('hy-cascader');
390
+ cascader.options = [
391
+ { label: 'Project', value: 'project', children: [
392
+ { label: 'Scenes', value: 'scenes', children: [
393
+ { label: 'Moon Temple', value: 'temple' },
394
+ ] },
395
+ ] },
396
+ ];
397
+ cascader.value = ['project', 'scenes', 'temple'];
398
+ ```
399
+
400
+ Selecting a leaf commits the complete value path and emits `value-change` with both values and resolved option
401
+ objects. Enable `changeOnSelect` (or `change-on-select`) when parent paths should also be committed. The component
402
+ supports string and number values, disabled options, clearing, a custom `displaySeparator`, controlled `open`
403
+ state, outside-pointer and Escape closing, and arrow/Home/End keyboard navigation. `open-change` reports panel
404
+ visibility. Shadow parts expose `control`, `trigger`, `label`, `arrow`, `clear`, `panel`, `column`, `option`,
405
+ `option-item`, and `empty` for product-specific styling.
406
+
407
+ ## Date and time pickers
408
+
409
+ Date and time selection remain independently importable, so an application only ships the picker it uses:
410
+
411
+ ```ts
412
+ import { defineDatePickerComponents } from '@haiyue/ui/date-picker';
413
+ import { defineTimePickerComponents } from '@haiyue/ui/time-picker';
414
+
415
+ defineDatePickerComponents();
416
+ defineTimePickerComponents();
417
+ ```
418
+
419
+ `<hy-date-picker>` emits ISO `YYYY-MM-DD` values and provides a locale-aware month calendar, `min` / `max`
420
+ constraints, Monday or Sunday `weekStart`, Today, clearing, outside-pointer and Escape closing, and arrow,
421
+ Home/End, and PageUp/PageDown keyboard navigation.
422
+
423
+ `<hy-time-picker>` emits 24-hour `HH:mm` or `HH:mm:ss` values. Enable `showSeconds`, configure
424
+ `minuteStep` / `secondStep`, and constrain selection with `min` / `max`. Its scrollable hour, minute, and second
425
+ columns support keyboard traversal, Now, explicit confirmation, clearing, and controlled `open` state. Both
426
+ components emit composed `value-change` and `open-change` events and expose their controls through shadow parts.
427
+
428
+ ## Skeleton
429
+
430
+ Import the loading placeholder independently and place the real content in its default slot:
431
+
432
+ ```ts
433
+ import { defineSkeletonComponents } from '@haiyue/ui/skeleton';
434
+
435
+ defineSkeletonComponents();
436
+ ```
437
+
438
+ `<hy-skeleton>` defaults to a title and three paragraph rows. Enable `active` for the shimmer animation, add
439
+ `avatar`, choose `avatarShape`, `avatarSize`, `size`, and `round`, or tune `rows`, `titleWidth`, and the
440
+ `paragraphWidths` property. Set `loading = false` to remove placeholder DOM and reveal the slotted content.
441
+ The host exposes `aria-busy`, honors reduced-motion preferences, inherits both Haiyue themes, and provides
442
+ `placeholder`, `content`, `avatar`, `body`, `title`, `paragraph`, and `row` shadow parts.
443
+
444
+ ## Steps
445
+
446
+ Use `@haiyue/ui/steps` to show task, form, or publishing progress. Assign `items` with a required `title` and
447
+ optional `description`, `subtitle`, `icon`, `status`, and `disabled` state. `current` is zero-based and derives
448
+ `finish`, `process`, and `wait` states automatically unless an item provides an explicit status. Set
449
+ `direction` to `horizontal` or `vertical`, use `size="small"` for compact layouts, and enable `clickable` when
450
+ users may navigate between steps. Click navigation updates `current` and emits the composed `step-change` event.
451
+ The ordered list exposes `aria-current="step"` and shadow parts for every structural and status element.
452
+
453
+ ## Badge
454
+
455
+ Import `@haiyue/ui/badge` to decorate slotted content with a count or notification dot, or to render a standalone
456
+ semantic status. Numeric counts are capped by `overflowCount` (99 by default); use `showZero`, `dot`, `size`,
457
+ `color`, `title`, and the `[x, y]` `offset` property for display control. The `default`, `success`, `processing`,
458
+ `warning`, and `error` statuses accept accompanying `text`, expose status semantics, and honor reduced-motion
459
+ preferences. Structural styling hooks include `wrapper`, `badge`, `badge-content`, `status`, `status-dot`, and
460
+ `status-text` shadow parts.
461
+
462
+ ## Collapse
463
+
464
+ Import `@haiyue/ui/collapse` and assign typed `items` containing `key`, `title`, optional `content`, `extra`,
465
+ `disabled`, and `showArrow` values. `activeKeys` supports multiple open panels, while `accordion` limits the
466
+ group to one. Configure `iconPosition`, `collapsible`, `bordered`, `ghost`, and `destroyOnHidden`; call
467
+ `toggle(key, expanded?)` for imperative control. Each header is a native keyboard-accessible button connected
468
+ to a labelled region, and user changes emit the composed `collapse-change` event with the active keys and
469
+ changed panel. The component exposes structural shadow parts from `collapse` and `panel` through `body`.
470
+
471
+ Enable `animated` / `animated = true` for smooth opening and closing. Animation is off by default;
472
+ initial rendering stays immediate. Set `animation-duration` / `animationDuration` in milliseconds
473
+ (default 200, range 0–10,000); zero disables animation. Without the attribute, the inherited
474
+ `--hy-collapse-animation-duration` token (for example `250ms`) supplies the duration.
475
+ `--hy-collapse-animation-easing` customizes the easing (default `ease`).
476
+
477
+ ```html
478
+ <hy-collapse animated animation-duration="250" destroy-on-hidden></hy-collapse>
479
+ ```
480
+
481
+ Rapid toggles reverse from the current height, and content resizing during expansion updates the target height.
482
+ Closed panels become inert and hidden from assistive technology immediately; focus returns to their header
483
+ when needed. With `destroyOnHidden`, content is removed after the closing animation finishes.
484
+ Disabling animation, setting duration to zero, or enabling reduced-motion preferences settles immediately.
485
+ Animations and content observers are released on disconnect. The existing `collapse-change` event still fires
486
+ when the expanded state changes, rather than waiting for animation completion. These options extend `HYCollapse`;
487
+ no new package exports or registration functions are required.
488
+
489
+ ## Affix
490
+
491
+ Import `@haiyue/ui/affix` to pin actions, navigation, or status content after it crosses a viewport threshold.
492
+ Use the `offset-top` or `offset-bottom` attributes, or the `topOffset` / `bottomOffset` properties, and assign an
493
+ element to `target` when the scroll container is not the browser window. The component preserves the original
494
+ layout with an internal placeholder, exposes the read-only `affixed` state, and emits the composed
495
+ `affix-change` event. Call `refresh()` after layout changes that do not trigger resize observation.
496
+
497
+ ## Tour
498
+
499
+ Import `@haiyue/ui/tour` for step-by-step product guidance. Assign `steps` with a title, optional description,
500
+ target selector, element, or resolver function, and an optional `top`, `right`, `bottom`, `left`, or `center`
501
+ placement. The component can render a spotlight mask, scroll targets into view, close from Escape or mask
502
+ interaction, and is controlled through `open` and zero-based `current`. Use `start()`, `next()`, `previous()`,
503
+ and `close()` from application code; observe `tour-change`, `tour-close`, `tour-finish`, and `tour-open-change`
504
+ for lifecycle state. Focus returns to the launch control when the tour ends.
505
+
506
+ ## Divider
507
+
508
+ Import `@haiyue/ui/divider` for semantic horizontal or vertical separators. Text can be supplied through the
509
+ default slot or the `label` property. Choose `solid`, `dashed`, `dotted`, or `double` with `lineStyle`, and place
510
+ text at `start`, `center`, or `end` with `textPlacement`. `thickness`, `color`, and `spacing` provide direct
511
+ appearance controls, while the `divider`, `line`, `line-before`, `line-after`, `text`, and `fallback` shadow
512
+ parts support product-specific styling. The internal separator exposes the correct `aria-orientation`.
513
+
514
+ ## Timeline
515
+
516
+ Use `@haiyue/ui/timeline` for ordered activity, history, and process displays. Assign typed `items` containing
517
+ `title`, optional `label` and `description`, semantic `status`, custom `color` or `dot`, and an optional per-item
518
+ `position`. The `left`, `right`, and `alternate` modes control placement; `reverse` flips the order and moves an
519
+ optional `pending` node to the leading edge. `renderItem` and `renderDot` provide DOM customization without
520
+ changing the data contract. The ordered list automatically collapses to a readable single-column layout on
521
+ narrow screens and its pending animation honors reduced-motion preferences.
522
+
523
+ ## Rate
524
+
525
+ Import and register the star rating independently:
526
+
527
+ ```ts
528
+ import { defineRateComponents } from '@haiyue/ui/rate';
529
+
530
+ defineRateComponents();
531
+ ```
532
+
533
+ `<hy-rate>` exposes a controlled numeric `value` and defaults to five stars. Add `allow-half` (or set
534
+ `allowHalf = true`) for 0.5 increments. Configure `count`, `allowClear`, `character`, and `tooltips`, or set
535
+ `disabled` / `readOnly` for non-editable states. The component exposes slider semantics, arrow/Home/End keyboard
536
+ control, `value-change` and `hover-change` composed events, plus `group`, `star`, and `fill` shadow parts.
537
+
538
+ ## Watermark
539
+
540
+ Wrap any content and render a non-interactive repeated text or image mark above it:
541
+
542
+ ```ts
543
+ import { defineWatermarkComponents } from '@haiyue/ui/watermark';
544
+
545
+ defineWatermarkComponents();
546
+ const watermark = document.querySelector('hy-watermark');
547
+ watermark.content = ['HAIYUE', 'INTERNAL'];
548
+ ```
549
+
550
+ Use `content` for one or more text lines, or set `image` to prefer an image mark. Geometry is controlled by
551
+ `rotate`, `gapX`, `gapY`, `offsetX`, `offsetY`, `markWidth`, and `markHeight`; typography and appearance use
552
+ `fontSize`, `fontFamily`, `fontWeight`, `color`, `opacity`, and `zIndex`. The SVG pattern lives inside the
553
+ component shadow root, is hidden from assistive technology, and uses `pointer-events: none`, so links, buttons,
554
+ and other slotted content remain interactive. Shadow parts expose `content`, `overlay`, `mark`, `text`, and
555
+ `image` for targeted styling.
556
+
557
+ ## Table
558
+
559
+ Import the data table from its focused entry. It applies local filters first, then stable sorting, and finally
560
+ pagination, so only the current page is rendered as rows:
561
+
562
+ ```ts
563
+ import { defineTableComponents } from '@haiyue/ui/table';
564
+
565
+ defineTableComponents();
566
+ const table = document.querySelector('hy-table');
567
+ table.columns = [
568
+ { key: 'name', title: 'Name', sortable: true, filterable: true },
569
+ { key: 'role', title: 'Role', filterOptions: roles },
570
+ { key: 'score', title: 'Score', sortable: true, align: 'right' },
571
+ ];
572
+ table.dataSource = records;
573
+ table.pageSize = 20;
574
+ ```
575
+
576
+ Use `page`, `pageSize`, `pageSizeOptions`, and `pagination` for paging; `filters`, `setFilter()`, and
577
+ `clearFilters()` for filtering; and `sort`, `sortBy()`, and `clearSort()` for ordering. Columns may provide a
578
+ custom `filter`, `sorter`, or `render` function. `table-change` reports the complete processed state after a
579
+ user or API change, while `row-click` returns the source record and its original absolute index. The `empty`
580
+ slot, semantic theme tokens, and exported shadow parts support content and visual customization.
581
+
582
+ Filterable columns show a funnel control beside the title. Set `table.showFilters = false` or
583
+ `show-filters="false"` to hide all filter controls while keeping programmatic filtering active. Set
584
+ `showFilter: false` on an individual column to hide only that column's funnel. The filter menu, trigger, panel,
585
+ input, and clear action are exposed through the `filter-menu`, `filter-trigger`, `filter-panel`, `filter`, and
586
+ `filter-clear` shadow parts.
587
+
85
588
  ## Drawer
86
589
 
87
590
  Import and register the drawer independently when a product needs an off-canvas panel:
@@ -156,6 +659,104 @@ Single-value mode uses `value`; interval mode exposes `lowerValue`, `upperValue`
156
659
  `rail`, `track`, `handle`, `handle-lower`, and `handle-upper` shadow parts. `value-input` reports live movement and
157
660
  `value-change` reports a committed pointer or keyboard change.
158
661
 
662
+ ## Virtual keyboard
663
+
664
+ Import the on-screen keyboard independently and bind it to a text input or textarea:
665
+
666
+ ```ts
667
+ import { defineVirtualKeyboardComponents } from '@haiyue/ui/virtual-keyboard';
668
+
669
+ defineVirtualKeyboardComponents();
670
+ const keyboard = document.querySelector('hy-virtual-keyboard');
671
+ keyboard.target = document.querySelector('textarea');
672
+ keyboard.physicalSync = true;
673
+ keyboard.mode = 'numeric'; // switch back with 'qwerty'
674
+ await keyboard.type('Haiyue UI', { interval: 45 });
675
+ ```
676
+
677
+ The default exported `HY_VIRTUAL_KEYBOARD_QWERTY_LAYOUT` includes digits, letters, Shift, Caps Lock, editing,
678
+ all four arrow directions, caret, and navigation keys. Set `mode` to `qwerty` or `numeric`; the numeric mode uses
679
+ the exported `HY_VIRTUAL_KEYBOARD_NUMERIC_LAYOUT` with digits, decimal, minus, deletion, and Enter keys. Assign
680
+ `layout` with rows of typed key descriptors for shortcut or product-specific keyboards. Pointer and native keyboard activation edit the bound target and emit its normal
681
+ `input` event; `physicalSync` mirrors real key state without duplicating native input. `press()`, `release()`,
682
+ `tap()`, `type()`, and `clear()` support guided playback. Observe `virtual-keyboard-down`,
683
+ `virtual-keyboard-up`, and `virtual-keyboard-input`, or style `keyboard`, `row`, `key`, and per-code key parts
684
+ with the `--hy-virtual-keyboard-*` tokens.
685
+
686
+ ## Draggable container
687
+
688
+ Import the transform-based container independently, then use any slotted element as its handle:
689
+
690
+ ```ts
691
+ import { defineDraggableComponents } from '@haiyue/ui/draggable';
692
+
693
+ defineDraggableComponents();
694
+ const panel = document.querySelector('hy-draggable');
695
+ panel.bounds = 'parent';
696
+ panel.axis = 'both';
697
+ panel.grid = 8;
698
+ panel.moveTo(24, 24);
699
+ ```
700
+
701
+ `bounds` accepts `none`, `parent`, `viewport`, or an `HTMLElement`; `axis` accepts `both`, `x`, or `y`.
702
+ Use `handle` to restrict pointer starts to a selector and `cancel` to exclude interactive content. The default
703
+ cancel selector protects inputs, buttons, links, editable content, and `[data-no-drag]`. Arrow keys move by one
704
+ grid step, Shift multiplies that step by ten, and Home resets the position. `moveTo()`, `moveBy()`, `reset()`,
705
+ and `refresh()` provide imperative control. Observe cancelable `drag-start`, followed by `drag-move` and
706
+ `drag-end`; style the exported `surface` part and `--hy-draggable-*` tokens.
707
+
708
+ ## Resizable container
709
+
710
+ Import the eight-handle transform frame independently. Its four corner points and four edge-midpoint handles
711
+ resize the rectangle; dragging the content surface moves it:
712
+
713
+ ```ts
714
+ import { defineResizableComponents } from '@haiyue/ui/resizable';
715
+
716
+ defineResizableComponents();
717
+ const frame = document.querySelector('hy-resizable');
718
+ frame.bounds = 'parent';
719
+ frame.grid = 8;
720
+ frame.aspectRatio = 16 / 9;
721
+ frame.setRect({ x: 48, y: 48, width: 240, height: 135 });
722
+ ```
723
+
724
+ Configure `minWidth`, `minHeight`, `maxWidth`, and `maxHeight`, or use the matching kebab-case attributes.
725
+ `bounds` accepts `none`, `parent`, `viewport`, or an `HTMLElement`; `movable="false"` keeps content stationary
726
+ while preserving resize handles. The focused frame and handles support arrows, Shift acceleration, and Home
727
+ reset. Imperative APIs include `setRect()`, `moveTo()`, `moveBy()`, `resizeTo()`, `reset()`, and `refresh()`.
728
+ Observe cancelable `resize-start`, continuous `resize`, and `resize-end` events. Shadow parts expose `frame`,
729
+ `content`, `handle`, and every directional handle such as `handle-nw`; appearance uses `--hy-resizable-*` tokens.
730
+
731
+ ## Virtual mouse
732
+
733
+ Import the fixed-position cursor visual independently. It never intercepts pointer input or synthesizes clicks on
734
+ page elements; host applications receive composed events and decide how actions map to product behavior:
735
+
736
+ ```ts
737
+ import { defineVirtualMouseComponents } from '@haiyue/ui/virtual-mouse';
738
+
739
+ defineVirtualMouseComponents();
740
+ const mouse = document.querySelector('hy-virtual-mouse');
741
+ mouse.images = {
742
+ idle: '/cursor-idle.png',
743
+ 'left-down': '/cursor-left.png',
744
+ 'right-down': '/cursor-right.png',
745
+ };
746
+ mouse.show();
747
+ await mouse.moveTo(420, 280, { animate: true, duration: 600 });
748
+ await mouse.leftClick();
749
+ await mouse.rightClick();
750
+ ```
751
+
752
+ Use `moveTo()` / `moveBy()` for coordinates, `press()` / `release()` for held-button states, and
753
+ `leftClick()` / `middleClick()` / `rightClick()` for timed click feedback. `animated`, `duration`, and `easing`
754
+ provide host defaults; every move may override them. State images may also be supplied through `idle-image`,
755
+ `left-down-image`, `middle-down-image`, and `right-down-image`. Style the exported `cursor`, `shape`, `image`,
756
+ and `indicator` parts or the `--hy-virtual-mouse-*` CSS variables. Events include `virtual-mouse-move-start`,
757
+ `virtual-mouse-move`, `virtual-mouse-move-end`, `virtual-mouse-down`, `virtual-mouse-up`, and
758
+ `virtual-mouse-click`.
759
+
159
760
  ## Themes
160
761
 
161
762
  Two optional CSS theme entries are provided. Import only the skin a product needs, or import both when the
@@ -189,7 +790,11 @@ npm run examples
189
790
  ```
190
791
 
191
792
  Then open <http://localhost:4173/>. The gallery provides a left-side component index and live examples for
192
- every exported component, including editable parameters and event output.
793
+ every exported component, including editable parameters and event output. The gallery shell itself dogfoods
794
+ Haiyue UI: theme actions, component search, command results, status, and example action controls use the
795
+ published Web Components rather than parallel page-only widgets. The navigation/content shell and eligible
796
+ preview/control cards use `hy-split` for keyboard- and pointer-adjustable sizing. Usage blocks are rendered as
797
+ read-only CodeMirror editors with HTML, JavaScript, and CSS syntax highlighting.
193
798
 
194
799
  ## Expandable container
195
800
 
@@ -230,4 +835,40 @@ npm run release:check
230
835
  ```
231
836
 
232
837
  Candidates: `.artifacts/packages/`. Review API changes before `npm run api:update`.
233
- See [release review](review/release-0.1.2.md).
838
+ See [release review](review/release-0.2.2.md).
839
+
840
+ ### 共享组件目录(开发中)
841
+
842
+ `@haiyue/ui/core` 的 `HYComponentProps` 增加五种节点,Web 适配复用对应组件子模块,Native 适配使用原生控件;不新增根导出,也不自动注册全部组件。现有 18 种节点保持兼容,支持范围由 renderer 的 `capabilities.components` 声明。
843
+
844
+ | 节点 | 对应 WebComponent | 当前共享属性 |
845
+ | --- | --- | --- |
846
+ | `Checkbox` | `hy-checkbox` | `text`, `checked`, `disabled`;区别于原生开关 `Toggle` |
847
+ | `RadioGroup` | 一组 `hy-radio` | `value`, `options`, `disabled`;值必须出现在选项中 |
848
+ | `Rate` | `hy-rate` | `value`(0 到 count 的整数), `count`(1–10), `disabled`, `readOnly` |
849
+ | `Badge` | `hy-badge` | 独立文本 `text`,计数截断由应用决定 |
850
+ | `Divider` | `hy-divider` | 水平分隔线,可选 `text` |
851
+
852
+ 交互节点受应用状态控制,通过同一 transaction 的 `valueChange` / `commit` 提议变更;应用拒绝时保留已接受值。评分的半星、悬浮效果,徽标的圆点、动画、悬挂计数,分隔线的垂直/虚线模式尚未纳入共享协议。请勿把 WebComponent 的所有属性直接传入通用节点。
853
+
854
+ Native 仓库的 `examples/ui-validation/mobile` 提供独立「Haiyue UI」组件实验室;折叠内容、步骤导航与按钮组是基础节点组合示例,不是新增协议节点。
855
+
856
+ Web 的 `hy-badge` 新增可选 `literal` 属性(默认为 false):启用后 `count` 按原始文字显示,保留 0、前导零和大数字。普通计数的隐藏零值、截断,以及 status/text 模式保持原行为;共享 Badge 适配显式启用此模式。
857
+
858
+ The portable presentation contract adds optional semantic `Button.variant`
859
+ (`primary`, `secondary`, `quiet`, `danger`), `size` and vector `icon` names;
860
+ `Text.textStyle` (`title`, `body`, `caption`) and `tone`; `Tabs.variant`
861
+ (`underline`, `segmented`); and native `Select.presentation`. Existing nodes stay
862
+ valid. `HYTheme.typography` scales with fontScale, and optional selected, pressed,
863
+ disabled, elevated and onAccent colors map to inherited `--hy-` properties.
864
+ `HYIconName`, `HYButtonVariant`, `HYTextStyle` and `HYTypography` are explicitly
865
+ exported from `@haiyue/ui/core`; `HY_ICONS` / `hyIconSvg` are explicitly exported
866
+ from `@haiyue/ui/portable`, with no platform access or registration at import time.
867
+
868
+ Portable forms accept optional `FormGroup.description`, rendered as visible helper
869
+ text and included in associated controls' accessible descriptions. Updating help
870
+ or validation errors preserves the existing input, selection and composition.
871
+ `@haiyue/ui/portable` explicitly exports `hyResponsiveGrid`,
872
+ `hyResponsiveWorkspace`, `HYResponsiveGridOptions` and
873
+ `HYResponsiveWorkspaceOptions`. These return logical-pixel layout data without
874
+ reading window or platform globals, so hosts can use actual split-window sizes.