@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/CONVENTIONS.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Component authoring conventions
|
|
2
|
+
|
|
3
|
+
`@stcn52/pro` is a component library, not a demo. Everything in it must be
|
|
4
|
+
reasonable to ship to a host application that knows nothing about PingCode Ship,
|
|
5
|
+
the demo store or the demo's routes. This file is the definition of done for a
|
|
6
|
+
component; `pnpm verify` is the machine check behind it.
|
|
7
|
+
|
|
8
|
+
## What the library is
|
|
9
|
+
|
|
10
|
+
A 1:1 restoration of the PingCode **Ship** workbench, published as tokens, CSS
|
|
11
|
+
layers and React components. Styling is **plain CSS classes driven by design
|
|
12
|
+
tokens** — no CSS-in-JS, no per-component stylesheet files, no inline geometry.
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
src/styles/tokens.css raw scale + purpose-named semantic tokens (light/dark)
|
|
16
|
+
src/styles/base.css reset, type scale, utilities
|
|
17
|
+
src/styles/primitives.css controls, overlays, table, navigation, states, charts
|
|
18
|
+
src/styles/ship.css the Ship surface: rail, headers, toolbar, detail sheet,
|
|
19
|
+
list workbench, wizard, detail blocks
|
|
20
|
+
src/components/*.tsx primitives (one file per component family)
|
|
21
|
+
src/components/table/ a family that outgrew one file: the DataTable parts,
|
|
22
|
+
re-exported unchanged by src/components/Table.tsx
|
|
23
|
+
src/ship/*.tsx product chrome and the extracted composites
|
|
24
|
+
src/index.ts the only barrel: every public name is re-exported here
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Rules
|
|
28
|
+
|
|
29
|
+
1. **Tokens only.** Colours, spacing, radii, type and durations come from
|
|
30
|
+
`tokens.css`. A new literal needs a reason in a comment next to it.
|
|
31
|
+
2. **Purpose-named colour.** `--surface-*`, `--fg-*`, `--border-*`, `--accent`,
|
|
32
|
+
`--status-*`. The raw `--gray-*` scale exists only underneath them.
|
|
33
|
+
3. **One stylesheet per layer.** A new component adds its rules to the layer it
|
|
34
|
+
belongs to, in the same order as the barrel, not to a new file. Element
|
|
35
|
+
resets are written with `:where()` so they carry zero specificity.
|
|
36
|
+
4. **Class naming is `pro-<block>__<element>--<modifier>`.** A class that
|
|
37
|
+
describes a _layout slot_ (`pro-row`, `pro-num`, `pro-detail__tools`) may be
|
|
38
|
+
used by a host; anything else is internal and a host should get a component
|
|
39
|
+
instead. Never add an `app-*` class: that prefix belongs to host applications.
|
|
40
|
+
5. **No host knowledge.** The library must not contain a route string
|
|
41
|
+
(`/ship/...`, `/pjm/...`), a store, a `localStorage` key, a demo id or a demo
|
|
42
|
+
name. Data arrives as props; navigation arrives as callbacks.
|
|
43
|
+
6. **Controlled by default where it matters.** Anything with a selection takes
|
|
44
|
+
`value` + `onChange`; use `useControllableState` so a component also works
|
|
45
|
+
uncontrolled (`defaultValue`, `defaultOpen`, `defaultExpanded`).
|
|
46
|
+
7. **Refs are forwarded** on every form control (focus management is the host's
|
|
47
|
+
job, and `⌘K`-style shortcuts depend on it).
|
|
48
|
+
8. **The five states are structural.** Anything that shows data accepts
|
|
49
|
+
`status="loading" | "error" | "ready"` plus `emptyState` / `errorState`, so no
|
|
50
|
+
screen can ship with only the populated case.
|
|
51
|
+
9. **Keyboard first.** One focus ring (`:focus-visible` in `base.css`), `Esc`
|
|
52
|
+
closes every floating layer, arrows move through lists, `Enter`/`Space`
|
|
53
|
+
activate, focus returns to the element that opened a layer, and dialogs trap
|
|
54
|
+
`Tab` inside themselves.
|
|
55
|
+
10. **Accessibility is not optional.** Every control has a label; an icon-only
|
|
56
|
+
button takes `label` (becomes `aria-label` + `title`); decorative icons are
|
|
57
|
+
`aria-hidden`; live regions exist before content arrives; motion is disabled
|
|
58
|
+
under `prefers-reduced-motion`.
|
|
59
|
+
11. **Export discipline.** Named exports only, no default exports, types exported
|
|
60
|
+
next to the component, and every public name re-exported from
|
|
61
|
+
`src/index.ts`. Adding an export means updating the README table and
|
|
62
|
+
`docs/components.md` in the same change.
|
|
63
|
+
12. **Every exported component has a test** under `src/__tests__/<Name>.test.tsx`
|
|
64
|
+
covering, at minimum: it renders; a controlled prop is honoured; the keyboard
|
|
65
|
+
path works; and `Esc`/focus behaviour where the component has a floating
|
|
66
|
+
layer.
|
|
67
|
+
13. **Semantic versioning.** A user-visible change adds a CHANGELOG entry under
|
|
68
|
+
`## [Unreleased]`; breaking a prop, a default or an exported name is a major
|
|
69
|
+
bump and needs a migration note.
|
|
70
|
+
|
|
71
|
+
## Documentation
|
|
72
|
+
|
|
73
|
+
`docs/api.md` and `docs/tokens.md` are **generated** from `src/` — run `pnpm gen:docs`
|
|
74
|
+
after touching a component, a prop or a token. `pnpm verify` regenerates them and
|
|
75
|
+
fails on any difference, so the committed reference cannot drift from the code.
|
|
76
|
+
|
|
77
|
+
The prose is hand-written and checked the other way round: every runtime export
|
|
78
|
+
must be named in `README.md`, and every component in `docs/components.md`. Adding
|
|
79
|
+
an export means adding it to both.
|
|
80
|
+
|
|
81
|
+
## Focus
|
|
82
|
+
|
|
83
|
+
`base.css` draws the focus ring for everything inside `.pro-root` /
|
|
84
|
+
`.pro-portal` with `.pro-root :focus-visible` (**0,2,0**). A component that paints
|
|
85
|
+
its own focus indicator — the open cell editors, whose accent hairline _is_ the
|
|
86
|
+
field — has to out-specify that rule: name the component, not the bare input
|
|
87
|
+
(`.pro-cell-editor :focus-visible`, not `.pro-quick-text__input { outline: none }`,
|
|
88
|
+
which is only 0,1,0 and loses). Two rings around one field is the symptom.
|
|
89
|
+
|
|
90
|
+
## Grid cells
|
|
91
|
+
|
|
92
|
+
`.pro-table th, .pro-table td { text-align: left; … }` is one class **plus an
|
|
93
|
+
element**, so a bare `.pro-table__pick { text-align: center }` loses to it. A rule
|
|
94
|
+
that aligns or states a table cell has to name the element too
|
|
95
|
+
(`.pro-table td.pro-table__pick`). The same applies to the pick cell's two states:
|
|
96
|
+
the checkbox is taken out of the flow and centred, so the invisible one cannot
|
|
97
|
+
push the row number off the axis the header's select-all sits on.
|
|
98
|
+
|
|
99
|
+
## Stories
|
|
100
|
+
|
|
101
|
+
Every exported component gets a story, next to its source
|
|
102
|
+
(`src/components/Button.stories.tsx`), under a `Components/<Group>/<Name>` or
|
|
103
|
+
`Ship/<Group>/<Name>` title. A story set is expected to show the states a host
|
|
104
|
+
will actually meet — the five list states, controlled and uncontrolled, the
|
|
105
|
+
keyboard path, an open floating layer — not just the happy one. `pnpm verify`
|
|
106
|
+
fails when an export has no story (`scripts/check-story-coverage.mjs`), and both
|
|
107
|
+
ESLint and Prettier cover the story files.
|
|
108
|
+
|
|
109
|
+
## Frozen columns
|
|
110
|
+
|
|
111
|
+
A pinned cell has to be opaque, or the columns sliding under it show through — but
|
|
112
|
+
it must never look like a column of its own. The **row** carries the state
|
|
113
|
+
background (`tr:hover`, `tr.is-selected`, `tr.is-cursor`, a host's own class) and
|
|
114
|
+
`td.is-fixed` takes `background: inherit`. A pinned cell that paints a colour of
|
|
115
|
+
its own is one row-state away from outlining itself.
|
|
116
|
+
|
|
117
|
+
## Splitting a component family
|
|
118
|
+
|
|
119
|
+
One file per family is the default, and most families stay one file. When one
|
|
120
|
+
grows past what a reader can hold — `DataTable` reached 912 lines — it becomes a
|
|
121
|
+
directory (`src/components/table/`) of modules cut by **what changes together**:
|
|
122
|
+
the public contract (`types`), the arithmetic (`geometry`), the keyboard
|
|
123
|
+
(`keyboard`), the grouping (`grouping`), and one module per thing the component
|
|
124
|
+
renders (`DataTable`, `TableHead`, `TableRow`, `SkeletonRows`, `BulkBar`,
|
|
125
|
+
`ColumnMenu`, `CellCommands`).
|
|
126
|
+
|
|
127
|
+
Two rules keep that readable and keep the tooling honest:
|
|
128
|
+
|
|
129
|
+
- **The public path stays where it was.** `src/components/Table.tsx` remains the
|
|
130
|
+
barrel (`export * from './table/types'` and `'./table/DataTable'`), so no host
|
|
131
|
+
and no story has to learn a new import. `src/index.ts` is unchanged.
|
|
132
|
+
- **The props type stays next to the component.** `scripts/gen-docs.mjs` resolves
|
|
133
|
+
`DataTableProps` **in the same file** as `DataTable`, so moving the type to a
|
|
134
|
+
separate module would silently empty the generated props table — which is also
|
|
135
|
+
why `scripts/public-surface.mjs` follows `export * from` rather than only
|
|
136
|
+
reading declarations: without that, every name behind a barrel would drop out
|
|
137
|
+
of `docs/api.md` and out of the test/story coverage checks.
|
|
138
|
+
|
|
139
|
+
## Working on it
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pnpm typecheck # tsc --noEmit
|
|
143
|
+
pnpm lint # eslint
|
|
144
|
+
pnpm test # vitest run
|
|
145
|
+
pnpm build # tsup (ESM + CJS + d.ts) then scripts/build-styles.mjs
|
|
146
|
+
pnpm verify # everything above, plus publint/attw and a pack smoke test
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`pnpm verify` is the gate: a change is done when it passes, and the docs and
|
|
150
|
+
CHANGELOG are updated in the same change.
|
|
151
|
+
|
|
152
|
+
React ref access and state-in-effect checks are errors. `pnpm verify` permits zero lint warnings; fix the cause rather than disabling a rule. Stable controlled setters publish committed props before descendant layout effects.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Klun
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,227 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @stcn52/pro
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A 1:1 restoration of the PingCode **Ship** workbench as a publishable React
|
|
4
|
+
component library: design tokens, primitives and the Ship product chrome, with
|
|
5
|
+
light and dark themes.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/styles/tokens.css raw PingCode scale + purpose-named semantic tokens
|
|
9
|
+
src/styles/base.css reset, type scale, utilities
|
|
10
|
+
src/components/* primitives (button, input, table, tree, overlay, charts…)
|
|
11
|
+
src/ship/* product chrome (rail, headers, toolbar, entity views)
|
|
12
|
+
src/icons/icons.ts 146 glyphs taken verbatim from PingCode's icon sprite
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Install and use
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @stcn52/pro react react-dom
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { AppRail, ListToolbar, DataTable, StatusTag } from '@stcn52/pro';
|
|
23
|
+
import '@stcn52/pro/styles.css'; // or '@stcn52/pro/tokens.css' for tokens only
|
|
24
|
+
|
|
25
|
+
export function Screen() {
|
|
26
|
+
return (
|
|
27
|
+
<div className="pro-root">
|
|
28
|
+
<StatusTag status="Pending" />
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Every component is a named export from the package root. The stylesheet is a
|
|
35
|
+
single file; the token layer is also published separately so a host application
|
|
36
|
+
can adopt the scale without the component styles.
|
|
37
|
+
|
|
38
|
+
### Consuming a local checkout
|
|
39
|
+
|
|
40
|
+
A host next to this repository depends on it with pnpm's `link:` protocol, so
|
|
41
|
+
imports resolve through the package's `exports` map into `dist/`:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{ "dependencies": { "@stcn52/pro": "link:../klun-pro" } }
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`file:` also works, but pnpm snapshots the directory at install time: a later
|
|
48
|
+
`pnpm build` here would not reach the host until it installs again, and the host
|
|
49
|
+
would quietly run a stale library. `link:` keeps the package live, and the host
|
|
50
|
+
still consumes the built artefact rather than the source.
|
|
51
|
+
|
|
52
|
+
## Storybook
|
|
53
|
+
|
|
54
|
+
Every component has a story, and the story is where to look first when a prop's
|
|
55
|
+
behaviour is not obvious from its name:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm storybook # http://localhost:6006
|
|
59
|
+
pnpm build:storybook # static site in dist-storybook/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The preview loads the same stylesheet the package publishes
|
|
63
|
+
(`src/styles/index.css`), renders each story inside `.pro-root` — where the
|
|
64
|
+
library's element resets live — and puts a light/dark switch in the toolbar that
|
|
65
|
+
sets `data-theme` on the frame. The docs addon reads the exported props types
|
|
66
|
+
with `react-docgen-typescript`, so an args table is generated from the same
|
|
67
|
+
declarations `docs/api.md` is generated from.
|
|
68
|
+
|
|
69
|
+
`scripts/check-story-coverage.mjs` runs inside `pnpm verify`: every runtime
|
|
70
|
+
export has to be named by a `*.stories.tsx`, with a budget that only goes down.
|
|
71
|
+
|
|
72
|
+
## Theming
|
|
73
|
+
|
|
74
|
+
Theme is selected with `data-theme` on any ancestor — usually `<html>`:
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<html data-theme="light">
|
|
78
|
+
<!-- or "dark" -->
|
|
79
|
+
<html data-theme="auto">
|
|
80
|
+
<!-- follows prefers-color-scheme -->
|
|
81
|
+
</html>
|
|
82
|
+
</html>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Components never branch on colour scheme; they only read CSS variables.
|
|
86
|
+
|
|
87
|
+
## What is in the box
|
|
88
|
+
|
|
89
|
+
| Group | Exports |
|
|
90
|
+
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
91
|
+
| Foundations | `cx`, `formatNumber`, `formatCount`, `formatDay`, `formatListTime`, `formatDateTime`, `formatCompact`, `pluralize`, `statusColor`, `avatarColor`, `initials`, `useControllableState` |
|
|
92
|
+
| Icons | `Icon`, `ICONS`, `IconName` |
|
|
93
|
+
| Actions | `Button`, `SplitButton`, `ActionButton` |
|
|
94
|
+
| Forms | `Input`, `Textarea`, `SearchInput`, `Field`, `Checkbox`, `Switch`, `Select`, `MultiSelect` |
|
|
95
|
+
| Overlays | `Popover`, `Menu`, `Tooltip`, `Dialog`, `ContextMenu` / `ContextMenuList` / `useContextMenu`, `useToast` / `ToastProvider`, `usePopoverClose`, `useAnchorRef` |
|
|
96
|
+
| Data | `DataTable` (`Column`, `SortState`), `Pagination`, `Tag` / `StatusTag` / `LevelTag` / `CountTag`, `Avatar` / `AvatarStack` / `AvatarPlaceholder` / `IconAvatar`, `Progress`, `Metric`, `BarChart`, `Donut`, `Sparkline`, `ScatterPlot`, `Crumbs`, `KeyValue`, `Card` |
|
|
97
|
+
| Navigation | `Nav`, `Tree` / `TreeGroup`, `Sidebar` / `SidebarCollapseProvider` / `useSidebarCollapsed`, `Segment`, `Chip`, `Divider` |
|
|
98
|
+
| States | `Empty`, `Spin`, `Result`, `EmptyState`, `ErrorState`, `EmptyArt`, `Skeleton`, `TableSkeleton`, `LoadingBlock`, `InlineSpinner`, `Banner` |
|
|
99
|
+
| Ship chrome | `AppRail`, `AppHeader`, `ProductHeader`, `HeaderActions`, `BrandMark`, `ListHeader`, `ListToolbar`, `FilterPanel`, `FilterChip`, `BoardView`, `RoadmapView`, `DocSplit`, `TitleCell`, `TypeBadge`, `ProductCell`, `StarButton`, `QuickStart`, `TableBanner`, `SelectionBar`, `VoteCount` |
|
|
100
|
+
| Entity surfaces | `DetailSheet`, `DetailBlock`, `DetailTool`, `DetailSection`, `DetailField`, `Feed`, `FeedFilter`, `CommentComposer`, `EditableText` |
|
|
101
|
+
| Inline editors | `PeoplePicker` (`PeoplePickerTab`), `QuickSelect`, `QuickText`, `useSelectAnchor`, `useListCursor` |
|
|
102
|
+
| Assistant | `AiPanel`, `PingMark` |
|
|
103
|
+
| Shell surfaces | `AccountMenu`, `ShortcutsDialog`, `QuickStartDialog` |
|
|
104
|
+
| Canonical data | `DEFAULT_SHARING` (`ReportSharing`), `defaultCanvasWidgets` / `isCanvasWidgetSpan`, `componentLine` / `primaryComponents`, `quarterWeekendDays`, `cursorAfter` / `matchesQuery`, `downloadAttachment` / `exportRowsToCsv` |
|
|
105
|
+
| Composites | `ListWorkbench`, `EntityPicker`, `EntityDialog`, `ProjectWizard`, `CommentThread`, `AttachmentUpload`, `LinkPicker`, `FilePreview`, `TransitionsTimeline`, `ShareDialog`, `ReportCanvas`, `RoadmapEditor`, `RichTextToolbar` | |
|
|
106
|
+
|
|
107
|
+
## Design rules the code follows
|
|
108
|
+
|
|
109
|
+
- **Tokens over literals.** Colours, spacing, radii and type come from
|
|
110
|
+
`tokens.css`; a new literal needs a reason. Element resets are written with
|
|
111
|
+
`:where()` so they carry zero specificity and never beat a component class.
|
|
112
|
+
- **Purpose-named colour.** `--surface-*`, `--fg-*`, `--border-*`, `--accent`,
|
|
113
|
+
`--status-*` — the raw `--gray-*` scale exists only underneath them.
|
|
114
|
+
- **The five states are real.** `DataTable` takes `status="loading" | "error" |
|
|
115
|
+
"ready"` plus `emptyState` / `errorState` nodes, so no list can ship with only
|
|
116
|
+
the populated case.
|
|
117
|
+
- **Keyboard first.** One focus ring style, `Esc` closes every floating layer,
|
|
118
|
+
`Dialog` traps Tab inside the sheet, `Tree` and the rail expose
|
|
119
|
+
`aria-current`, table headers expose `aria-sort`, and a live region announces
|
|
120
|
+
row counts.
|
|
121
|
+
- **Motion is small and optional.** 120–180 ms transitions, all of them
|
|
122
|
+
disabled under `prefers-reduced-motion`.
|
|
123
|
+
|
|
124
|
+
## Build
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pnpm install
|
|
128
|
+
pnpm build # tsup (ESM + CJS + .d.ts) then scripts/build-styles.mjs
|
|
129
|
+
pnpm typecheck
|
|
130
|
+
pnpm gen:icons <path-to-icons-common-full.json> # regenerates src/icons/icons.ts
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`pnpm build` writes `dist/index.{js,cjs,d.ts}`, `dist/styles.css` and
|
|
134
|
+
`dist/tokens.css`.
|
|
135
|
+
|
|
136
|
+
## Fidelity
|
|
137
|
+
|
|
138
|
+
`docs/measurements.md` records where every measurement came from (live DOM
|
|
139
|
+
probes, pixel sampling, and PingCode's own stylesheets) and lists the known
|
|
140
|
+
gaps — the most important being that four Ship tabs were captured while their
|
|
141
|
+
grid was still a loading skeleton, so their column sets come from the DOM rather
|
|
142
|
+
than from pixels, and that no dark-theme screenshot of the running product was
|
|
143
|
+
obtainable, so dark mode is built from PingCode's own `:root[theme=dark]`
|
|
144
|
+
token block.
|
|
145
|
+
|
|
146
|
+
## Additional common components
|
|
147
|
+
|
|
148
|
+
`Radio` / `RadioGroup`, `Tabs`, `Collapse`, `Badge`, `Slider`, `Steps`, `Alert`, `CheckboxGroup`, `PasswordInput`, `Rate`, `Cascader`, `Transfer`, `DatePicker`, and `DateRangePicker` complement the Ship primitives.
|
|
149
|
+
Their option-based APIs and behaviour are informed by [Ant Design](https://github.com/ant-design/ant-design), implemented with native controls and the existing tokens; no antd runtime dependency is required.
|
|
150
|
+
Tree/DirectoryTree include cached directory ranges, RTL navigation, leaf icons and
|
|
151
|
+
source-aligned drop geometry; see the onDrop position migration in `docs/components.md`.
|
|
152
|
+
|
|
153
|
+
Cascader supports multiple parent/leaf paths, intermediate selection, field mapping,
|
|
154
|
+
lazy children with retry and controlled opening/search.
|
|
155
|
+
|
|
156
|
+
Selection components support controlled and uncontrolled state. Transfer also supports
|
|
157
|
+
independent controlled checks, directional moves, per-side paging and custom lists. See Storybook and `docs/components.md`.
|
|
158
|
+
|
|
159
|
+
Releases and deployments use the platform workflow (build → approval → publish →
|
|
160
|
+
deploy). See [RELEASING.md](./RELEASING.md); local release commands validate only.
|
|
161
|
+
|
|
162
|
+
`Tree` now supports controlled expansion/selection/checking, lazy loading,
|
|
163
|
+
search highlighting, drag-and-drop and fixed-height virtual scrolling.
|
|
164
|
+
`DirectoryTree` adds file-browser Ctrl/Meta/Shift selection and click/double-click expansion.
|
|
165
|
+
|
|
166
|
+
### Global configuration and forms
|
|
167
|
+
|
|
168
|
+
`ConfigProvider` supplies nested `locale` (`en-US` / `zh-CN`), `direction` and
|
|
169
|
+
`disabled` defaults. Explicit control props win. `useProConfig` and
|
|
170
|
+
`useComponentDisabled` expose these defaults to host controls.
|
|
171
|
+
|
|
172
|
+
`Form`, `FormItem`, `FormList`, `useForm`, `useFormInstance` and `useWatch` provide
|
|
173
|
+
nested field state, dynamic arrays, validation, resets and async submission.
|
|
174
|
+
`Form.Item`, `Form.List` and the compound hooks are also available. Full Ant
|
|
175
|
+
Design API compatibility is not implemented. See [component reference](docs/components.md).
|
|
176
|
+
|
|
177
|
+
Select and MultiSelect support grouped options, labeled values, clearing, custom rendering,
|
|
178
|
+
controlled popups, async states, custom/remote search and opt-in virtual scrolling.
|
|
179
|
+
MultiSelect also supports tags, token separators, and selection limits; see
|
|
180
|
+
[component contracts](docs/components.md#select--multiselect).
|
|
181
|
+
|
|
182
|
+
全库完善的待办、优先级和验收标准见[AntD 对照计划](docs/antd-alignment-plan.md)。
|
|
183
|
+
|
|
184
|
+
Common input additions: `InputNumber` (number/null), `AutoComplete` (editable suggestions),
|
|
185
|
+
`TreeSelect` (hierarchical single/multiple/check selection) and `TimePicker` (local ISO clock).
|
|
186
|
+
They integrate with Form and ConfigProvider; see the component guide for native API differences.
|
|
187
|
+
|
|
188
|
+
General display entries: `Breadcrumb`, responsive `Descriptions`, formatted `Statistic`,
|
|
189
|
+
and `Typography` with Text/Title/Paragraph/Link, copying, editing and CSS ellipsis.
|
|
190
|
+
|
|
191
|
+
General layout entries: `Layout` (Header/Content/Footer/Sider), `Row`/`Col` (24-column
|
|
192
|
+
responsive grid), `Grid.useBreakpoint`, `Flex`, `Space`/Compact and `Splitter`/Panel.
|
|
193
|
+
|
|
194
|
+
`Dropdown` combines a native Button trigger with `Menu`; `Popconfirm` adds controlled opening,
|
|
195
|
+
async confirmation, cancellation and retry feedback using the existing Popover.
|
|
196
|
+
|
|
197
|
+
`Drawer` shares Dialog's modal stack, focus restoration and body scroll lock, with four physical
|
|
198
|
+
edge placements, bounded width/height and independent keyboard/mask/close-button controls.
|
|
199
|
+
|
|
200
|
+
`Image` renders actual image bytes with native refs, fallback/loading content and controlled
|
|
201
|
+
Dialog previews; `Image.PreviewGroup` navigates an explicit `items` list.
|
|
202
|
+
|
|
203
|
+
`Upload` keeps real File objects, supports manual/preflight uploads and explicit XHR `action`
|
|
204
|
+
or cancellable `customRequest`, controlled lists, accept/count limits and drag/drop.
|
|
205
|
+
|
|
206
|
+
`App` hosts separate message and notification stacks. Use `App.useApp()` for the nearest context;
|
|
207
|
+
exported `message`/`notification` use the last registered App and restore the prior host on unmount.
|
|
208
|
+
|
|
209
|
+
Standalone Calendar and Timeline provide event calendars and chronological lists without Ship data dependencies.
|
|
210
|
+
|
|
211
|
+
List (with ListItem and ListItemMeta), Listy and Masonry provide paginated lists, grouped fixed-height virtual lists, and measured responsive masonry layouts.
|
|
212
|
+
|
|
213
|
+
Affix, Anchor, FloatButton (with FloatButtonGroup) and BackTop support scroll navigation and floating actions.
|
|
214
|
+
|
|
215
|
+
Mentions provides native textarea suggestions; ColorPicker provides validated solid/gradient color editing, formats, alpha and presets.
|
|
216
|
+
|
|
217
|
+
Carousel, Tour, QRCode, Watermark and BorderBeam add media navigation, guided steps, real QR encoding, repeated marks and perimeter decoration.
|
|
218
|
+
|
|
219
|
+
DataTable supports hierarchical rows, grouped headers, multi-column sorting, radio selection and fixed-height virtual windows; see the component guide for summary scope and full-render fallbacks.
|
|
220
|
+
|
|
221
|
+
DatePicker supports ISO periods, local datetime confirmation, multiple dates, lazy presets and strict display formats; DateRangePicker shares date/time constraints and atomic tuple presets.
|
|
222
|
+
|
|
223
|
+
ConfigProvider supports nested `locale`, `direction`, `disabled`, `theme` and Klun CSS `tokens`; portalled overlays retain this configuration. See [configuration behavior](docs/components.md).
|
|
224
|
+
|
|
225
|
+
Avatar supports numeric sizes, square shapes and measured text scaling; AvatarStack names hidden members in its overflow marker. See [component contracts](docs/components.md).
|
|
226
|
+
|
|
227
|
+
Card exposes `Card.Grid` / `Card.Meta` (also `CardGrid` / `CardMeta`) for responsive content composition.
|
package/RELEASING.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
All releases and deployments must run through the Klun platform workflow:
|
|
4
|
+
**build → approval → publish → deploy**. Local commands are for validation and
|
|
5
|
+
artifact inspection. Never replace the workflow with `kc deploy`, a direct local
|
|
6
|
+
npm publish, or manual cluster changes. If a workflow fails, fix it and rerun it.
|
|
7
|
+
|
|
8
|
+
## Prepare the change
|
|
9
|
+
|
|
10
|
+
1. Commit the code, tests, generated docs and release notes.
|
|
11
|
+
2. Choose a version: patch for compatible fixes, minor for additive components or
|
|
12
|
+
props, major for breaking API changes. While 0.x, a breaking minor still needs
|
|
13
|
+
an explicit migration note.
|
|
14
|
+
3. Update `package.json` and move the applicable `CHANGELOG.md` entries from
|
|
15
|
+
`Unreleased` into `## [x.y.z] — YYYY-MM-DD`.
|
|
16
|
+
4. Run `pnpm verify` and `pnpm build:storybook` locally. For an already dated
|
|
17
|
+
version, `pnpm release x.y.z --dry-run` performs local validation only. It does
|
|
18
|
+
not commit, tag, publish, deploy, or call the platform.
|
|
19
|
+
|
|
20
|
+
## Platform workflow
|
|
21
|
+
|
|
22
|
+
Configure the workflow on the platform for this repository and environment.
|
|
23
|
+
The repository does not contain an environment-specific platform workflow ID or
|
|
24
|
+
registry credentials; those must come from the platform configuration.
|
|
25
|
+
|
|
26
|
+
| Stage | Required behavior |
|
|
27
|
+
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
28
|
+
| Build | Check out the selected commit on a connected build runner. Install with `pnpm install --frozen-lockfile`, then run `pnpm verify` and `pnpm build:storybook`. Store the npm tarball, Storybook bundle and check results as run artifacts. |
|
|
29
|
+
| Approval | Review the exact commit, version, release notes, validation results and artifact before allowing publication. |
|
|
30
|
+
| Publish | Publish the approved artifact to the registry configured on the platform, using platform-managed credentials. Record its version, checksum and source commit; create the release tag through this workflow. |
|
|
31
|
+
| Deploy | Deploy the approved Storybook artifact or consuming application through the workflow when there is a deployment target. An npm package has no cluster deployment of its own; record that stage as not applicable when only the package is released. |
|
|
32
|
+
|
|
33
|
+
Runner selection is declared through the platform's build-runner node and its
|
|
34
|
+
connections. Approval must precede publication and deployment. Retrying uses the
|
|
35
|
+
same reviewed commit; a different commit requires a new reviewed run.
|
|
36
|
+
|
|
37
|
+
## Local safeguards
|
|
38
|
+
|
|
39
|
+
`pnpm release` rejects invocations without `--dry-run`. The script only validates;
|
|
40
|
+
it contains no commit, tag or publication path. `pnpm pack` is safe for inspecting
|
|
41
|
+
a local artifact. `prepublishOnly` runs `pnpm verify` as an additional package
|
|
42
|
+
check; it cannot authenticate platform approval, so approval enforcement belongs
|
|
43
|
+
to the platform and its registry credentials.
|
|
44
|
+
|
|
45
|
+
## Recovery
|
|
46
|
+
|
|
47
|
+
Repair failed workflow steps and rerun the workflow. Roll back a deployed site or
|
|
48
|
+
consumer by selecting its prior approved artifact in the platform workflow. Do
|
|
49
|
+
not overwrite an existing npm version; publish a new corrected version through
|
|
50
|
+
a new approved run. Keep the run ID, approval, logs and artifact checksums with
|
|
51
|
+
the release record.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
@rc-component/qrcode 2.0.0 is bundled for SVG/canvas QR encoding.
|
|
4
|
+
|
|
5
|
+
The MIT License (MIT)
|
|
6
|
+
Copyright (c) 2015-present Alipay.com, https://www.alipay.com/
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
in the Software without restriction, including without limitation the rights
|
|
11
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
furnished to do so, subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in
|
|
16
|
+
all copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
19
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
21
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
22
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
23
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
24
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
25
|
+
|
|
26
|
+
The bundled QR Code generator also carries Copyright (c) Project Nayuki (MIT License).
|
|
27
|
+
The MIT permission and disclaimer above apply to that code.
|
|
28
|
+
|
|
29
|
+
## @babel/runtime helpers
|
|
30
|
+
|
|
31
|
+
MIT License
|
|
32
|
+
|
|
33
|
+
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
|
34
|
+
|
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
36
|
+
a copy of this software and associated documentation files (the
|
|
37
|
+
"Software"), to deal in the Software without restriction, including
|
|
38
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
39
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
40
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
41
|
+
the following conditions:
|
|
42
|
+
|
|
43
|
+
The above copyright notice and this permission notice shall be
|
|
44
|
+
included in all copies or substantial portions of the Software.
|
|
45
|
+
|
|
46
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
47
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
48
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
49
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
50
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
51
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
52
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|