@nanisoft/prism-llms 0.4.0 → 0.5.1

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 +4037 -386
  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 +299 -156
  8. package/dist/index.d.ts +12 -7
  9. package/dist/index.js +9 -7
  10. package/dist/llms-full.txt +8248 -2013
  11. package/dist/llms.txt +98 -93
  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 +98 -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 +107 -0
  27. package/dist/md/blocks/settings-panel-01.md +146 -0
  28. package/dist/md/blocks/site-footer.md +103 -11
  29. package/dist/md/blocks/site-header.md +107 -11
  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 +244 -0
  34. package/dist/md/changelogs/prism-mcp-server.md +95 -0
  35. package/dist/md/changelogs/prism-tokens.md +126 -0
  36. package/dist/md/changelogs/prism-ui.md +467 -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 +114 -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/docs-shell.md +210 -15
  95. package/dist/md/pages/marketing-page.md +199 -0
  96. package/dist/md/pages/not-found-page.md +105 -0
  97. package/dist/md/pages/settings-page.md +206 -0
  98. package/dist/prism-skill.md +50 -0
  99. package/dist/store.d.ts +203 -0
  100. package/dist/store.js +317 -0
  101. package/package.json +29 -26
  102. package/dist/demo-graph.d.ts.map +0 -1
  103. package/dist/demo-graph.js.map +0 -1
  104. package/dist/extractor.d.ts.map +0 -1
  105. package/dist/extractor.js.map +0 -1
  106. package/dist/index.d.ts.map +0 -1
  107. package/dist/index.js.map +0 -1
  108. package/dist/markdown.d.ts.map +0 -1
  109. package/dist/markdown.js.map +0 -1
  110. package/dist/md/blocks/component-demo.md +0 -19
  111. package/dist/md/blocks/page-header.md +0 -19
  112. package/dist/md/components/affix.md +0 -14
  113. package/dist/md/components/anchor.md +0 -14
  114. package/dist/md/components/auto-complete.md +0 -14
  115. package/dist/md/components/back-top.md +0 -14
  116. package/dist/md/components/border-beam.md +0 -14
  117. package/dist/md/components/calendar.md +0 -14
  118. package/dist/md/components/carousel.md +0 -14
  119. package/dist/md/components/cascader.md +0 -14
  120. package/dist/md/components/col.md +0 -14
  121. package/dist/md/components/collapse.md +0 -14
  122. package/dist/md/components/color-picker.md +0 -14
  123. package/dist/md/components/date-picker.md +0 -14
  124. package/dist/md/components/descriptions.md +0 -14
  125. package/dist/md/components/display-title.md +0 -20
  126. package/dist/md/components/divider.md +0 -14
  127. package/dist/md/components/drawer.md +0 -14
  128. package/dist/md/components/dropdown.md +0 -14
  129. package/dist/md/components/empty.md +0 -14
  130. package/dist/md/components/flex.md +0 -14
  131. package/dist/md/components/float-button.md +0 -14
  132. package/dist/md/components/form.md +0 -14
  133. package/dist/md/components/grid.md +0 -14
  134. package/dist/md/components/image.md +0 -14
  135. package/dist/md/components/input-number.md +0 -14
  136. package/dist/md/components/layout.md +0 -14
  137. package/dist/md/components/list.md +0 -14
  138. package/dist/md/components/listy.md +0 -14
  139. package/dist/md/components/masonry.md +0 -14
  140. package/dist/md/components/mentions.md +0 -14
  141. package/dist/md/components/menu.md +0 -14
  142. package/dist/md/components/modal.md +0 -14
  143. package/dist/md/components/popconfirm.md +0 -14
  144. package/dist/md/components/qrcode.md +0 -14
  145. package/dist/md/components/radio.md +0 -14
  146. package/dist/md/components/rate.md +0 -14
  147. package/dist/md/components/result.md +0 -14
  148. package/dist/md/components/row.md +0 -14
  149. package/dist/md/components/segmented.md +0 -14
  150. package/dist/md/components/space.md +0 -14
  151. package/dist/md/components/spin.md +0 -14
  152. package/dist/md/components/splitter.md +0 -14
  153. package/dist/md/components/statistic.md +0 -14
  154. package/dist/md/components/steps.md +0 -14
  155. package/dist/md/components/tag.md +0 -14
  156. package/dist/md/components/time-picker.md +0 -14
  157. package/dist/md/components/timeline.md +0 -14
  158. package/dist/md/components/tour.md +0 -14
  159. package/dist/md/components/transfer.md +0 -14
  160. package/dist/md/components/tree-select.md +0 -14
  161. package/dist/md/components/tree.md +0 -14
  162. package/dist/md/components/upload.md +0 -14
  163. package/dist/md/components/watermark.md +0 -14
  164. package/dist/md/docs/brand.md +0 -41
  165. package/dist/md/pages/blog-layout.md +0 -19
  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
@@ -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,114 @@
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.
@@ -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
- antd Progress, unchanged — a pass-through re-export. Import from '@nanisoft/prism-ui'.
3
+ The bar that reports how far a task has progressed.
4
4
 
5
- ```ts
6
- import { Progress } from '@nanisoft/prism-ui/components';
5
+ ```tsx
6
+ import { Progress } from '@nanisoft/prism-ui/components/progress'
7
7
  ```
8
8
 
9
- `Progress` is antd's [Progress](https://ant.design/components/progress), re-exported unchanged.
9
+ ## Overview
10
10
 
11
- - Extends: antd **Progress** — for inherited props and demos, use the antd MCP (`antd_info Progress`).
12
- - Always import from '@nanisoft/prism-ui', never from `antd` directly.
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
- _No additional props beyond the antd base component._
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.