@astryxdesign/charts 0.7.6-canary.f73623d → 0.7.6-canary.f78b205
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/package.json +3 -3
- package/src/Chart.spec.md +0 -208
- package/src/ChartAxis.spec.md +0 -211
- package/src/ChartGrid.spec.md +0 -184
- package/src/ChartLegend.spec.md +0 -203
- package/src/ChartSwatch.spec.md +0 -189
- package/src/ChartTooltip.spec.md +0 -240
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/charts",
|
|
3
|
-
"version": "0.7.6-canary.
|
|
3
|
+
"version": "0.7.6-canary.f78b205",
|
|
4
4
|
"description": "Astryx charts — a config-model data visualization library (d3-based). Published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
|
|
5
5
|
"author": "Meta Open Source",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@stylexjs/stylex": ">=0.10.0",
|
|
52
|
-
"@astryxdesign/core": "0.7.6-canary.
|
|
52
|
+
"@astryxdesign/core": "0.7.6-canary.f78b205",
|
|
53
53
|
"react": ">=19.0.0",
|
|
54
54
|
"react-dom": ">=19.0.0"
|
|
55
55
|
},
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"d3-shape": "^3.2.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@astryxdesign/cli": "0.7.6-canary.
|
|
62
|
+
"@astryxdesign/cli": "0.7.6-canary.f78b205",
|
|
63
63
|
"@babel/cli": "^7.29.7",
|
|
64
64
|
"@babel/core": "^7.29.7",
|
|
65
65
|
"@babel/preset-react": "^7.29.7",
|
package/src/Chart.spec.md
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
schema_version: 3
|
|
3
|
-
template_version: 4
|
|
4
|
-
kind: component
|
|
5
|
-
id: component:Chart
|
|
6
|
-
authority: draft
|
|
7
|
-
archive_reason: null
|
|
8
|
-
superseded_by: null
|
|
9
|
-
approved_by: null
|
|
10
|
-
approved_at: null
|
|
11
|
-
owners: [cixzhang]
|
|
12
|
-
review_triggers: [public-api, behavior, layout, theming, accessibility]
|
|
13
|
-
verified_by:
|
|
14
|
-
[
|
|
15
|
-
packages/charts/src/Chart.test.tsx,
|
|
16
|
-
apps/storybook/stories/charts/Chart.stories.tsx,
|
|
17
|
-
]
|
|
18
|
-
modules: []
|
|
19
|
-
families: []
|
|
20
|
-
design_specs: []
|
|
21
|
-
architecture:
|
|
22
|
-
[
|
|
23
|
-
architecture:component-test-sufficiency,
|
|
24
|
-
architecture:component-theming-surface,
|
|
25
|
-
]
|
|
26
|
-
contributing: []
|
|
27
|
-
system_specs: [spec:AST-002, spec:AST-029]
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
# Chart component contract
|
|
31
|
-
|
|
32
|
-
## Intent
|
|
33
|
-
|
|
34
|
-
Chart coordinates one responsive Cartesian plot. It derives shared scales,
|
|
35
|
-
assigns default series colors, delegates drawing to series definitions, and hosts
|
|
36
|
-
optional chart chrome and interaction layers.
|
|
37
|
-
|
|
38
|
-
## Compatibility and migration
|
|
39
|
-
|
|
40
|
-
- Released default preserved: `not yet stable`; `@astryxdesign/charts` is canary-only.
|
|
41
|
-
- Compatibility class: existing props, defaults, render order, and output remain unchanged by this observational backfill.
|
|
42
|
-
- Controlled/uncontrolled behavior: not applicable.
|
|
43
|
-
- Migration decision: none; this draft does not authorize a public API change.
|
|
44
|
-
|
|
45
|
-
Consumer migration instructions belong in consumer docs and release notes.
|
|
46
|
-
|
|
47
|
-
## Ownership boundary
|
|
48
|
-
|
|
49
|
-
**Owns**
|
|
50
|
-
|
|
51
|
-
- Measuring the chart container and deriving one plot area and scale set.
|
|
52
|
-
- Ordering, clipping, and coordinating series, chart chrome, and interaction slots.
|
|
53
|
-
- The chart image's accessible name and small-data table fallback.
|
|
54
|
-
|
|
55
|
-
**Does not own / non-goals**
|
|
56
|
-
|
|
57
|
-
- Mark-specific geometry or rendering; each series definition owns those details.
|
|
58
|
-
- Axis, grid, legend, or tooltip presentation beyond their placement in the root.
|
|
59
|
-
- Product-specific interpretation, summary, or analysis of the supplied data.
|
|
60
|
-
|
|
61
|
-
## Public concepts
|
|
62
|
-
|
|
63
|
-
| Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
|
|
64
|
-
| ---------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | -------------------------------------------- | ----------------- | ------------ | ----------------------------------------------------------------------------------------------------- |
|
|
65
|
-
| Data model | `data`, `xKey`, `series` | Rows, shared x field, and mark definitions for one plot. | Always required. | none | `component:Chart` | experimental | Missing fields are rejected by TypeScript; malformed row values are handled by each mark. |
|
|
66
|
-
| Height | finite number | Outer SVG height in CSS pixels. | All charts. | `300` | `component:Chart` | experimental | Negative or non-finite values resolve to `0`. |
|
|
67
|
-
| Plot margin | partial `top`, `right`, `bottom`, `left` numbers | Insets the shared plot area. | All charts. | `{top: 24, right: 24, bottom: 32, left: 48}` | `component:Chart` | experimental | Non-finite resulting geometry is clamped to `0`; the physical field names remain an open API finding. |
|
|
68
|
-
| Y baseline | `auto`, `zero`, `data` | Chooses mark-aware zero/headroom, symmetric zero, or tight data extent. | Used when `yDomain` is absent. | `auto` | `component:Chart` | experimental | Unknown values are rejected by TypeScript. |
|
|
69
|
-
| Explicit domains | `xDomain`, `yDomain` finite numeric pairs | Pins numeric scale domains. | `xDomain` is ignored for categorical x; `yDomain` overrides baseline and nicening. | absent | `component:Chart` | experimental | Non-finite pairs fall back to automatic derivation. |
|
|
70
|
-
| Chart chrome | `grid`, `axes`, `legend`, `tooltip` | Places caller-supplied or built-in chart context consumers around the series. | Optional. | off/absent | `component:Chart` | experimental | False/omitted boolean-or-config values disable the built-in surface. |
|
|
71
|
-
| Extension slots | `interactions`, `children` | Adds interaction overlays and advanced SVG content in defined paint order. | Optional. | absent | `component:Chart` | experimental | Caller content renders as supplied. |
|
|
72
|
-
| Accessible text | `title`, `subtitle`, generated fallback | Names and describes the chart image. | All charts; visible when supplied. | localized generated name | `component:Chart` | experimental | A generic localized name is used when no primary series exists. |
|
|
73
|
-
| Root DOM surface | `BaseProps<HTMLDivElement>`, `ref` | Forwards standard DOM, data, ARIA, class, style, StyleX, events, and the root element ref. | All charts. | absent | `component:Chart` | experimental | Component-owned SVG semantics remain on the SVG. |
|
|
74
|
-
|
|
75
|
-
## Behavioral and layout contract
|
|
76
|
-
|
|
77
|
-
Draft requirements identify their basis so observed code is not mistaken for an intentional decision.
|
|
78
|
-
|
|
79
|
-
| ID | Candidate invariant | Basis | Draft review state |
|
|
80
|
-
| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | ------------------ |
|
|
81
|
-
| FR1 | Chart MUST reserve its configured height while width is zero, then recompute plot geometry after container resizes. | current implementation and `Chart measurement gate` tests | verify |
|
|
82
|
-
| FR2 | All series, axes, grid lines, tooltips, and interactions MUST consume one shared scale set derived from the current data, domains, baseline, and measured plot size. | README, implementation, and package tests | verify |
|
|
83
|
-
| FR3 | Paint order MUST remain grid → clipped series → axes → pointer layer → interactions → built-in tooltip → children. | current implementation and render-delegation tests | verify |
|
|
84
|
-
| FR4 | Primary series without a static color MUST receive deterministic colors from the active theme palette; utility marks MUST NOT consume palette or legend slots. | implementation, palette test, and browser evidence | verify |
|
|
85
|
-
| FR5 | Pointer movement MUST be normalized into plot coordinates and dispatch the nearest x-position; leaving the plot MUST clear the pointer state. | current implementation and tooltip browser evidence | verify |
|
|
86
|
-
| FR6 | `legend=true` MUST derive items from primary series; legend and tooltip config objects MUST enable their surfaces while overriding supported options. | current implementation and focused tests | verify |
|
|
87
|
-
| FR7 | The chart MUST expose a named `role="img"`; a supplied subtitle MUST be its description; datasets up to 100 row×series cells MUST also be mirrored in a visually hidden table. | current implementation, WCAG 1.1.1, and accessibility tests | verify |
|
|
88
|
-
| FR8 | Root DOM props and `ref` MUST reach the root container while Chart's own SVG name and description remain authoritative. | shared BaseProps convention and focused regression test | verify |
|
|
89
|
-
|
|
90
|
-
### Allowed variation
|
|
91
|
-
|
|
92
|
-
- **AV1 — Series output.** Mark definitions may render different SVG or canvas content while preserving the shared layout and render-order seams.
|
|
93
|
-
- **AV2 — Consumer chrome.** Grid, axes, interaction, and children slots may be absent or contain any valid chart-context consumer.
|
|
94
|
-
|
|
95
|
-
### Representative states
|
|
96
|
-
|
|
97
|
-
| State | Required invariant | Allowed variation |
|
|
98
|
-
| ------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
99
|
-
| Width not measured | Height-reserving root only; no invalid SVG geometry. | Consumer root styling and DOM props remain applied. |
|
|
100
|
-
| Normal data | Shared finite scales and one clipped group per resolved series. | Mark shape, color, and content come from series definitions. |
|
|
101
|
-
| Empty data | Finite fallback scales; no invalid mark geometry. | Visible empty-state treatment remains unsettled. |
|
|
102
|
-
| Small data | Named image plus hidden data table. | Cell text follows supplied row values. |
|
|
103
|
-
| More than 100 cells | Named image; built-in hidden table omitted. | Equivalent large-data alternative remains unsettled. |
|
|
104
|
-
| Title and subtitle | Visible header; SVG title/description associations. | Consumer text content. |
|
|
105
|
-
| Legend enabled | Derived or explicit items at top, bottom, start, or end. | Alignment and supplied items. |
|
|
106
|
-
| Tooltip enabled | Pointer updates the indicator and grouped tooltip; leave clears it. | Custom renderer and placement. |
|
|
107
|
-
| Narrow / RTL | No horizontal page overflow; logical stack placement follows direction. | Physical chart-domain order remains data-owned. |
|
|
108
|
-
|
|
109
|
-
### Transformation and precedence order
|
|
110
|
-
|
|
111
|
-
- **ORD1 — Dimensions.** Merge default and supplied margins → clamp height and inner dimensions → derive scales → resolve series → render in FR3 order.
|
|
112
|
-
- **ORD2 — Domains.** A finite explicit domain wins; otherwise derive finite data extent → expand degenerate extent → apply the requested baseline/headroom → apply nicening only to automatic domains.
|
|
113
|
-
- **ORD3 — Accessible name.** Supplied title wins; otherwise format primary-series labels with the provider locale and interpolate them with `xKey`; with no primary series, use the localized generic name.
|
|
114
|
-
|
|
115
|
-
### Performance and resources
|
|
116
|
-
|
|
117
|
-
- **PR1 — Resize observation.** Each mounted chart observes its root with a dedicated `ResizeObserver` and disconnects it on unmount; migration to the shared observer remains an audit FIX.
|
|
118
|
-
- **PR2 — Pointer dispatch.** Pointer movement updates subscribers directly; tooltip React state changes only when the nearest data index changes.
|
|
119
|
-
|
|
120
|
-
## Accessibility contract
|
|
121
|
-
|
|
122
|
-
- **AR1 — Named image.** The SVG MUST expose `role="img"` with the resolved accessible name.
|
|
123
|
-
- **AR2 — Description.** A supplied subtitle MUST be linked through `aria-describedby` to an SVG `desc`.
|
|
124
|
-
- **AR3 — Small-data alternative.** Up to 100 row×primary-series cells MUST be mirrored in a semantically headed, visually hidden table.
|
|
125
|
-
- **AR4 — Large-data gap.** The current name-only path above the table cutoff does not guarantee an equivalent alternative; resolution requires owner review and remains an audit finding.
|
|
126
|
-
- **AR5 — Tooltip supplement.** Pointer tooltip content MUST NOT be the only available source for required chart information.
|
|
127
|
-
|
|
128
|
-
## Design relationships
|
|
129
|
-
|
|
130
|
-
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
131
|
-
| ---------------- | ------------------------------------------------------- | ---------------------------------------------------------- | -------------- | ------------------ |
|
|
132
|
-
| Header | Core Text roles | delegated to `component:Text` | supporting | FR7 |
|
|
133
|
-
| Plot and marks | Meaningful graphics meet rendered contrast requirements | objective WCAG threshold; mark representation is unsettled | primary | FR2, FR4 |
|
|
134
|
-
| Legend | Labels and swatches preserve series association | delegated to `component:ChartLegend` | supporting | FR6 |
|
|
135
|
-
| Tooltip | Temporal overlay | current Design Conventions | supporting | FR5, FR6, AR5 |
|
|
136
|
-
| Hidden table | Nonvisual data alternative | objective accessibility semantics | supporting | AR3, AR4 |
|
|
137
|
-
|
|
138
|
-
### Theming anatomy
|
|
139
|
-
|
|
140
|
-
<!-- anatomy-theming:v1 -->
|
|
141
|
-
|
|
142
|
-
```json
|
|
143
|
-
{
|
|
144
|
-
"Header": {
|
|
145
|
-
"none": {
|
|
146
|
-
"reason": "intentional: Text owns the visible title and subtitle styling."
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
"Plot": {
|
|
150
|
-
"none": {
|
|
151
|
-
"reason": "unsettled: Chart does not currently expose a public theme target for the SVG plot root."
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
"Grid and axes": {
|
|
155
|
-
"none": {
|
|
156
|
-
"reason": "unsettled: ChartGrid and ChartAxis own their output but do not yet have current component contracts."
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
"Legend": {
|
|
160
|
-
"none": {
|
|
161
|
-
"reason": "unsettled: ChartLegend owns the visible legend but does not yet have a current component contract."
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
"Tooltip and interactions": {
|
|
165
|
-
"none": {
|
|
166
|
-
"reason": "unsettled: ChartTooltip and consumer interaction layers own their painting surfaces."
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
"Data table": {
|
|
170
|
-
"none": {
|
|
171
|
-
"reason": "intentional: The small-data table is visually hidden accessibility content."
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## Family and system relationships
|
|
178
|
-
|
|
179
|
-
- `architecture:component-test-sufficiency` owns evidence quality and rational state partitioning.
|
|
180
|
-
- `architecture:component-theming-surface` owns anatomy-to-theme reachability.
|
|
181
|
-
- `spec:AST-002` owns public API admission and operation shape.
|
|
182
|
-
- `spec:AST-029` owns observational audit backfill and the external evidence receipt.
|
|
183
|
-
|
|
184
|
-
## Verification map
|
|
185
|
-
|
|
186
|
-
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
187
|
-
| ------------------ | ------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
|
|
188
|
-
| FR1, PR1 | `Chart.test.tsx`; Chromium narrow captures | zero and positive width; resize; 320 px | Removing measurement or cleanup leaves a blank/stale plot or a leaked observer. | `audit:Chart/responsive-code-health` |
|
|
189
|
-
| FR2–FR4, ORD1–ORD2 | Chart and package tests; light/dark browser matrix | band and linear x; automatic/explicit domains; grouped/stacked/utility marks | A scale diverges, geometry becomes non-finite, clipping/order changes, or palette ownership drifts. | `audit:Chart/behavior-theming` |
|
|
190
|
-
| FR5–FR6, PR2 | tooltip/legend tests; Chromium hover and layout captures | hover/leave; derived/configured legend; all placements | Tooltip state goes stale, pointer work causes per-move commits, or chrome renders in the wrong layer. | `audit:Chart/behavior` |
|
|
191
|
-
| FR7, AR1–AR5, ORD3 | accessible-name/table tests; package-specific axe; browser receipts | title/subtitle; generated name; small, empty, and large data | Name/description disappears, the small-data table is lost, localization regresses, or the large-data gap is hidden. | `audit:Chart/accessibility-i18n` |
|
|
192
|
-
| FR8 | root-prop/ref regression test and package typecheck | placeholder and measured render | DOM props or ref stop reaching the root, or consumer styling replaces component styling. | `audit:Chart/public-api` |
|
|
193
|
-
|
|
194
|
-
## Decision log
|
|
195
|
-
|
|
196
|
-
None. This draft records observed behavior and open gaps only.
|
|
197
|
-
|
|
198
|
-
## Open questions
|
|
199
|
-
|
|
200
|
-
- **OQ1 — Large-data alternative.** What equivalent nonvisual data or summary contract must Chart guarantee after the 100-cell table cutoff? (`human-api`)
|
|
201
|
-
- **OQ2 — Directional margins.** Should the experimental physical `left`/`right` margin fields migrate to logical names before a stable release? (`human-api`)
|
|
202
|
-
- **OQ3 — Series metadata.** How should per-chart identity, stack state, and resolved colors move behind a private boundary before the canary API stabilizes? (`human-api`)
|
|
203
|
-
- **OQ4 — Theming root.** Should Chart expose a public target for its plot/root surface, or intentionally remain token-only? (`human-design`)
|
|
204
|
-
|
|
205
|
-
## Content boundary
|
|
206
|
-
|
|
207
|
-
This file does not duplicate consumer prop tables/examples, current audit results,
|
|
208
|
-
implementation steps, or shared system rules. It links to their owners.
|
package/src/ChartAxis.spec.md
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
schema_version: 3
|
|
3
|
-
template_version: 5
|
|
4
|
-
kind: component
|
|
5
|
-
id: component:ChartAxis
|
|
6
|
-
authority: draft
|
|
7
|
-
archive_reason: null
|
|
8
|
-
superseded_by: null
|
|
9
|
-
approved_by: null
|
|
10
|
-
approved_at: null
|
|
11
|
-
owners: [cixzhang]
|
|
12
|
-
review_triggers: [public-api, behavior, layout, theming, accessibility]
|
|
13
|
-
verified_by:
|
|
14
|
-
[
|
|
15
|
-
packages/charts/src/ChartAxis.test.tsx,
|
|
16
|
-
apps/storybook/stories/charts/ChartAxis.stories.tsx,
|
|
17
|
-
]
|
|
18
|
-
modules: []
|
|
19
|
-
families: []
|
|
20
|
-
design_specs: []
|
|
21
|
-
architecture:
|
|
22
|
-
[
|
|
23
|
-
architecture:component-test-sufficiency,
|
|
24
|
-
architecture:component-theming-surface,
|
|
25
|
-
]
|
|
26
|
-
contributing: []
|
|
27
|
-
system_specs: [spec:AST-002, spec:AST-029]
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
# ChartAxis component contract
|
|
31
|
-
|
|
32
|
-
## Contract at a glance
|
|
33
|
-
|
|
34
|
-
| Area | Contract |
|
|
35
|
-
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
36
|
-
| Public contract | No API shape or default changes. Truncation and automatic horizontal density now count complete grapheme clusters under the objective Unicode text-segmentation standard. |
|
|
37
|
-
| Behavior | The selected physical plot edge determines scale, placement, label direction, and the default edge line; explicit formatting and density inputs refine labels. |
|
|
38
|
-
| End-user impact | Chart readers keep complete tick-label characters, and equally short Unicode labels are no longer thinned more aggressively than ASCII labels. |
|
|
39
|
-
| Builder impact | None. Existing callsites remain valid and receive direct CLI documentation for the current surface. |
|
|
40
|
-
| Compatibility/readiness | The canary API and defaults are preserved. This record is draft observational evidence; rendered and accessibility-tree evidence remains incomplete. |
|
|
41
|
-
| Review checks | Reject a changed public shape/default, an axis using the wrong Chart scale, broken physical-edge placement, split grapheme labels, or hidden line/tick precedence. |
|
|
42
|
-
| Governing rules | `spec:AST-029/FR3–FR7`, `architecture:component-test-sufficiency/INV1–INV9`, and [Unicode Text Segmentation](https://www.unicode.org/reports/tr29/). |
|
|
43
|
-
|
|
44
|
-
This table is a review projection; the body below is authoritative.
|
|
45
|
-
|
|
46
|
-
## Intent
|
|
47
|
-
|
|
48
|
-
ChartAxis renders labelled Cartesian x or y scale output inside a Chart. It owns
|
|
49
|
-
physical-edge placement, tick selection and formatting, optional tick marks, and the
|
|
50
|
-
optional axis edge line while Chart owns the scale domains and plot geometry.
|
|
51
|
-
|
|
52
|
-
## Compatibility and migration
|
|
53
|
-
|
|
54
|
-
- Released default preserved: yes; the package is canary-only and has no stable release.
|
|
55
|
-
- Compatibility class: no public API or default changes; Unicode truncation and automatic thinning intentionally change only labels containing multi-code-unit graphemes, while representative ASCII behavior is preserved.
|
|
56
|
-
- Controlled/uncontrolled behavior: not applicable.
|
|
57
|
-
- Migration decision: none; this draft does not authorize a public API change.
|
|
58
|
-
|
|
59
|
-
Consumer migration instructions belong in consumer docs and release notes.
|
|
60
|
-
|
|
61
|
-
## Ownership boundary
|
|
62
|
-
|
|
63
|
-
**Owns**
|
|
64
|
-
|
|
65
|
-
- Selecting the Chart-provided x or y scale for one physical plot edge.
|
|
66
|
-
- Generating, formatting, thinning, truncating, positioning, and hiding tick labels.
|
|
67
|
-
- Rendering its optional edge line and optional outward tick marks.
|
|
68
|
-
- Applying optional transition styling to tick position and visibility changes.
|
|
69
|
-
|
|
70
|
-
**Does not own / non-goals**
|
|
71
|
-
|
|
72
|
-
- Data, domains, scale construction, or plot dimensions — owned by `component:Chart`.
|
|
73
|
-
- Grid lines — owned by `component:ChartGrid`.
|
|
74
|
-
- Product-specific units, locale choices, or label wording supplied through `tickFormat` — owned by the product callsite.
|
|
75
|
-
- A standalone chart data alternative — owned by `component:Chart` and its surrounding product content.
|
|
76
|
-
|
|
77
|
-
## Public concepts
|
|
78
|
-
|
|
79
|
-
| Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
|
|
80
|
-
| ---------------- | -------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------ | --------------------- | ------------ | ------------------------------------------------------------------------------- |
|
|
81
|
-
| Physical edge | `top`, `right`, `bottom`, `left` | Chooses the plot edge, scale axis, transform, and outward label side. | Required for every axis. | none | `component:ChartAxis` | experimental | Unknown values are rejected by TypeScript. |
|
|
82
|
-
| Tick target | finite number | Requests an approximate continuous-scale tick count from d3. | Continuous scales; also configures the automatic formatter. | `5` | `component:ChartAxis` | experimental | Negative/non-finite values fall back to 5; fractions floor; values cap at 1000. |
|
|
83
|
-
| Label cap | number or absent | Evenly skips labels when the generated set exceeds the requested cap. | Every scale. | automatic from available space | `component:ChartAxis` | experimental | Values outside the intended positive-count domain are not specified. |
|
|
84
|
-
| Label formatter | `(value: unknown) => string` or absent | Replaces the band string or d3 continuous-scale formatter. | Every tick. | scale-appropriate built-in formatter | `component:ChartAxis` | experimental | Exceptions from consumer formatters propagate. |
|
|
85
|
-
| Label truncation | positive character count or absent | Keeps that many user-perceived characters, then appends an ellipsis. | Every formatted label. | absent | `component:ChartAxis` | experimental | Zero/omitted disables truncation; other invalid values are not specified. |
|
|
86
|
-
| Edge line | shown or hidden | Renders a line along the selected axis edge. | Every edge; tick marks force it on. | shown only for `bottom` | `component:ChartAxis` | experimental | Not applicable. |
|
|
87
|
-
| Tick marks | shown or hidden | Renders an outward perpendicular mark beside each visible tick label. | Every edge. | hidden | `component:ChartAxis` | experimental | Not applicable. |
|
|
88
|
-
| Tick transition | animated or immediate | Animates tick transform and opacity during scale changes. | Generated ticks. | animated | `component:ChartAxis` | experimental | Not applicable. |
|
|
89
|
-
|
|
90
|
-
## Behavioral and layout contract
|
|
91
|
-
|
|
92
|
-
Draft requirements identify their basis so observed code is not mistaken for an
|
|
93
|
-
intentional decision.
|
|
94
|
-
|
|
95
|
-
| ID | Candidate invariant | Basis | Draft review state |
|
|
96
|
-
| ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------ |
|
|
97
|
-
| FR1 | A top or bottom axis MUST consume Chart's x scale; a left or right axis MUST consume the categorical y scale when present and the linear y scale otherwise. | implementation, types, and focused tests | verify |
|
|
98
|
-
| FR2 | Continuous tick generation MUST use one sanitized count for both d3 tick generation and its default formatter; band scales MUST use their complete domain before thinning. | implementation | verify |
|
|
99
|
-
| FR3 | A supplied `tickFormat` MUST win; otherwise continuous scales use d3 formatting and band values use `String`. | implementation and focused tests | verify |
|
|
100
|
-
| FR4 | Explicit `maxTicks` MUST win over the size-derived cap. | implementation and focused tests | verify |
|
|
101
|
-
| FR5 | Truncation MUST keep complete Unicode grapheme clusters while preserving the documented content-count-plus-ellipsis output. | focused red/green test and Unicode Standard Annex #29 | settled |
|
|
102
|
-
| FR6 | Automatic horizontal density MUST estimate formatted label length in user-perceived characters rather than UTF-16 storage units. | focused red/green equivalence test and Unicode segmentation | settled |
|
|
103
|
-
| FR7 | Bottom MUST show an edge line by default and the other edges MUST hide it by default. `showTicks` MUST force the edge line on and render one mark per surviving tick. | implementation, JSDoc, focused tests, and Storybook | verify |
|
|
104
|
-
| FR8 | Bottom and right axes MUST translate to the corresponding plot edge. Top and left remain at the plot origin. Labels and tick marks extend outwards from that physical edge. | implementation and focused tests | verify |
|
|
105
|
-
| FR9 | On a mixed-sign linear y domain, the bottom edge line MUST align with y=0; categorical y leaves it on the plot edge. | implementation | verify |
|
|
106
|
-
| FR10 | Tick movement and visibility MAY transition when `animated` is true and MUST be immediate when false. Out-of-range ticks remain mounted with zero opacity during updates. | implementation and streaming examples; motion intent unsettled | human decision |
|
|
107
|
-
|
|
108
|
-
### Allowed variation
|
|
109
|
-
|
|
110
|
-
- **AV1 — Tick count.** d3 may choose a nearby continuous tick count rather than the requested number.
|
|
111
|
-
- **AV2 — Label set.** Automatic and explicit density limits may omit evenly spaced labels while preserving their scale order.
|
|
112
|
-
- **AV3 — Supplied text.** Product callsites may format values in their own units and locale through `tickFormat`.
|
|
113
|
-
|
|
114
|
-
### Representative states
|
|
115
|
-
|
|
116
|
-
| State | Required invariant | Allowed variation |
|
|
117
|
-
| --------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------- |
|
|
118
|
-
| Bottom categorical | Band labels are centered; the edge line is shown by default. | Automatic density may omit labels. |
|
|
119
|
-
| Top categorical | Band labels render outside the top edge. | Edge line remains hidden unless requested. |
|
|
120
|
-
| Left continuous | d3 labels render outside the left edge. | d3 chooses exact tick values. |
|
|
121
|
-
| Right continuous | Axis translates to the right edge and labels render outside it. | d3 chooses exact tick values. |
|
|
122
|
-
| Vertical categorical | Row labels use `yBandScale` and align with band centers. | Automatic density may omit labels. |
|
|
123
|
-
| Explicit formatting | Every retained label uses the supplied formatter. | Consumer-owned wording and units. |
|
|
124
|
-
| Truncated label | Complete grapheme clusters precede the appended ellipsis. | The caller chooses the content-character limit. |
|
|
125
|
-
| Tick marks shown | Every retained label has an outward mark and an edge line. | Edge-line visibility input is subsumed in this state. |
|
|
126
|
-
| Mixed-sign linear y data | Bottom line represents y=0 rather than the plot boundary. | Exact pixel position follows the supplied domain. |
|
|
127
|
-
| Streaming / changing domain | Tick positions and visibility update; animation follows `animated`. | Tick identity follows the raw value. |
|
|
128
|
-
|
|
129
|
-
### Transformation and precedence order
|
|
130
|
-
|
|
131
|
-
- **ORD1 — Scale.** Resolve physical orientation → choose Chart scale → generate and format each tick once → derive the grapheme-aware density cap → evenly filter labels.
|
|
132
|
-
- **ORD2 — Label.** Apply the supplied formatter or the scale default → preserve complete grapheme clusters when truncating → render the result.
|
|
133
|
-
- **ORD3 — Edge.** Resolve the position default → apply `showAxisLine` → force the line on when `showTicks` is true.
|
|
134
|
-
|
|
135
|
-
### Performance and resources
|
|
136
|
-
|
|
137
|
-
- **PR1 — Bounded continuous ticks.** Sanitization caps the d3 request at 1000 so a consumer value cannot allocate an unbounded tick array.
|
|
138
|
-
- **PR2 — Derived tick state.** Tick generation and formatting remain render-derived and memoized; each generated label is formatted once and shared by density and rendering, and ChartAxis owns no listener, observer, timer, or persistent resource.
|
|
139
|
-
|
|
140
|
-
## Accessibility contract
|
|
141
|
-
|
|
142
|
-
- **AR1 — Visible text integrity.** A truncated tick label MUST preserve complete user-perceived characters under Unicode grapheme-cluster boundaries.
|
|
143
|
-
- **AR2 — Chart-level alternative.** ChartAxis renders inside Chart's named image. Chart owns the accessible chart name and supported small-data table; axis labels and pointer content do not replace that alternative.
|
|
144
|
-
- **AR3 — Nested axis semantics gap.** The implementation currently emits a position-labelled `role="group"`. Whether that group should be independently exposed and localized beneath Chart's `role="img"` remains unverified and requires owner review.
|
|
145
|
-
|
|
146
|
-
## Design relationships
|
|
147
|
-
|
|
148
|
-
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
149
|
-
| ---------------- | ------------------------------------------------------ | ------------------------------------------------- | -------------- | ------------------ |
|
|
150
|
-
| Axis edge line | Grounds the physical plot edge when present. | unsettled; no current design record is linked | supporting | FR7, FR9 |
|
|
151
|
-
| Tick marks | Associate retained labels with positions on the scale. | unsettled; no current design record is linked | supporting | FR7 |
|
|
152
|
-
| Tick labels | Preserve readable value/category text around the plot. | Unicode grapheme boundaries settle text integrity | supporting | FR3, FR5, FR6, AR1 |
|
|
153
|
-
| Tick transition | Shows continuity during scale changes. | unsettled; `design:motion` remains draft | supporting | FR10 |
|
|
154
|
-
|
|
155
|
-
### Theming anatomy
|
|
156
|
-
|
|
157
|
-
<!-- anatomy-theming:v1 -->
|
|
158
|
-
|
|
159
|
-
```json
|
|
160
|
-
{
|
|
161
|
-
"Axis edge line": {
|
|
162
|
-
"none": {
|
|
163
|
-
"reason": "unsettled: ChartAxis consumes semantic color tokens but no current component or family contract decides whether the line is a public theme target."
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
"Tick marks": {
|
|
167
|
-
"none": {
|
|
168
|
-
"reason": "unsettled: ChartAxis consumes semantic color tokens but no current component or family contract decides whether tick marks are a public theme target."
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
"Tick labels": {
|
|
172
|
-
"none": {
|
|
173
|
-
"reason": "unsettled: ChartAxis consumes semantic color tokens but no current component or family contract decides whether labels are a public theme target."
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## Family and system relationships
|
|
180
|
-
|
|
181
|
-
- No current family or design record governs ChartAxis.
|
|
182
|
-
- `architecture:component-test-sufficiency` owns rational public-state partitions, observable assertions, and red-before-green audit remediation.
|
|
183
|
-
- `architecture:component-theming-surface` owns anatomy-to-target disposition; token consumption alone does not enroll ChartAxis in public component theming.
|
|
184
|
-
- `spec:AST-002` owns public API admission and forbids an audit from smuggling a new public choice into a repair.
|
|
185
|
-
- `spec:AST-029` owns this observational backfill, closed evidence receipt, safe remediation, and fail-closed eligibility report.
|
|
186
|
-
|
|
187
|
-
## Verification map
|
|
188
|
-
|
|
189
|
-
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
190
|
-
| ------------- | ------------------------------------------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------- |
|
|
191
|
-
| FR1, FR8 | `ChartAxis.test.tsx`; `ChartAxis.stories.tsx` | top, right, bottom, left; band and linear | An edge uses the wrong scale, transform, or outward label side. | `audit:ChartAxis/behavior-layout` |
|
|
192
|
-
| FR2, FR3 | `ChartAxis.test.tsx` | default count; band, linear, and custom formatting | Generation and formatting disagree or a supplied formatter is ignored. | `audit:ChartAxis/behavior` |
|
|
193
|
-
| FR4 | `ChartAxis.test.tsx` | automatic cap and explicit `maxTicks` | Explicit capping stops winning over size-derived thinning. | `audit:ChartAxis/behavior` |
|
|
194
|
-
| FR5, FR6, AR1 | red-before-green grapheme regressions; density tests; browser story | ASCII, emoji, flag, and ZWJ labels; truncated wide/narrow plots | A visible label splits a grapheme or equal perceived-width labels retain different ticks. | `audit:ChartAxis/i18n-testing` |
|
|
195
|
-
| FR7 | `ChartAxis.test.tsx`; Axes & Grids Storybook fixture | defaults; line requested; ticks requested | Tick marks lose their edge line or line defaults change. | `audit:ChartAxis/behavior` |
|
|
196
|
-
| FR9 | source review; browser evidence remains pending | positive-only, negative-only, mixed-sign, y-band | The mixed-sign zero line moves to the edge or a categorical axis crosses the plot. | `audit:ChartAxis/behavior-design` |
|
|
197
|
-
| FR10 | streaming stories; exact-head browser evidence remains pending | animated, immediate, entering/leaving tick | Disabling animation retains a transition or a moving label jumps to stale geometry. | `audit:ChartAxis/design-testing` |
|
|
198
|
-
| AR2, AR3 | Chart accessibility tests; package axe; accessibility-tree review | title/subtitle, small-data table, nested axis groups | Chart loses its alternative or an unreviewed nested semantic claim is treated as fact. | `audit:ChartAxis/accessibility` |
|
|
199
|
-
|
|
200
|
-
## Decision log
|
|
201
|
-
|
|
202
|
-
None. This draft records observed behavior and one objective Unicode correction; it does not approve new ChartAxis policy.
|
|
203
|
-
|
|
204
|
-
## Open questions
|
|
205
|
-
|
|
206
|
-
- **OQ1 — Axis semantics.** Should ChartAxis remain purely visual content within Chart's single named image, or expose each axis as an independently localized accessibility group? (`human-api`)
|
|
207
|
-
|
|
208
|
-
## Content boundary
|
|
209
|
-
|
|
210
|
-
This file does not duplicate consumer prop tables/examples, current audit results,
|
|
211
|
-
implementation steps, or shared system rules. It links to their owners.
|