@stcn52/pro 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +615 -0
- package/CONVENTIONS.md +152 -0
- package/LICENSE +21 -0
- package/README.md +226 -2
- package/RELEASING.md +51 -0
- package/THIRD_PARTY_NOTICES.md +52 -0
- package/dist/index.cjs +23153 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5067 -0
- package/dist/index.d.ts +5067 -0
- package/dist/index.js +22941 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +10475 -0
- package/dist/tokens.css +322 -0
- package/docs/antd-alignment-plan.md +983 -0
- package/docs/api.md +3654 -0
- package/docs/components.md +1702 -0
- package/docs/measurements.md +152 -0
- package/docs/qa/README.md +50 -0
- package/docs/qa/browser-checks.json +394 -0
- package/docs/qa/d-chrome-checklist-dark.png +0 -0
- package/docs/qa/d-chrome-checks.json +234 -0
- package/docs/qa/d-chrome-detail-dark.png +0 -0
- package/docs/qa/d-chrome-filters-dark.png +0 -0
- package/docs/qa/d-chrome-shell-dark.png +0 -0
- package/docs/qa/d-detail-checks.json +222 -0
- package/docs/qa/d-detail-comments-failed-dark.png +0 -0
- package/docs/qa/d-detail-preview-dark.png +0 -0
- package/docs/qa/d-entity-checks.json +294 -0
- package/docs/qa/d-entity-failed-dark.png +0 -0
- package/docs/qa/d-workbench-canvas-dark.png +0 -0
- package/docs/qa/d-workbench-checks.json +338 -0
- package/docs/qa/d-workbench-edit-failed-dark.png +0 -0
- package/docs/qa/d-workbench-roadmap-dark.png +0 -0
- package/docs/qa/d-workbench-wizard-failed-dark.png +0 -0
- package/docs/qa/date-range-mobile-dark.jpg +0 -0
- package/docs/qa/p0-cascader-checks.json +228 -0
- package/docs/qa/p0-cascader-multiple-dark.png +0 -0
- package/docs/qa/p0-config-checks.json +430 -0
- package/docs/qa/p0-config-nested-dark.png +0 -0
- package/docs/qa/p0-date-checks.json +595 -0
- package/docs/qa/p0-date-time-dark.png +0 -0
- package/docs/qa/p0-form-lifecycle-checks.json +30 -0
- package/docs/qa/p0-form-lifecycle.png +0 -0
- package/docs/qa/p0-select-checks.json +378 -0
- package/docs/qa/p0-select-virtual-dark.png +0 -0
- package/docs/qa/p0-table-checks.json +290 -0
- package/docs/qa/p0-table-virtual-dark.png +0 -0
- package/docs/qa/p0-transfer-checks.json +322 -0
- package/docs/qa/p0-transfer-pagination-dark.png +0 -0
- package/docs/qa/p0-tree-checks.json +242 -0
- package/docs/qa/p0-tree-range-dark.png +0 -0
- package/docs/qa/p1-app-browser-checks.json +34 -0
- package/docs/qa/p1-app-feedback-dark.png +0 -0
- package/docs/qa/p1-avatar-checks.json +370 -0
- package/docs/qa/p1-avatar-dark.png +0 -0
- package/docs/qa/p1-browser-checks.json +218 -0
- package/docs/qa/p1-card-checks.json +262 -0
- package/docs/qa/p1-card-dark.png +0 -0
- package/docs/qa/p1-content-navigation-browser-checks.json +114 -0
- package/docs/qa/p1-controls-browser-checks.json +86 -0
- package/docs/qa/p1-controls-desktop-dark.png +0 -0
- package/docs/qa/p1-dialog-nested-dark.png +0 -0
- package/docs/qa/p1-display-browser-checks.json +114 -0
- package/docs/qa/p1-display-desktop-dark.png +0 -0
- package/docs/qa/p1-divider-dark.png +0 -0
- package/docs/qa/p1-drawer-browser-checks.json +302 -0
- package/docs/qa/p1-drawer-rtl-dark.png +0 -0
- package/docs/qa/p1-general-input-browser-checks.json +114 -0
- package/docs/qa/p1-general-input-desktop-dark.png +0 -0
- package/docs/qa/p1-image-browser-checks.json +38 -0
- package/docs/qa/p1-image-preview-dark.png +0 -0
- package/docs/qa/p1-inline-browser-checks.json +58 -0
- package/docs/qa/p1-inline-desktop-dark.png +0 -0
- package/docs/qa/p1-layout-browser-checks.json +114 -0
- package/docs/qa/p1-layout-desktop-dark.png +0 -0
- package/docs/qa/p1-menu-checks.json +357 -0
- package/docs/qa/p1-menu-long-dark.png +0 -0
- package/docs/qa/p1-nav-dark.png +0 -0
- package/docs/qa/p1-nav-sidebar-checks.json +218 -0
- package/docs/qa/p1-navigation-browser-checks.json +114 -0
- package/docs/qa/p1-navigation-mobile-dark.png +0 -0
- package/docs/qa/p1-pagination-checks.json +309 -0
- package/docs/qa/p1-pagination-dark.png +0 -0
- package/docs/qa/p1-pagination-mobile-dark.png +0 -0
- package/docs/qa/p1-popup-actions-browser-checks.json +58 -0
- package/docs/qa/p1-popup-actions-desktop-dark.png +0 -0
- package/docs/qa/p1-progress-browser-checks.json +30 -0
- package/docs/qa/p1-progress-desktop-dark.png +0 -0
- package/docs/qa/p1-rate-half-desktop-dark.png +0 -0
- package/docs/qa/p1-segment-checks.json +426 -0
- package/docs/qa/p1-segment-dark.png +0 -0
- package/docs/qa/p1-sidebar-dark.png +0 -0
- package/docs/qa/p1-slider-rate-browser-checks.json +114 -0
- package/docs/qa/p1-states-browser-checks.json +34 -0
- package/docs/qa/p1-states-checks.json +342 -0
- package/docs/qa/p1-states-dark.png +0 -0
- package/docs/qa/p1-states-mobile-dark.png +0 -0
- package/docs/qa/p1-tabs-editable-dark.png +0 -0
- package/docs/qa/p1-tag-dark.png +0 -0
- package/docs/qa/p1-tag-divider-checks.json +330 -0
- package/docs/qa/p1-upload-browser-checks.json +30 -0
- package/docs/qa/p1-upload-list-dark.png +0 -0
- package/docs/qa/p2-ai-panel-checks.json +401 -0
- package/docs/qa/p2-ai-panel-dark.png +0 -0
- package/docs/qa/p2-alert-dark.png +0 -0
- package/docs/qa/p2-app-final-checks.json +309 -0
- package/docs/qa/p2-app-final-dark.png +0 -0
- package/docs/qa/p2-badge-alert-checks.json +466 -0
- package/docs/qa/p2-beam-motion-checks.json +58 -0
- package/docs/qa/p2-calendar-dark.png +0 -0
- package/docs/qa/p2-calendar-timeline-checks.json +254 -0
- package/docs/qa/p2-charts-checks.json +242 -0
- package/docs/qa/p2-charts-dark.png +0 -0
- package/docs/qa/p2-color-gradient-dark.png +0 -0
- package/docs/qa/p2-content-navigation-checks.json +794 -0
- package/docs/qa/p2-dialog-popover-dark.png +0 -0
- package/docs/qa/p2-display-checks.json +128 -0
- package/docs/qa/p2-display-dark.png +0 -0
- package/docs/qa/p2-drawer-final-dark.png +0 -0
- package/docs/qa/p2-extras-checks.json +482 -0
- package/docs/qa/p2-general-inputs-checks.json +154 -0
- package/docs/qa/p2-general-inputs-dark.png +0 -0
- package/docs/qa/p2-icon-checks.json +466 -0
- package/docs/qa/p2-icon-dark.png +0 -0
- package/docs/qa/p2-image-dark.png +0 -0
- package/docs/qa/p2-inline-editors-checks.json +199 -0
- package/docs/qa/p2-input-button-checks.json +778 -0
- package/docs/qa/p2-input-dark.png +0 -0
- package/docs/qa/p2-layout-final-checks.json +136 -0
- package/docs/qa/p2-layout-final-dark.png +0 -0
- package/docs/qa/p2-lists-checks.json +290 -0
- package/docs/qa/p2-masonry-dark.png +0 -0
- package/docs/qa/p2-media-checks.json +212 -0
- package/docs/qa/p2-mentions-color-checks.json +362 -0
- package/docs/qa/p2-overlay-checks.json +370 -0
- package/docs/qa/p2-people-picker-dark.png +0 -0
- package/docs/qa/p2-popconfirm-final-dark.png +0 -0
- package/docs/qa/p2-popup-final-checks.json +223 -0
- package/docs/qa/p2-qr-browser-decode.json +30 -0
- package/docs/qa/p2-quick-select-dark.png +0 -0
- package/docs/qa/p2-quick-text-dark.png +0 -0
- package/docs/qa/p2-rate-dark.png +0 -0
- package/docs/qa/p2-scroll-navigation-checks.json +198 -0
- package/docs/qa/p2-scroll-navigation-dark.png +0 -0
- package/docs/qa/p2-selection-bar-checks.json +302 -0
- package/docs/qa/p2-selection-bar-dark.png +0 -0
- package/docs/qa/p2-slider-rate-checks.json +262 -0
- package/docs/qa/p2-switch-dark.png +0 -0
- package/docs/qa/p2-tabs-dark.png +0 -0
- package/docs/qa/p2-timeline-dark.png +0 -0
- package/docs/qa/p2-toast-dark.png +0 -0
- package/docs/qa/p2-toggle-checks.json +834 -0
- package/docs/qa/p2-tour-dark.png +0 -0
- package/docs/qa/p2-upload-dark.png +0 -0
- package/docs/qa/table-details.md +26 -0
- package/docs/qa/table-mobile-dark.jpg +0 -0
- package/docs/qa/transfer-mobile-light.jpg +0 -0
- package/docs/qa/tree-browser-checks.json +226 -0
- package/docs/qa/tree-details.md +25 -0
- package/docs/qa/tree-directory-mobile-dark.jpg +0 -0
- package/docs/tokens.md +255 -0
- package/package.json +92 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@stcn52/pro` are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
6
|
+
the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
- Clear all 13 lint warnings: publish controlled props before layout effects, reset closed overlays without effect cascades, isolate ref-backed event handlers and render composer tools as components; enforce hook checks and a zero-warning verification gate.
|
|
11
|
+
|
|
12
|
+
- Ship editors: validate owned drag sessions, quarter/year boundaries and wizard drafts; wait for real workbench imports/deletes/edits and preserve new selection, parse quoted multiline CSV safely, guard queued callbacks after unmount, and contain mobile canvas cards.
|
|
13
|
+
|
|
14
|
+
- Ship entities: await real entity/picker/share submissions, retain failed drafts and isolate reopened sessions; deduplicate relation counts without dropping off-page IDs, respect provider disabled, validate scheduled recipients, and copy only host-supplied links after confirmed success.
|
|
15
|
+
|
|
16
|
+
- Ship detail: asynchronous comment submission with draft-preserving retry, cyclic thread safety, provider-aware relationship controls, attachment reader/timer cleanup and latest callbacks, explicit preview download stand-ins and CSV formula protection.
|
|
17
|
+
|
|
18
|
+
- Ship chrome: provider-aware rail/header/tools, per-rail disabled overrides, safe empty filters and operator resets, localized business controls, F2/IME title editing, finite badges, controlled inline editing focus and responsive reading surfaces.
|
|
19
|
+
|
|
20
|
+
- App feedback: inherit nested placement/caps, isolate closed message handles from reused keys, and settle all close subscribers while preserving reentrant notices and timers when host callbacks fail.
|
|
21
|
+
|
|
22
|
+
- Popup actions: drop blocked uncontrolled menus/confirmations, preserve controlled ownership and protect modified/IME open keys; localize confirmation labels/errors, retain zero content and normalize nonfinite drawer dimensions.
|
|
23
|
+
|
|
24
|
+
- Layout: localized sider/splitter controls and explicit sider disabled overrides; finite numeric dimensions/gaps/flex, responsive collapse deduplication, pointer capture completion and stale-drag/IME protection.
|
|
25
|
+
|
|
26
|
+
- Display: locale and explicit-null breadcrumb separators, fractional-only statistics; Typography protects IME commits and external focus, cancels stale async copy attempts before clipboard writes and localizes controls.
|
|
27
|
+
|
|
28
|
+
- Upload/Image: localize controls, preserve falsy rejection errors and latest async transfer configuration, avoid duplicate stale removals; drop blocked uncontrolled previews, normalize rotations and retain zero placeholders.
|
|
29
|
+
|
|
30
|
+
- General inputs: finite/IME-safe numeric stepping, duplicate suggestion/tree/time change suppression, inherited-disabled tree search overrides; localize numeric/tree controls and clock validity, discard blocked uncontrolled popups.
|
|
31
|
+
|
|
32
|
+
- Overlays: Escape dismisses one leaf layer, modal Tab includes related portals, nested popovers rise above their anchors; tooltips merge descriptions and fit/re-measure viewport edges, toasts pause for keyboard focus and normalize invalid durations.
|
|
33
|
+
|
|
34
|
+
- Badge/Alert: numeric-string caps and zero rules, finite overflow/offset handling, localized status/close labels and reentrant-safe afterClose tracking.
|
|
35
|
+
|
|
36
|
+
- Tabs/Collapse/Steps: recover owned focus after dynamic removal, hiding or disabling; preserve external focus during tab removal, localize editable labels and protect modified/IME navigation keys.
|
|
37
|
+
|
|
38
|
+
- Input/Buttons: IME-safe Enter and clear behavior, localized clear/password controls, existing-id Field labels and merged accessible feedback; zero-content actions and split-menu disabled overrides.
|
|
39
|
+
|
|
40
|
+
- Radio/Checkbox/Switch: native group container refs/attributes, zero-valued checkbox labels, duplicate radio selection suppression, wrapped radio groups and IME-safe switch keys.
|
|
41
|
+
|
|
42
|
+
- Slider/Rate: disabled and canceled completion guards, finite extreme ranges and valid marks; selected-star clearing, zero-count ratings, locale labels and hover resets.
|
|
43
|
+
|
|
44
|
+
- AiPanel: Promise submission locks, failed-draft retry, stale-session protection, locale/disabled and IME handling; share Dialog modal stacking and follow streamed text in the actual body scroll container.
|
|
45
|
+
|
|
46
|
+
- Inline editors: disabled/readOnly and field configuration forwarding, accessible synchronous validation, IME protection, safe clear/unassigned identifiers and dynamic option focus; PeoplePicker accepts host loading/error/retry.
|
|
47
|
+
|
|
48
|
+
- SelectionBar: respect disabled commands and global overrides; lock pending operations, retain failed selections and await all round-robin writes before reporting success.
|
|
49
|
+
|
|
50
|
+
- Charts: localized empty data, finite/extreme numeric geometry, proportion-safe donut totals, data descriptions and responsive legends; protect interactive scatter points.
|
|
51
|
+
- Icon: safe prototype-like-name fallback, accessible unknown glyphs, native span refs/attributes and bounded numeric sizes.
|
|
52
|
+
- States/Progress: visible default Skeleton geometry, bounded placeholder/step counts, locale and native refs; honor null progress formatting and wrap narrow feedback content.
|
|
53
|
+
- Nav/Sidebar: isolate overflow keyboard/disabled state, preserve host routes and native refs, track label sizing; localize sidebar controls and end resizing on lost pointer capture.
|
|
54
|
+
- Segment: single keyboard entry, dynamic focus recovery, duplicate selection suppression, native refs/custom content/block layout; Chip consumes provider disabled.
|
|
55
|
+
- Tag/Divider: native attributes/ref, custom tag icons and close-event isolation; locale/disabled overrides, dotted rules and wrapping RTL captions.
|
|
56
|
+
- Card: native section attributes/ref, compact/inner variants, Grid/Meta composition, localized loading and narrow-content wrapping.
|
|
57
|
+
- Avatar: numeric sizing, square shape, measured children scaling, Unicode initials, srcSet fallback, native refs and accessible stack overflow.
|
|
58
|
+
- Pagination: suppress current/empty paging notifications, bound numeric precision, discard disabled size-menu state and protect IME quick entry; verify controlled/default state and total changes.
|
|
59
|
+
|
|
60
|
+
- Menu/ContextMenu: single Tab entry, dynamic focus recovery, disabled branches and RTL nested Escape/backward handling; bounded long menus preserve internal scroll, and submenus flip into available viewport space.
|
|
61
|
+
|
|
62
|
+
- ConfigProvider: nested light/dark themes and merged CSS tokens now reach body portals; undefined token overrides inherit. Pagination and selector/date labels consume locale, table controls consume disabled, and RTL spacing, popup alignment and fixed-column offsets mirror correctly.
|
|
63
|
+
|
|
64
|
+
- DatePicker/DateRangePicker: local time confirmation, week/month/quarter/year modes, multiple dates, lazy presets, strict format parsing, controlled popups and shared date/time bounds. ISO string values and native refs remain unchanged.
|
|
65
|
+
|
|
66
|
+
- DataTable: hierarchical rows, nested headers, additive sort arrays, radio selection, fixed-height virtual windows and aggregate change events. Summary now receives processed roots before pagination; merged/detail/group bodies retain full rendering.
|
|
67
|
+
|
|
68
|
+
- Complete Cascader multiple/intermediate paths, shared Tree check conduction, field mapping,
|
|
69
|
+
controlled popups/search, rich labels and source-safe lazy loading with retry.
|
|
70
|
+
|
|
71
|
+
- Complete Tree/DirectoryTree cached range selection, expansion-independent directory picks,
|
|
72
|
+
leaf icons, RTL/IME behavior and native drag geometry. `onDrop.dropPosition` now uses
|
|
73
|
+
the target sibling index; `relativeDropPosition` exposes the previous -1/0/1 meaning.
|
|
74
|
+
|
|
75
|
+
- Complete Transfer independent controlled checks, directional move payloads, page-safe selections,
|
|
76
|
+
rich/custom lists, search hooks and native refs with guarded custom callbacks.
|
|
77
|
+
|
|
78
|
+
- Complete Select/MultiSelect grouped virtual choices, labeled-value caching, controlled opening,
|
|
79
|
+
clear controls, custom option/label/tag rendering and async states while preserving string callbacks.
|
|
80
|
+
|
|
81
|
+
- Add Carousel, target-aware modal Tour, real SVG/canvas QRCode, native Watermark and responsive SVG BorderBeam; reuse Dialog focus/stack behavior for Tour.
|
|
82
|
+
|
|
83
|
+
- Add Mentions with caret-safe insertion, IME and keyboard suggestions; add ColorPicker with solid/gradient HEX/RGB/HSB editing, alpha, presets and controlled opening.
|
|
84
|
+
|
|
85
|
+
- Add Form conditional/render items, selective updates, preserve policies and filtered focus/scroll options
|
|
86
|
+
while protecting StrictMode and dynamic list remounts.
|
|
87
|
+
|
|
88
|
+
- Add App-bound message/notification APIs and static host restoration; add keyed Toast updates,
|
|
89
|
+
destroy-all, close callbacks, timer cleanup and persistent-hover handling.
|
|
90
|
+
|
|
91
|
+
- Add real-file Upload with async preflight/manual mode, multipart XHR or cancellable custom requests,
|
|
92
|
+
progress/error lists, accept/count limits and drag/drop.
|
|
93
|
+
|
|
94
|
+
- Add native Image loading/fallback and controlled previews with zoom, rotation and explicit groups.
|
|
95
|
+
|
|
96
|
+
- Add four-edge Drawer sharing Dialog modal behavior, bounded dimensions and independent
|
|
97
|
+
keyboard, mask and close-button controls.
|
|
98
|
+
|
|
99
|
+
- Add Dropdown and Popconfirm with native button refs, existing Menu/Popover behavior,
|
|
100
|
+
controlled visibility and async confirmation retry/cancellation.
|
|
101
|
+
|
|
102
|
+
- Fix nested Dialog scroll locks, top-layer keyboard handling, focus restoration and hidden/disabled focus filtering.
|
|
103
|
+
|
|
104
|
+
- Add compound Layout, responsive Row/Col/Grid, Flex/Space/Compact and accessible Splitter
|
|
105
|
+
with controlled sizing, bounds, keyboard/pointer adjustment and collapse restoration.
|
|
106
|
+
|
|
107
|
+
- Add Breadcrumb, responsive Descriptions, string-preserving Statistic and compound Typography
|
|
108
|
+
with async copying, editing, expansion and native link/heading semantics.
|
|
109
|
+
|
|
110
|
+
- Add InputNumber, AutoComplete, TreeSelect and TimePicker with Form/config integration,
|
|
111
|
+
numeric drafts, IME-safe suggestions, reused Tree loading/checks and native clock validation.
|
|
112
|
+
|
|
113
|
+
- Extend Badge status/rich counts/RTL offsets and Alert banner/title/variants/custom close lifecycle.
|
|
114
|
+
|
|
115
|
+
- Add Input affixes, clear/count/status/variants with native reset and Form integration;
|
|
116
|
+
extend button shapes/ghost/danger, loading actions, RTL switch text/keyboard and group option attributes.
|
|
117
|
+
- Expand Tabs editing/lifecycle/placement, Collapse keyboard/extra actions and Steps item states.
|
|
118
|
+
|
|
119
|
+
- P1 navigation: controlled Menu selection/expansion and inline/horizontal modes,
|
|
120
|
+
independent-menu state isolation, RTL/disabled Nav and ContextMenu, controlled
|
|
121
|
+
Sidebar sizing and collapsed focus isolation. Share rich-label search text.
|
|
122
|
+
|
|
123
|
+
- P1: expand Pagination, Segment, Avatar, Tag, Card and Divider contracts;
|
|
124
|
+
preserve controlled DataTable pagination and add display/interaction regressions.
|
|
125
|
+
|
|
126
|
+
- Add absolute FormItem dependency paths with user-triggered transitive
|
|
127
|
+
revalidation, cyclic dependency protection and stale async-result regression coverage.
|
|
128
|
+
|
|
129
|
+
- Add opt-in fixed-height Select/MultiSelect virtual scrolling, complete-list
|
|
130
|
+
keyboard navigation, tags/token separators and distinct-value maxCount.
|
|
131
|
+
- Preserve virtual option focus during scrolling and prevent delayed Popover
|
|
132
|
+
autofocus from overriding user navigation; defer tokenization during IME input.
|
|
133
|
+
|
|
134
|
+
- Add nested Form name paths, subtree validation/reset, copied values and
|
|
135
|
+
FormList dynamic/nested arrays with stable keys; expose Form.Item/Form.List
|
|
136
|
+
aliases and guard unsafe paths, cycles and excessive depth/indexes.
|
|
137
|
+
|
|
138
|
+
- Add ConfigProvider locale/direction/disabled defaults and a flat-field Form
|
|
139
|
+
foundation with async validation, resets, watched values and submission.
|
|
140
|
+
- Existing core controls consume disabled defaults; portals retain language
|
|
141
|
+
and direction, and Select/SplitButton close interactive layers when disabled.
|
|
142
|
+
|
|
143
|
+
- Complete Tree hierarchy capabilities: controlled state, cascade/strict checks, multi-selection, two-level lazy loading and retry, search, connector lines/custom rendering, virtual scrolling, ref scrolling and drag lifecycle/drop rules.
|
|
144
|
+
- Add DirectoryTree with folder/file icons, click/double-click expansion and Ctrl/Meta/Shift selection; retain legacy Tree route and reorder APIs.
|
|
145
|
+
|
|
146
|
+
- Complete DataTable details: local/remote pagination, local sorting and column filters, disabled row selection, expandable details, hidden/wrapping/merged cells, summary/title/footer and scroll configuration.
|
|
147
|
+
- Fix grouped and merged-cell cursor navigation, auxiliary column alignment, embedded control clicks, loading/error feedback and fixed expansion-column geometry.
|
|
148
|
+
|
|
149
|
+
### Added
|
|
150
|
+
|
|
151
|
+
- Select/MultiSelect shared search: rich-label text, custom filtering/sorting,
|
|
152
|
+
controlled queries, remote search callbacks, and enabled-option keyboard navigation.
|
|
153
|
+
|
|
154
|
+
- `Cascader`, `Transfer`, `DatePicker`, and `DateRangePicker`: searchable hierarchy,
|
|
155
|
+
dual-list selection, themed calendar and mutually constrained date ranges.
|
|
156
|
+
|
|
157
|
+
- `CheckboxGroup`, `PasswordInput`, and `Rate`, reusing the existing controls
|
|
158
|
+
with controlled/uncontrolled state, native keyboard interaction and no new dependencies.
|
|
159
|
+
|
|
160
|
+
- `Slider`, `Steps`, and `Alert`: native range input, accessible controlled step
|
|
161
|
+
navigation, and dismissible inline feedback. Includes stories, tests and docs.
|
|
162
|
+
|
|
163
|
+
- `Radio` / `RadioGroup`, `Tabs`, `Collapse`, and `Badge`, informed by Ant Design
|
|
164
|
+
component contracts and implemented with existing tokens and no new dependencies.
|
|
165
|
+
Includes native radio navigation, accessible tab panels, controlled/uncontrolled
|
|
166
|
+
selections, accordion mode, badge overflow, Storybook examples and tests.
|
|
167
|
+
|
|
168
|
+
### Fixed
|
|
169
|
+
|
|
170
|
+
- MultiSelect disabled choices, nested labels, dialog/checkbox semantics, large
|
|
171
|
+
and invalid states, and clearing that preserves locked and unknown selections.
|
|
172
|
+
- Select popup declaration now matches its dialog container.
|
|
173
|
+
|
|
174
|
+
### Changed
|
|
175
|
+
|
|
176
|
+
- Local release script now validates only with `--dry-run`; tagging, publication
|
|
177
|
+
and deployment require the platform workflow.
|
|
178
|
+
|
|
179
|
+
### Fixed
|
|
180
|
+
|
|
181
|
+
- **A cell's commands no longer slice the value they sit on.** The boxes a
|
|
182
|
+
`Column.actions` cell reveals on hover had no backdrop of their own, so the
|
|
183
|
+
value under them ended mid-glyph — in the `Cell Commands` story the ID cell read
|
|
184
|
+
`S` and then two boxes. The overlay now fades into the cell's **own** tint
|
|
185
|
+
(`--pro-cell-overlay`: the row's wash at rest, the accent tint while the pointer
|
|
186
|
+
is on the cell), exactly the way the row's commands already faded into the row,
|
|
187
|
+
so a narrow column loses its value gradually instead of cutting it. The story
|
|
188
|
+
itself was demoing the feature in a 90px ID column while its two boxes measured
|
|
189
|
+
52px; it now uses a 160px cell, where the value and both boxes read together
|
|
190
|
+
(the product's own ID column is 120px and carries one box).
|
|
191
|
+
- **The `Cell Commands` story named an icon the sprite does not have.** `copy`
|
|
192
|
+
is not in `ICONS`, and an unknown name draws an empty box — which is what the
|
|
193
|
+
screenshot showed. It uses `hashtag`, the glyph the demo's own "Copy ID"
|
|
194
|
+
affordance uses.
|
|
195
|
+
|
|
196
|
+
### Fixed
|
|
197
|
+
|
|
198
|
+
- **A widget inside a cell keeps its own keys.** The grid's key listener sits on
|
|
199
|
+
the `<tr>`, so everything pressed inside a cell bubbled to it and the row acted
|
|
200
|
+
on it: a space in a rename field selected the row instead of typing a space, an
|
|
201
|
+
`Enter` on a `Column.actions` box opened the record (and the row's
|
|
202
|
+
`preventDefault` stopped the box from running at all), and an arrow key inside
|
|
203
|
+
an in-cell editor moved the cursor and pulled the focus out from under it,
|
|
204
|
+
committing the half-typed value. The row now answers only for the grid
|
|
205
|
+
(`src/components/table/keyboard.ts`): a key is the widget's when something
|
|
206
|
+
already handled it or when the focus is inside an `input`, `textarea`, `select`,
|
|
207
|
+
`button`, `a[href]`, `[contenteditable]` or one of the combobox / listbox /
|
|
208
|
+
textbox / slider / switch roles — a list of roles, not of this library's
|
|
209
|
+
classes, so a host's own editor inside a cell is treated the same way.
|
|
210
|
+
- **Focus follows the cursor in a grouped grid too.** `groupBy` renders one
|
|
211
|
+
`<tbody>` per group and the focus query only looked inside a single one, so ↑ ↓
|
|
212
|
+
moved the outlined cell while the keyboard stayed behind. The query now runs
|
|
213
|
+
over the whole scroll container, whichever body the cell is in.
|
|
214
|
+
- **The grid stops jumping while it loads.** The skeleton rows carried no pinned
|
|
215
|
+
geometry, so a grid with a frozen column drew its header frozen and its loading
|
|
216
|
+
rows unfrozen, then snapped sideways when the data landed. The skeletons wear
|
|
217
|
+
the same offsets as the rows they stand in for.
|
|
218
|
+
- **The frozen edge shadow is drawn once.** With `selectable` + `showIndex` + a
|
|
219
|
+
frozen column, the body drew the shadow on the index cell _and_ on the last
|
|
220
|
+
frozen data column while the header drew it once; the body now agrees with the
|
|
221
|
+
header (the shadow belongs to the outermost pinned cell of the run).
|
|
222
|
+
- **A group header spans the header tools column.** `headerTools` adds a column
|
|
223
|
+
to the header row, and the group row's `colSpan` did not count it, so the group
|
|
224
|
+
band stopped one column short (visible wherever a list groups _and_ shows the
|
|
225
|
+
column-settings gear).
|
|
226
|
+
- **A row keeps its announced position when it has a context menu.** The
|
|
227
|
+
`aria-rowindex` was added to the wrapper instead of the row, so every row of a
|
|
228
|
+
right-clickable grid — i.e. every `ListWorkbench` row — announced no position
|
|
229
|
+
at all. It is now set on the `<tr>` itself, which is also the menu's trigger.
|
|
230
|
+
- **`RichTextToolbar` is back in the published surface.** It is re-exported by
|
|
231
|
+
`src/ship/EntityDialog.tsx` rather than declared in it, and
|
|
232
|
+
`scripts/public-surface.mjs` only read declarations, so the name was missing
|
|
233
|
+
from `docs/api.md`, from the test-coverage check and from the story-coverage
|
|
234
|
+
check while being a real runtime export. The script now follows
|
|
235
|
+
`export * from` and `export { … } from` (the public surface keeps its 268 other
|
|
236
|
+
names unchanged).
|
|
237
|
+
|
|
238
|
+
### Changed
|
|
239
|
+
|
|
240
|
+
- **`DataTable` is split by concern.** The 912-line `src/components/Table.tsx`
|
|
241
|
+
became `src/components/table/`: the props contract (`types`), the pinned-column
|
|
242
|
+
arithmetic and the skeleton geometry (`geometry`), the keyboard (`keyboard`),
|
|
243
|
+
the grouping (`grouping`), and the pieces the grid is assembled from —
|
|
244
|
+
`DataTable`, `TableHead`, `TableRow`, `SkeletonRows`, `BulkBar`, `ColumnMenu`,
|
|
245
|
+
`CellCommands`. `src/components/Table.tsx` stays as the barrel so every import
|
|
246
|
+
path (`../components/Table`, the stories, the tests, `src/index.ts`) is
|
|
247
|
+
unchanged, and `DataTableProps` stays next to `DataTable` because generated docs
|
|
248
|
+
resolve a component's props type in the component's own file.
|
|
249
|
+
|
|
250
|
+
### Changed
|
|
251
|
+
|
|
252
|
+
- **The pointer works in two levels**, the product's own: the row it is in takes the
|
|
253
|
+
light wash (`--surface-table-row-hover`, with the pick cell's gutter following it)
|
|
254
|
+
and the cell under it takes a step deeper — the accent tint, which over that wash
|
|
255
|
+
lands on the reference's measured `#ebf0fb`. A hovered row still reads as a row and
|
|
256
|
+
the cell it points at reads as the target, instead of one lone cell lighting up in
|
|
257
|
+
a grid of unchanged rows.
|
|
258
|
+
- **A selected grid row is neutral, not blue.** Sampled off the reference: the
|
|
259
|
+
selected row is `#fafafa` while the accent stays on its checkbox (`#57abfb`), so
|
|
260
|
+
a selected row still reads as a row and the control carries the state. The grid
|
|
261
|
+
uses a new `--surface-table-row-selected` (the head's tone in both themes); the
|
|
262
|
+
accent-tinted `--surface-selected` is unchanged for everything else.
|
|
263
|
+
- The pick column wears the header's tone (`--surface-table-head`, `#fafafa`) like
|
|
264
|
+
a spreadsheet's row-header gutter, instead of the rows' white. A row carrying a
|
|
265
|
+
state of its own — hover, selection — still wins, so the gutter is never the odd
|
|
266
|
+
one out in its own row.
|
|
267
|
+
- **The grid is drawn as a grid.** The cells had a bottom border only, so the
|
|
268
|
+
columns were separated by whitespace and nothing but the frozen edge; every
|
|
269
|
+
column now carries the same hairline on its right (the filler and the structural
|
|
270
|
+
pick / action / tool cells included in the exclusion, since they are not
|
|
271
|
+
columns), which is what makes it read as a table.
|
|
272
|
+
- **The grid is a spreadsheet, not a list of rows.** Hovering lights up the cell
|
|
273
|
+
under the pointer (a light wash and a hairline) instead of washing the whole row,
|
|
274
|
+
and the keyboard cursor is a **cell**: ← → walk the columns, ↑ ↓ the rows,
|
|
275
|
+
Home/End jump to the ends of the row, Enter opens the record, Space toggles its
|
|
276
|
+
selection, and focus rides with the cursor on a roving tabindex — one tab stop
|
|
277
|
+
for the whole grid, which is the cursor cell. The arrow arithmetic moved out of
|
|
278
|
+
`useListCursor` (still exported) because a row index is no longer the thing being
|
|
279
|
+
moved.
|
|
280
|
+
|
|
281
|
+
### Added
|
|
282
|
+
|
|
283
|
+
- **`Column.actions` — commands that live inside a cell.** Each column can carry
|
|
284
|
+
`[{ id, icon, label, onSelect(row) }]`: the boxes overlay the cell's right edge,
|
|
285
|
+
appear while the pointer is on **that cell** (or it holds focus), and each brings
|
|
286
|
+
its own tooltip and callback — the product's "Click to copy" on the identifier,
|
|
287
|
+
next to the value. The component owns the box, the reveal and the tooltip; the
|
|
288
|
+
host supplies the icon, the name and the write, which is all an integration needs.
|
|
289
|
+
- The **assignee cell's** person-add affordance: the host can name it
|
|
290
|
+
(`assignLabel(row)`) and take it over (`onAssign(row)`), or leave both out and let
|
|
291
|
+
the cell open its own people picker.
|
|
292
|
+
|
|
293
|
+
- `Toast` grew the things a host kept re-implementing: six **placements**
|
|
294
|
+
(`ToastProvider placement`, default unchanged at `top-center`), a **`warning`**
|
|
295
|
+
tone (the product's amber), an optional **title** with the message as its
|
|
296
|
+
description, one inline **action** (Undo / View / Retry) that does not dismiss
|
|
297
|
+
the toast itself, a **`filled`** variant on the tone's own colour, a
|
|
298
|
+
**`closeable`** switch, an **icon** override, and `max` to cap the stack.
|
|
299
|
+
`push` now returns the toast's id so a host can dismiss it early, and its third
|
|
300
|
+
argument takes an options object as well as the bare duration it took before.
|
|
301
|
+
|
|
302
|
+
### Added
|
|
303
|
+
|
|
304
|
+
- **The selection bar is `DataTable`'s.** The product covers the grid's header row
|
|
305
|
+
with it while rows are selected, and the stylesheet was written for exactly that
|
|
306
|
+
(`.pro-selection-bar` is absolutely positioned, 50px, full width) — but only
|
|
307
|
+
`ListWorkbench` rendered one, above the table, so a `DataTable` on its own had no
|
|
308
|
+
bar at all. The table now renders it **in place of the header row**: the covered
|
|
309
|
+
header stands down (`inert`, and the select-all lives on the bar instead of
|
|
310
|
+
existing twice), the bar's box centres in the pick column and its count starts
|
|
311
|
+
where the first data column does, so nothing is off by a few pixels. `SelectionBar`
|
|
312
|
+
moved from the ship layer to `src/components/SelectionBar.tsx` (same public
|
|
313
|
+
export), and `buildBulkCommands` there turns the host's data into the bar the
|
|
314
|
+
table and the board both use.
|
|
315
|
+
- The grid keeps the column widths it was given: `table-layout: fixed` spreads the
|
|
316
|
+
leftover space over every column, so a 44px pick column came out 66px and nothing
|
|
317
|
+
could line up with it. A trailing auto-width filler column takes the slack.
|
|
318
|
+
- **The bulk bar is the component's.** `ListWorkbench` takes `bulk` — the data and
|
|
319
|
+
the write for Update status, Move in baseline, Schedule, Distribute workitems and
|
|
320
|
+
Edit properties — and builds the whole bar itself, in the product's order, above
|
|
321
|
+
whatever `bulkActions` adds and its own More (export / delete) and Cancel. The
|
|
322
|
+
round-robin spread, the confirmation message and the bulk edit dialog are the
|
|
323
|
+
library's; a page supplies choices and a write and nothing else. That is the
|
|
324
|
+
point of the exercise: a page should not re-implement a command the product
|
|
325
|
+
always shows.
|
|
326
|
+
- A lone command in `bulkActions` keeps its own label, icon and `onSelect`
|
|
327
|
+
instead of being folded into a submenu named after its id — which is what a bar
|
|
328
|
+
needs to mix grouped commands (Update status ›) with single ones (Distribute
|
|
329
|
+
workitems).
|
|
330
|
+
- **Frozen columns are part of the list view.** `ListView.frozen` names the
|
|
331
|
+
columns pinned to the left edge; `ListWorkbench` pins them (`fixed: 'left'`),
|
|
332
|
+
answers the column menu's Freeze / Unfreeze into that view state, and forwards
|
|
333
|
+
Move / Insert / Remove to the host, which owns `columns`. The demo's lists
|
|
334
|
+
freeze `id`, so the grid opens the way the product's does: the checkbox column
|
|
335
|
+
and the ID scroll together, the rest goes under them, and the frozen run carries
|
|
336
|
+
the edge shadow. The header ⋯ now works in the real list, not only in the
|
|
337
|
+
DataTable story.
|
|
338
|
+
- **`Menu` grows submenus.** An item may carry `items`: it renders a caret and
|
|
339
|
+
`aria-haspopup="menu"` / `aria-expanded`, opens those entries beside its own row
|
|
340
|
+
and keeps the parent open until something in the child is chosen (`ArrowRight`
|
|
341
|
+
opens it, `ArrowLeft` closes it and restores the focus). `divider: true` renders
|
|
342
|
+
the hairline `ContextMenuItem` already supported, so `Menu` and the context menu
|
|
343
|
+
finally agree on what an item is. `SelectionBar`'s hand-rolled submenu can move
|
|
344
|
+
onto this.
|
|
345
|
+
- **`DataTable`'s column menu** (`onColumnCommand`), the product's header ⋯:
|
|
346
|
+
Sort by (a real submenu — Ascending / Descending / Clear sort, the active
|
|
347
|
+
direction checked), Move left / Move right (disabled at the ends), Insert left /
|
|
348
|
+
Insert right, Freeze or Unfreeze (the pin reflects `column.fixed`) and Remove
|
|
349
|
+
this column. The library reports a `ColumnCommand` and reorders nothing itself —
|
|
350
|
+
the host owns `columns`. The story's harness applies every command, so the demo
|
|
351
|
+
moves, inserts, freezes and removes columns for real.
|
|
352
|
+
- `DataTable` gained the two things its grid was missing next to its stylesheet:
|
|
353
|
+
- **A row cursor** (`cursor`): one tab stop for the body, ↑ ↓ walking an
|
|
354
|
+
`is-cursor` row, Home / End jumping, Enter opening it, Space toggling its
|
|
355
|
+
selection, and a pointer click parking the cursor where it landed. It uses the
|
|
356
|
+
library's own `useListCursor`, which clamps the cursor when a filter shrinks
|
|
357
|
+
the list under it. `ListWorkbench` turns it on, so the product's list screen is
|
|
358
|
+
one tab stop instead of fifty.
|
|
359
|
+
- **The cursor row shows its checkbox.** The pick cell is "the row number at
|
|
360
|
+
rest, the checkbox on hover / selected / while a selection is active" — the
|
|
361
|
+
keyboard cursor is the pointer's hover, and it was missing from that list, so
|
|
362
|
+
the cursor row kept printing its number over an invisible checkbox. The number
|
|
363
|
+
now steps aside only when there _is_ a checkbox to take its place
|
|
364
|
+
(`:has(.pro-checkbox)`), so a host with no selection writer keeps its numbers.
|
|
365
|
+
- **Density** `'default' | 'compact'`: 36px rows and header with `--text-sm`
|
|
366
|
+
cells, and a reserved actions column instead of the floating overlay (that is
|
|
367
|
+
what `.pro-table__cell--actions`, until now dead, right-aligns).
|
|
368
|
+
|
|
369
|
+
### Fixed
|
|
370
|
+
|
|
371
|
+
- **The row's commands sit at the row's end again.** The overlay resolved its
|
|
372
|
+
containing block against the actions cell — zero-width and `position: sticky`
|
|
373
|
+
whenever a column was frozen — so with a frozen column the pencil and the ⋯
|
|
374
|
+
landed at the **scrollport's** edge (mid-grid) instead of the row's. The cell
|
|
375
|
+
keeps the frozen edge's shadow and gives up the pinning, so the overlay's
|
|
376
|
+
containing block is the row itself: measured in the story, `offsetParent` is the
|
|
377
|
+
`TR` and the box sits 16px from the row's right edge.
|
|
378
|
+
|
|
379
|
+
- The pick cell's checkbox belongs to the **pick cell**. It used to appear as soon
|
|
380
|
+
as the pointer was anywhere in the row, so pointing at a title, a status or an
|
|
381
|
+
empty column offered a selection box the operator never asked for — the opposite
|
|
382
|
+
of the cell the interaction now belongs to. Only the pick cell reveals it; a
|
|
383
|
+
selected row, the cursor row and the bulk-selection mode keep theirs on screen,
|
|
384
|
+
because there the box is a state rather than an offer.
|
|
385
|
+
|
|
386
|
+
- The selection bar is exactly as tall as the header row it stands in for. It was
|
|
387
|
+
pinned at 50px while the grid's header measured 44px, so it hung 6px past the row
|
|
388
|
+
— visible as the `Cancel` button's box sticking out below the table's top edge.
|
|
389
|
+
Both now read one token (`--table-head-height`), so they cannot drift apart
|
|
390
|
+
again: measured in the story, the bar and the header row are the same 44px box
|
|
391
|
+
(40→84) with the first data row starting exactly at its bottom edge.
|
|
392
|
+
|
|
393
|
+
- A frozen column cannot look like a column of its own any more. The pinned cells
|
|
394
|
+
painted their own `--surface-default` and stayed in line with their row only
|
|
395
|
+
because the row states out-specified them (`tr:hover td` is 0,2,3 against
|
|
396
|
+
`td.is-fixed` at 0,2,1); any other row background — a host's own row class, a
|
|
397
|
+
state the stylesheet does not know — was covered by that opaque cell instead, and
|
|
398
|
+
a band that stops matching its row is what reads as an outlined column. The row
|
|
399
|
+
carries the background now and the pinned cells take `background: inherit`, so
|
|
400
|
+
the band is the row's colour by construction and still opaque for the columns
|
|
401
|
+
sliding under it.
|
|
402
|
+
- The pick column is centred. Its checkbox and its row number are two states of
|
|
403
|
+
one 44px slot, but the checkbox was laid out in the flow with `opacity: 0`, so
|
|
404
|
+
it took 16px + a gap and pushed the number off the axis — the header's
|
|
405
|
+
select-all sat 14px left of where the number was, and neither matched the
|
|
406
|
+
column. The checkbox is now absolutely centred and the cell aligns its content,
|
|
407
|
+
with the selector naming the element (`.pro-table td.pro-table__pick`) because
|
|
408
|
+
`.pro-table td` outranks a bare class. Measured on the built demo: every row's
|
|
409
|
+
number and box, and the header's box, are within 0px of the cell's centre.
|
|
410
|
+
- The pick cell no longer depends on `:has()` to hide its row number: the cell
|
|
411
|
+
says `is-selectable` when it really holds a checkbox. A browser without `:has()`
|
|
412
|
+
drops that whole rule, which left the checkbox drawn _next to_ the number.
|
|
413
|
+
- `DataTable` now does what its stylesheet already promised:
|
|
414
|
+
- **Only pin what is frozen.** The checkbox and actions columns were pinned
|
|
415
|
+
whenever the grid had a selection or row commands, so an unfrozen grid carried
|
|
416
|
+
a right-edge shadow with nothing to shadow and an opaque background on the
|
|
417
|
+
pick cell. They are pinned now only when a data column is (`column.fixed`).
|
|
418
|
+
- **Fixed columns work.** `.is-fixed-left` / `.is-fixed-right` and the two
|
|
419
|
+
`--shadow-table-fixed-*` tokens were dead CSS — nothing set the classes. A
|
|
420
|
+
column takes `fixed: 'left' | 'right'`, the component measures the offsets
|
|
421
|
+
from the preceding pinned widths, and the outer column of each run gets the
|
|
422
|
+
edge shadow. The checkbox and actions columns are pinned like the product's.
|
|
423
|
+
- **Group headers fold.** They drew a caret and did nothing; they are buttons
|
|
424
|
+
with `aria-expanded` now, uncontrolled (open) or controlled through
|
|
425
|
+
`expandedGroups` / `onExpandedGroupsChange`.
|
|
426
|
+
- **No dead controls.** The pick column keeps its row number, but its checkbox
|
|
427
|
+
(and the select-all box) only render when `onSelectedKeysChange` can write the
|
|
428
|
+
selection — the five host call sites that passed `selectable` without a
|
|
429
|
+
handler were showing checkboxes that did nothing. A `sortable` column whose
|
|
430
|
+
table has no `onSortChange` is disabled with a title instead of silently
|
|
431
|
+
ignoring clicks.
|
|
432
|
+
- `aria-rowcount` counts the header row as ARIA requires, and flat rows carry
|
|
433
|
+
`aria-rowindex`.
|
|
434
|
+
- Removed the unused `.pro-table__cell--compact` rule.
|
|
435
|
+
|
|
436
|
+
### Fixed
|
|
437
|
+
|
|
438
|
+
- The focus ring is drawn once. `base.css`'s `.pro-root :focus-visible` (0,2,0)
|
|
439
|
+
out-specified the inline cell editors' own `outline: none` (0,1,0), so an open
|
|
440
|
+
cell showed the global 2px ring _and_ the cell's accent hairline — two
|
|
441
|
+
concentric boxes around the title. `.pro-cell-editor :focus-visible` now wins on
|
|
442
|
+
order, and `CONVENTIONS.md` records the specificity trap.
|
|
443
|
+
- The global focus rule no longer sets `border-radius`, which used to overrule a
|
|
444
|
+
component's own radius the moment it took focus (a focused button rendered 2px
|
|
445
|
+
instead of 4px). The ring follows the element's radius natively.
|
|
446
|
+
|
|
447
|
+
### Changed
|
|
448
|
+
|
|
449
|
+
- `Tag` (and with it `StatusTag` and `CountTag`) is cut with the button's corner:
|
|
450
|
+
`border-radius: var(--radius)` instead of an 18px pill, and `LevelTag`'s badge
|
|
451
|
+
follows. A tag and a button are the same kind of object on the page, so they now
|
|
452
|
+
share the radius token. `Tag`'s `square` prop is gone — the button shape is the
|
|
453
|
+
default — and `pill` is the opt-in for the fully-rounded shape.
|
|
454
|
+
|
|
455
|
+
### Added
|
|
456
|
+
|
|
457
|
+
- Storybook (`pnpm storybook`, `pnpm build:storybook`): the react-vite framework,
|
|
458
|
+
the docs, a11y and themes addons, a preview that loads the published
|
|
459
|
+
stylesheet, renders inside `.pro-root` and switches `data-theme` from the
|
|
460
|
+
toolbar. The args tables come from `react-docgen-typescript` reading the same
|
|
461
|
+
props declarations `docs/api.md` documents.
|
|
462
|
+
- `scripts/check-story-coverage.mjs`, wired into `pnpm verify`: every runtime
|
|
463
|
+
export has to be named by a `.stories.tsx`. The budget went 101 → 0, so all 113
|
|
464
|
+
exports are covered today (48 story files).
|
|
465
|
+
|
|
466
|
+
## [0.2.0] — 2026-10-07
|
|
467
|
+
|
|
468
|
+
The release that makes `@stcn52/pro` a library you can consume rather than a
|
|
469
|
+
source tree you have to share: a repository, a test suite, a gate, generated
|
|
470
|
+
reference documentation and a package whose contents are checked.
|
|
471
|
+
|
|
472
|
+
### Added
|
|
473
|
+
|
|
474
|
+
- **Repository** — a standalone git repository with `LICENSE` (MIT),
|
|
475
|
+
`.gitignore`, this changelog and `CONVENTIONS.md` (the authoring spec), plus
|
|
476
|
+
`engines`, `packageManager` and `files` in `package.json`.
|
|
477
|
+
- **Tests** — vitest + Testing Library + jsdom: 263 tests over 17 files covering
|
|
478
|
+
every one of the 113 exported components and hooks (rendering, controlled
|
|
479
|
+
values, the keyboard path, `Esc` and focus). `scripts/check-test-coverage.mjs`
|
|
480
|
+
enforces the claim: it reads the runtime exports out of `src/` and fails when
|
|
481
|
+
any of them is named by no test.
|
|
482
|
+
- **Static quality** — ESLint 10 flat config with the React hooks rules (16
|
|
483
|
+
known warnings, pinned with `--max-warnings`), and Prettier across the
|
|
484
|
+
repository.
|
|
485
|
+
- **`pnpm verify`** — one gate: package contract, typecheck, boundaries, test
|
|
486
|
+
coverage, docs, lint, format, tests, build, pack, `publint --strict`,
|
|
487
|
+
`are-the-types-wrong` and a pack smoke test that unpacks the tarball into a
|
|
488
|
+
throwaway consumer and imports the built ESM, the built CJS and the stylesheet
|
|
489
|
+
from there. Everything runs offline.
|
|
490
|
+
- **Boundary checks** — `scripts/check-boundaries.mjs` fails on any host symbol
|
|
491
|
+
in `src/` (repository name, router, storage, route literals, the demo store,
|
|
492
|
+
`app-*` class names) and on any host stylesheet rule whose subject is a
|
|
493
|
+
`pro-*` class. Every class the library renders must be `pro-*` (or an `is-*`
|
|
494
|
+
state hook).
|
|
495
|
+
- **Generated documentation** — `pnpm gen:docs` writes `docs/api.md` (every runtime
|
|
496
|
+
export with the props table of its props type, read from the TypeScript AST)
|
|
497
|
+
and `docs/tokens.md` (the token declarations, grouped as `tokens.css` groups
|
|
498
|
+
them, dark overrides apart). `scripts/check-docs.mjs` fails on a stale
|
|
499
|
+
generated file and on an export the README or `docs/components.md` does not
|
|
500
|
+
name.
|
|
501
|
+
- **`ListHeader`'s title is a real `<h2>`** (with `font: inherit`, so the
|
|
502
|
+
measured 15px/400 type is unchanged): it is the only title a tab page renders.
|
|
503
|
+
|
|
504
|
+
### Changed
|
|
505
|
+
|
|
506
|
+
- `Field`'s generated id is handed to the control only (a component, or a
|
|
507
|
+
labellable native element) — injecting it into a `<span>` wrapper used to point
|
|
508
|
+
the label at something a label cannot name. `EntityDialog` names its field ids
|
|
509
|
+
explicitly.
|
|
510
|
+
- `Sidebar` follows a shell-level collapse: `SidebarCollapseProvider` wraps a
|
|
511
|
+
page tree once and every sidebar inside collapses with it, instead of a host
|
|
512
|
+
stylesheet hiding `.pro-sidebar`.
|
|
513
|
+
- `EntityDialog` no longer renders the host's `app-counter` / `app-input-wrap`
|
|
514
|
+
classes; the counter is the library's own `pro-input-counter` /
|
|
515
|
+
`pro-input-wrap`. `RichTextToolbar` and the rest of `EntityDialog`'s host
|
|
516
|
+
classes became `pro-richtext*` / `pro-dialog__*`, and the `@mention` highlight
|
|
517
|
+
became `.pro-mention` in the stylesheet.
|
|
518
|
+
- The narrow-screen rules that hid the sidebar (1024px) and the rail (640px)
|
|
519
|
+
live in the library now, not in the demo's stylesheet.
|
|
520
|
+
- `QuickStart` takes `done` / `total` for the checklist counter; `Tag` takes
|
|
521
|
+
`tone="accent"` and `size="sm"` for the quarter chip.
|
|
522
|
+
- The `New project` wizard's classes moved from the host's `proj-*` prefix into
|
|
523
|
+
the library's `pro-wizard__*` namespace.
|
|
524
|
+
|
|
525
|
+
### Fixed
|
|
526
|
+
|
|
527
|
+
- `Menu`'s typeahead swallowed keystrokes typed into a searchable menu's search
|
|
528
|
+
field: it preventDefaulted any printable character that matched an item, so `d`
|
|
529
|
+
could not be entered in a list containing "Duplicate".
|
|
530
|
+
- `Input`'s `size?: 'md' | 'lg'` was intersected with the DOM's numeric `size`
|
|
531
|
+
attribute, which collapsed the prop to `undefined` for a typed caller.
|
|
532
|
+
- `TypeBadge` threw on a kind it does not know; it renders a neutral badge now.
|
|
533
|
+
- `Icon` returned nothing for an unknown name while the docs promised a warning
|
|
534
|
+
and an empty box; it warns and keeps the box.
|
|
535
|
+
- `Dialog` derived its title id from `Math.random()` during render (now
|
|
536
|
+
`useId()`); `Tree` carried two dead assignments; `ContextMenu`'s `useCallback`
|
|
537
|
+
missed the coordinates it reads; `PeoplePicker`'s effect missed `setCursor`;
|
|
538
|
+
`Toast` kept a stale `eslint-disable`.
|
|
539
|
+
- `exports["."]` pointed the `require` condition at the ESM type declarations;
|
|
540
|
+
`import` and `require` carry their own `types` (`index.d.ts` / `index.d.cts`).
|
|
541
|
+
|
|
542
|
+
### Notes
|
|
543
|
+
|
|
544
|
+
- Still 0.x: the demo is the only consumer, and 1.0.0 is for the point where the
|
|
545
|
+
API is frozen for a second one.
|
|
546
|
+
- `docs/measurements.md` keeps recording where each measurement came from.
|
|
547
|
+
|
|
548
|
+
## [0.1.0] — 2026-10-07
|
|
549
|
+
|
|
550
|
+
The first cut: the Ship workbench restored as a library, then the demo's
|
|
551
|
+
components pulled out of the demo.
|
|
552
|
+
|
|
553
|
+
### Added
|
|
554
|
+
|
|
555
|
+
- **Foundations** — `cx`, the `Intl`-backed formatters (`formatNumber`,
|
|
556
|
+
`formatListTime`, `formatDateTime`, `formatCompact`, `pluralize`),
|
|
557
|
+
`useControllableState`, `statusColor`, `avatarColor`, `initials`, `nextRuleId`.
|
|
558
|
+
- **Tokens and styles** — `tokens.css` (raw scale + purpose-named semantic
|
|
559
|
+
tokens, light and dark), `base.css`, `primitives.css`, `ship.css`, published
|
|
560
|
+
together as `styles.css` and separately as `tokens.css`.
|
|
561
|
+
- **Icons** — `Icon`, `ICONS`, `IconName`: 146 glyphs taken verbatim from the
|
|
562
|
+
product's sprite.
|
|
563
|
+
- **Primitives** — `Button`, `SplitButton`, `ActionButton`, `Input`, `Textarea`,
|
|
564
|
+
`SearchInput`, `Field`, `Checkbox`, `Switch`, `Select`, `MultiSelect`,
|
|
565
|
+
`Popover`, `Menu`, `ContextMenu`, `Tooltip`, `Dialog`, `Toast` /
|
|
566
|
+
`ToastProvider` / `useToast`, `DataTable`, `Pagination`, `Tag` / `StatusTag` /
|
|
567
|
+
`LevelTag` / `CountTag`, `Avatar` / `AvatarStack`, `Progress`, `Metric`,
|
|
568
|
+
`BarChart`, `Donut`, `Sparkline`, `ScatterPlot`, `Crumbs`, `KeyValue`, `Card`,
|
|
569
|
+
`Nav`, `Tree` / `TreeGroup`, `Sidebar`, `Segment`, `Chip`, `Divider`,
|
|
570
|
+
`EmptyState`, `ErrorState`, `Skeleton`, `TableSkeleton`, `LoadingBlock`,
|
|
571
|
+
`InlineSpinner`, `Banner`.
|
|
572
|
+
- **Ship surface** — `AppRail`, `AppHeader`, `ProductHeader`, `HeaderActions`,
|
|
573
|
+
`BrandMark`, `ListHeader`, `ListToolbar`, `FilterPanel`, `FilterChip`,
|
|
574
|
+
`BoardView`, `RoadmapView`, `DocSplit`, `TitleCell`, `TypeBadge`, `ProductCell`,
|
|
575
|
+
`StarButton`, `QuickStart`, `TableBanner`, `SelectionBar`, `VoteCount`,
|
|
576
|
+
`DetailSheet` / `DetailSection` / `DetailField` / `Feed` / `FeedFilter` /
|
|
577
|
+
`CommentComposer`.
|
|
578
|
+
- **Composites extracted from the demo** — `ListWorkbench`, `CommentThread`,
|
|
579
|
+
`AttachmentUpload`, `LinkPicker`, `FilePreview`, `TransitionsTimeline`,
|
|
580
|
+
`EntityDialog`, `EntityPicker`, `ShareDialog`, `ReportCanvas`, `RoadmapEditor`,
|
|
581
|
+
`ProjectWizard`, `DetailBlock`, `DetailTool`, `EditableText`, `AccountMenu`,
|
|
582
|
+
`ShortcutsDialog`, `QuickStartDialog`.
|
|
583
|
+
- **Theming** — `data-theme="light" | "dark" | "auto"` on any ancestor;
|
|
584
|
+
components only read CSS variables.
|
|
585
|
+
|
|
586
|
+
### Changed
|
|
587
|
+
|
|
588
|
+
- `EntityDialog` no longer renders the host's `app-counter` / `app-input-wrap`
|
|
589
|
+
classes; the counter is the library's own `pro-input-counter` /
|
|
590
|
+
`pro-input-wrap`.
|
|
591
|
+
- `QuickStart` takes `done` / `total` for the checklist counter; `Tag` takes
|
|
592
|
+
`tone="accent"` and `size="sm"` for the quarter chip.
|
|
593
|
+
- The `New project` wizard's classes moved from the host's `proj-*` prefix into
|
|
594
|
+
the library's `pro-wizard__*` namespace.
|
|
595
|
+
|
|
596
|
+
- Add general Empty, Spin and Result feedback entries; extend Skeleton with
|
|
597
|
+
compound placeholders and content switching, cancellable loading delay,
|
|
598
|
+
localized descriptions, inert busy content and reduced-motion handling.
|
|
599
|
+
|
|
600
|
+
- Extend Slider with native double range handles, marks, vertical layout, step
|
|
601
|
+
normalization, tooltips and completed interaction events; extend Rate with
|
|
602
|
+
half-star ratings, configurable count, hover feedback and custom characters.
|
|
603
|
+
|
|
604
|
+
- Extend Progress with circle/dashboard, segmented steps, percent/status,
|
|
605
|
+
success overlays, formatted information and logical dashboard gaps in RTL.
|
|
606
|
+
|
|
607
|
+
- Extend Tabs with placements, RTL keys, editable cards, dynamic selection and
|
|
608
|
+
close-focus recovery; add Collapse header keys/extra actions/lifecycle variants
|
|
609
|
+
and Steps item statuses, offsets, localized text and provider-disabled support.
|
|
610
|
+
|
|
611
|
+
- Add standalone Calendar and Timeline with ISO date selection, month/year views, keyboard/RTL navigation, controlled data, custom cells, pending items and logical layouts.
|
|
612
|
+
|
|
613
|
+
- Add List/List.Item.Meta, grouped Listy with fixed-height virtualization and scroll refs, and measured responsive Masonry.
|
|
614
|
+
|
|
615
|
+
- Add Affix, Anchor, FloatButton/Group and shared BackTop with custom scroll containers, logical placement, progress and reduced-motion support.
|