@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
@@ -0,0 +1,135 @@
1
+ # AppShell01
2
+
3
+ A navigation shell with a desktop rail, a top bar and a mobile navigation sheet.
4
+
5
+ ```tsx
6
+ import { AppShell01 } from '@nanisoft/prism-ui/blocks/app-shell-01'
7
+ ```
8
+
9
+ ## Overview
10
+
11
+ AppShell01 is the frame an application screen repeats: a navigation rail from
12
+ the large breakpoint up, a top bar with a breadcrumb trail and actions, and a
13
+ left-anchored sheet that carries the same navigation on narrow screens. The page
14
+ content is a slot, so the shell never decides what a screen contains.
15
+
16
+ The block composes these components:
17
+
18
+ | Part | Component | Role |
19
+ | --- | --- | --- |
20
+ | Rail | Separator | the fixed navigation column and its dividers |
21
+ | Top bar | Breadcrumb, Button | the trail and the sheet trigger |
22
+ | Sheet | Dialog | the left drawer that holds navigation on small screens |
23
+ | Content | children | the application-owned main region |
24
+
25
+ The navigation is passed as a node rather than a route table. The block never
26
+ imports a router and fetches nothing, so the application keeps its own links and
27
+ data.
28
+
29
+ ## Guidelines
30
+
31
+ ### When to use
32
+
33
+ Use AppShell01 when several screens share one navigation frame. It works when
34
+ the navigation is stable across routes and the top bar carries the current
35
+ location rather than a page's own controls.
36
+
37
+ ### When not to use
38
+
39
+ Do not use it on a marketing page or a docs article. Those pages have no
40
+ authenticated navigation rail, and the frame would collapse around content that
41
+ does not need it.
42
+
43
+ Do not use it for a single screen. One page does not justify a shell; render the
44
+ navigation directly.
45
+
46
+ ### Best practices
47
+
48
+ - Pass the same navigation node to both the rail and the sheet. The block
49
+ renders it twice, so keep ids in the navigation unique or avoid ids there.
50
+ - Keep the breadcrumb to the ancestors and the current page. The page's own
51
+ title belongs in the page header, not the top bar.
52
+ - Put account controls, a theme switch or a search in `actions`.
53
+ - Give the shell a real `navigationLabel`: it names two navigation landmarks
54
+ and the sheet trigger, and it is the only required string.
55
+
56
+ ### Content guidelines
57
+
58
+ - A brand mark is a wordmark or a short product name, not a headline.
59
+ - A breadcrumb label is the destination's display name.
60
+ - `navigationLabel` names the area for assistive technology, such as "Primary".
61
+
62
+ **The application shell with a rail, a top bar and a mobile navigation sheet.**
63
+
64
+ ```tsx
65
+ 'use client'
66
+
67
+ import { AppShell01 } from '@nanisoft/prism-ui/blocks/app-shell-01'
68
+
69
+ const LINKS = [
70
+ { href: '#dashboard', label: 'Dashboard', current: true },
71
+ { href: '#projects', label: 'Projects', current: false },
72
+ { href: '#team', label: 'Team', current: false },
73
+ ]
74
+
75
+ /** The application shell with a rail, a top bar and a mobile navigation sheet. */
76
+ export default function AppShell01Demo() {
77
+ return (
78
+ <AppShell01
79
+ navigationLabel="Primary"
80
+ brand={<span className="text-sm font-semibold">Northwind</span>}
81
+ breadcrumbs={[
82
+ { label: 'Dashboard', href: '#dashboard' },
83
+ { label: 'Projects' },
84
+ ]}
85
+ actions={
86
+ <span className="bg-muted text-muted-foreground rounded-full px-3 py-1 text-xs font-medium">
87
+ AR
88
+ </span>
89
+ }
90
+ navigation={
91
+ <ul className="flex flex-col gap-1 text-sm">
92
+ {LINKS.map((link) => (
93
+ <li key={link.href}>
94
+ <a
95
+ href={link.href}
96
+ className={
97
+ link.current
98
+ ? 'bg-accent text-accent-foreground block rounded-md px-3 py-2 font-medium'
99
+ : 'text-muted-foreground hover:text-foreground block rounded-md px-3 py-2'
100
+ }
101
+ >
102
+ {link.label}
103
+ </a>
104
+ </li>
105
+ ))}
106
+ </ul>
107
+ }
108
+ >
109
+ <div className="border-border rounded-xl border border-dashed p-6">
110
+ <h3 className="font-semibold">Main content</h3>
111
+ <p className="text-muted-foreground mt-1 text-sm">
112
+ The shell owns the frame; the application owns this region.
113
+ </p>
114
+ </div>
115
+ </AppShell01>
116
+ )
117
+ }
118
+ ```
119
+
120
+ ## Props
121
+
122
+ **`navigation`** `ReactNode` · required · default: — — The navigation rendered in the desktop rail and in the mobile sheet. Pass nodes rather than a route table: the block never imports a router.
123
+ **`navigationLabel`** `string` · required · default: — — The accessible name for the navigation regions and the sheet trigger.
124
+ **`brand`** `ReactNode` · optional · default: — — The brand or product mark at the top of the rail and the sheet.
125
+ **`breadcrumbs`** `AppShellCrumb[]` · optional · default: — — The trail shown in the top bar.
126
+ **`actions`** `ReactNode` · optional · default: — — Actions at the end of the top bar, e.g. an account menu.
127
+ **`railHeader`** `ReactNode` · optional · default: — — A slot above the navigation, e.g. a workspace switcher.
128
+ **`railFooter`** `ReactNode` · optional · default: — — A slot below the navigation, e.g. a user menu.
129
+ **`children`** `ReactNode` · required · default: —
130
+
131
+ ## Composition
132
+
133
+ **`exports`** `AppShell01` — the public runtime names this Block promises
134
+ **`source`** `packages/ui/src/blocks/app-shell-01/index.tsx` — the file this Block is defined in
135
+ **`dependencies`** `Breadcrumb, Button, Dialog, Separator` — the public Prism exports this item composes
@@ -0,0 +1,135 @@
1
+ # AuthForm01
2
+
3
+ A sign-in card with labelled credential fields, a remember control and an error slot.
4
+
5
+ ```tsx
6
+ import { AuthForm01 } from '@nanisoft/prism-ui/blocks/auth-form-01'
7
+ ```
8
+
9
+ ## Overview
10
+
11
+ AuthForm01 is a sign-in card: a title, a supporting line, an error slot, the
12
+ credential fields, an optional remember row and the submit control.
13
+
14
+ The block composes these components:
15
+
16
+ | Part | Component | Role |
17
+ | --- | --- | --- |
18
+ | Surface | Card | the panel that centres the form |
19
+ | Fields | Field, Input | labelled email and password controls |
20
+ | Choices | Checkbox | the remember-me row |
21
+ | Feedback | Alert | the error message above the fields |
22
+ | Submit | Button | the one action on the card |
23
+
24
+ The block owns no credentials and makes no request. Each field value and the
25
+ submit handler come from the consumer, and the error line is a prop, so the
26
+ consumer's validation decides when it appears.
27
+
28
+ ## Guidelines
29
+
30
+ ### When to use
31
+
32
+ Use AuthForm01 for a sign-in or a similar single-step credential screen. It
33
+ works when the screen exists to collect one email and one secret and send them
34
+ somewhere.
35
+
36
+ ### When not to use
37
+
38
+ Do not use it for registration, password reset or profile editing. Those have
39
+ different field sets; compose a form from the same parts.
40
+
41
+ Do not use it for an account picker or single sign-on landing; that is a
42
+ different shape, and `footer` is not the place for it.
43
+
44
+ ### Best practices
45
+
46
+ - Set `type`, `autoComplete` and `required` on every field. Browsers use them to
47
+ fill and validate, so the typing is the whole reason the field is typed.
48
+ - Keep the error to one sentence and mark the failed fields. The Alert names the
49
+ problem; `aria-invalid` on each input is what a screen reader announces.
50
+ - Disable the submit control while `pending` and pass `pendingLabel`, so the
51
+ reader sees that work is happening.
52
+
53
+ ### Content guidelines
54
+
55
+ - The title is a short verb phrase in sentence case: "Sign in", "Continue".
56
+ - The description states the outcome, not a policy.
57
+ - An error says what to do next: "Enter your email and password to continue."
58
+
59
+ **A sign-in card with controlled fields and a submit-time error.**
60
+
61
+ ```tsx
62
+ 'use client'
63
+
64
+ import { useState } from 'react'
65
+
66
+ import { AuthForm01 } from '@nanisoft/prism-ui/blocks/auth-form-01'
67
+
68
+ /** A sign-in card with controlled fields and a submit-time error. */
69
+ export default function AuthForm01Demo() {
70
+ const [email, setEmail] = useState('')
71
+ const [password, setPassword] = useState('')
72
+ const [error, setError] = useState<string>()
73
+
74
+ return (
75
+ <AuthForm01
76
+ title="Sign in"
77
+ description="Welcome back. Enter your details to continue."
78
+ error={error}
79
+ submitLabel="Sign in"
80
+ fields={[
81
+ {
82
+ id: 'auth-email',
83
+ label: 'Email',
84
+ type: 'email',
85
+ autoComplete: 'email',
86
+ placeholder: 'you@example.com',
87
+ value: email,
88
+ onChange: setEmail,
89
+ required: true,
90
+ },
91
+ {
92
+ id: 'auth-password',
93
+ label: 'Password',
94
+ type: 'password',
95
+ autoComplete: 'current-password',
96
+ value: password,
97
+ onChange: setPassword,
98
+ required: true,
99
+ },
100
+ ]}
101
+ remember={{ id: 'auth-remember', label: 'Remember me for 30 days' }}
102
+ onSubmit={(event) => {
103
+ event.preventDefault()
104
+ setError(
105
+ email && password ? undefined : 'Enter your email and password to continue.',
106
+ )
107
+ }}
108
+ footer={
109
+ <p className="text-muted-foreground text-center text-sm">
110
+ No account yet? Create one.
111
+ </p>
112
+ }
113
+ />
114
+ )
115
+ }
116
+ ```
117
+
118
+ ## Props
119
+
120
+ **`title`** `string` · required · default: —
121
+ **`description`** `string` · optional · default: —
122
+ **`fields`** `AuthFormField[]` · required · default: — — The credential fields, in order.
123
+ **`error`** `string` · optional · default: — — An error message shown above the fields and marked on each control.
124
+ **`remember`** `AuthFormRemember` · optional · default: — — A remember-me row under the fields.
125
+ **`submitLabel`** `string` · required · default: — — The submit button label.
126
+ **`pendingLabel`** `string` · optional · default: — — The label shown while `pending` is true. Falls back to `submitLabel`.
127
+ **`pending`** `boolean` · optional · default: — — Disables the submit control while a request is in flight.
128
+ **`onSubmit`** `(event: FormEvent<HTMLFormElement>) => void` · optional · default: —
129
+ **`footer`** `ReactNode` · optional · default: — — A row under the submit button, e.g. a link to another screen.
130
+
131
+ ## Composition
132
+
133
+ **`exports`** `AuthForm01` — the public runtime names this Block promises
134
+ **`source`** `packages/ui/src/blocks/auth-form-01/index.tsx` — the file this Block is defined in
135
+ **`dependencies`** `Alert, Button, Card, Checkbox, Field, Input` — the public Prism exports this item composes
@@ -0,0 +1,88 @@
1
+ # Cta01
2
+
3
+ A closing call to action on a filled primary surface.
4
+
5
+ ```tsx
6
+ import { Cta01 } from '@nanisoft/prism-ui/blocks/cta-01'
7
+ ```
8
+
9
+ ## Overview
10
+
11
+ Cta01 is the closing band of a page: a headline, an optional supporting line and
12
+ one action, on a filled primary surface. It is the last thing a reader sees, so
13
+ it carries exactly one decision.
14
+
15
+ The copy and the action are props. The block previously shipped the library's
16
+ own pitch, which described the library rather than whatever product installed
17
+ it.
18
+
19
+ ## Guidelines
20
+
21
+ ### When to use
22
+
23
+ Use Cta01 at the end of a marketing page, after the reader has seen the product
24
+ and is ready to act. It works when there is one clear next step.
25
+
26
+ ### When not to use
27
+
28
+ Do not use it more than once on a page. A second closing band tells the reader
29
+ the page ended twice.
30
+
31
+ Do not use it inside an application screen. Its filled surface is a marketing
32
+ emphasis, and inside a task flow it competes with the working surface.
33
+
34
+ Do not use it when the action is a download or an external link with no landing
35
+ page. The band promises a next step; the action must deliver one.
36
+
37
+ ### Best practices
38
+
39
+ - Keep the description optional and short. The headline and the action carry the
40
+ band.
41
+ - Use one action. This block takes a single action object rather than a list,
42
+ because two equal choices at the end of a page cancel each other out.
43
+ - Set `headingLevel` to match the page outline, and leave the default when the
44
+ band is composed under a heading the page already owns.
45
+ - Keep the headline shorter than the hero's. The reader has already read the
46
+ page; the closing line reminds rather than introduces.
47
+
48
+ ### Content guidelines
49
+
50
+ - The headline states the next step, not a repeat of the page title.
51
+ - The description adds one concrete detail: what the reader gets, or what it
52
+ costs.
53
+ - The action label is verb-first and sentence case: "Read the guides", "Start
54
+ free".
55
+
56
+ **The closing band, with one action.**
57
+
58
+ ```tsx
59
+ import { Cta01 } from '@nanisoft/prism-ui/blocks/cta-01'
60
+
61
+ /** The closing band, with one action. */
62
+ export default function Cta01Demo() {
63
+ return (
64
+ <Cta01
65
+ headingLevel="h3"
66
+ title="A closing line, two lines at most"
67
+ description="A sentence that says what happens next, then one action."
68
+ action={{ label: 'Do the thing', href: '/components/button' }}
69
+ />
70
+ )
71
+ }
72
+ ```
73
+
74
+ ## Props
75
+
76
+ **`title`** `string` · required · default: —
77
+ **`description`** `string` · optional · default: —
78
+ **`action`** `Cta01Action` · optional · default: — — The one action this band carries. Omit it for a closing statement that asks for nothing, and use `actionSlot` for a control that is not a call to action.
79
+ **`actionSlot`** `ReactNode` · optional · default: — — A slot for a control the block does not own, such as a client router's link or a menu. This is what a call to action with no destination becomes: a slot the consumer fills, rather than a control the block renders and cannot make work.
80
+ **`secondaryAction`** `Cta01Action` · optional · default: — — The second action, rendered beside the first at outline weight. It is a prop rather than a second `action` array because `action` is the one this Block styles as the closing ask and a second action in the same weight is two closing asks; a reader who has to choose between two equally-weighted buttons has been given a menu where a page wanted a decision. Three of the four NaniSoft sites render two actions in their closing band and all four do, and all four wrote the pair by hand, so each one re-decided the gap, the order and the weight between them.
81
+ **`note`** `ReactNode` · optional · default: — — The line under the actions: the footnote, the caveat, the sentence that qualifies the ask. Three of the four sites render one, and each wrote it by hand. A `ReactNode` rather than a string because the honest line is sometimes not one sentence: three of the four carry a link inside it, and a string prop would force a caller to compose a paragraph to say "this is in development, here is where to watch it".
82
+ **`headingLevel`** `HeadingLevel` · optional · default: — — Heading level for the headline. See `HeadingLevel`.
83
+
84
+ ## Composition
85
+
86
+ **`exports`** `Cta01` — the public runtime names this Block promises
87
+ **`source`** `packages/ui/src/blocks/cta-01/index.tsx` — the file this Block is defined in
88
+ **`dependencies`** `CtaLink, Section` — the public Prism exports this item composes
@@ -0,0 +1,196 @@
1
+ # DataTable01
2
+
3
+ A table section with a toolbar, filters, row selection and pagination.
4
+
5
+ ```tsx
6
+ import { DataTable01 } from '@nanisoft/prism-ui/blocks/data-table-01'
7
+ ```
8
+
9
+ ## Overview
10
+
11
+ DataTable01 is a table section for a paged collection: a toolbar, a search
12
+ field, a filter popover, optional row selection, a per-row action menu and
13
+ pagination. It renders the rows it is given and reports every interaction
14
+ through a callback.
15
+
16
+ The block composes these components:
17
+
18
+ | Part | Component | Role |
19
+ | --- | --- | --- |
20
+ | Toolbar | Input, Button, DropdownMenu, Popover | search, filters, column visibility |
21
+ | Grid | Table, Checkbox | the rows, with an optional selection column |
22
+ | Row menu | DropdownMenu | the actions for one row |
23
+ | Paging | Pagination, Button | the page window and the step controls |
24
+
25
+ The block owns no data and does no filtering, sorting or fetching. The page
26
+ number, the search text, the filter values and the selected ids are controlled
27
+ props, so a server page or a client cache drives it by the same contract. When a
28
+ controlled prop is omitted, that interaction falls back to internal state.
29
+
30
+ ## Guidelines
31
+
32
+ ### When to use
33
+
34
+ Use DataTable01 for a collection a reader scans, compares and acts on. It earns
35
+ its space when there is more than one column, a set that pages, and at least one
36
+ of search, filters or row selection.
37
+
38
+ ### When not to use
39
+
40
+ Do not use it for fewer than a dozen rows with no paging. A plain `Table` with a
41
+ heading is lighter and reads the same.
42
+
43
+ Do not hide the page's primary action in the row menu. Keep the main action on
44
+ the screen and reserve the menu for secondary commands.
45
+
46
+ ### Best practices
47
+
48
+ - Own the data at the call site. Filter and page there, and pass only the
49
+ current page in, so the table stays a view rather than a state store.
50
+ - Give every row a stable `getRowId`. An index-based id loses the selection
51
+ when the page changes.
52
+ - Pass every string in `labels`, and reset the page to one when the search or a
53
+ filter changes.
54
+
55
+ ### Content guidelines
56
+
57
+ - A column header is a short noun: "Account", "Seats".
58
+ - A row action is a verb phrase: "View details", "Rename", "Delete".
59
+
60
+ **A data table wired to local state: search, filters, selection and paging.**
61
+
62
+ ```tsx
63
+ 'use client'
64
+
65
+ import { useState } from 'react'
66
+
67
+ import { Button } from '@nanisoft/prism-ui/components/button'
68
+ import { DataTable01, type DataTableRow } from '@nanisoft/prism-ui/blocks/data-table-01'
69
+
70
+ const ACCOUNTS: DataTableRow[] = [
71
+ { id: 'northwind', name: 'Northwind', plan: 'Team', status: 'Active', seats: '24' },
72
+ { id: 'contoso', name: 'Contoso', plan: 'Business', status: 'Active', seats: '86' },
73
+ { id: 'fabrikam', name: 'Fabrikam', plan: 'Team', status: 'Paused', seats: '12' },
74
+ { id: 'adventure', name: 'Adventure Works', plan: 'Starter', status: 'Active', seats: '4' },
75
+ { id: 'litware', name: 'Litware', plan: 'Business', status: 'Active', seats: '140' },
76
+ { id: 'proseware', name: 'Proseware', plan: 'Starter', status: 'Paused', seats: '7' },
77
+ ]
78
+
79
+ const PAGE_SIZE = 3
80
+
81
+ /** A data table wired to local state: search, filters, selection and paging. */
82
+ export default function DataTable01Demo() {
83
+ const [query, setQuery] = useState('')
84
+ const [filters, setFilters] = useState<Record<string, string | undefined>>({})
85
+ const [selected, setSelected] = useState<string[]>([])
86
+ const [page, setPage] = useState(1)
87
+
88
+ const filtered = ACCOUNTS.filter((row) => {
89
+ const matchesQuery = String(row.name).toLowerCase().includes(query.toLowerCase())
90
+ const matchesStatus = !filters.status || row.status === filters.status
91
+ return matchesQuery && matchesStatus
92
+ })
93
+ const pageCount = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE))
94
+ const pageRows = filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)
95
+
96
+ return (
97
+ <DataTable01
98
+ title="Accounts"
99
+ description="Every workspace you can manage."
100
+ columns={[
101
+ { id: 'name', header: 'Account', label: 'Account', cell: (row) => String(row.name) },
102
+ { id: 'plan', header: 'Plan', label: 'Plan', cell: (row) => String(row.plan) },
103
+ { id: 'status', header: 'Status', label: 'Status', cell: (row) => String(row.status) },
104
+ {
105
+ id: 'seats',
106
+ header: 'Seats',
107
+ label: 'Seats',
108
+ className: 'text-right',
109
+ cell: (row) => String(row.seats),
110
+ },
111
+ ]}
112
+ rows={pageRows}
113
+ getRowId={(row) => String(row.id)}
114
+ selectable
115
+ selectedIds={selected}
116
+ onSelectedIdsChange={setSelected}
117
+ searchValue={query}
118
+ onSearchChange={(value) => {
119
+ setQuery(value)
120
+ setPage(1)
121
+ }}
122
+ filters={[
123
+ {
124
+ id: 'status',
125
+ label: 'Status',
126
+ options: [
127
+ { label: 'Active', value: 'Active' },
128
+ { label: 'Paused', value: 'Paused' },
129
+ ],
130
+ },
131
+ ]}
132
+ filterValues={filters}
133
+ onFilterChange={(id, value) => {
134
+ setFilters((previous) => ({ ...previous, [id]: value }))
135
+ setPage(1)
136
+ }}
137
+ page={page}
138
+ pageCount={pageCount}
139
+ onPageChange={setPage}
140
+ rowActions={() => [
141
+ { label: 'View details' },
142
+ { label: 'Rename' },
143
+ { label: 'Delete', variant: 'destructive' },
144
+ ]}
145
+ toolbarActions={<Button size="sm">New account</Button>}
146
+ labels={{
147
+ search: 'Search accounts',
148
+ filters: 'Filters',
149
+ reset: 'Reset filters',
150
+ columns: 'Columns',
151
+ viewColumns: 'View',
152
+ selectAll: 'Select every account on this page',
153
+ selectRow: 'Select this account',
154
+ rowActions: 'Account actions',
155
+ previous: 'Previous',
156
+ next: 'Next',
157
+ page: (value) => `Go to page ${value}`,
158
+ selectedCount: (count) => `${count} selected`,
159
+ empty: 'No accounts match the current search and filters.',
160
+ }}
161
+ />
162
+ )
163
+ }
164
+ ```
165
+
166
+ ## Props
167
+
168
+ **`title`** `ReactNode` · optional · default: —
169
+ **`description`** `ReactNode` · optional · default: —
170
+ **`columns`** `DataTableColumn[]` · required · default: —
171
+ **`rows`** `DataTableRow[]` · required · default: — — The rows for the current page. The block renders them; it never fetches.
172
+ **`getRowId`** `(row: DataTableRow) => string` · required · default: — — Returns a stable identity for a row.
173
+ **`caption`** `ReactNode` · optional · default: — — Names the table for assistive technology when no heading does.
174
+ **`selectable`** `boolean` · optional · default: — — Adds the selection column and the selection summary.
175
+ **`selectedIds`** `string[]` · optional · default: —
176
+ **`defaultSelectedIds`** `string[]` · optional · default: —
177
+ **`onSelectedIdsChange`** `(ids: string[]) => void` · optional · default: —
178
+ **`searchValue`** `string` · optional · default: —
179
+ **`onSearchChange`** `(value: string) => void` · optional · default: —
180
+ **`filters`** `DataTableFilter[]` · optional · default: —
181
+ **`filterValues`** `Record<string, string | undefined>` · optional · default: —
182
+ **`onFilterChange`** `(id: string, value: string | undefined) => void` · optional · default: —
183
+ **`page`** `number` · optional · default: — — The current page, 1-based.
184
+ **`defaultPage`** `number` · optional · default: —
185
+ **`pageCount`** `number` · required · default: — — How many pages exist. At least 1.
186
+ **`onPageChange`** `(page: number) => void` · optional · default: —
187
+ **`rowActions`** `(row: DataTableRow) => DataTableRowAction[]` · optional · default: — — The per-row action menu. Return an empty array to omit the menu.
188
+ **`toolbarActions`** `ReactNode` · optional · default: — — Controls rendered at the end of the toolbar, e.g. a create Button.
189
+ **`emptyMessage`** `ReactNode` · optional · default: — — Replaces the fallback empty line.
190
+ **`labels`** `DataTable01Labels` · required · default: —
191
+
192
+ ## Composition
193
+
194
+ **`exports`** `DataTable01` — the public runtime names this Block promises
195
+ **`source`** `packages/ui/src/blocks/data-table-01/index.tsx` — the file this Block is defined in
196
+ **`dependencies`** `Button, Checkbox, DropdownMenu, Input, Pagination, Popover, Table` — the public Prism exports this item composes
@@ -0,0 +1,92 @@
1
+ # FeatureGrid01
2
+
3
+ A feature grid with optional icon tiles and a section heading.
4
+
5
+ ```tsx
6
+ import { FeatureGrid01 } from '@nanisoft/prism-ui/blocks/feature-grid-01'
7
+ ```
8
+
9
+ ## Overview
10
+
11
+ FeatureGrid01 is a grid of short feature blurbs under an optional section
12
+ heading. Each feature carries an icon, a title and a body, and the whole list is
13
+ a prop.
14
+
15
+ The `variant` prop chooses between `icon` tiles and a bare `bare` layout that
16
+ leans on the type alone. The list was previously hardcoded, which meant an
17
+ installed block argued for the library inside the consumer's product; it is a
18
+ prop now.
19
+
20
+ ## Guidelines
21
+
22
+ ### When to use
23
+
24
+ Use FeatureGrid01 to summarise a small set of peer features whose blurbs are
25
+ short. It reads best with two to four items, and it aligns to two columns from
26
+ the `sm` breakpoint.
27
+
28
+ ### When not to use
29
+
30
+ Do not use it for a list that is actually a set of steps. Order matters in a
31
+ process, and a grid communicates that order does not.
32
+
33
+ Do not use it for long descriptions. A body longer than two sentences turns the
34
+ grid into a wall of text; use separate sections instead.
35
+
36
+ Do not use the `icon` variant when the icons are decorative and unrelated. Use
37
+ `variant="bare"` so the type carries the structure.
38
+
39
+ ### Best practices
40
+
41
+ - Keep every body to the same approximate length so the tiles stay the same
42
+ height and a reader can scan the column edges.
43
+ - Use two to four features. Five items leave one orphan on its own row unless the
44
+ grid is full-bleed.
45
+ - Pass a `title` only when the section needs a heading. The grid renders
46
+ without one, which is correct when the surrounding page already introduces it.
47
+ - Keep icons from `lucide-react` and give each one a distinct silhouette, so the
48
+ tiles are distinguishable at a glance.
49
+
50
+ ### Content guidelines
51
+
52
+ - A feature title is two or three words in sentence case.
53
+ - A feature body is one sentence and states what the feature does for the
54
+ reader, not how it is implemented.
55
+ - Do not repeat the section description in a feature body.
56
+
57
+ **The feature grid with four neutral placeholder features.**
58
+
59
+ ```tsx
60
+ import { Blocks, Palette, ShieldCheck, Zap } from 'lucide-react'
61
+
62
+ import { FeatureGrid01 } from '@nanisoft/prism-ui/blocks/feature-grid-01'
63
+
64
+ /** The feature grid with four neutral placeholder features. */
65
+ export default function FeatureGrid01Demo() {
66
+ return (
67
+ <FeatureGrid01
68
+ headingLevel="h3"
69
+ eyebrow="Preview"
70
+ title="Section heading"
71
+ description="An optional line that explains what the set below it has in common."
72
+ features={[
73
+ { icon: Palette, title: 'First item', body: 'A short sentence describing the first thing in the set.' },
74
+ { icon: Blocks, title: 'Second item', body: 'A short sentence describing the second thing in the set.' },
75
+ { icon: Zap, title: 'Third item', body: 'A short sentence describing the third thing in the set.' },
76
+ { icon: ShieldCheck, title: 'Fourth item', body: 'A short sentence describing the fourth thing in the set.' },
77
+ ]}
78
+ />
79
+ )
80
+ }
81
+ ```
82
+
83
+ ## Props
84
+
85
+ **`variant`** `'icon'` · optional · default: —
86
+ **`features`** `IconFeature[]` · required · default: —
87
+
88
+ ## Composition
89
+
90
+ **`exports`** `FeatureGrid01` — the public runtime names this Block promises
91
+ **`source`** `packages/ui/src/blocks/feature-grid-01/index.tsx` — the file this Block is defined in
92
+ **`dependencies`** `Card, Section` — the public Prism exports this item composes