@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.
Files changed (175) hide show
  1. package/README.md +88 -0
  2. package/THIRD-PARTY-NOTICES.md +48 -0
  3. package/dist/data.json +3998 -375
  4. package/dist/demo-graph.d.ts +21 -12
  5. package/dist/demo-graph.js +37 -21
  6. package/dist/extractor.d.ts +24 -17
  7. package/dist/extractor.js +269 -153
  8. package/dist/index.d.ts +12 -7
  9. package/dist/index.js +9 -7
  10. package/dist/llms-full.txt +7988 -1989
  11. package/dist/llms.txt +97 -91
  12. package/dist/markdown.d.ts +69 -23
  13. package/dist/markdown.js +131 -72
  14. package/dist/md/blocks/app-shell-01.md +135 -0
  15. package/dist/md/blocks/auth-form-01.md +135 -0
  16. package/dist/md/blocks/cta-01.md +88 -0
  17. package/dist/md/blocks/data-table-01.md +196 -0
  18. package/dist/md/blocks/feature-grid-01.md +92 -0
  19. package/dist/md/blocks/hero-01.md +90 -0
  20. package/dist/md/blocks/instrument-panel-01.md +109 -0
  21. package/dist/md/blocks/logo-strip-01.md +97 -0
  22. package/dist/md/blocks/note-grid-01.md +102 -0
  23. package/dist/md/blocks/page-header-01.md +97 -0
  24. package/dist/md/blocks/pricing-01.md +91 -0
  25. package/dist/md/blocks/process-rail-01.md +106 -0
  26. package/dist/md/blocks/product-grid-01.md +113 -0
  27. package/dist/md/blocks/settings-panel-01.md +148 -0
  28. package/dist/md/blocks/site-footer.md +111 -0
  29. package/dist/md/blocks/site-header.md +119 -0
  30. package/dist/md/blocks/stack-grid-01.md +108 -0
  31. package/dist/md/blocks/stats-01.md +89 -0
  32. package/dist/md/blocks/status-ledger-01.md +121 -0
  33. package/dist/md/changelogs/prism-llms.md +206 -0
  34. package/dist/md/changelogs/prism-mcp-server.md +88 -0
  35. package/dist/md/changelogs/prism-tokens.md +126 -0
  36. package/dist/md/changelogs/prism-ui.md +429 -0
  37. package/dist/md/components/accordion.md +108 -0
  38. package/dist/md/components/alert.md +90 -7
  39. package/dist/md/components/avatar.md +89 -7
  40. package/dist/md/components/badge.md +74 -7
  41. package/dist/md/components/breadcrumb.md +84 -7
  42. package/dist/md/components/button.md +90 -7
  43. package/dist/md/components/card.md +90 -7
  44. package/dist/md/components/checkbox.md +101 -7
  45. package/dist/md/components/cta-link.md +98 -0
  46. package/dist/md/components/diagram.md +124 -0
  47. package/dist/md/components/dialog.md +128 -0
  48. package/dist/md/components/dropdown-menu.md +125 -0
  49. package/dist/md/components/fact-list.md +85 -0
  50. package/dist/md/components/field.md +116 -0
  51. package/dist/md/components/input.md +86 -7
  52. package/dist/md/components/kbd.md +77 -0
  53. package/dist/md/components/pagination.md +95 -7
  54. package/dist/md/components/popover.md +95 -7
  55. package/dist/md/components/product-mark.md +123 -0
  56. package/dist/md/components/product-switcher.md +88 -0
  57. package/dist/md/components/progress.md +88 -7
  58. package/dist/md/components/prose.md +91 -0
  59. package/dist/md/components/radio-group.md +111 -0
  60. package/dist/md/components/section.md +91 -0
  61. package/dist/md/components/select.md +143 -7
  62. package/dist/md/components/separator.md +77 -0
  63. package/dist/md/components/skeleton.md +71 -7
  64. package/dist/md/components/slider.md +90 -7
  65. package/dist/md/components/switch.md +104 -7
  66. package/dist/md/components/table.md +104 -7
  67. package/dist/md/components/tabs.md +105 -7
  68. package/dist/md/components/textarea.md +101 -0
  69. package/dist/md/components/tooltip.md +95 -7
  70. package/dist/md/components/typography.md +82 -7
  71. package/dist/md/content/about-content.md +36 -0
  72. package/dist/md/content/audience.md +43 -0
  73. package/dist/md/content/glossary.md +69 -0
  74. package/dist/md/content/product-vocabulary.md +53 -0
  75. package/dist/md/content/voice.md +52 -0
  76. package/dist/md/content/writing-mechanics.md +58 -0
  77. package/dist/md/foundation/colors.md +10 -0
  78. package/dist/md/foundation/iconography.md +14 -0
  79. package/dist/md/foundation/motion.md +10 -0
  80. package/dist/md/foundation/radii.md +9 -0
  81. package/dist/md/foundation/shadows.md +9 -0
  82. package/dist/md/foundation/spacings.md +8 -0
  83. package/dist/md/foundation/typography.md +9 -0
  84. package/dist/md/foundation/variables.md +9 -0
  85. package/dist/md/overview/architecture.md +76 -0
  86. package/dist/md/overview/brand.md +41 -0
  87. package/dist/md/overview/composition.md +77 -0
  88. package/dist/md/overview/quickstart.md +97 -0
  89. package/dist/md/overview/theming.md +89 -0
  90. package/dist/md/overview/using-llms.md +83 -0
  91. package/dist/md/pages/auth-page.md +149 -0
  92. package/dist/md/pages/blog-post-page.md +136 -0
  93. package/dist/md/pages/dashboard-page.md +241 -0
  94. package/dist/md/pages/marketing-page.md +199 -0
  95. package/dist/md/pages/not-found-page.md +105 -0
  96. package/dist/md/pages/settings-page.md +206 -0
  97. package/dist/prism-skill.md +50 -0
  98. package/dist/store.d.ts +203 -0
  99. package/dist/store.js +317 -0
  100. package/package.json +29 -26
  101. package/dist/demo-graph.d.ts.map +0 -1
  102. package/dist/demo-graph.js.map +0 -1
  103. package/dist/extractor.d.ts.map +0 -1
  104. package/dist/extractor.js.map +0 -1
  105. package/dist/index.d.ts.map +0 -1
  106. package/dist/index.js.map +0 -1
  107. package/dist/markdown.d.ts.map +0 -1
  108. package/dist/markdown.js.map +0 -1
  109. package/dist/md/blocks/component-demo.md +0 -19
  110. package/dist/md/blocks/page-header.md +0 -19
  111. package/dist/md/components/affix.md +0 -14
  112. package/dist/md/components/anchor.md +0 -14
  113. package/dist/md/components/auto-complete.md +0 -14
  114. package/dist/md/components/back-top.md +0 -14
  115. package/dist/md/components/border-beam.md +0 -14
  116. package/dist/md/components/calendar.md +0 -14
  117. package/dist/md/components/carousel.md +0 -14
  118. package/dist/md/components/cascader.md +0 -14
  119. package/dist/md/components/col.md +0 -14
  120. package/dist/md/components/collapse.md +0 -14
  121. package/dist/md/components/color-picker.md +0 -14
  122. package/dist/md/components/date-picker.md +0 -14
  123. package/dist/md/components/descriptions.md +0 -14
  124. package/dist/md/components/display-title.md +0 -20
  125. package/dist/md/components/divider.md +0 -14
  126. package/dist/md/components/drawer.md +0 -14
  127. package/dist/md/components/dropdown.md +0 -14
  128. package/dist/md/components/empty.md +0 -14
  129. package/dist/md/components/flex.md +0 -14
  130. package/dist/md/components/float-button.md +0 -14
  131. package/dist/md/components/form.md +0 -14
  132. package/dist/md/components/grid.md +0 -14
  133. package/dist/md/components/image.md +0 -14
  134. package/dist/md/components/input-number.md +0 -14
  135. package/dist/md/components/layout.md +0 -14
  136. package/dist/md/components/list.md +0 -14
  137. package/dist/md/components/listy.md +0 -14
  138. package/dist/md/components/masonry.md +0 -14
  139. package/dist/md/components/mentions.md +0 -14
  140. package/dist/md/components/menu.md +0 -14
  141. package/dist/md/components/modal.md +0 -14
  142. package/dist/md/components/popconfirm.md +0 -14
  143. package/dist/md/components/qrcode.md +0 -14
  144. package/dist/md/components/radio.md +0 -14
  145. package/dist/md/components/rate.md +0 -14
  146. package/dist/md/components/result.md +0 -14
  147. package/dist/md/components/row.md +0 -14
  148. package/dist/md/components/segmented.md +0 -14
  149. package/dist/md/components/space.md +0 -14
  150. package/dist/md/components/spin.md +0 -14
  151. package/dist/md/components/splitter.md +0 -14
  152. package/dist/md/components/statistic.md +0 -14
  153. package/dist/md/components/steps.md +0 -14
  154. package/dist/md/components/tag.md +0 -14
  155. package/dist/md/components/time-picker.md +0 -14
  156. package/dist/md/components/timeline.md +0 -14
  157. package/dist/md/components/tour.md +0 -14
  158. package/dist/md/components/transfer.md +0 -14
  159. package/dist/md/components/tree-select.md +0 -14
  160. package/dist/md/components/tree.md +0 -14
  161. package/dist/md/components/upload.md +0 -14
  162. package/dist/md/components/watermark.md +0 -14
  163. package/dist/md/docs/brand.md +0 -41
  164. package/dist/md/pages/blog-layout.md +0 -19
  165. package/dist/md/pages/docs-shell.md +0 -23
  166. package/dist/md/theme/blue-dark.md +0 -127
  167. package/dist/md/theme/blue-light.md +0 -129
  168. package/dist/md/theme/green-dark.md +0 -127
  169. package/dist/md/theme/green-light.md +0 -129
  170. package/dist/md/theme/lavender-dark.md +0 -127
  171. package/dist/md/theme/lavender-light.md +0 -129
  172. package/dist/md/theme/peach-dark.md +0 -127
  173. package/dist/md/theme/peach-light.md +0 -129
  174. package/dist/md/theme/rose-dark.md +0 -127
  175. 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
