@nanisoft/prism-llms 0.3.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 +3998 -375
- 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 +7988 -1989
- package/dist/llms.txt +97 -91
- 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 +111 -0
- package/dist/md/blocks/site-header.md +119 -0
- 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,88 @@
|
|
|
1
|
+
# ProductSwitcher
|
|
2
|
+
|
|
3
|
+
A switch between the members of a set of products, each drawn with its own ProductMark and the current one marked aria-current.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { ProductSwitcher } from '@nanisoft/prism-ui/components/product-switcher'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A ProductSwitcher is a switch between the members of a set of products. Each
|
|
12
|
+
member is drawn with its own `ProductMark`, so the two parts of a product's
|
|
13
|
+
identity - the ring in the brand ink and the core in its own pack fill - are the
|
|
14
|
+
same two colours in a switcher, in a row and on a page header.
|
|
15
|
+
|
|
16
|
+
All four NaniSoft sites need it and each one wrote it: the company's own site
|
|
17
|
+
moves between its products from a row of coloured marks, and each product site
|
|
18
|
+
names its siblings in its header.
|
|
19
|
+
|
|
20
|
+
## Guidelines
|
|
21
|
+
|
|
22
|
+
### When to use
|
|
23
|
+
|
|
24
|
+
Use a ProductSwitcher where a reader can move between whole products rather than
|
|
25
|
+
between pages of one: a site header, a footer, a page that lists the family.
|
|
26
|
+
|
|
27
|
+
Use one size across the whole switcher. A set where one mark is larger than the
|
|
28
|
+
rest reads as a hierarchy that is not there.
|
|
29
|
+
|
|
30
|
+
### When not to use
|
|
31
|
+
|
|
32
|
+
Do not use a ProductSwitcher to switch between pages of one product. That is
|
|
33
|
+
`Pagination` or `Tabs`, and a set of product marks is a claim about where the
|
|
34
|
+
reader is, not a position in a sequence.
|
|
35
|
+
|
|
36
|
+
Do not use it for a set of one. Pass nothing rather than a switcher with a single
|
|
37
|
+
member; a switcher with nothing to switch to is a heading.
|
|
38
|
+
|
|
39
|
+
Do not use it as a menu. It renders every member at once. If you want a control
|
|
40
|
+
that opens a list, compose `DropdownMenu` with the marks.
|
|
41
|
+
|
|
42
|
+
### Best practices
|
|
43
|
+
|
|
44
|
+
- Pass `currentId` on the page a member is showing, and omit it on a page that is
|
|
45
|
+
not one of the members.
|
|
46
|
+
- The current member is marked with `aria-current="page"`, never with a colour
|
|
47
|
+
alone. There is no prop that overrides that marking, which is the reason this
|
|
48
|
+
is a component rather than a list of anchors you write yourself.
|
|
49
|
+
- Leave `pack` off the one member that has no pack of its own. That member wears
|
|
50
|
+
the full spectrum, which says "no single colour" once rather than five times.
|
|
51
|
+
- Pass `label` when the set is not a set of products. The default name is
|
|
52
|
+
`Products`, and a consumer whose set is not products should pass its own word.
|
|
53
|
+
|
|
54
|
+
### Content guidelines
|
|
55
|
+
|
|
56
|
+
- Use each product's own name, in the case it uses everywhere else.
|
|
57
|
+
- Keep a name to one or two words. The mark carries the identity; the name carries
|
|
58
|
+
the label.
|
|
59
|
+
- Never abbreviate a name to fit beside its mark. Drop the mark, shorten the row,
|
|
60
|
+
or let the name wrap.
|
|
61
|
+
|
|
62
|
+
**Three members, with the one the reader is on marked, and one wearing the spectrum.**
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { ProductSwitcher } from '@nanisoft/prism-ui/components/product-switcher'
|
|
66
|
+
|
|
67
|
+
/** Three members, with the one the reader is on marked, and one wearing the spectrum. */
|
|
68
|
+
export default function ProductSwitcherDemo() {
|
|
69
|
+
return (
|
|
70
|
+
<ProductSwitcher
|
|
71
|
+
currentId="nexus"
|
|
72
|
+
products={[
|
|
73
|
+
{ id: 'nexus', name: 'Nexus', pack: 'lavender', href: '#nexus' },
|
|
74
|
+
{ id: 'atlas', name: 'Atlas', pack: 'mint', href: '#atlas' },
|
|
75
|
+
{ id: 'www', name: 'NaniSoft', href: '#www' },
|
|
76
|
+
]}
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Props
|
|
83
|
+
|
|
84
|
+
**`products`** `readonly SwitcherProduct[]` · required · default: — — The set to move between, in the order a reader should meet it. Order is the caller's because it is a claim about which product matters first.
|
|
85
|
+
**`currentId`** `string` · optional · default: — — The `id` of the member the reader is on. Marked `aria-current="page"`, which is how a reader and a screen reader both know where they are. Omit it when the switcher is rendered on a page that is not one of the members.
|
|
86
|
+
**`size`** `ProductMarkSize` · optional · default: `'sm'` — The drawn size of every mark, so a set shows one size rather than a mix. See `ProductMarkSize`.
|
|
87
|
+
**`label`** `string` · optional · default: — — A heading for the set, for a switcher that is not inside a landmark the reader can already name. Rendered as the navigation's accessible name and as no visible text, because the marks beside it are the labels.
|
|
88
|
+
**`className`** `string` · optional · default: — — Layout only, exactly as on every Component. Changing a Prism-owned visual property from here is prohibited.
|
|
@@ -1,14 +1,95 @@
|
|
|
1
1
|
# Progress
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The bar that reports how far a task has progressed.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
import { Progress } from '@nanisoft/prism-ui/components'
|
|
5
|
+
```tsx
|
|
6
|
+
import { Progress } from '@nanisoft/prism-ui/components/progress'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Overview
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
A Progress bar reports how far a task has progressed. It exposes its value, its
|
|
12
|
+
minimum and its maximum through ARIA, so a screen reader announces the position
|
|
13
|
+
rather than the width of a coloured bar. Pass a number for a task of known
|
|
14
|
+
length, or `value={null}` for a task whose end is unknown, which is announced as
|
|
15
|
+
indeterminate.
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
The bar is a status, not a control. The reader watches it; nothing about it is
|
|
18
|
+
clickable or focusable. Decorative movement is deliberately absent: the bar
|
|
19
|
+
changes width only when the value changes.
|
|
20
|
+
|
|
21
|
+
## Guidelines
|
|
22
|
+
|
|
23
|
+
### When to use
|
|
24
|
+
|
|
25
|
+
Use Progress when a process has measurable steps and the reader benefits from
|
|
26
|
+
knowing how much is left: an upload, a build, a migration, a batch import.
|
|
27
|
+
|
|
28
|
+
### When not to use
|
|
29
|
+
|
|
30
|
+
Do not use Progress for a short wait under about a second. A spinner or a
|
|
31
|
+
disabled control is quieter and more honest.
|
|
32
|
+
|
|
33
|
+
Do not use it as a loading placeholder for content whose shape you know. A
|
|
34
|
+
Skeleton mirrors the layout that is coming and reduces the sense of waiting.
|
|
35
|
+
|
|
36
|
+
Do not use an indeterminate bar for a task of known length. Showing a moving bar
|
|
37
|
+
for a countable task hides real information.
|
|
38
|
+
|
|
39
|
+
### Best practices
|
|
40
|
+
|
|
41
|
+
- Give the bar an accessible name with `aria-label` or an adjacent heading, so
|
|
42
|
+
the value is announced against a subject.
|
|
43
|
+
- Show the value as text next to the bar when the reader needs the number, and
|
|
44
|
+
keep it in step with the bar.
|
|
45
|
+
- Use `value={null}` only while the length is genuinely unknown, and switch to a
|
|
46
|
+
number as soon as one is available.
|
|
47
|
+
- Announce completion in the surrounding UI. A bar that disappears at 100
|
|
48
|
+
percent leaves the reader unsure whether it finished or failed.
|
|
49
|
+
- For a task that fails partway, replace the bar with an Alert that names the
|
|
50
|
+
failure rather than leaving it frozen.
|
|
51
|
+
|
|
52
|
+
### Content guidelines
|
|
53
|
+
|
|
54
|
+
- Name the task in progress, not the component: "Uploading assets", "Preparing
|
|
55
|
+
preview".
|
|
56
|
+
- Use sentence case and a verb ending in "ing" for the in-progress label.
|
|
57
|
+
- Keep the completion message separate and past tense: "Upload complete".
|
|
58
|
+
|
|
59
|
+
**Progress at a known value, an unknown length, and complete.**
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import { Progress } from '@nanisoft/prism-ui/components/progress'
|
|
63
|
+
|
|
64
|
+
/** Progress at a known value, an unknown length, and complete. */
|
|
65
|
+
export default function ProgressDemo() {
|
|
66
|
+
return (
|
|
67
|
+
<div className="flex max-w-measure-narrow flex-col gap-8">
|
|
68
|
+
<div className="flex flex-col gap-2">
|
|
69
|
+
<div className="flex items-center justify-between text-sm">
|
|
70
|
+
<span className="font-medium">Uploading assets</span>
|
|
71
|
+
<span className="text-muted-foreground">68%</span>
|
|
72
|
+
</div>
|
|
73
|
+
<Progress value={68} aria-label="Uploading assets" />
|
|
74
|
+
</div>
|
|
75
|
+
<div className="flex flex-col gap-2">
|
|
76
|
+
<span className="font-medium text-sm">Preparing preview</span>
|
|
77
|
+
<Progress value={null} aria-label="Preparing preview" />
|
|
78
|
+
</div>
|
|
79
|
+
<div className="flex flex-col gap-2">
|
|
80
|
+
<span className="font-medium text-sm">Build complete</span>
|
|
81
|
+
<Progress value={100} aria-label="Build complete" />
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Props
|
|
89
|
+
|
|
90
|
+
**`value`** `number | null` · required · default: — — The current value. Pass `null` for an indeterminate task. There is no default: a progress bar without a value is a claim, so the consumer states where the task is.
|
|
91
|
+
**`max`** `number` · optional · default: `100` — The maximum value.
|
|
92
|
+
**`min`** `number` · optional · default: `0` — The minimum value.
|
|
93
|
+
**`format`** `Intl.NumberFormatOptions` · optional · default: — — Options passed to `Intl.NumberFormat` when the value is rendered.
|
|
94
|
+
**`locale`** `Intl.LocalesArgument` · optional · default: — — The locale used when formatting the value.
|
|
95
|
+
**`getAriaValueText`** `(formattedValue: string, value: number | null) => string` · optional · default: — — Returns the text alternative announced for a value.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Prose
|
|
2
|
+
|
|
3
|
+
Consumer-authored body copy held to the reading measure and to the block rhythm, so a document does not restate either.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Prose } from '@nanisoft/prism-ui/components/prose'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A Prose is a run of body copy you wrote, held to the reading measure and to the
|
|
12
|
+
block rhythm so a document does not have to restate either. You pass the content
|
|
13
|
+
as `children`; Prism owns the width, the spacing between blocks and the
|
|
14
|
+
treatments.
|
|
15
|
+
|
|
16
|
+
Every NaniSoft site publishes long-form pages, and each one re-derived the same
|
|
17
|
+
answer: a column that stops growing, paragraphs that are too far apart or too
|
|
18
|
+
close, and a link that is either an unstyled word or an over-decorated one. This
|
|
19
|
+
is that answer once.
|
|
20
|
+
|
|
21
|
+
## Guidelines
|
|
22
|
+
|
|
23
|
+
### When to use
|
|
24
|
+
|
|
25
|
+
Use a Prose wherever the content is authored somewhere else and Prism should own
|
|
26
|
+
its presentation: a blog post body, a documentation page, a description that
|
|
27
|
+
turned out to be three paragraphs.
|
|
28
|
+
|
|
29
|
+
The treatments are child selectors, so your own elements are the ones styled.
|
|
30
|
+
Writing a plain `<p>` and a plain `<h2>` gets the system treatment, and writing
|
|
31
|
+
Prism's own `Heading` and `Text` gets the same result, because the two spellings
|
|
32
|
+
converge on the same element.
|
|
33
|
+
|
|
34
|
+
### When not to use
|
|
35
|
+
|
|
36
|
+
Do not use a Prose for a supporting line under a heading. That is `Text`, and a
|
|
37
|
+
measure around one sentence is a measure around one sentence.
|
|
38
|
+
|
|
39
|
+
Do not use it to fix a width. The measure is the component's whole job, and a run
|
|
40
|
+
set wider than the measure is the defect it exists to remove. `fullWidth` exists
|
|
41
|
+
for the case where the prose genuinely is not a reading column, and it is opt-in
|
|
42
|
+
on purpose.
|
|
43
|
+
|
|
44
|
+
### Best practices
|
|
45
|
+
|
|
46
|
+
- Pass plain semantic elements. Do not add class names of your own to size or
|
|
47
|
+
colour text; that is the override path this system does not have.
|
|
48
|
+
- Keep heading levels consistent with the document. A Prose does not know what
|
|
49
|
+
surrounds it.
|
|
50
|
+
- Use `size="lg"` for a marketing page's supporting copy and the default for a
|
|
51
|
+
document body. Do not mix the two on one page.
|
|
52
|
+
|
|
53
|
+
### Content guidelines
|
|
54
|
+
|
|
55
|
+
- Aim for a sentence or two per paragraph. A paragraph a reader scrolls past is a
|
|
56
|
+
paragraph that needed to be two.
|
|
57
|
+
- Link the first mention of a term, not every mention.
|
|
58
|
+
- Use a list when the items are peers. A list of sentences is a paragraph with
|
|
59
|
+
punctuation.
|
|
60
|
+
|
|
61
|
+
**A run of prose, with the block treatments applied to the caller's own elements.**
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { Prose } from '@nanisoft/prism-ui/components/prose'
|
|
65
|
+
|
|
66
|
+
/** A run of prose, with the block treatments applied to the caller's own elements. */
|
|
67
|
+
export default function ProseDemo() {
|
|
68
|
+
return (
|
|
69
|
+
<Prose>
|
|
70
|
+
<h2>A heading</h2>
|
|
71
|
+
<p>
|
|
72
|
+
A paragraph of body copy, held to the reading measure. The measure is the
|
|
73
|
+
emitted container-measure token, so a line stops growing at the same place
|
|
74
|
+
in every pack and in both modes.
|
|
75
|
+
</p>
|
|
76
|
+
<ul>
|
|
77
|
+
<li>Lists are styled as part of the run.</li>
|
|
78
|
+
<li>So are code, quotations, tables and headings.</li>
|
|
79
|
+
</ul>
|
|
80
|
+
<blockquote>A quotation keeps the muted ink and a left rule.</blockquote>
|
|
81
|
+
</Prose>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Props
|
|
87
|
+
|
|
88
|
+
**`children`** `ReactNode` · required · default: — — The authored body. Any flow content: paragraphs, lists, headings, tables, code, images. The vertical rhythm and the treatments below apply to whatever is passed, so the caller writes plain elements and Prism styles them.
|
|
89
|
+
**`size`** `ProseSize` · optional · default: `'base'` — The reading size. `base` is the document body; `lg` is the one step up a marketing page's supporting copy is set at.
|
|
90
|
+
**`fullWidth`** `boolean` · optional · default: — — Drops the measure so the run fills the space it is given. The measure is the whole point of the component, so this is opt-in and not a prop a caller sets because the width looked wrong: a line longer than the measure is the defect this exists to remove.
|
|
91
|
+
**`className`** `string` · optional · default: — — Layout only, exactly as on every Component. Changing a Prism-owned visual property from here is prohibited.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# RadioGroup
|
|
2
|
+
|
|
3
|
+
The control that chooses exactly one option from a small visible set.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { RadioGroup, RadioGroupItem } from '@nanisoft/prism-ui/components/radio-group'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A RadioGroup chooses exactly one option from a small set that stays visible. It
|
|
12
|
+
ships as `RadioGroup` and `RadioGroupItem`. The group owns the value and the
|
|
13
|
+
keyboard model; each item contributes one value.
|
|
14
|
+
|
|
15
|
+
The group is a single Tab stop. Once focus is inside, the arrow keys move
|
|
16
|
+
between items and select as they move, Home and End jump to the ends, and Space
|
|
17
|
+
selects the focused item. The selected item is exposed through the native radio
|
|
18
|
+
input beside each control.
|
|
19
|
+
|
|
20
|
+
## Guidelines
|
|
21
|
+
|
|
22
|
+
### When to use
|
|
23
|
+
|
|
24
|
+
Use a RadioGroup when the options are mutually exclusive and few enough that
|
|
25
|
+
showing them all at once helps the reader compare. Two to five options is the
|
|
26
|
+
comfortable range.
|
|
27
|
+
|
|
28
|
+
### When not to use
|
|
29
|
+
|
|
30
|
+
Do not use a RadioGroup for a long list. Past roughly seven options, a Select
|
|
31
|
+
keeps the form compact and adds typeahead.
|
|
32
|
+
|
|
33
|
+
Do not use one when several answers may stand together. Checkboxes state that
|
|
34
|
+
each choice is independent; radio items imply a single answer.
|
|
35
|
+
|
|
36
|
+
### Best practices
|
|
37
|
+
|
|
38
|
+
- Give the group a visible legend or an `aria-label`. The group's name is what
|
|
39
|
+
the reader hears when focus enters, so it must describe the question.
|
|
40
|
+
- Put one item per row with the label beside its control, and point `FieldLabel`
|
|
41
|
+
at the item's `id` so the whole row is clickable.
|
|
42
|
+
- Do not pre-check an option the reader has not chosen unless it is a genuine
|
|
43
|
+
default you would defend.
|
|
44
|
+
- Use `disabled` only with nearby text that explains why, not to hide an option
|
|
45
|
+
that should not be offered.
|
|
46
|
+
- Keep the item order stable across renders. Reordering radio items when a
|
|
47
|
+
value changes makes the group feel unpredictable.
|
|
48
|
+
|
|
49
|
+
### Content guidelines
|
|
50
|
+
|
|
51
|
+
- Keep option labels parallel in form and length, so the differences are easy
|
|
52
|
+
to weigh.
|
|
53
|
+
- Use sentence case and no trailing periods on the option labels.
|
|
54
|
+
- Put an explanation in a helper line under the label, not in the label itself.
|
|
55
|
+
|
|
56
|
+
**A radio group with one option preselected and one disabled.**
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
'use client'
|
|
60
|
+
|
|
61
|
+
import { FieldLabel } from '@nanisoft/prism-ui/components/field'
|
|
62
|
+
import { RadioGroup, RadioGroupItem } from '@nanisoft/prism-ui/components/radio-group'
|
|
63
|
+
|
|
64
|
+
/** A radio group with one option preselected and one disabled. */
|
|
65
|
+
export default function RadioGroupDemo() {
|
|
66
|
+
return (
|
|
67
|
+
<RadioGroup
|
|
68
|
+
defaultValue="daily"
|
|
69
|
+
aria-label="Notification frequency"
|
|
70
|
+
className="max-w-measure-narrow"
|
|
71
|
+
>
|
|
72
|
+
<div className="flex items-start gap-3">
|
|
73
|
+
<RadioGroupItem id="radio-daily" value="daily" className="mt-0.5" />
|
|
74
|
+
<div className="flex flex-col gap-1">
|
|
75
|
+
<FieldLabel htmlFor="radio-daily">Daily digest</FieldLabel>
|
|
76
|
+
<span className="text-muted-foreground text-sm">One message each morning.</span>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
<div className="flex items-start gap-3">
|
|
80
|
+
<RadioGroupItem id="radio-weekly" value="weekly" className="mt-0.5" />
|
|
81
|
+
<div className="flex flex-col gap-1">
|
|
82
|
+
<FieldLabel htmlFor="radio-weekly">Weekly summary</FieldLabel>
|
|
83
|
+
<span className="text-muted-foreground text-sm">One message on Monday.</span>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="flex items-start gap-3">
|
|
87
|
+
<RadioGroupItem id="radio-never" value="never" disabled className="mt-0.5" />
|
|
88
|
+
<div className="flex flex-col gap-1">
|
|
89
|
+
<FieldLabel htmlFor="radio-never" className="text-muted-foreground">
|
|
90
|
+
Never
|
|
91
|
+
</FieldLabel>
|
|
92
|
+
<span className="text-muted-foreground text-sm">
|
|
93
|
+
Disabled while an audit hold is active.
|
|
94
|
+
</span>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</RadioGroup>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Props
|
|
103
|
+
|
|
104
|
+
**`value`** `string` · optional · default: — — The selected item's value, when the group is controlled.
|
|
105
|
+
**`defaultValue`** `string` · optional · default: — — The item selected initially, for an uncontrolled group.
|
|
106
|
+
**`onValueChange`** `(value: string) => void` · optional · default: — — Called when the selection changes.
|
|
107
|
+
**`name`** `string` · optional · default: — — The form field name submitted with the form.
|
|
108
|
+
**`form`** `string` · optional · default: — — Identifies the form that owns the hidden inputs.
|
|
109
|
+
**`disabled`** `boolean` · optional · default: — — Whether every item ignores user interaction.
|
|
110
|
+
**`readOnly`** `boolean` · optional · default: — — Whether the user may not change the selection.
|
|
111
|
+
**`required`** `boolean` · optional · default: — — Whether a value must be chosen before the form submits.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Section
|
|
2
|
+
|
|
3
|
+
The container and heading primitives every Block composes for rhythm.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Section, SectionHeading } from '@nanisoft/prism-ui/components/section'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
`Section` is the container primitive every Block composes. It owns the page
|
|
12
|
+
container width and the vertical rhythm (`py-16 sm:py-24`), so one page keeps one
|
|
13
|
+
rhythm instead of each block re-deriving its own padding.
|
|
14
|
+
|
|
15
|
+
`SectionHeading` is the heading that sits inside it: an optional eyebrow, a
|
|
16
|
+
title, and an optional description. Its `as` prop selects the heading level, and
|
|
17
|
+
it defaults to `h2` because a Block is composed rather than a page.
|
|
18
|
+
|
|
19
|
+
## Guidelines
|
|
20
|
+
|
|
21
|
+
### When to use
|
|
22
|
+
|
|
23
|
+
Use `Section` for any full-width band of a page, and `SectionHeading` for the
|
|
24
|
+
heading that introduces it. A Block uses both, and a page composition uses them
|
|
25
|
+
between blocks to keep the rhythm continuous.
|
|
26
|
+
|
|
27
|
+
Use `SectionHeading` with `as="h1"` when the section is the page's primary
|
|
28
|
+
heading, and with a deeper level when the document already names the content.
|
|
29
|
+
|
|
30
|
+
### When not to use
|
|
31
|
+
|
|
32
|
+
Do not use `Section` for a card or an inline group. It is a page-level band, and
|
|
33
|
+
its padding is the page's vertical rhythm; nesting it produces uneven spacing.
|
|
34
|
+
|
|
35
|
+
Do not re-declare the container width or the section padding at a call site. If
|
|
36
|
+
a band needs a different width, that is a token or a component change, not a
|
|
37
|
+
`max-w-*` on the section.
|
|
38
|
+
|
|
39
|
+
### Best practices
|
|
40
|
+
|
|
41
|
+
- One `h1` per page. Every other heading nests under it, and `SectionHeading`'s
|
|
42
|
+
default `h2` is the level below the page title.
|
|
43
|
+
- Pass `headingLevel` or `as` at the call site when a Block sits under a heading
|
|
44
|
+
the document already owns, so the outline stays single-rooted.
|
|
45
|
+
- Keep `eyebrow` opt-in. It has no default, because a hardcoded eyebrow makes
|
|
46
|
+
every consumer inherit a claim about their product.
|
|
47
|
+
- Use `align="left"` for data sections and the centered default for hero and
|
|
48
|
+
closing sections, and keep the choice consistent within a page.
|
|
49
|
+
|
|
50
|
+
### Content guidelines
|
|
51
|
+
|
|
52
|
+
- A heading is a noun phrase in sentence case.
|
|
53
|
+
- A description is one or two sentences and states the section's job.
|
|
54
|
+
- An eyebrow is a short label, three words at most, and it never repeats the
|
|
55
|
+
heading.
|
|
56
|
+
|
|
57
|
+
**A section band with a heading, at a heading level the demo owns.**
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { Section, SectionHeading } from '@nanisoft/prism-ui/components/section'
|
|
61
|
+
|
|
62
|
+
/** A section band with a heading, at a heading level the demo owns. */
|
|
63
|
+
export default function SectionDemo() {
|
|
64
|
+
return (
|
|
65
|
+
<Section className="bg-muted/30 rounded-xl">
|
|
66
|
+
<SectionHeading
|
|
67
|
+
as="h3"
|
|
68
|
+
eyebrow="Release 2.4"
|
|
69
|
+
title="What changed"
|
|
70
|
+
description="Three fixes and one new block. No token changes."
|
|
71
|
+
align="left"
|
|
72
|
+
className="mb-6"
|
|
73
|
+
/>
|
|
74
|
+
<p className="text-muted-foreground text-sm">
|
|
75
|
+
The section owns the container width and the vertical rhythm, so this
|
|
76
|
+
band keeps the page's spacing without re-declaring it.
|
|
77
|
+
</p>
|
|
78
|
+
</Section>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Props
|
|
84
|
+
|
|
85
|
+
**`index`** `string` · optional · default: — — A short ordinal for the section: "01", "02", "7". It is rendered in the mono face above the title, because a section's position in a sequence is machine notation rather than a word, and the mono stack is what this repository annotates machine-readable values with. It is a separate prop from `eyebrow` and not a default value of it, because the two say different things: an eyebrow is a word a reader reads, and an index is a number that is only meaningful beside the section it counts. All four NaniSoft sites render one of these above every section heading, and three of them render it beside a label rather than above a title, which is the same fact in a different arrangement.
|
|
86
|
+
**`eyebrow`** `ReactNode` · optional · default: —
|
|
87
|
+
**`title`** `ReactNode` · required · default: —
|
|
88
|
+
**`description`** `ReactNode` · optional · default: —
|
|
89
|
+
**`align`** `'center' | 'left'` · optional · default: —
|
|
90
|
+
**`as`** `HeadingLevel` · optional · default: — — Heading level. Defaults to `h2` because blocks compose under a page heading. A page that renders a block as its primary heading passes `as="h1"`; a document with no `h1` gives screen-reader and search engines no top-level entry point.
|
|
91
|
+
**`className`** `string` · optional · default: —
|
|
@@ -1,14 +1,150 @@
|
|
|
1
1
|
# Select
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The control that chooses one option from a list that opens on demand.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
import { Select } from '@nanisoft/prism-ui/components'
|
|
5
|
+
```tsx
|
|
6
|
+
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, SelectGroup, SelectLabel, SelectSeparator } from '@nanisoft/prism-ui/components/select'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Overview
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
A Select chooses one option from a list that opens on demand. It ships as
|
|
12
|
+
`Select`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectItem`,
|
|
13
|
+
`SelectGroup`, `SelectLabel` and `SelectSeparator`. `Select` holds the value,
|
|
14
|
+
`SelectTrigger` shows the current choice, and `SelectContent` carries the
|
|
15
|
+
options. Pass the options to the root as `items` too, so the trigger can render
|
|
16
|
+
a label before any option has mounted.
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
The trigger is a button with a combobox role, so it is reachable by Tab. In the
|
|
19
|
+
open popup the arrow keys move through the options, typing letters jumps to a
|
|
20
|
+
match, Enter chooses, and Escape closes without changing the value.
|
|
21
|
+
|
|
22
|
+
## Guidelines
|
|
23
|
+
|
|
24
|
+
### When to use
|
|
25
|
+
|
|
26
|
+
Use a Select when the option set is long enough that a radio group would
|
|
27
|
+
overwhelm the form, or when only the chosen value needs to stay visible. It fits
|
|
28
|
+
settings and filters where the reader picks one value from a known list.
|
|
29
|
+
|
|
30
|
+
### When not to use
|
|
31
|
+
|
|
32
|
+
Do not use a Select for two or three mutually exclusive options. A RadioGroup
|
|
33
|
+
shows every choice at once and needs no opening click.
|
|
34
|
+
|
|
35
|
+
Do not use it when the reader may choose more than one value, or for navigation.
|
|
36
|
+
Checkboxes state independence; a link handles a route change.
|
|
37
|
+
|
|
38
|
+
### Best practices
|
|
39
|
+
|
|
40
|
+
- Pair the Select with a `FieldLabel` whose `htmlFor` matches the trigger's
|
|
41
|
+
`id`. The value shows in the trigger, so the label names the field.
|
|
42
|
+
- Pass `items` so the trigger can resolve a label before an option has mounted.
|
|
43
|
+
Without it, Base UI falls back to the raw value.
|
|
44
|
+
- Give `SelectValue` a placeholder that says what to do, such as "Choose a
|
|
45
|
+
region", rather than naming a default the reader did not choose.
|
|
46
|
+
- Add `SelectGroup` and `SelectLabel` once a list passes roughly eight options,
|
|
47
|
+
so the reader can scan by group.
|
|
48
|
+
- A disabled option is still readable. Explain why it cannot be chosen in
|
|
49
|
+
adjacent text rather than leaving a dead row unexplained.
|
|
50
|
+
|
|
51
|
+
### Content guidelines
|
|
52
|
+
|
|
53
|
+
- Write option labels as sentence-case nouns: "Europe West", not "EUROPE WEST".
|
|
54
|
+
- Order options by the reader's expectation: size, plan, region, or product.
|
|
55
|
+
- Reserve the first option for a real choice. Do not add an empty "Select one"
|
|
56
|
+
row when the placeholder already asks the question.
|
|
57
|
+
|
|
58
|
+
**A labelled Select with a grouped option list and a controlled value.**
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
'use client'
|
|
62
|
+
|
|
63
|
+
import { useState } from 'react'
|
|
64
|
+
|
|
65
|
+
import { Field, FieldLabel } from '@nanisoft/prism-ui/components/field'
|
|
66
|
+
import {
|
|
67
|
+
Select,
|
|
68
|
+
SelectContent,
|
|
69
|
+
SelectGroup,
|
|
70
|
+
SelectItem,
|
|
71
|
+
SelectLabel,
|
|
72
|
+
SelectTrigger,
|
|
73
|
+
SelectValue,
|
|
74
|
+
} from '@nanisoft/prism-ui/components/select'
|
|
75
|
+
|
|
76
|
+
/** A labelled Select with a grouped option list and a controlled value. */
|
|
77
|
+
export default function SelectDemo() {
|
|
78
|
+
const [role, setRole] = useState('editor')
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div className="flex max-w-measure-narrow flex-col gap-6">
|
|
82
|
+
<Field>
|
|
83
|
+
<FieldLabel htmlFor="select-role">Role</FieldLabel>
|
|
84
|
+
<Select
|
|
85
|
+
value={role}
|
|
86
|
+
onValueChange={(value) => setRole(value ?? '')}
|
|
87
|
+
items={{ viewer: 'Viewer', editor: 'Editor', admin: 'Admin' }}
|
|
88
|
+
>
|
|
89
|
+
<SelectTrigger id="select-role" className="w-full">
|
|
90
|
+
<SelectValue placeholder="Choose a role" />
|
|
91
|
+
</SelectTrigger>
|
|
92
|
+
<SelectContent>
|
|
93
|
+
<SelectGroup>
|
|
94
|
+
<SelectLabel>Team roles</SelectLabel>
|
|
95
|
+
<SelectItem value="viewer">Viewer</SelectItem>
|
|
96
|
+
<SelectItem value="editor">Editor</SelectItem>
|
|
97
|
+
<SelectItem value="admin">Admin</SelectItem>
|
|
98
|
+
</SelectGroup>
|
|
99
|
+
</SelectContent>
|
|
100
|
+
</Select>
|
|
101
|
+
</Field>
|
|
102
|
+
<Field>
|
|
103
|
+
<FieldLabel htmlFor="select-region">Region</FieldLabel>
|
|
104
|
+
<Select
|
|
105
|
+
defaultValue="eu-west"
|
|
106
|
+
items={{
|
|
107
|
+
'eu-west': 'Europe West',
|
|
108
|
+
'us-east': 'US East',
|
|
109
|
+
'ap-south': 'Asia South',
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
<SelectTrigger id="select-region" className="w-full">
|
|
113
|
+
<SelectValue placeholder="Choose a region" />
|
|
114
|
+
</SelectTrigger>
|
|
115
|
+
<SelectContent>
|
|
116
|
+
<SelectItem value="eu-west">Europe West</SelectItem>
|
|
117
|
+
<SelectItem value="us-east">US East</SelectItem>
|
|
118
|
+
<SelectItem value="ap-south" disabled>
|
|
119
|
+
Asia South (paused)
|
|
120
|
+
</SelectItem>
|
|
121
|
+
</SelectContent>
|
|
122
|
+
</Select>
|
|
123
|
+
</Field>
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Props
|
|
130
|
+
|
|
131
|
+
**`value`** `string` · optional · default: — — The selected value, when the select is controlled.
|
|
132
|
+
**`defaultValue`** `string` · optional · default: — — The value selected initially, for an uncontrolled select.
|
|
133
|
+
**`onValueChange`** `(value: string | null) => void` · optional · default: — — Called when the selected value changes.
|
|
134
|
+
**`open`** `boolean` · optional · default: — — The controlled open state of the popup.
|
|
135
|
+
**`defaultOpen`** `boolean` · optional · default: — — The initially open state of the popup.
|
|
136
|
+
**`onOpenChange`** `(open: boolean) => void` · optional · default: — — Called when the popup opens or closes.
|
|
137
|
+
**`name`** `string` · optional · default: — — The form field name submitted with the form.
|
|
138
|
+
**`form`** `string` · optional · default: — — Identifies the form that owns the hidden input.
|
|
139
|
+
**`required`** `boolean` · optional · default: — — Whether a value must be chosen before the form submits.
|
|
140
|
+
**`disabled`** `boolean` · optional · default: — — Whether the select ignores user interaction.
|
|
141
|
+
**`readOnly`** `boolean` · optional · default: — — Whether the user may open the popup but not change the value.
|
|
142
|
+
**`items`** `Record<string, React.ReactNode> | ReadonlyArray<{ label: React.ReactNode; value: string; }>` · optional · default: — — The options, keyed by value, so the trigger can render a label before any item has mounted. Without it, `SelectValue` shows the raw value.
|
|
143
|
+
**`itemToStringLabel`** `(value: string) => string` · optional · default: — — Converts an item value to the label shown in the trigger.
|
|
144
|
+
**`children`** `React.ReactNode` · optional · default: — — The trigger and the popup content.
|
|
145
|
+
**`label`** `React.ReactNode` · required · default: —
|
|
146
|
+
**`size`** `'sm' | 'default'` · optional · default: `default` — The trigger's height.
|
|
147
|
+
**`placeholder`** `React.ReactNode` · optional · default: — — Shown when no value is selected.
|
|
148
|
+
**`side`** `'top' | 'right' | 'bottom' | 'left'` · optional · default: `bottom` — Which side of the trigger the list is placed on.
|
|
149
|
+
**`align`** `'start' | 'center' | 'end'` · optional · default: `center` — How the list aligns against the trigger.
|
|
150
|
+
**`sideOffset`** `number` · optional · default: `4` — The distance in pixels between the trigger and the list.
|