@nanisoft/prism-llms 0.4.0 → 0.5.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/README.md +88 -0
- package/THIRD-PARTY-NOTICES.md +48 -0
- package/dist/data.json +3996 -387
- package/dist/demo-graph.d.ts +21 -12
- package/dist/demo-graph.js +37 -21
- package/dist/extractor.d.ts +24 -17
- package/dist/extractor.js +269 -153
- package/dist/index.d.ts +12 -7
- package/dist/index.js +9 -7
- package/dist/llms-full.txt +7968 -2013
- package/dist/llms.txt +97 -93
- package/dist/markdown.d.ts +69 -23
- package/dist/markdown.js +131 -72
- package/dist/md/blocks/app-shell-01.md +135 -0
- package/dist/md/blocks/auth-form-01.md +135 -0
- package/dist/md/blocks/cta-01.md +88 -0
- package/dist/md/blocks/data-table-01.md +196 -0
- package/dist/md/blocks/feature-grid-01.md +92 -0
- package/dist/md/blocks/hero-01.md +90 -0
- package/dist/md/blocks/instrument-panel-01.md +109 -0
- package/dist/md/blocks/logo-strip-01.md +97 -0
- package/dist/md/blocks/note-grid-01.md +102 -0
- package/dist/md/blocks/page-header-01.md +97 -0
- package/dist/md/blocks/pricing-01.md +91 -0
- package/dist/md/blocks/process-rail-01.md +106 -0
- package/dist/md/blocks/product-grid-01.md +113 -0
- package/dist/md/blocks/settings-panel-01.md +148 -0
- package/dist/md/blocks/site-footer.md +103 -11
- package/dist/md/blocks/site-header.md +111 -11
- package/dist/md/blocks/stack-grid-01.md +108 -0
- package/dist/md/blocks/stats-01.md +89 -0
- package/dist/md/blocks/status-ledger-01.md +121 -0
- package/dist/md/changelogs/prism-llms.md +206 -0
- package/dist/md/changelogs/prism-mcp-server.md +88 -0
- package/dist/md/changelogs/prism-tokens.md +126 -0
- package/dist/md/changelogs/prism-ui.md +429 -0
- package/dist/md/components/accordion.md +108 -0
- package/dist/md/components/alert.md +90 -7
- package/dist/md/components/avatar.md +89 -7
- package/dist/md/components/badge.md +74 -7
- package/dist/md/components/breadcrumb.md +84 -7
- package/dist/md/components/button.md +90 -7
- package/dist/md/components/card.md +90 -7
- package/dist/md/components/checkbox.md +101 -7
- package/dist/md/components/cta-link.md +98 -0
- package/dist/md/components/diagram.md +124 -0
- package/dist/md/components/dialog.md +128 -0
- package/dist/md/components/dropdown-menu.md +125 -0
- package/dist/md/components/fact-list.md +85 -0
- package/dist/md/components/field.md +116 -0
- package/dist/md/components/input.md +86 -7
- package/dist/md/components/kbd.md +77 -0
- package/dist/md/components/pagination.md +95 -7
- package/dist/md/components/popover.md +95 -7
- package/dist/md/components/product-mark.md +123 -0
- package/dist/md/components/product-switcher.md +88 -0
- package/dist/md/components/progress.md +88 -7
- package/dist/md/components/prose.md +91 -0
- package/dist/md/components/radio-group.md +111 -0
- package/dist/md/components/section.md +91 -0
- package/dist/md/components/select.md +143 -7
- package/dist/md/components/separator.md +77 -0
- package/dist/md/components/skeleton.md +71 -7
- package/dist/md/components/slider.md +90 -7
- package/dist/md/components/switch.md +104 -7
- package/dist/md/components/table.md +104 -7
- package/dist/md/components/tabs.md +105 -7
- package/dist/md/components/textarea.md +101 -0
- package/dist/md/components/tooltip.md +95 -7
- package/dist/md/components/typography.md +82 -7
- package/dist/md/content/about-content.md +36 -0
- package/dist/md/content/audience.md +43 -0
- package/dist/md/content/glossary.md +69 -0
- package/dist/md/content/product-vocabulary.md +53 -0
- package/dist/md/content/voice.md +52 -0
- package/dist/md/content/writing-mechanics.md +58 -0
- package/dist/md/foundation/colors.md +10 -0
- package/dist/md/foundation/iconography.md +14 -0
- package/dist/md/foundation/motion.md +10 -0
- package/dist/md/foundation/radii.md +9 -0
- package/dist/md/foundation/shadows.md +9 -0
- package/dist/md/foundation/spacings.md +8 -0
- package/dist/md/foundation/typography.md +9 -0
- package/dist/md/foundation/variables.md +9 -0
- package/dist/md/overview/architecture.md +76 -0
- package/dist/md/overview/brand.md +41 -0
- package/dist/md/overview/composition.md +77 -0
- package/dist/md/overview/quickstart.md +97 -0
- package/dist/md/overview/theming.md +89 -0
- package/dist/md/overview/using-llms.md +83 -0
- package/dist/md/pages/auth-page.md +149 -0
- package/dist/md/pages/blog-post-page.md +136 -0
- package/dist/md/pages/dashboard-page.md +241 -0
- package/dist/md/pages/marketing-page.md +199 -0
- package/dist/md/pages/not-found-page.md +105 -0
- package/dist/md/pages/settings-page.md +206 -0
- package/dist/prism-skill.md +50 -0
- package/dist/store.d.ts +203 -0
- package/dist/store.js +317 -0
- package/package.json +29 -26
- package/dist/demo-graph.d.ts.map +0 -1
- package/dist/demo-graph.js.map +0 -1
- package/dist/extractor.d.ts.map +0 -1
- package/dist/extractor.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/markdown.d.ts.map +0 -1
- package/dist/markdown.js.map +0 -1
- package/dist/md/blocks/component-demo.md +0 -19
- package/dist/md/blocks/page-header.md +0 -19
- package/dist/md/components/affix.md +0 -14
- package/dist/md/components/anchor.md +0 -14
- package/dist/md/components/auto-complete.md +0 -14
- package/dist/md/components/back-top.md +0 -14
- package/dist/md/components/border-beam.md +0 -14
- package/dist/md/components/calendar.md +0 -14
- package/dist/md/components/carousel.md +0 -14
- package/dist/md/components/cascader.md +0 -14
- package/dist/md/components/col.md +0 -14
- package/dist/md/components/collapse.md +0 -14
- package/dist/md/components/color-picker.md +0 -14
- package/dist/md/components/date-picker.md +0 -14
- package/dist/md/components/descriptions.md +0 -14
- package/dist/md/components/display-title.md +0 -20
- package/dist/md/components/divider.md +0 -14
- package/dist/md/components/drawer.md +0 -14
- package/dist/md/components/dropdown.md +0 -14
- package/dist/md/components/empty.md +0 -14
- package/dist/md/components/flex.md +0 -14
- package/dist/md/components/float-button.md +0 -14
- package/dist/md/components/form.md +0 -14
- package/dist/md/components/grid.md +0 -14
- package/dist/md/components/image.md +0 -14
- package/dist/md/components/input-number.md +0 -14
- package/dist/md/components/layout.md +0 -14
- package/dist/md/components/list.md +0 -14
- package/dist/md/components/listy.md +0 -14
- package/dist/md/components/masonry.md +0 -14
- package/dist/md/components/mentions.md +0 -14
- package/dist/md/components/menu.md +0 -14
- package/dist/md/components/modal.md +0 -14
- package/dist/md/components/popconfirm.md +0 -14
- package/dist/md/components/qrcode.md +0 -14
- package/dist/md/components/radio.md +0 -14
- package/dist/md/components/rate.md +0 -14
- package/dist/md/components/result.md +0 -14
- package/dist/md/components/row.md +0 -14
- package/dist/md/components/segmented.md +0 -14
- package/dist/md/components/space.md +0 -14
- package/dist/md/components/spin.md +0 -14
- package/dist/md/components/splitter.md +0 -14
- package/dist/md/components/statistic.md +0 -14
- package/dist/md/components/steps.md +0 -14
- package/dist/md/components/tag.md +0 -14
- package/dist/md/components/time-picker.md +0 -14
- package/dist/md/components/timeline.md +0 -14
- package/dist/md/components/tour.md +0 -14
- package/dist/md/components/transfer.md +0 -14
- package/dist/md/components/tree-select.md +0 -14
- package/dist/md/components/tree.md +0 -14
- package/dist/md/components/upload.md +0 -14
- package/dist/md/components/watermark.md +0 -14
- package/dist/md/docs/brand.md +0 -41
- package/dist/md/pages/blog-layout.md +0 -19
- package/dist/md/pages/docs-shell.md +0 -23
- package/dist/md/theme/blue-dark.md +0 -127
- package/dist/md/theme/blue-light.md +0 -129
- package/dist/md/theme/green-dark.md +0 -127
- package/dist/md/theme/green-light.md +0 -129
- package/dist/md/theme/lavender-dark.md +0 -127
- package/dist/md/theme/lavender-light.md +0 -129
- package/dist/md/theme/peach-dark.md +0 -127
- package/dist/md/theme/peach-light.md +0 -129
- package/dist/md/theme/rose-dark.md +0 -127
- package/dist/md/theme/rose-light.md +0 -129
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# @nanisoft/prism-tokens
|
|
2
|
+
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4f9ce77: A server-rendered pack boundary can now be mode-correct
|
|
8
|
+
|
|
9
|
+
The only dark selector for a pack was `[data-pack="<id>"].dark`, which requires
|
|
10
|
+
the mode class on the same element. A server cannot know the reader's mode, so a
|
|
11
|
+
subtree carrying a second pack rendered in that pack's light values on a dark
|
|
12
|
+
page. The token build now emits the two-member list
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
[data-pack="<id>"].dark, .dark [data-pack="<id>"]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
as one rule with one declaration block, for all five packs. The compound half is
|
|
19
|
+
retained, because it is what a dark surface on a light page is and it is a
|
|
20
|
+
capability the package already published.
|
|
21
|
+
|
|
22
|
+
Consumers get a second change alongside it. `themeAttributes` now takes `mode` as
|
|
23
|
+
optional, because a required one is that same impossibility written into the type:
|
|
24
|
+
the only way to ask for a boundary with no mode class of its own was to pass
|
|
25
|
+
`'light'` as a guess, and the guess is wrong for half of readers. Omitting `mode`
|
|
26
|
+
is the honest spelling of "wear the mode of the element carrying `.dark`". The
|
|
27
|
+
change is a widening, so every existing caller still compiles.
|
|
28
|
+
|
|
29
|
+
The theme-boundary law in `DESIGN.md` is rewritten to match. It previously
|
|
30
|
+
instructed an implementer to put `data-pack` and `class="dark"` on a boundary
|
|
31
|
+
together, which works for a client-applied boundary and cannot work for a
|
|
32
|
+
server-rendered one.
|
|
33
|
+
- 5dcb347: Every colour role now has a contrast row or a stated reason, and there is a brand ink
|
|
34
|
+
|
|
35
|
+
The contrast gate decided what to measure by a naming convention: any root token ending in
|
|
36
|
+
`-foreground` had to be the first element of a pair. Six of the seven roles that were in no row at
|
|
37
|
+
all could not be reported by that rule, because `chart-1` through `chart-5` and `sidebar-border`
|
|
38
|
+
do not end in `-foreground`, and `sidebar-ring` does not either. A new role therefore defaulted to
|
|
39
|
+
silence. The gate now walks the token source instead of the table, so a role nobody has written
|
|
40
|
+
down is a failure rather than an absence, and the role set is read from `src/semantic/` rather than
|
|
41
|
+
from the pair table, or the walk would be checking the table against itself.
|
|
42
|
+
|
|
43
|
+
`sidebar-ring` is what the walk immediately found. It had no row at all, and its shipped values
|
|
44
|
+
measured 2.42:1 in the base pack's light mode, 1.73:1 in its dark mode, 2.86:1 in Mint and 2.97:1
|
|
45
|
+
in Sky against the sidebar surface: a focus indicator four of twelve pack and mode combinations
|
|
46
|
+
could not be seen against, reported as compliant because it was not measured. The values moved, not
|
|
47
|
+
the row. The base pack goes from neutral 400 and neutral 700 to neutral 500 in both modes, because
|
|
48
|
+
the base pack's ring is one ramp rather than two; the pastels go from brand 500 to brand 600 in
|
|
49
|
+
light, because the sidebar is neutral 50 rather than neutral 0 and brand 500 is one step short of
|
|
50
|
+
3:1 in two packs. The dark pastels keep brand 300 at 8.06:1 or better. `sidebar-border` gains an
|
|
51
|
+
advisory row on the sidebar surface with the same judgement `border` and `input` already carry,
|
|
52
|
+
which is how its 1.18:1 to 1.37:1 became a number on the record rather than an unmeasured value.
|
|
53
|
+
|
|
54
|
+
`chart-1` through `chart-5` are exempted with a reason rather than measured against a ground. A
|
|
55
|
+
series is a graphic object: shadcn consumes the five as the stroke and fill of a series and reads
|
|
56
|
+
its tooltip and legend text from `foreground` and `muted-foreground`, which are each gated against
|
|
57
|
+
their own ground. What binds a five-way set is that no two series resolve to the same value, so
|
|
58
|
+
that is what the gate asserts instead, in every pack and both modes. The measured tightest pair is
|
|
59
|
+
37/255 in a channel, Peach in dark mode between `chart-1` and `chart-5`. No minimum separation is
|
|
60
|
+
asserted, because a threshold with no standard behind it is a number that gets bent. `radius` is
|
|
61
|
+
exempted as a length rather than a colour, and the exclusion is a declared entry with a reason
|
|
62
|
+
instead of a name filter buried in a loop. Every exemption is printed on every run with the roles
|
|
63
|
+
that share it.
|
|
64
|
+
|
|
65
|
+
**`brand-ink` is a new semantic role: a brand hue read as text.** Three sites want a brand colour
|
|
66
|
+
they can read on a surface and `primary` cannot serve it, because `primary` is a fill: a pastel
|
|
67
|
+
brand 400 measures 2.20:1 to 2.44:1 on its own pack's page and 1.90:1 to 2.05:1 on the accent
|
|
68
|
+
surface. It is brand 700 in light and brand 200 in dark, in all five packs and the base, and it is
|
|
69
|
+
gated at 4.5:1 against three grounds rather than one: the page, a card, and the accent surface.
|
|
70
|
+
The accent is the ground that decides the step in both directions, because a light ink has to
|
|
71
|
+
survive the pack's own brand 100 and a dark ink has to survive brand 800, and brand 600 and brand
|
|
72
|
+
400 respectively are the steps that fail each. The measured worst case across all six sources, both
|
|
73
|
+
modes and all three grounds is 5.57:1 in Mint's light mode. The dark step is brand 200 rather than
|
|
74
|
+
the brand 300 the accent ground would have permitted, because brand 300 is `primary` in every
|
|
75
|
+
pack's dark mode and a brand ink that is the brand fill is the confusion the role exists to end. A
|
|
76
|
+
test asserts that `brand-ink` never resolves to the same value as `primary`, `primary-foreground`
|
|
77
|
+
or `foreground` in any source or mode.
|
|
78
|
+
|
|
79
|
+
**The two values that were already in the contract are the two answers this gate rules out, and
|
|
80
|
+
both are written into `DESIGN.md` as prohibitions with a number attached.** `primary-foreground` is
|
|
81
|
+
the pack's brand 950 step, in both modes and all five packs, published under three further names in
|
|
82
|
+
light mode, and it is the value a reader of the contract reaches for when they want the brand colour
|
|
83
|
+
as text. It clears its own row by 7.39:1 to 11.06:1 and it measures 1.00:1 to 1.82:1 on the dark
|
|
84
|
+
page ground, the dark card and the dark accent surface. In light mode it reads 15.05:1 to 18.05:1
|
|
85
|
+
on the page, so half the modes it looks right and half it disappears, and no row in the contract
|
|
86
|
+
could see the difference. `ring` is the other: the pack's brand hue as a non-text boundary, gated
|
|
87
|
+
at 3:1 against the page ground alone, and it measures 2.66:1 to 4.35:1 on the accent surface in all
|
|
88
|
+
six light-mode sources. Neither was wrong arithmetically. Both are invisible on the ground a brand
|
|
89
|
+
ink lands on, and both now have a role that is measured there.
|
|
90
|
+
|
|
91
|
+
**A role is measured in both modes or the run fails.** Every colour role, exempt ones included, has
|
|
92
|
+
to resolve to an sRGB value in light and in dark in every pack, so an exemption buys a role freedom
|
|
93
|
+
from a ground and never from a mode. This is what a role present in one mode and absent from the
|
|
94
|
+
other looks like, and the build's own key-set guard does not reach it because it compares light
|
|
95
|
+
against light.
|
|
96
|
+
|
|
97
|
+
The old `-foreground` name test is gone rather than kept beside the walk. It was never a second
|
|
98
|
+
opinion on coverage, which the walk settles, and its only additional content is that a role named
|
|
99
|
+
`*-foreground` must be the foreground of a row rather than the background of one, which is a claim
|
|
100
|
+
about the shadcn naming convention and belongs to the Contract Rule.
|
|
101
|
+
|
|
102
|
+
No consumer action is required. `brand-ink` is additive: it is a new custom property, the stylesheet
|
|
103
|
+
gains a `text-brand-ink` utility, and no existing token changed except `sidebar-ring`, whose value
|
|
104
|
+
moved in the base pack and in the light mode of every pastel. A consumer that styled its own sidebar
|
|
105
|
+
focus ring from `--sidebar-ring` will see a more visible ring, which is the point.
|
|
106
|
+
|
|
107
|
+
## 0.5.1
|
|
108
|
+
|
|
109
|
+
### Patch Changes
|
|
110
|
+
|
|
111
|
+
- 2fc6a0a: Retune `muted-foreground` so muted text clears 4.5:1 on the muted surface
|
|
112
|
+
|
|
113
|
+
The base pack's `muted-foreground` moves from neutral 500 to neutral 600. It
|
|
114
|
+
cleared 4.5:1 on the page background but fell to 4.34:1 on `muted`, where the
|
|
115
|
+
pill, avatar fallback, kbd and tab-list pattern place it. The contrast gate now
|
|
116
|
+
also checks `muted-foreground` on `muted`. The pastel packs were already pinned
|
|
117
|
+
to their neutral 700 and are unchanged.
|
|
118
|
+
|
|
119
|
+
## 0.5.0
|
|
120
|
+
|
|
121
|
+
Prism was rebuilt from a fresh repository on a clean break. The token pipeline is
|
|
122
|
+
DTCG 2025.10 compiled with Style Dictionary, the semantic names keep the shadcn
|
|
123
|
+
contract verbatim, and motion, typography, spacing, shadows, breakpoints and
|
|
124
|
+
containers all reach CSS through a single `@theme static` block.
|
|
125
|
+
|
|
126
|
+
Changesets are appended above this entry for every published change.
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
# @nanisoft/prism-ui
|
|
2
|
+
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 956fc8f: A call to action with a destination renders a link, and an icon is required only where a tile is
|
|
8
|
+
|
|
9
|
+
Every primary call to action in the Block family declared an `href` its type then
|
|
10
|
+
never rendered. The control was a `<button>` with no handler: the type said the
|
|
11
|
+
component could navigate, the documentation implied it, and the markup could not
|
|
12
|
+
do either. Sixteen of them across the family, five of them to another origin.
|
|
13
|
+
|
|
14
|
+
**`CtaLink` is a new Component.** It renders a native `<a>` and carries the
|
|
15
|
+
visual weight of a call to action, so assistive technology announces a link and
|
|
16
|
+
the browser's own affordances all work: a status bar showing the destination, a
|
|
17
|
+
context menu to copy it, middle-click to open a new tab. It is a Component in its
|
|
18
|
+
own right rather than an `as` or `href` prop on `Button`, which is the answer
|
|
19
|
+
`BreadcrumbLink` and `PaginationLink` already give twice in this package. It is a
|
|
20
|
+
server component, so the swap costs no client JavaScript.
|
|
21
|
+
|
|
22
|
+
`href` is required on `CtaLink`: an anchor without one is not a link. `newTab` is
|
|
23
|
+
a declared prop and the only way to open a new browsing context, because `target`
|
|
24
|
+
is not accepted, so the relationship cannot be opted out of by accident. When it
|
|
25
|
+
is set, `rel` defaults to `noopener noreferrer`; a consumer that needs a
|
|
26
|
+
different relationship passes `rel` and it wins. Prism does not parse the
|
|
27
|
+
destination and does not decide what counts as external.
|
|
28
|
+
|
|
29
|
+
**`Cta01` no longer offers an action that navigates nothing.** `Cta01Action`'s
|
|
30
|
+
`href` is required, there is no optional arm and no dead-button arm, and a new
|
|
31
|
+
`actionSlot` takes a control the Block does not own, such as a client router's
|
|
32
|
+
link. The Block makes no guess about cross-origin. The one rendered change in
|
|
33
|
+
this release is a button becoming the link its type always said it was: the link
|
|
34
|
+
is styled from the same recipe as the button it replaces, at every shared variant
|
|
35
|
+
and size, and a test asserts that class-for-class.
|
|
36
|
+
|
|
37
|
+
**`FeatureGrid01`'s icon is required only where a tile is rendered.** The
|
|
38
|
+
requirement is a union discriminated on `variant` rather than an optional prop,
|
|
39
|
+
because an optional prop turns a safe-at-render condition into an unsafe one and
|
|
40
|
+
permits an empty accent tile per feature. The `icon` variant is the one an
|
|
41
|
+
omitted `variant` selects, so the default and the required icon live on the same
|
|
42
|
+
arm; the `bare` variant renders no tile and requires no icon, and the type says
|
|
43
|
+
so rather than the renderer finding out. `IconFeature` and `BareFeature` are
|
|
44
|
+
exported, and the union is the type the site's API table is extracted from.
|
|
45
|
+
|
|
46
|
+
**The version the four downstream site plans pin is `0.6.0`.** It is
|
|
47
|
+
`@nanisoft/prism-ui@0.6.0`, and `@nanisoft/prism-tokens@0.6.0` with it, because the
|
|
48
|
+
two are linked in `.changeset/config.json` and the pending
|
|
49
|
+
`a-server-rendered-pack-boundary-can-be-mode-correct` changeset already declares a
|
|
50
|
+
minor for both from `0.5.1`. This one declares a minor as well and so does not
|
|
51
|
+
raise it.
|
|
52
|
+
|
|
53
|
+
Migration: a `Cta01` action needs a destination. Where the action was a label
|
|
54
|
+
alone, give it the `href` it was always declared with, or move the control into
|
|
55
|
+
the new `actionSlot`. A `FeatureGrid01` in the `bare` variant can now drop the
|
|
56
|
+
`icon` its type used to demand; the `icon` variant still demands one per feature.
|
|
57
|
+
- d001983: A diagram is a Component, and a product's mark is one item rather than two copies
|
|
58
|
+
|
|
59
|
+
Three of the four product sites draw something in the position where an empty box
|
|
60
|
+
is most visible, and all of it was a canvas. A canvas reads computed style from
|
|
61
|
+
one element while a pack is an attribute on an ancestor, so a scoped `data-pack`
|
|
62
|
+
boundary hands it the pack's light values on a dark page, and no token gate can
|
|
63
|
+
see it: the value the drawing holds is a legal token value, applied to the wrong
|
|
64
|
+
pack. Cutting the canvases without a replacement is the alternative, and it
|
|
65
|
+
leaves three heroes with an empty slot.
|
|
66
|
+
|
|
67
|
+
`Diagram` draws named things and the labelled relations between them as inline
|
|
68
|
+
vector markup. Every stroke and every fill is a semantic utility, never a
|
|
69
|
+
resolved value, so a boundary restyles the drawing through the cascade exactly as
|
|
70
|
+
it restyles a heading. It is a server Component: no hook, no mode, no context, no
|
|
71
|
+
prop spread, and no client code, so a consumer renders it from a server file
|
|
72
|
+
with no provider mounted. Its node mark is a circle and a relation is a path
|
|
73
|
+
because both are shapes with no radius concept, which is what keeps a boundary
|
|
74
|
+
from moving anything but colour; a `<rect>` was rejected because its corner
|
|
75
|
+
attribute is a CSS property and no utility pins it. Every mark names an explicit
|
|
76
|
+
stroke width, an explicit stroke and an explicit fill, because a shape left to
|
|
77
|
+
its defaults either paints opaque black over its own labels or resolves its edge
|
|
78
|
+
to the surface it sits on. A relation naming a node it does not have is dropped,
|
|
79
|
+
and the count of dropped relations is on the element rather than swallowed.
|
|
80
|
+
|
|
81
|
+
`ProductMark` promotes the two-part mark the product row and the product switcher
|
|
82
|
+
each hand-wrote into one catalogue item. The ring is `brand-ink` and the core is
|
|
83
|
+
`primary`, which is not a preference: a pastel brand value is a fill and never
|
|
84
|
+
text, so the core may be `primary` and the name may not, and a wordmark reads
|
|
85
|
+
`brand-ink` rather than `foreground` or `primary-foreground`. A hand-written copy
|
|
86
|
+
gets one of those two wrong and nothing in the rendered result says which. The
|
|
87
|
+
mark carries its own `data-pack` boundary, so a product's hue follows from the
|
|
88
|
+
pack the caller passed rather than from whichever pack the page is wearing, and
|
|
89
|
+
the boundary sits on an element with no radius utility, which is the placement
|
|
90
|
+
the pack-boundary law allows. A product with no pack of its own is drawn as the
|
|
91
|
+
full spectrum rather than as a colourless mark, built from the five series tokens
|
|
92
|
+
because they are the only five-way colour set the contract publishes.
|
|
93
|
+
|
|
94
|
+
`scripts/check-vector-ink.mjs` holds both Components to the emitted contract. It
|
|
95
|
+
fails a literal colour, a gradient whose stops are not contract references, a
|
|
96
|
+
`var(--x)` naming a property the contract does not publish, and a paint utility
|
|
97
|
+
whose suffix is not a contract role, which is the last of the four a colour
|
|
98
|
+
regex cannot see because a Tailwind class is a name and not a value. Its scanned
|
|
99
|
+
set is a declared list of two file names rather than a pattern, a Component that
|
|
100
|
+
is not on disk fails the run rather than emptying it, and every exclusion carries
|
|
101
|
+
a reason and is printed on every run, with an exclusion that resolves to nothing
|
|
102
|
+
a finding rather than a line that quietly stops appearing.
|
|
103
|
+
- 4f9ce77: A server-rendered pack boundary can now be mode-correct
|
|
104
|
+
|
|
105
|
+
The only dark selector for a pack was `[data-pack="<id>"].dark`, which requires
|
|
106
|
+
the mode class on the same element. A server cannot know the reader's mode, so a
|
|
107
|
+
subtree carrying a second pack rendered in that pack's light values on a dark
|
|
108
|
+
page. The token build now emits the two-member list
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
[data-pack="<id>"].dark, .dark [data-pack="<id>"]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
as one rule with one declaration block, for all five packs. The compound half is
|
|
115
|
+
retained, because it is what a dark surface on a light page is and it is a
|
|
116
|
+
capability the package already published.
|
|
117
|
+
|
|
118
|
+
Consumers get a second change alongside it. `themeAttributes` now takes `mode` as
|
|
119
|
+
optional, because a required one is that same impossibility written into the type:
|
|
120
|
+
the only way to ask for a boundary with no mode class of its own was to pass
|
|
121
|
+
`'light'` as a guess, and the guess is wrong for half of readers. Omitting `mode`
|
|
122
|
+
is the honest spelling of "wear the mode of the element carrying `.dark`". The
|
|
123
|
+
change is a widening, so every existing caller still compiles.
|
|
124
|
+
|
|
125
|
+
The theme-boundary law in `DESIGN.md` is rewritten to match. It previously
|
|
126
|
+
instructed an implementer to put `data-pack` and `class="dark"` on a boundary
|
|
127
|
+
together, which works for a client-applied boundary and cannot work for a
|
|
128
|
+
server-rendered one.
|
|
129
|
+
- c126ee3: A stored theme is written when a reader decides, and not before
|
|
130
|
+
|
|
131
|
+
`PrismProvider` wrote `prism-theme` on every resolved change, including the
|
|
132
|
+
first resolution from the server-rendered attributes or from its own defaults. A
|
|
133
|
+
first-time visitor therefore ended the load with a stored value they never chose,
|
|
134
|
+
and that value outranked the site's default on every later visit, so a site that
|
|
135
|
+
changed its default could not reach anyone who had ever loaded the page.
|
|
136
|
+
|
|
137
|
+
The write is now gated on a decision. It happens when a caller changes the pack,
|
|
138
|
+
the mode or the toggle, and when the library recovers a decision from
|
|
139
|
+
`prism-theme-mode`, a key earlier lines wrote and this one does not. It does not
|
|
140
|
+
happen on a first resolution from the document or the defaults, so a first visit
|
|
141
|
+
ends with an empty store and a returning visit keeps its choice.
|
|
142
|
+
|
|
143
|
+
Two readers of one stored value now share one rule. `resolveTheme` in
|
|
144
|
+
`@nanisoft/prism-ui/theming` is the rule, `PrismProvider` calls it, and the boot
|
|
145
|
+
script implements it as a string. The script cannot import the function, because
|
|
146
|
+
the build minifies and a renamed identifier inside its own `try` would throw
|
|
147
|
+
there and fail open, so the two are held together by a build-failing equivalence
|
|
148
|
+
gate that runs the emitted string and the rule over one table of stored values:
|
|
149
|
+
nothing stored, a valid pair, a valid mode with a retired pack, a valid pack with
|
|
150
|
+
a retired mode, garbage, a JSON array, a JSON string, `null`, an empty object, a
|
|
151
|
+
partial, a server-rendered pack and mode, and the retired key. Every fall-through
|
|
152
|
+
is asserted to be whole, which is the divergence this fixes: the old string
|
|
153
|
+
validated the pack and the mode independently, so a stored `{ mode: 'dark' }` with
|
|
154
|
+
no pack half-applied there and fell through whole in the rule.
|
|
155
|
+
|
|
156
|
+
A value that is present but is not a pair is no longer repaired field by field,
|
|
157
|
+
and it is not cleared. It is the only record that this reader ever chose anything.
|
|
158
|
+
|
|
159
|
+
The boot script records where the theme came from in `data-theme-origin` on
|
|
160
|
+
`<html>`, and it is the only writer: the provider never touches it, because two
|
|
161
|
+
writers would make the origin a race rather than a record. The value is one of
|
|
162
|
+
|
|
163
|
+
| Value | Meaning |
|
|
164
|
+
| --- | --- |
|
|
165
|
+
| `stored` | the key held a valid `{ pack, mode }` pair |
|
|
166
|
+
| `legacy` | the key was empty and `prism-theme-mode` held a recoverable mode |
|
|
167
|
+
| `unparsed` | the key held a value that is not a pair, and the theme fell through whole |
|
|
168
|
+
| `document` | the key was empty and the root element's own attributes supplied the theme |
|
|
169
|
+
| `default` | neither did, so the consumer's defaults apply |
|
|
170
|
+
|
|
171
|
+
It is written on every path the script reaches, so an absent origin is never an
|
|
172
|
+
unread one. It is not `data-theme`, which the migration guide retires; it records
|
|
173
|
+
the provenance of a resolution and never a pack.
|
|
174
|
+
|
|
175
|
+
The migration clause reads `prism-theme-mode`, puts the recovered decision in
|
|
176
|
+
`prism-theme` and removes the key it read, in one guarded step. That is how it
|
|
177
|
+
expires: it fires only while a retired key still holds a mode, at most once per
|
|
178
|
+
reader, and it is retired for good by deleting the last entry of
|
|
179
|
+
`LEGACY_MODE_STORAGE_KEYS`. There is no date and no version constant in it.
|
|
180
|
+
|
|
181
|
+
The pre-paint string gets its own ceiling in raw bytes,
|
|
182
|
+
`check-boot-budget.mjs`, because it runs before paint on every page and adding it
|
|
183
|
+
to the per-component client budget would corrupt the unit that table measures. The
|
|
184
|
+
ceiling is derived by addition: the pinned non-migration base, plus the measured
|
|
185
|
+
clause, plus one migration generation.
|
|
186
|
+
- 76c8d96: Fourteen items, four catalogue gates, and a Block that publishes its interface
|
|
187
|
+
|
|
188
|
+
**Fourteen items ship.** Three Components (`Prose`, `FactList`, `ProductSwitcher`),
|
|
189
|
+
nine Blocks (`ProcessRail01`, `StatusLedger01`, `ProductGrid01`, `StackGrid01`,
|
|
190
|
+
`LogoStrip01`, `NoteGrid01`, `InstrumentPanel01`, `SiteHeader`, `SiteFooter`) and two
|
|
191
|
+
Pages (`NotFoundPage`, `BlogPostPage`). Every one of them earns its place by the
|
|
192
|
+
growth rule rather than by taste: a marketing Block when at least three of the four
|
|
193
|
+
sites compose that section today, a Component when it has one job no existing
|
|
194
|
+
Component can express. The evidence is in the ticket and in each item's own
|
|
195
|
+
JSDoc, which names the sites and the line numbers.
|
|
196
|
+
|
|
197
|
+
**The three contested shapes are settled as specified, and the specifications
|
|
198
|
+
held.** A process rail admits four steps and refuses five, in the type: `steps` is
|
|
199
|
+
a tuple union, so a five-element array is a compile error and not a fifth column. A
|
|
200
|
+
status ledger has four tiers rather than five, and the words for a tier are the
|
|
201
|
+
caller's: the four sites between them use eight words for those four states
|
|
202
|
+
(`live`, `available` and `complete` are one; `approved`, `specified` and `designed`
|
|
203
|
+
are one; then `planned`; then `direction`), and the vocabulary is what `statusLabel`
|
|
204
|
+
is for. A product row's mark is two parts because a filled dot fails contrast on a
|
|
205
|
+
light card, so the mark is `ProductMark`: a hairline ring in `brand-ink` around a
|
|
206
|
+
core in the product's own `primary` fill, with the name in the brand ink beside it.
|
|
207
|
+
|
|
208
|
+
**Four gates the catalogue's own rules depend on now exist and are wired into
|
|
209
|
+
`check` and, because they read only `src/`, into `build`.** `check-item-docs`
|
|
210
|
+
holds AGENTS.md's claim that a documentation comment is the only path from an Item
|
|
211
|
+
to its published interface. `check-block-copy` holds DESIGN.md's claim that a
|
|
212
|
+
Block ships no copy and no sample data. `check-item-category` holds CONTEXT.md's
|
|
213
|
+
closed set of seven Categories and the sentence that a Block and a Page have none.
|
|
214
|
+
`check-block-imports` holds the claim that a Block fetches nothing and a Page
|
|
215
|
+
imports no router and no data client. Each resolves its roots from its own
|
|
216
|
+
location, fails a root that resolves to nothing, prints its coverage and every
|
|
217
|
+
exclusion on every run, has no report-only mode, and is proved red by a fixture
|
|
218
|
+
before it is proved green.
|
|
219
|
+
|
|
220
|
+
**Two of those four gates were red on the tree they were written against, and both
|
|
221
|
+
findings were real.** `check-item-docs` found seven exported functions whose
|
|
222
|
+
documentation comment was not attached to the declaration: `CardHeader`,
|
|
223
|
+
`CardTitle`, `CardDescription`, `CardContent`, `CardFooter`, `SectionHeading` and
|
|
224
|
+
`Hero01`. A comment three functions above a declaration does not reach the emitted
|
|
225
|
+
`.d.ts`, so those seven were absent from the corpus. `check-block-copy` found
|
|
226
|
+
`pricing-01` rendering the word "Popular" on a featured plan that passed no badge:
|
|
227
|
+
a hardcoded claim every consumer of the Block inherited, published by the corpus as
|
|
228
|
+
part of the Block's own documentation. The fallback is gone; a featured plan with
|
|
229
|
+
no badge now renders no badge.
|
|
230
|
+
|
|
231
|
+
**Five additive fields on four shipped items**, each with three of the four
|
|
232
|
+
consumers passing a value the item could not take, counted per consumer with a
|
|
233
|
+
file and a line and never per string. `SectionHeading.index`, for the mono ordinal
|
|
234
|
+
all four sites render above every section head (www `Landing.tsx:49`, atlas
|
|
235
|
+
`landing.tsx:48`, nexus `Landing.tsx:38`, alphalens `Landing.tsx:66`).
|
|
236
|
+
`Cta01.secondaryAction`, for the pair of actions all four closing bands render
|
|
237
|
+
(www `Landing.tsx:186`, atlas `landing.tsx:243`, nexus `Landing.tsx:221`,
|
|
238
|
+
alphalens `Landing.tsx:285`). `Cta01.note`, for the footnote three of the four
|
|
239
|
+
render under it (atlas `landing.tsx:250`, nexus `Landing.tsx:228`, alphalens
|
|
240
|
+
`Landing.tsx:292`). `FeatureGrid01.numbered`, for the ordinal all four render on
|
|
241
|
+
every card (www `Landing.tsx:166`, atlas `landing.tsx:116`, nexus `Landing.tsx:132`,
|
|
242
|
+
alphalens `Landing.tsx:142`). `Hero01.align`, for the left-aligned hero three of
|
|
243
|
+
the four compose (atlas `landing.tsx:69`, nexus `Landing.tsx:63`, alphalens
|
|
244
|
+
`Landing.tsx:87`). All five are additive: nothing changed shape and nothing was
|
|
245
|
+
removed.
|
|
246
|
+
|
|
247
|
+
**A Block and a Page publish both an interface section and a composition section.**
|
|
248
|
+
`packages/llms` read the extractor's output for a Block and threw the interface half
|
|
249
|
+
away, so the tool told an agent a Block had no own props. The extractor reads a
|
|
250
|
+
named props type off an emitted declaration whether that declaration belongs to a
|
|
251
|
+
Component or to a Block, so both sections are now built and both are assembled into
|
|
252
|
+
the mirror file, `llms-full.txt` and the Store's `doc`.
|
|
253
|
+
|
|
254
|
+
The Store now carries both fields for every kind, and `get_item_props` prints
|
|
255
|
+
both when it has both. The sentence "a Block has no own props" is gone from the
|
|
256
|
+
tool as well as from the published document. It was the one place the two
|
|
257
|
+
sections were still exclusive, because that tool branched on `item.props` and
|
|
258
|
+
fell back to the composition section, so a Block was answered with its
|
|
259
|
+
composition and a denial of the interface it publishes. The test asserts the
|
|
260
|
+
sentence's absence, so a refactor that restores it fails even if the composition
|
|
261
|
+
is still printed, and a second test covers the one-present case so the
|
|
262
|
+
both-present branch cannot swallow it.
|
|
263
|
+
|
|
264
|
+
**Four accessible names became required props** on `SiteHeader`, `LogoStrip01`,
|
|
265
|
+
`NotFoundPage` and `BlogPostPage`, and a Block that ships no copy ships no
|
|
266
|
+
reader-facing copy either. `navLabel`, `productsLabel`, `label`, `linksLabel` and
|
|
267
|
+
`trailLabel` are words a screen reader reads out, and no Block should be choosing
|
|
268
|
+
them for a consumer whose site calls its own landmarks something else. This is the
|
|
269
|
+
one breaking change in the release, and it is on four new Blocks and two new Pages
|
|
270
|
+
plus one new required prop on `SiteHeader`, all of which are new in the same
|
|
271
|
+
release, so no existing call site changes.
|
|
272
|
+
|
|
273
|
+
**`ProductSwitcher.label` has no default** for the same reason: a consumer whose set
|
|
274
|
+
is not a set of products should pass its own word rather than accept a claim about
|
|
275
|
+
what the set is.
|
|
276
|
+
|
|
277
|
+
### Patch Changes
|
|
278
|
+
|
|
279
|
+
- 8d24f32: A pack boundary's effect on corner radius is stated, and gated
|
|
280
|
+
|
|
281
|
+
A scoped `data-pack` boundary resolves the pack's colour AND the pack's corner
|
|
282
|
+
radius beneath it, because radius is the only non-colour member of a pack block
|
|
283
|
+
and the token build emits it the same way. The radius range across the five packs
|
|
284
|
+
is 0.5rem to 1rem, so a row of elements each carrying its own pack shows a spread
|
|
285
|
+
of corner radii, and a small pill becomes a different pill five times over. The
|
|
286
|
+
governing law stated the colour half and was silent on the shape half, so an
|
|
287
|
+
implementer following it exactly produced mismatched corners and called it
|
|
288
|
+
correct.
|
|
289
|
+
|
|
290
|
+
The law now states both halves and where a boundary may sit. The agent-facing
|
|
291
|
+
surface no longer says the attribute belongs on the root element, which it did
|
|
292
|
+
while listing the radius among the values it will pick up: a tool that shows the
|
|
293
|
+
value and denies the subtree is worse than a tool that is silent.
|
|
294
|
+
|
|
295
|
+
`check-pack-boundary.mjs` holds the law. It reads the emitted `--radius-*`
|
|
296
|
+
bindings rather than a list of class names, which is the part that matters: a
|
|
297
|
+
scale step like `rounded-xl` is `calc(var(--radius) * 1.4)`, so an element
|
|
298
|
+
carrying one is pinned to a step and the step is pack-relative. The first version
|
|
299
|
+
of the gate treated "carries a radius utility" as the safe case and passed
|
|
300
|
+
exactly the defect the ticket is about. The gate also reads the colour contract
|
|
301
|
+
from the token source, so a second per-pack axis the token build has not been
|
|
302
|
+
asked about is a finding rather than a property silently counted as a colour.
|
|
303
|
+
|
|
304
|
+
One live boundary was found and repaired: the themes page scoped five cards, one
|
|
305
|
+
per pack, each with `rounded-xl`, so the page a reader uses to compare packs was
|
|
306
|
+
comparing shape as well as colour. The cards now carry a literal radius and the
|
|
307
|
+
pack's radius is shown in the row's own label, where it is information rather
|
|
308
|
+
than an accident.
|
|
309
|
+
- feb1384: The catalogue is a set comparison between three lists, not a count
|
|
310
|
+
|
|
311
|
+
A module on disk with no catalogue entry left every count correct. It shipped,
|
|
312
|
+
`shadcn add` installed it, and `registry.json` listed it, so it was absent from
|
|
313
|
+
the corpus, the documentation site and every agent-facing tool with a fully
|
|
314
|
+
green gate run. The two lists a reader trusts, the catalogue and the registry,
|
|
315
|
+
were on the wrong side of that hole, and the checks that believed they covered it
|
|
316
|
+
compared lengths or compared a file against something derived from itself.
|
|
317
|
+
`validate-registry.mjs` holds the registry against the disk and the manifest and
|
|
318
|
+
never reads the catalogue. `sync-registry.mjs` reads the disk, so it cannot
|
|
319
|
+
disagree with the disk about what is on it. The site's
|
|
320
|
+
`test/catalogue-order.test.ts` holds the catalogue against the generated
|
|
321
|
+
ordering and the documentation tree, and both are built from the catalogue, so a
|
|
322
|
+
disagreement there is impossible by construction.
|
|
323
|
+
|
|
324
|
+
`scripts/check-catalogue.mjs` reads the three sets independently and compares
|
|
325
|
+
them in both directions, name for name, with one printed line per offending
|
|
326
|
+
item. A length assertion cannot report which item is wrong, so nothing in the
|
|
327
|
+
run reports a length on its own: the three set sizes print as supplementary
|
|
328
|
+
coverage underneath the findings that carry the detail. All six directions a
|
|
329
|
+
three-set comparison implies are implemented, plus the kind of an item in each
|
|
330
|
+
pair of sets, the three naming rules that reconcile the three conventions, and a
|
|
331
|
+
claim that a canonical key is held by only one entry in each set.
|
|
332
|
+
|
|
333
|
+
The registry generator deliberately keeps reading the disk. Deriving the
|
|
334
|
+
registry from the catalogue is the obvious way to remove the second list, and it
|
|
335
|
+
would delete the disagreement the check exists to see, because the generator
|
|
336
|
+
would then agree with the catalogue by construction.
|
|
337
|
+
|
|
338
|
+
The version and the roster are two claims on two labelled lines, so a version
|
|
339
|
+
bump and a roster error cannot produce the same output. The run states its
|
|
340
|
+
coverage every time: roots resolved, files walked, files actually read, and how
|
|
341
|
+
many comparisons passed. Roots resolve from the script's own location and never
|
|
342
|
+
from the working directory, and a root that resolves to nothing fails the run
|
|
343
|
+
naming both causes.
|
|
344
|
+
|
|
345
|
+
`PRISM_CATALOGUE_ROOT` points a run at another package root. It changes which
|
|
346
|
+
directory is read and nothing else, which is what lets the tests run the real
|
|
347
|
+
command over a fixture tree and read the real output. The gate fails on a
|
|
348
|
+
catalogue it cannot read, including an empty one: a roster that cannot be read
|
|
349
|
+
and a roster with nothing in it are different facts, and only one of them is a
|
|
350
|
+
green run.
|
|
351
|
+
- 4744cce: The Slider thumb rings at full strength, and the surface check now reads both ways
|
|
352
|
+
|
|
353
|
+
Two changes, and only two, in the component package.
|
|
354
|
+
|
|
355
|
+
**The focus indicator.** The Slider's thumb suppressed the browser outline and
|
|
356
|
+
drew its ring at `ring-ring/50`, so the element a keyboard user lands on carried
|
|
357
|
+
an indicator that composites to between 1.14:1 and 2.74:1 against every surface
|
|
358
|
+
in all six themes. That fails WCAG 1.4.11 on the one indicator a keyboard user
|
|
359
|
+
has, and the Slider's own JSDoc says it is reachable by Tab. Thirteen other
|
|
360
|
+
components already drew that ring at full strength; the Slider was the one that
|
|
361
|
+
was missed. Nothing said so, because the contrast gate measures the `ring`
|
|
362
|
+
TOKEN and the alpha is applied in the component rather than in the token, so it
|
|
363
|
+
reads the Slider's ring as compliant.
|
|
364
|
+
|
|
365
|
+
`packages/ui/scripts/check-focus-indicators.mjs` is the new gate. It reads the
|
|
366
|
+
class strings on the elements of every shipped Component, derives the set of
|
|
367
|
+
components whose own JSDoc claims keyboard reach or operation, and fails any of
|
|
368
|
+
them that suppresses a focus style without declaring a `ring-ring` colour at
|
|
369
|
+
full alpha alongside a `focus-visible:ring-N` width. The claim is read from the
|
|
370
|
+
JSDoc because `AGENTS.md` names that as this repository's documentation source,
|
|
371
|
+
so a component that stops claiming to be focusable is a documentation change and
|
|
372
|
+
shows up in the table the run prints rather than in a list someone maintains
|
|
373
|
+
beside the code. The unit is a class string on one element, so a Dialog's panel
|
|
374
|
+
or a Tooltip's trigger can suppress the outline legitimately; every such
|
|
375
|
+
exclusion is declared with its reason, printed with the slots it resolved to,
|
|
376
|
+
and fails the run if it stops matching anything. The run fails if the table
|
|
377
|
+
empties, and states how much it read, classified, tabled and excluded.
|
|
378
|
+
|
|
379
|
+
**The surface check.** `scripts/check-surface.mjs` compared the published
|
|
380
|
+
surface against the source in one direction for two of its three rules. A
|
|
381
|
+
wildcard subpath that resolved to zero declarations used to leave those two
|
|
382
|
+
rules reading no file at all and the run still printed its success line, which is
|
|
383
|
+
how a published surface drifts from its source without a consumer failing first.
|
|
384
|
+
A wildcard target that matches nothing is now a finding naming the target. The
|
|
385
|
+
internal side, which the gate deliberately did not check, is now a declared
|
|
386
|
+
boundary checked in both directions: a new file under `dist/lib` is a finding
|
|
387
|
+
naming it, and a declared internal declaration that is no longer emitted is a
|
|
388
|
+
finding naming it too. The boundary and the per-target match counts are printed
|
|
389
|
+
on every run. The three existing rules and their messages are unchanged.
|
|
390
|
+
|
|
391
|
+
**The version the four downstream site plans pin is `0.6.0`.** It is
|
|
392
|
+
`@nanisoft/prism-ui@0.6.0`, and `@nanisoft/prism-tokens@0.6.0` with it, because
|
|
393
|
+
the two are linked in `.changeset/config.json` and the pending
|
|
394
|
+
`a-server-rendered-pack-boundary-can-be-mode-correct` changeset declares a minor
|
|
395
|
+
for both from `0.5.1`. The patch declared here does not raise it: changesets
|
|
396
|
+
takes the highest bump in the queue, and a minor is already queued. A site plan
|
|
397
|
+
that pins `0.6.0` therefore resolves every subpath the export map publishes,
|
|
398
|
+
including `./components`, `./blocks`, `./pages`, `./provider`, `./theming`,
|
|
399
|
+
`./catalog` and `./styles.css`.
|
|
400
|
+
|
|
401
|
+
No public prop, no type and no export changed. The one rendering change is a
|
|
402
|
+
ring alpha on the Slider thumb, in both modes.
|
|
403
|
+
- Updated dependencies [4f9ce77]
|
|
404
|
+
- Updated dependencies [5dcb347]
|
|
405
|
+
- @nanisoft/prism-tokens@0.6.0
|
|
406
|
+
|
|
407
|
+
## 0.5.1
|
|
408
|
+
|
|
409
|
+
### Patch Changes
|
|
410
|
+
|
|
411
|
+
- 2fc6a0a: Retune `muted-foreground` so muted text clears 4.5:1 on the muted surface
|
|
412
|
+
|
|
413
|
+
The base pack's `muted-foreground` moves from neutral 500 to neutral 600. It
|
|
414
|
+
cleared 4.5:1 on the page background but fell to 4.34:1 on `muted`, where the
|
|
415
|
+
pill, avatar fallback, kbd and tab-list pattern place it. The contrast gate now
|
|
416
|
+
also checks `muted-foreground` on `muted`. The pastel packs were already pinned
|
|
417
|
+
to their neutral 700 and are unchanged.
|
|
418
|
+
- Updated dependencies [2fc6a0a]
|
|
419
|
+
- @nanisoft/prism-tokens@0.5.1
|
|
420
|
+
|
|
421
|
+
## 0.5.0
|
|
422
|
+
|
|
423
|
+
Prism was rebuilt from a fresh repository on a clean break. The package is now a
|
|
424
|
+
published React library a consumer installs and composes, not component source to
|
|
425
|
+
copy. It ships one precompiled `styles.css`, the optional `PrismProvider` and the
|
|
426
|
+
`data-pack` plus `dark` theme axes, and the Components, Blocks and Pages
|
|
427
|
+
taxonomy. There is no override path.
|
|
428
|
+
|
|
429
|
+
Changesets are appended above this entry for every published change.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Accordion
|
|
2
|
+
|
|
3
|
+
The stack of headers that each reveal a panel in place.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@nanisoft/prism-ui/components/accordion'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
An Accordion is a stack of headers that each reveal a panel in place. It ships
|
|
12
|
+
as `Accordion`, `AccordionItem`, `AccordionTrigger` and `AccordionContent`, all
|
|
13
|
+
from the same module. Only one item is open at a time unless `multiple` is set.
|
|
14
|
+
|
|
15
|
+
Each trigger is a real button, and the library ties it to its panel, so the
|
|
16
|
+
header announces whether the item is expanded. Enter or Space opens the focused
|
|
17
|
+
item, and the header text stays visible when the panel is closed.
|
|
18
|
+
|
|
19
|
+
## Guidelines
|
|
20
|
+
|
|
21
|
+
### When to use
|
|
22
|
+
|
|
23
|
+
Use an Accordion when a page holds several long sections that a reader opens
|
|
24
|
+
selectively: frequently asked questions, advanced settings, or a policy split
|
|
25
|
+
into questions.
|
|
26
|
+
|
|
27
|
+
### When not to use
|
|
28
|
+
|
|
29
|
+
Do not use an Accordion when the reader needs two sections side by side. Only
|
|
30
|
+
one is open at a time by default, so comparison is impossible.
|
|
31
|
+
|
|
32
|
+
Do not use it to hide the primary content of a page. If a section is essential,
|
|
33
|
+
it should be open, not behind a click.
|
|
34
|
+
|
|
35
|
+
Do not use an Accordion for a short list of statements. A definition list reads
|
|
36
|
+
better and needs no interaction.
|
|
37
|
+
|
|
38
|
+
### Best practices
|
|
39
|
+
|
|
40
|
+
- Give every `AccordionItem` a stable `value`, and control the open set with
|
|
41
|
+
`value` and `onValueChange` when the state matters beyond the component.
|
|
42
|
+
- Open the item a reader most likely wants first, or none at all. Opening all of
|
|
43
|
+
them restores the wall of text the accordion was meant to break up.
|
|
44
|
+
- Use one heading level for the triggers. Each header is a heading element, so
|
|
45
|
+
the accordion participates in the page outline.
|
|
46
|
+
- Keep the trigger text a short question or label the reader can scan without
|
|
47
|
+
opening the panel.
|
|
48
|
+
- Set `multiple` only when the sections are truly independent and comparing them
|
|
49
|
+
is a normal task.
|
|
50
|
+
|
|
51
|
+
### Content guidelines
|
|
52
|
+
|
|
53
|
+
- Phrase the trigger as the question or the topic, not as "Click to expand".
|
|
54
|
+
- Use sentence case and a question mark on a question, no period on a label.
|
|
55
|
+
- Keep the panel prose self-contained. A reader who opens one item should not
|
|
56
|
+
need another to make sense of it.
|
|
57
|
+
|
|
58
|
+
**An accordion with one panel open and the rest available on demand.**
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
'use client'
|
|
62
|
+
|
|
63
|
+
import {
|
|
64
|
+
Accordion,
|
|
65
|
+
AccordionContent,
|
|
66
|
+
AccordionItem,
|
|
67
|
+
AccordionTrigger,
|
|
68
|
+
} from '@nanisoft/prism-ui/components/accordion'
|
|
69
|
+
|
|
70
|
+
/** An accordion with one panel open and the rest available on demand. */
|
|
71
|
+
export default function AccordionDemo() {
|
|
72
|
+
return (
|
|
73
|
+
<Accordion defaultValue={['shipping']} className="max-w-measure-narrow">
|
|
74
|
+
<AccordionItem value="shipping">
|
|
75
|
+
<AccordionTrigger>How long does shipping take?</AccordionTrigger>
|
|
76
|
+
<AccordionContent>
|
|
77
|
+
Orders leave the warehouse within one working day and arrive in two to
|
|
78
|
+
five, depending on the region.
|
|
79
|
+
</AccordionContent>
|
|
80
|
+
</AccordionItem>
|
|
81
|
+
<AccordionItem value="returns">
|
|
82
|
+
<AccordionTrigger>What is the return window?</AccordionTrigger>
|
|
83
|
+
<AccordionContent>
|
|
84
|
+
Return anything unused within thirty days for a full refund.
|
|
85
|
+
</AccordionContent>
|
|
86
|
+
</AccordionItem>
|
|
87
|
+
<AccordionItem value="support">
|
|
88
|
+
<AccordionTrigger>How do I reach support?</AccordionTrigger>
|
|
89
|
+
<AccordionContent>
|
|
90
|
+
Reply to any order email, or write to support and include the order
|
|
91
|
+
number.
|
|
92
|
+
</AccordionContent>
|
|
93
|
+
</AccordionItem>
|
|
94
|
+
</Accordion>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Props
|
|
100
|
+
|
|
101
|
+
**`value`** `string[]` · optional · default: — — The open item values, when the accordion is controlled.
|
|
102
|
+
**`defaultValue`** `string[]` · optional · default: — — The item values open initially, for an uncontrolled accordion.
|
|
103
|
+
**`onValueChange`** `(value: string[]) => void` · optional · default: — — Called when the open set changes.
|
|
104
|
+
**`multiple`** `boolean` · optional · default: — — Whether more than one item may be open at once.
|
|
105
|
+
**`disabled`** `boolean` · optional · default: — — Whether every item ignores user interaction.
|
|
106
|
+
**`hiddenUntilFound`** `boolean` · optional · default: — — Whether the browser's page search may expand a panel.
|
|
107
|
+
**`keepMounted`** `boolean` · optional · default: — — Whether a closed panel stays in the DOM.
|
|
108
|
+
**`onOpenChange`** `(open: boolean) => void` · optional · default: — — Called when this item opens or closes.
|