@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,116 @@
|
|
|
1
|
+
# Field
|
|
2
|
+
|
|
3
|
+
The labelled wrapper that pairs a form control with its label, description and error.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Field, FieldLabel, FieldDescription, FieldError, FieldGroup } from '@nanisoft/prism-ui/components/field'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A Field pairs a form control with its label, its helper text and its error. It
|
|
12
|
+
ships as `Field`, `FieldLabel`, `FieldDescription`, `FieldError` and
|
|
13
|
+
`FieldGroup`, all from the same module.
|
|
14
|
+
|
|
15
|
+
The parts are presentational, and the consumer owns the wiring. `FieldLabel`
|
|
16
|
+
renders a native `<label>` and takes the control's `id` as `htmlFor`.
|
|
17
|
+
`FieldDescription` and `FieldError` take an `id` that the control references
|
|
18
|
+
through `aria-describedby`. Nothing generates an `id`, so a field stays a
|
|
19
|
+
Server Component and the markup is settled before it reaches the browser.
|
|
20
|
+
|
|
21
|
+
`FieldError` carries `role="alert"`, so it is announced when it appears. Render
|
|
22
|
+
it only while the field is invalid, and mark the control itself with
|
|
23
|
+
`aria-invalid` so the failure is visible as well as spoken.
|
|
24
|
+
|
|
25
|
+
## Guidelines
|
|
26
|
+
|
|
27
|
+
### When to use
|
|
28
|
+
|
|
29
|
+
Use a Field around any form control that needs a visible label. Pair it with
|
|
30
|
+
`Input`, `Textarea` or a future control that does not ship its own label.
|
|
31
|
+
|
|
32
|
+
Use `FieldGroup` when several fields belong to one decision, such as an address
|
|
33
|
+
or a notification preference, so the set reads as one block.
|
|
34
|
+
|
|
35
|
+
### When not to use
|
|
36
|
+
|
|
37
|
+
Do not use a Field as a layout grid. It controls label, control, helper and
|
|
38
|
+
error order, not column placement; wrap fields in your own grid for that.
|
|
39
|
+
|
|
40
|
+
Do not use `FieldDescription` as the only label. A placeholder or a hint is not
|
|
41
|
+
an accessible name, and it disappears as soon as the reader types.
|
|
42
|
+
|
|
43
|
+
Do not render `FieldError` alongside valid content. An error that is always
|
|
44
|
+
present stops meaning anything.
|
|
45
|
+
|
|
46
|
+
### Best practices
|
|
47
|
+
|
|
48
|
+
- Put the label above the control. It survives zoom and translation better than
|
|
49
|
+
a label to the side.
|
|
50
|
+
- Point `htmlFor` at the control's `id`, and keep those two values stable so the
|
|
51
|
+
label is programmatically attached rather than merely adjacent.
|
|
52
|
+
- Reference both the description and the error from `aria-describedby`, and put
|
|
53
|
+
the error first when both are present.
|
|
54
|
+
- Replace the helper text with the error while the field is invalid instead of
|
|
55
|
+
stacking both. The reader needs one instruction at a time.
|
|
56
|
+
- Mark the control with `aria-invalid` and let the error sentence say what to do
|
|
57
|
+
next. The colour is a reinforcement, never the message.
|
|
58
|
+
- Group related fields with `FieldGroup` and give the group a heading when it
|
|
59
|
+
helps a screen reader move through a long form.
|
|
60
|
+
|
|
61
|
+
### Content guidelines
|
|
62
|
+
|
|
63
|
+
- Start an error with what is wrong and how to fix it: "Enter an address in the
|
|
64
|
+
form name@example.com", not "Invalid input".
|
|
65
|
+
- Keep a helper line to one sentence. A paragraph belongs above the field, not
|
|
66
|
+
under it.
|
|
67
|
+
- Do not label a field with an instruction. "Email" is a name; "Enter your
|
|
68
|
+
email address to continue" is copy that belongs beside the control.
|
|
69
|
+
|
|
70
|
+
**A group of fields: two valid controls and one showing an error.**
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import {
|
|
74
|
+
Field,
|
|
75
|
+
FieldDescription,
|
|
76
|
+
FieldError,
|
|
77
|
+
FieldGroup,
|
|
78
|
+
FieldLabel,
|
|
79
|
+
} from '@nanisoft/prism-ui/components/field'
|
|
80
|
+
import { Input } from '@nanisoft/prism-ui/components/input'
|
|
81
|
+
import { Textarea } from '@nanisoft/prism-ui/components/textarea'
|
|
82
|
+
|
|
83
|
+
/** A group of fields: two valid controls and one showing an error. */
|
|
84
|
+
export default function FieldDemo() {
|
|
85
|
+
return (
|
|
86
|
+
<FieldGroup className="max-w-measure-narrow">
|
|
87
|
+
<Field>
|
|
88
|
+
<FieldLabel htmlFor="field-display-name">Display name</FieldLabel>
|
|
89
|
+
<Input id="field-display-name" defaultValue="Ada Lovelace" />
|
|
90
|
+
<FieldDescription>Shown on your profile and in mentions.</FieldDescription>
|
|
91
|
+
</Field>
|
|
92
|
+
<Field>
|
|
93
|
+
<FieldLabel htmlFor="field-bio">Bio</FieldLabel>
|
|
94
|
+
<Textarea id="field-bio" placeholder="A sentence about yourself." />
|
|
95
|
+
</Field>
|
|
96
|
+
<Field>
|
|
97
|
+
<FieldLabel htmlFor="field-email">Email</FieldLabel>
|
|
98
|
+
<Input
|
|
99
|
+
id="field-email"
|
|
100
|
+
type="email"
|
|
101
|
+
defaultValue="not-an-email"
|
|
102
|
+
aria-invalid
|
|
103
|
+
aria-describedby="field-email-error"
|
|
104
|
+
/>
|
|
105
|
+
<FieldError id="field-email-error">
|
|
106
|
+
Enter an address in the form name@example.com.
|
|
107
|
+
</FieldError>
|
|
108
|
+
</Field>
|
|
109
|
+
</FieldGroup>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Props
|
|
115
|
+
|
|
116
|
+
> Extends: the native `<div>` element. No additional Prism-specific props.
|
|
@@ -1,14 +1,93 @@
|
|
|
1
1
|
# Input
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The single-line text control for a form.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
import { Input } from '@nanisoft/prism-ui/components'
|
|
5
|
+
```tsx
|
|
6
|
+
import { Input } from '@nanisoft/prism-ui/components/input'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Overview
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
An Input is the single-line text control. It renders a native `<input>`, so it
|
|
12
|
+
submits, validates, autocompletes and takes focus without extra work, and it
|
|
13
|
+
accepts every standard input type.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
The focus ring is drawn at full strength rather than at half alpha, so it clears
|
|
16
|
+
the 3:1 non-text threshold on every surface. When the control is marked with
|
|
17
|
+
`aria-invalid`, the border and the ring switch to the destructive token, which
|
|
18
|
+
makes a failed field visible as well as announced.
|
|
19
|
+
|
|
20
|
+
## Guidelines
|
|
21
|
+
|
|
22
|
+
### When to use
|
|
23
|
+
|
|
24
|
+
Use an Input for a short, single-line value: a name, an address, a search term,
|
|
25
|
+
a quantity, a date or a password.
|
|
26
|
+
|
|
27
|
+
Pair it with a Field so the control keeps a visible label, and pass the correct
|
|
28
|
+
`type` so mobile keyboards and browser validation both do their job.
|
|
29
|
+
|
|
30
|
+
### When not to use
|
|
31
|
+
|
|
32
|
+
Do not use an Input for free-form text longer than a line. A Textarea gives the
|
|
33
|
+
reader room to see what they have written.
|
|
34
|
+
|
|
35
|
+
Do not use one for a choice between options. A radio group, a select or a
|
|
36
|
+
switch states the options and their current state; a text box asks the reader to
|
|
37
|
+
remember them.
|
|
38
|
+
|
|
39
|
+
Do not use an Input as a display field for a value the reader cannot change.
|
|
40
|
+
Render the value as text.
|
|
41
|
+
|
|
42
|
+
### Best practices
|
|
43
|
+
|
|
44
|
+
- Keep a visible label. A placeholder is a hint, not a name, and it vanishes on
|
|
45
|
+
the first keystroke.
|
|
46
|
+
- Choose the `type` and `inputMode` that match the value, and set `autoComplete`
|
|
47
|
+
so the browser can fill it. Getting this right saves more effort than any
|
|
48
|
+
visual detail.
|
|
49
|
+
- Show the error beside the field and mark the control with `aria-invalid`.
|
|
50
|
+
Colour alone never carries the failure.
|
|
51
|
+
- Disable a control only when the reason is visible nearby. A disabled input
|
|
52
|
+
with no explanation is a dead end.
|
|
53
|
+
- Keep the default height and radius. Size is a token decision, and a taller
|
|
54
|
+
input breaks alignment with every other control on the row.
|
|
55
|
+
|
|
56
|
+
### Content guidelines
|
|
57
|
+
|
|
58
|
+
- A placeholder may show the expected format, for example `name@example.com`,
|
|
59
|
+
and nothing more.
|
|
60
|
+
- A helper line states the rule, not the field's name: "At least eight
|
|
61
|
+
characters", not "Password".
|
|
62
|
+
- Do not write an error in the imperative twice. One instruction per message.
|
|
63
|
+
|
|
64
|
+
**Input types at rest, disabled, and marked invalid.**
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { Field, FieldLabel } from '@nanisoft/prism-ui/components/field'
|
|
68
|
+
import { Input } from '@nanisoft/prism-ui/components/input'
|
|
69
|
+
|
|
70
|
+
/** Input types at rest, disabled, and marked invalid. */
|
|
71
|
+
export default function InputDemo() {
|
|
72
|
+
return (
|
|
73
|
+
<div className="flex max-w-measure-narrow flex-col gap-4">
|
|
74
|
+
<Field>
|
|
75
|
+
<FieldLabel htmlFor="input-email">Email</FieldLabel>
|
|
76
|
+
<Input id="input-email" type="email" placeholder="name@example.com" />
|
|
77
|
+
</Field>
|
|
78
|
+
<Field>
|
|
79
|
+
<FieldLabel htmlFor="input-workspace">Workspace</FieldLabel>
|
|
80
|
+
<Input id="input-workspace" defaultValue="Locked workspace" disabled />
|
|
81
|
+
</Field>
|
|
82
|
+
<Field>
|
|
83
|
+
<FieldLabel htmlFor="input-handle">Handle</FieldLabel>
|
|
84
|
+
<Input id="input-handle" defaultValue="with spaces" aria-invalid />
|
|
85
|
+
</Field>
|
|
86
|
+
</div>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Props
|
|
92
|
+
|
|
93
|
+
> Extends: the native `<input>` element. No additional Prism-specific props.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Kbd
|
|
2
|
+
|
|
3
|
+
The inline label for a keyboard key or shortcut.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Kbd } from '@nanisoft/prism-ui/components/kbd'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A Kbd is the inline label for a keyboard key or shortcut. It renders a native
|
|
12
|
+
`<kbd>`, so assistive technology can identify it as input the reader types
|
|
13
|
+
rather than as text to read.
|
|
14
|
+
|
|
15
|
+
It sits inline with surrounding copy and takes its surface from the muted token.
|
|
16
|
+
Shortcuts are written with one element per key, so `Ctrl` and `K` are two Kbd
|
|
17
|
+
elements with a space between them.
|
|
18
|
+
|
|
19
|
+
## Guidelines
|
|
20
|
+
|
|
21
|
+
### When to use
|
|
22
|
+
|
|
23
|
+
Use a Kbd when the reader must press a key to do something: a documented
|
|
24
|
+
shortcut, a hint in a menu or a tooltip, or an onboarding step that names the
|
|
25
|
+
keys.
|
|
26
|
+
|
|
27
|
+
### When not to use
|
|
28
|
+
|
|
29
|
+
Do not use a Kbd for a piece of code or a filename. Inline code already has its
|
|
30
|
+
own treatment.
|
|
31
|
+
|
|
32
|
+
Do not use one as a button label. A control that can be clicked shows a verb; a
|
|
33
|
+
keyboard shortcut is an alternative, not the action.
|
|
34
|
+
|
|
35
|
+
Do not use a Kbd for input the reader does not type, such as the name of a menu
|
|
36
|
+
command.
|
|
37
|
+
|
|
38
|
+
### Best practices
|
|
39
|
+
|
|
40
|
+
- Use one Kbd per key. A single element holding the whole chord hides the
|
|
41
|
+
individual keys from anyone scanning or reading by element.
|
|
42
|
+
- Name the modifier as the keyboard shows it and say which platform you assume.
|
|
43
|
+
There is no server-safe way to detect the reader's platform, so "Ctrl on
|
|
44
|
+
Windows and Linux, Cmd on macOS" is more honest than picking one.
|
|
45
|
+
- Keep the hint inside a sentence that already states the action, so the keys
|
|
46
|
+
are never the only instruction.
|
|
47
|
+
- Do not style a Kbd to look pressable. It reports a key, it does not receive a
|
|
48
|
+
press, and it is excluded from pointer events on purpose.
|
|
49
|
+
- Keep the label to the key itself. Do not add the word "key" after it, because
|
|
50
|
+
the element already says what it is.
|
|
51
|
+
|
|
52
|
+
**Shortcuts written with one element per key.**
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { Kbd } from '@nanisoft/prism-ui/components/kbd'
|
|
56
|
+
|
|
57
|
+
/** Shortcuts written with one element per key. */
|
|
58
|
+
export default function KbdDemo() {
|
|
59
|
+
return (
|
|
60
|
+
<div className="flex flex-col gap-3 text-sm">
|
|
61
|
+
<p className="flex items-center gap-1.5">
|
|
62
|
+
Open the command menu <Kbd>Ctrl</Kbd> <Kbd>K</Kbd>
|
|
63
|
+
</p>
|
|
64
|
+
<p className="flex items-center gap-1.5">
|
|
65
|
+
Save the draft <Kbd>Ctrl</Kbd> <Kbd>S</Kbd>
|
|
66
|
+
</p>
|
|
67
|
+
<p className="flex items-center gap-1.5">
|
|
68
|
+
Close the dialog <Kbd>Esc</Kbd>
|
|
69
|
+
</p>
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Props
|
|
76
|
+
|
|
77
|
+
> Extends: the native `<kbd>` element. No additional Prism-specific props.
|
|
@@ -1,14 +1,102 @@
|
|
|
1
1
|
# Pagination
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The control that moves between pages of a paged collection.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
import { Pagination } from '@nanisoft/prism-ui/components'
|
|
5
|
+
```tsx
|
|
6
|
+
import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis } from '@nanisoft/prism-ui/components/pagination'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Overview
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
A Pagination moves between the pages of a paged collection. It ships as a
|
|
12
|
+
parent and six parts: `Pagination`, `PaginationContent`, `PaginationItem`,
|
|
13
|
+
`PaginationLink`, `PaginationPrevious`, `PaginationNext` and
|
|
14
|
+
`PaginationEllipsis`, all from the same module.
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
`Pagination` is a labelled `<nav>`, and `PaginationContent` is a `<ul>` so the
|
|
17
|
+
page numbers form one list for assistive technology. The current page is marked
|
|
18
|
+
with `aria-current="page"`, the step controls carry their own accessible names,
|
|
19
|
+
and the ellipsis is hidden from the accessibility tree because the links around
|
|
20
|
+
it already name the range.
|
|
21
|
+
|
|
22
|
+
## Guidelines
|
|
23
|
+
|
|
24
|
+
### When to use
|
|
25
|
+
|
|
26
|
+
Use a Pagination when a result set is longer than one screen and the total is
|
|
27
|
+
known. The page a reader is on, and how many pages exist, are both part of the
|
|
28
|
+
information the control carries.
|
|
29
|
+
|
|
30
|
+
### When not to use
|
|
31
|
+
|
|
32
|
+
Do not use it for a short list that fits on one page. A single page link is
|
|
33
|
+
furniture around nothing.
|
|
34
|
+
|
|
35
|
+
Do not use it as a step control in a wizard. A checkout or an onboarding flow
|
|
36
|
+
has a fixed order and no page numbers, so a pair of previous and next buttons
|
|
37
|
+
describes it better.
|
|
38
|
+
|
|
39
|
+
Do not replace it with infinite scroll and no page numbers. A reader who cannot
|
|
40
|
+
return to a position loses their place.
|
|
41
|
+
|
|
42
|
+
### Best practices
|
|
43
|
+
|
|
44
|
+
- Render the current page as a link with `isActive`, so it is announced with
|
|
45
|
+
`aria-current="page"` and stays consistent in the row.
|
|
46
|
+
- Show a window of pages, not every page. Use `PaginationEllipsis` for the
|
|
47
|
+
hidden run and keep the first, last and neighbours visible.
|
|
48
|
+
- Keep `PaginationPrevious` and `PaginationNext` at the ends of the row. On
|
|
49
|
+
narrow layouts their labels collapse to the chevron and the accessible name
|
|
50
|
+
stays complete.
|
|
51
|
+
- Pass a real `href` on each link. A page of results is a location, so the link
|
|
52
|
+
should be right-clickable and openable in a new tab.
|
|
53
|
+
- State the range near the control, for example "1 to 20 of 348". Page numbers
|
|
54
|
+
alone do not tell the reader how much remains.
|
|
55
|
+
|
|
56
|
+
**A paged result set with the second page current.**
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import {
|
|
60
|
+
Pagination,
|
|
61
|
+
PaginationContent,
|
|
62
|
+
PaginationEllipsis,
|
|
63
|
+
PaginationItem,
|
|
64
|
+
PaginationLink,
|
|
65
|
+
PaginationNext,
|
|
66
|
+
PaginationPrevious,
|
|
67
|
+
} from '@nanisoft/prism-ui/components/pagination'
|
|
68
|
+
|
|
69
|
+
/** A paged result set with the second page current. */
|
|
70
|
+
export default function PaginationDemo() {
|
|
71
|
+
return (
|
|
72
|
+
<Pagination>
|
|
73
|
+
<PaginationContent>
|
|
74
|
+
<PaginationItem>
|
|
75
|
+
<PaginationPrevious href="#" />
|
|
76
|
+
</PaginationItem>
|
|
77
|
+
<PaginationItem>
|
|
78
|
+
<PaginationLink href="#">1</PaginationLink>
|
|
79
|
+
</PaginationItem>
|
|
80
|
+
<PaginationItem>
|
|
81
|
+
<PaginationLink href="#" isActive>
|
|
82
|
+
2
|
|
83
|
+
</PaginationLink>
|
|
84
|
+
</PaginationItem>
|
|
85
|
+
<PaginationItem>
|
|
86
|
+
<PaginationLink href="#">3</PaginationLink>
|
|
87
|
+
</PaginationItem>
|
|
88
|
+
<PaginationItem>
|
|
89
|
+
<PaginationEllipsis />
|
|
90
|
+
</PaginationItem>
|
|
91
|
+
<PaginationItem>
|
|
92
|
+
<PaginationNext href="#" />
|
|
93
|
+
</PaginationItem>
|
|
94
|
+
</PaginationContent>
|
|
95
|
+
</Pagination>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Props
|
|
101
|
+
|
|
102
|
+
> Extends: the native `<nav>` element. No additional Prism-specific props.
|
|
@@ -1,14 +1,102 @@
|
|
|
1
1
|
# Popover
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The anchored floating surface for content richer than a tooltip.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
import { Popover } from '@nanisoft/prism-ui/components'
|
|
5
|
+
```tsx
|
|
6
|
+
import { Popover, PopoverTrigger, PopoverContent } from '@nanisoft/prism-ui/components/popover'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Overview
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
A Popover is a floating surface opened by a trigger. It ships as `Popover`,
|
|
12
|
+
`PopoverTrigger` and `PopoverContent`, all from the same module. It is
|
|
13
|
+
positioned by the library, flips near an edge, closes on Escape or an outside
|
|
14
|
+
press, and returns focus to the trigger when it closes.
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
A Popover is richer than a Tooltip and lighter than a Dialog. It can hold a
|
|
17
|
+
small form, a filter set, or a compact detail view without covering the page the
|
|
18
|
+
way a modal does.
|
|
19
|
+
|
|
20
|
+
## Guidelines
|
|
21
|
+
|
|
22
|
+
### When to use
|
|
23
|
+
|
|
24
|
+
Use a Popover for content that is more than a label but not a whole screen: a
|
|
25
|
+
share form, a filter panel, a date range, a small preview. It keeps the reader
|
|
26
|
+
in context while offering more than the page shows.
|
|
27
|
+
|
|
28
|
+
### When not to use
|
|
29
|
+
|
|
30
|
+
Do not use a Popover for a required decision. An outside press can close it, so
|
|
31
|
+
a flow that must be completed needs a Dialog.
|
|
32
|
+
|
|
33
|
+
Do not put a single short explanation in a Popover. That is a Tooltip, which
|
|
34
|
+
needs no click.
|
|
35
|
+
|
|
36
|
+
Do not use a Popover as a menu of commands. A DropdownMenu carries the menu
|
|
37
|
+
semantics and the keyboard model a reader expects for actions.
|
|
38
|
+
|
|
39
|
+
### Best practices
|
|
40
|
+
|
|
41
|
+
- Use `side` and `align` to keep the panel near its trigger and clear of the
|
|
42
|
+
content it annotates, and let the library flip it near an edge.
|
|
43
|
+
- Keep one task per Popover. If it needs its own tabs or steps, it has outgrown
|
|
44
|
+
the surface.
|
|
45
|
+
- Use the trigger's `openOnHover` only when hovering is a convenience on top of
|
|
46
|
+
a click, never as the only way to open.
|
|
47
|
+
- Because an outside press closes the popover, save or apply changes as they
|
|
48
|
+
happen, or ask before discarding.
|
|
49
|
+
- Keep the trigger labelled. The popover's content does not name the trigger for
|
|
50
|
+
assistive technology.
|
|
51
|
+
|
|
52
|
+
### Content guidelines
|
|
53
|
+
|
|
54
|
+
- Lead with a short heading that names the panel, such as "Share this view".
|
|
55
|
+
- Keep body copy to one or two sentences, and put detail in the form itself.
|
|
56
|
+
- Use sentence case for the heading and no closing period on a fragment.
|
|
57
|
+
|
|
58
|
+
**A popover holding a small share form.**
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
'use client'
|
|
62
|
+
|
|
63
|
+
import { Button } from '@nanisoft/prism-ui/components/button'
|
|
64
|
+
import { Input } from '@nanisoft/prism-ui/components/input'
|
|
65
|
+
import { Popover, PopoverContent, PopoverTrigger } from '@nanisoft/prism-ui/components/popover'
|
|
66
|
+
|
|
67
|
+
/** A popover holding a small share form. */
|
|
68
|
+
export default function PopoverDemo() {
|
|
69
|
+
return (
|
|
70
|
+
<Popover>
|
|
71
|
+
<PopoverTrigger>Share</PopoverTrigger>
|
|
72
|
+
<PopoverContent>
|
|
73
|
+
<div className="flex flex-col gap-3">
|
|
74
|
+
<div className="flex flex-col gap-1">
|
|
75
|
+
<p className="text-sm font-medium">Share this view</p>
|
|
76
|
+
<p className="text-muted-foreground text-sm">
|
|
77
|
+
Anyone with the link can read, not edit.
|
|
78
|
+
</p>
|
|
79
|
+
</div>
|
|
80
|
+
<div className="flex gap-2">
|
|
81
|
+
<Input defaultValue="https://prism.nanisoft.com/themes" readOnly />
|
|
82
|
+
<Button variant="outline">Copy</Button>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</PopoverContent>
|
|
86
|
+
</Popover>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Props
|
|
92
|
+
|
|
93
|
+
**`open`** `boolean` · optional · default: — — The controlled open state.
|
|
94
|
+
**`defaultOpen`** `boolean` · optional · default: — — The initially open state, for an uncontrolled popover.
|
|
95
|
+
**`onOpenChange`** `(open: boolean) => void` · optional · default: — — Called when the open state changes.
|
|
96
|
+
**`modal`** `boolean | 'trap-focus'` · optional · default: `false` — Whether the popover traps interaction while open.
|
|
97
|
+
**`children`** `React.ReactNode` · optional · default: — — The trigger and content.
|
|
98
|
+
**`openOnHover`** `boolean` · optional · default: — — Whether the trigger should also open the popover on hover.
|
|
99
|
+
**`side`** `'top' | 'right' | 'bottom' | 'left'` · optional · default: `bottom` — Which side of the trigger the popover is placed on.
|
|
100
|
+
**`align`** `'start' | 'center' | 'end'` · optional · default: `center` — How the popover aligns against the trigger.
|
|
101
|
+
**`sideOffset`** `number` · optional · default: `4` — The distance in pixels between the trigger and the popover.
|
|
102
|
+
**`alignOffset`** `number` · optional · default: `0` — The offset in pixels along the alignment axis.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# ProductMark
|
|
2
|
+
|
|
3
|
+
A product's two-part colour mark: a brand-ink ring around the pack's own fill, beside the product's name in the brand ink.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { ProductMark } from '@nanisoft/prism-ui/components/product-mark'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A ProductMark is a product's two-part colour mark: a ring in the brand ink around
|
|
12
|
+
a core in the product's own pack fill, beside the product's name in the same
|
|
13
|
+
brand ink. It is a server component and ships no client code.
|
|
14
|
+
|
|
15
|
+
The mark is promoted to a component because a product row and a product switcher
|
|
16
|
+
both need it, and two hand-written copies is the arrangement this design system
|
|
17
|
+
exists to remove. One implementation also means one place where the two colour
|
|
18
|
+
laws are applied, and those laws are not obvious:
|
|
19
|
+
|
|
20
|
+
**The ring and the name are ink; the core is a fill.** A pastel brand value is a
|
|
21
|
+
fill and never text, so the core takes `primary`. The ring and the name take
|
|
22
|
+
`brand-ink`, which is the role for something that must read *as the brand*:
|
|
23
|
+
gated at 4.5:1 against the page, a card and the accent surface, in both modes of
|
|
24
|
+
all six packs, worst measured 5.57:1. Plain `foreground` is not a brand ink, and
|
|
25
|
+
neither is a foreground paired with a fill, so a mark drawn in `primary` text is
|
|
26
|
+
the wrong answer twice over.
|
|
27
|
+
|
|
28
|
+
**A product with no pack wears the spectrum, not a colourless mark.** A mark with
|
|
29
|
+
no `pack` is drawn as a conic sweep of all five chart steps. A colourless mark
|
|
30
|
+
would take the reading page's accent and change per site, so a product with no
|
|
31
|
+
single colour would be a different colour on every site that listed it. The one
|
|
32
|
+
entry with no pack is the company root, and the spectrum says so once rather
|
|
33
|
+
than five times.
|
|
34
|
+
|
|
35
|
+
## Guidelines
|
|
36
|
+
|
|
37
|
+
### When to use
|
|
38
|
+
|
|
39
|
+
Use a ProductMark wherever a reader is being shown which product they are in, or
|
|
40
|
+
which of a set of products a link goes to: a product row, a product switcher, a
|
|
41
|
+
site header's brand lockup, a footer grid. Wherever a site draws the same mark
|
|
42
|
+
twice, it should be drawing this.
|
|
43
|
+
|
|
44
|
+
Pass the product's `id` as the key within the set it is distinguished in. It is
|
|
45
|
+
carried on the DOM as `data-product`, and it is what makes two marks in the same
|
|
46
|
+
view traceable to their product.
|
|
47
|
+
|
|
48
|
+
### When not to use
|
|
49
|
+
|
|
50
|
+
Do not use a ProductMark to colour a section, a surface or a heading. The mark
|
|
51
|
+
identifies a member of a set, and the design system keeps mark and ground on
|
|
52
|
+
separate axes for exactly that reason: a pack is a signal, never a ground.
|
|
53
|
+
|
|
54
|
+
Do not put a boundary on a ProductMark's disc. A pack boundary moves the pack's
|
|
55
|
+
corner radius as well as its colour, and the mark is a fully-rounded element, so
|
|
56
|
+
a boundary on it changes nothing a reader can see. Carry the pack through `pack`
|
|
57
|
+
instead, which is the axis the mark actually reads.
|
|
58
|
+
|
|
59
|
+
Do not hand-write a second mark. If a surface needs a mark this component does
|
|
60
|
+
not cover, extend this one.
|
|
61
|
+
|
|
62
|
+
### Best practices
|
|
63
|
+
|
|
64
|
+
- Give every product in a set a distinct pack, or let one wear the spectrum. A
|
|
65
|
+
set where two members share a pack has two marks that say the same thing.
|
|
66
|
+
- Use one size across a row. `sm` beside a hairline row, `md` in body content,
|
|
67
|
+
`lg` only in a page header; a row of mixed sizes reads as a hierarchy that is
|
|
68
|
+
not there.
|
|
69
|
+
- The mark is `aria-hidden` and the name beside it is the accessible content. Do
|
|
70
|
+
not put meaning in the ring's colour that is not also in the name.
|
|
71
|
+
- Prefer `md`. It is the size that reads at body text, and a mark is a
|
|
72
|
+
co-occurrence with a name rather than a thing to look at.
|
|
73
|
+
|
|
74
|
+
### Content guidelines
|
|
75
|
+
|
|
76
|
+
- The name is the product's own name, in the case it uses everywhere else.
|
|
77
|
+
- Keep the name to one or two words. The mark carries the identity; the name
|
|
78
|
+
carries the label.
|
|
79
|
+
- Never abbreviate a product's name to fit beside its mark. Drop the mark, or
|
|
80
|
+
shorten the row, or let the name wrap.
|
|
81
|
+
|
|
82
|
+
**The mark at each size, including one with no pack.**
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { ProductMark } from '@nanisoft/prism-ui/components/product-mark'
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The mark at each size, including one with no pack.
|
|
89
|
+
*
|
|
90
|
+
* The last row is the case that matters: a product with no pack of its own wears
|
|
91
|
+
* the full spectrum rather than a colourless mark, because a colourless mark
|
|
92
|
+
* would take the reading page's accent and change per site.
|
|
93
|
+
*/
|
|
94
|
+
export default function ProductMarkDemo() {
|
|
95
|
+
return (
|
|
96
|
+
<div className="flex flex-col gap-4">
|
|
97
|
+
<div className="flex flex-col items-start gap-3">
|
|
98
|
+
<ProductMark id="nexus" name="Nexus" pack="lavender" size="lg" />
|
|
99
|
+
<ProductMark id="atlas" name="Atlas" pack="mint" size="md" />
|
|
100
|
+
<ProductMark id="alphalens" name="AlphaLens" pack="blush" size="sm" />
|
|
101
|
+
</div>
|
|
102
|
+
<ProductMark id="www" name="NaniSoft" size="md" />
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Props
|
|
109
|
+
|
|
110
|
+
**`id`** `string` · required · default: — — The product's key within the set it is distinguished in. It is carried on the markup as `data-product` so a test can name one mark rather than the first one, and so two marks in one document are individually addressable.
|
|
111
|
+
**`name`** `string` · required · default: — — The product's name, which is the mark's second part and the word that carries the identity. The mark sets it in `brand-ink` rather than in `foreground`, which is DESIGN.md's Brand Ink Rule: a name that has to read as the brand reads `brand-ink`, and `foreground` is a tinted neutral with almost no chroma by design.
|
|
112
|
+
**`pack`** `PackId | null` · optional · default: — — The product's pack, which is the mark's hue. Omit it, or pass `null`, for the one entry in a set that has no pack of its own: that entry is drawn as the full spectrum rather than as a colourless mark. See `SPECTRUM` above. `default` is a real answer and not the same as the empty one. The base pack is a pack a product can wear, and it is the absence of a `data-pack` attribute, so a product whose pack is `default` carries no attribute and its core resolves the base pack's `primary` from the page.
|
|
113
|
+
**`size`** `ProductMarkSize` · optional · default: `'md'` — Which of the three drawn sizes to use.
|
|
114
|
+
**`className`** `string` · optional · default: — — Layout only, exactly as on every Component. Changing a Prism-owned visual property from here is prohibited, and this Component spreads no other prop, so there is no second route to its ink.
|
|
115
|
+
**`stored`** `string | null` · required · default: — — Raw contents of the key this line writes, or `null` when it is absent.
|
|
116
|
+
**`legacy`** `string | null` · required · default: — — Raw contents of one key this line no longer writes, or `null`.
|
|
117
|
+
**`documentPack`** `string | null` · required · default: — — `data-pack` on the root element as rendered, valid or not.
|
|
118
|
+
**`documentDark`** `boolean` · required · default: — — Whether the root element carries `.dark` as rendered.
|
|
119
|
+
**`defaultPack`** `PackId` · required · default: —
|
|
120
|
+
**`defaultMode`** `Mode` · required · default: —
|
|
121
|
+
**`mode`** `Mode` · required · default: —
|
|
122
|
+
**`origin`** `ThemeOrigin` · required · default: — — Which source named the pair, for `THEME_ORIGIN_ATTRIBUTE`.
|
|
123
|
+
**`key`** `string` · required · default: —
|