- antd Input, unchanged — a pass-through re-export. Import from '@nanisoft/prism-ui'.
3
+ The single-line text control for a form.
4
4
 
5
- ```ts
6
- import { Input } from '@nanisoft/prism-ui/components';
5
+ ```tsx
6
+ import { Input } from '@nanisoft/prism-ui/components/input'
7
7
  ```
8
8
 
9
- `Input` is antd's [Input](https://ant.design/components/input), re-exported unchanged.
9
+ ## Overview
10
10
 
11
- - Extends: antd **Input** — for inherited props and demos, use the antd MCP (`antd_info Input`).
12
- - Always import from '@nanisoft/prism-ui', never from `antd` directly.
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
- _No additional props beyond the antd base component._
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
- antd Pagination, unchanged — a pass-through re-export. Import from '@nanisoft/prism-ui'.
3
+ The control that moves between pages of a paged collection.
4
4
 
5
- ```ts
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
- `Pagination` is antd's [Pagination](https://ant.design/components/pagination), re-exported unchanged.
9
+ ## Overview
10
10
 
11
- - Extends: antd **Pagination** — for inherited props and demos, use the antd MCP (`antd_info Pagination`).
12
- - Always import from '@nanisoft/prism-ui', never from `antd` directly.
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
- _No additional props beyond the antd base component._
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
- antd Popover, unchanged — a pass-through re-export. Import from '@nanisoft/prism-ui'.
3
+ The anchored floating surface for content richer than a tooltip.
4
4
 
5
- ```ts
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
- `Popover` is antd's [Popover](https://ant.design/components/popover), re-exported unchanged.
9
+ ## Overview
10
10
 
11
- - Extends: antd **Popover** — for inherited props and demos, use the antd MCP (`antd_info Popover`).
12
- - Always import from '@nanisoft/prism-ui', never from `antd` directly.
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
- _No additional props beyond the antd base component._
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: —