@particle-academy/react-fancy 6.2.0 → 6.4.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 (126) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +2 -0
  3. package/dist/autocomplete.cjs +5 -5
  4. package/dist/autocomplete.js +4 -4
  5. package/dist/breadcrumbs.cjs +2 -2
  6. package/dist/breadcrumbs.d.cts +13 -2
  7. package/dist/breadcrumbs.d.ts +13 -2
  8. package/dist/breadcrumbs.js +1 -1
  9. package/dist/card.cjs +8 -8
  10. package/dist/card.js +2 -2
  11. package/dist/chat-thread.cjs +5 -4
  12. package/dist/chat-thread.js +3 -2
  13. package/dist/{chunk-K7JOZQRK.cjs → chunk-2G6TIX5Q.cjs} +4 -4
  14. package/dist/{chunk-K7JOZQRK.cjs.map → chunk-2G6TIX5Q.cjs.map} +1 -1
  15. package/dist/chunk-5EW47IH7.js +194 -0
  16. package/dist/chunk-5EW47IH7.js.map +1 -0
  17. package/dist/{chunk-TH4JZAMK.js → chunk-5TP642UT.js} +4 -4
  18. package/dist/{chunk-TH4JZAMK.js.map → chunk-5TP642UT.js.map} +1 -1
  19. package/dist/chunk-6BB32POL.js +29 -0
  20. package/dist/chunk-6BB32POL.js.map +1 -0
  21. package/dist/{chunk-XIA2UAVO.js → chunk-6GVOW3UL.js} +4 -4
  22. package/dist/{chunk-XIA2UAVO.js.map → chunk-6GVOW3UL.js.map} +1 -1
  23. package/dist/{chunk-4JT2QANA.cjs → chunk-6H7ZN23X.cjs} +3 -3
  24. package/dist/{chunk-4JT2QANA.cjs.map → chunk-6H7ZN23X.cjs.map} +1 -1
  25. package/dist/chunk-7ZCNZUZK.cjs +183 -0
  26. package/dist/chunk-7ZCNZUZK.cjs.map +1 -0
  27. package/dist/chunk-AHZIT3CM.js +204 -0
  28. package/dist/chunk-AHZIT3CM.js.map +1 -0
  29. package/dist/{chunk-MP55W37V.cjs → chunk-BYO5RUDE.cjs} +4 -4
  30. package/dist/{chunk-MP55W37V.cjs.map → chunk-BYO5RUDE.cjs.map} +1 -1
  31. package/dist/{chunk-2XO6EYZ7.js → chunk-EENHSMV2.js} +3 -3
  32. package/dist/{chunk-2XO6EYZ7.js.map → chunk-EENHSMV2.js.map} +1 -1
  33. package/dist/{chunk-WJHPZS3U.js → chunk-GTS3QA7M.js} +11 -4
  34. package/dist/chunk-GTS3QA7M.js.map +1 -0
  35. package/dist/{chunk-7JLKOVHX.cjs → chunk-HLI6RB5V.cjs} +4 -4
  36. package/dist/{chunk-7JLKOVHX.cjs.map → chunk-HLI6RB5V.cjs.map} +1 -1
  37. package/dist/chunk-HZUKPYR3.cjs +31 -0
  38. package/dist/chunk-HZUKPYR3.cjs.map +1 -0
  39. package/dist/chunk-J2BWXCES.js +177 -0
  40. package/dist/chunk-J2BWXCES.js.map +1 -0
  41. package/dist/{chunk-CKO2KCUN.cjs → chunk-MPCZUZ4O.cjs} +7 -175
  42. package/dist/chunk-MPCZUZ4O.cjs.map +1 -0
  43. package/dist/{chunk-G7227RTY.cjs → chunk-NIAG6OF6.cjs} +4 -22
  44. package/dist/chunk-NIAG6OF6.cjs.map +1 -0
  45. package/dist/{chunk-FBWUXSKH.js → chunk-P24A2BIR.js} +4 -22
  46. package/dist/chunk-P24A2BIR.js.map +1 -0
  47. package/dist/{chunk-3AA2KGZG.js → chunk-QF2FODTG.js} +5 -173
  48. package/dist/chunk-QF2FODTG.js.map +1 -0
  49. package/dist/{chunk-A6NYZ3F5.js → chunk-RWU2MFUL.js} +4 -4
  50. package/dist/{chunk-A6NYZ3F5.js.map → chunk-RWU2MFUL.js.map} +1 -1
  51. package/dist/{chunk-EWE776WI.cjs → chunk-SKMORSBO.cjs} +11 -4
  52. package/dist/chunk-SKMORSBO.cjs.map +1 -0
  53. package/dist/{chunk-WF6AYHOS.js → chunk-UMDOSJUH.js} +4 -4
  54. package/dist/{chunk-WF6AYHOS.js.map → chunk-UMDOSJUH.js.map} +1 -1
  55. package/dist/{chunk-23KQF47X.js → chunk-UUEAFG6V.js} +3 -3
  56. package/dist/{chunk-23KQF47X.js.map → chunk-UUEAFG6V.js.map} +1 -1
  57. package/dist/chunk-VAVS6WRZ.cjs +206 -0
  58. package/dist/chunk-VAVS6WRZ.cjs.map +1 -0
  59. package/dist/{chunk-SRICSNL4.cjs → chunk-VQLPAYQF.cjs} +12 -12
  60. package/dist/{chunk-SRICSNL4.cjs.map → chunk-VQLPAYQF.cjs.map} +1 -1
  61. package/dist/chunk-Y3QAEF2P.cjs +196 -0
  62. package/dist/chunk-Y3QAEF2P.cjs.map +1 -0
  63. package/dist/{chunk-KSSTFLV2.cjs → chunk-Z44A7NPD.cjs} +6 -6
  64. package/dist/{chunk-KSSTFLV2.cjs.map → chunk-Z44A7NPD.cjs.map} +1 -1
  65. package/dist/code-block.cjs +19 -0
  66. package/dist/code-block.cjs.map +1 -0
  67. package/dist/code-block.d.cts +55 -0
  68. package/dist/code-block.d.ts +55 -0
  69. package/dist/code-block.js +10 -0
  70. package/dist/code-block.js.map +1 -0
  71. package/dist/code-view.cjs +3 -2
  72. package/dist/code-view.js +2 -1
  73. package/dist/composer.cjs +1 -1
  74. package/dist/composer.js +1 -1
  75. package/dist/content-renderer.cjs +5 -4
  76. package/dist/content-renderer.js +2 -1
  77. package/dist/dropdown.cjs +1 -1
  78. package/dist/dropdown.js +1 -1
  79. package/dist/editor.cjs +10 -8
  80. package/dist/editor.js +8 -6
  81. package/dist/index.cjs +125 -113
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.cts +2 -0
  84. package/dist/index.d.ts +2 -0
  85. package/dist/index.js +32 -28
  86. package/dist/index.js.map +1 -1
  87. package/dist/input.cjs +3 -3
  88. package/dist/input.js +3 -3
  89. package/dist/inputs.cjs +15 -15
  90. package/dist/inputs.js +6 -6
  91. package/dist/json-editor.cjs +16 -16
  92. package/dist/json-editor.js +5 -5
  93. package/dist/magic-wand.cjs +2 -2
  94. package/dist/magic-wand.js +2 -2
  95. package/dist/mobile-menu.cjs +1 -1
  96. package/dist/mobile-menu.js +1 -1
  97. package/dist/paste-pills.cjs +1 -1
  98. package/dist/paste-pills.js +1 -1
  99. package/dist/popover.cjs +1 -1
  100. package/dist/popover.js +1 -1
  101. package/dist/prompt-input.cjs +1 -1
  102. package/dist/prompt-input.js +1 -1
  103. package/dist/reason-tag.cjs +1 -1
  104. package/dist/reason-tag.js +1 -1
  105. package/dist/select.cjs +5 -5
  106. package/dist/select.js +4 -4
  107. package/dist/sidebar.cjs +1 -1
  108. package/dist/sidebar.js +1 -1
  109. package/dist/stepper.cjs +14 -0
  110. package/dist/stepper.cjs.map +1 -0
  111. package/dist/stepper.d.cts +72 -0
  112. package/dist/stepper.d.ts +72 -0
  113. package/dist/stepper.js +5 -0
  114. package/dist/stepper.js.map +1 -0
  115. package/dist/tooltip.cjs +1 -1
  116. package/dist/tooltip.js +1 -1
  117. package/docs/Breadcrumbs.md +10 -1
  118. package/docs/CodeBlock.md +84 -0
  119. package/docs/Stepper.md +124 -0
  120. package/package.json +21 -1
  121. package/dist/chunk-3AA2KGZG.js.map +0 -1
  122. package/dist/chunk-CKO2KCUN.cjs.map +0 -1
  123. package/dist/chunk-EWE776WI.cjs.map +0 -1
  124. package/dist/chunk-FBWUXSKH.js.map +0 -1
  125. package/dist/chunk-G7227RTY.cjs.map +0 -1
  126. package/dist/chunk-WJHPZS3U.js.map +0 -1
package/dist/sidebar.js CHANGED
@@ -6,8 +6,8 @@ import './chunk-CPY7NHXM.js';
6
6
  import './chunk-ZQ3VXRUY.js';
7
7
  import './chunk-5U2DZ7AV.js';
8
8
  import './chunk-3K2CEAI7.js';
9
- import './chunk-MQ6VGG62.js';
10
9
  import './chunk-5VMILVWD.js';
10
+ import './chunk-MQ6VGG62.js';
11
11
  import './chunk-RBCMKPBX.js';
12
12
  import './chunk-S53A6JIE.js';
13
13
  import './chunk-RGANGU7X.js';
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ var chunkY3QAEF2P_cjs = require('./chunk-Y3QAEF2P.cjs');
4
+ require('./chunk-SNHU2AI4.cjs');
5
+ require('./chunk-ZU5Q77OT.cjs');
6
+
7
+
8
+
9
+ Object.defineProperty(exports, "Stepper", {
10
+ enumerable: true,
11
+ get: function () { return chunkY3QAEF2P_cjs.Stepper; }
12
+ });
13
+ //# sourceMappingURL=stepper.cjs.map
14
+ //# sourceMappingURL=stepper.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"stepper.cjs"}
@@ -0,0 +1,72 @@
1
+ import * as react from 'react';
2
+ import { OlHTMLAttributes, ReactNode } from 'react';
3
+
4
+ /**
5
+ * Where a step stands. `upcoming`, `current` and `complete` are derived from
6
+ * the step's position against `current`; `error` is only ever declared, on the
7
+ * step itself, and overrides the derived state.
8
+ */
9
+ type StepperStepState = "upcoming" | "current" | "complete" | "error";
10
+ type StepperOrientation = "vertical" | "horizontal";
11
+ /** One step, as data. Everything an agent needs to emit a stepper is JSON. */
12
+ interface StepperStep$1 {
13
+ /** Stable identity, rendered as `data-step-id`. Recommended for agent handles. */
14
+ id?: string;
15
+ /** Step heading. */
16
+ title: ReactNode;
17
+ /** Short supporting line under the title. */
18
+ description?: ReactNode;
19
+ /** The step's body: instructions, a code sample, a screenshot. */
20
+ content?: ReactNode;
21
+ /**
22
+ * Override the derived state. Usually `"error"`; the others are accepted so
23
+ * a caller can mark a skipped step complete without moving `current`.
24
+ */
25
+ state?: StepperStepState;
26
+ /** With `clickable`, renders this step's button disabled. */
27
+ disabled?: boolean;
28
+ }
29
+ interface StepperProps extends Omit<OlHTMLAttributes<HTMLOListElement>, "onChange" | "children" | "defaultValue"> {
30
+ /** The steps as data. Wins over `children` when both are given. */
31
+ steps?: StepperStep$1[];
32
+ /** `Stepper.Step` elements, read as data. Ignored when `steps` is given. */
33
+ children?: ReactNode;
34
+ /** Controlled index of the current step. `steps.length` means all complete. */
35
+ current?: number;
36
+ /** Uncontrolled starting index. Default `0`. */
37
+ defaultCurrent?: number;
38
+ /** Called with the chosen step's index. Only fires when `clickable`. */
39
+ onChange?: (index: number) => void;
40
+ /** Default `"vertical"`. Horizontal suits short content. */
41
+ orientation?: StepperOrientation;
42
+ /**
43
+ * Render each step's header as a button that makes it current. Off by
44
+ * default: a Stepper is content, with no interactive elements at all.
45
+ */
46
+ clickable?: boolean;
47
+ /** Show every step's content (default), or only the current step's. */
48
+ showContent?: "all" | "current";
49
+ /** Words for each state, read by screen readers. English by default. */
50
+ stateLabels?: Partial<Record<StepperStepState, string>>;
51
+ }
52
+ /** Declarative form of a `StepperStep`; its children are the step's content. */
53
+ interface StepperStepProps extends Omit<StepperStep$1, "content"> {
54
+ children?: ReactNode;
55
+ }
56
+
57
+ /**
58
+ * Declarative step. Renders nothing itself: `Stepper` reads its props as data
59
+ * and renders it through the same path as an entry in `steps`, so the two forms
60
+ * cannot drift apart in markup, states or handles. Its children are the step's
61
+ * content. It must be a DIRECT child of `Stepper` (not wrapped in another
62
+ * component) for the same reason `Breadcrumbs.Item` must.
63
+ */
64
+ declare function StepperStep(_props: StepperStepProps): null;
65
+ declare namespace StepperStep {
66
+ var displayName: string;
67
+ }
68
+ declare const Stepper: react.ForwardRefExoticComponent<StepperProps & react.RefAttributes<HTMLOListElement>> & {
69
+ Step: typeof StepperStep;
70
+ };
71
+
72
+ export { Stepper, type StepperOrientation, type StepperProps, type StepperStep$1 as StepperStep, type StepperStepProps, type StepperStepState };
@@ -0,0 +1,72 @@
1
+ import * as react from 'react';
2
+ import { OlHTMLAttributes, ReactNode } from 'react';
3
+
4
+ /**
5
+ * Where a step stands. `upcoming`, `current` and `complete` are derived from
6
+ * the step's position against `current`; `error` is only ever declared, on the
7
+ * step itself, and overrides the derived state.
8
+ */
9
+ type StepperStepState = "upcoming" | "current" | "complete" | "error";
10
+ type StepperOrientation = "vertical" | "horizontal";
11
+ /** One step, as data. Everything an agent needs to emit a stepper is JSON. */
12
+ interface StepperStep$1 {
13
+ /** Stable identity, rendered as `data-step-id`. Recommended for agent handles. */
14
+ id?: string;
15
+ /** Step heading. */
16
+ title: ReactNode;
17
+ /** Short supporting line under the title. */
18
+ description?: ReactNode;
19
+ /** The step's body: instructions, a code sample, a screenshot. */
20
+ content?: ReactNode;
21
+ /**
22
+ * Override the derived state. Usually `"error"`; the others are accepted so
23
+ * a caller can mark a skipped step complete without moving `current`.
24
+ */
25
+ state?: StepperStepState;
26
+ /** With `clickable`, renders this step's button disabled. */
27
+ disabled?: boolean;
28
+ }
29
+ interface StepperProps extends Omit<OlHTMLAttributes<HTMLOListElement>, "onChange" | "children" | "defaultValue"> {
30
+ /** The steps as data. Wins over `children` when both are given. */
31
+ steps?: StepperStep$1[];
32
+ /** `Stepper.Step` elements, read as data. Ignored when `steps` is given. */
33
+ children?: ReactNode;
34
+ /** Controlled index of the current step. `steps.length` means all complete. */
35
+ current?: number;
36
+ /** Uncontrolled starting index. Default `0`. */
37
+ defaultCurrent?: number;
38
+ /** Called with the chosen step's index. Only fires when `clickable`. */
39
+ onChange?: (index: number) => void;
40
+ /** Default `"vertical"`. Horizontal suits short content. */
41
+ orientation?: StepperOrientation;
42
+ /**
43
+ * Render each step's header as a button that makes it current. Off by
44
+ * default: a Stepper is content, with no interactive elements at all.
45
+ */
46
+ clickable?: boolean;
47
+ /** Show every step's content (default), or only the current step's. */
48
+ showContent?: "all" | "current";
49
+ /** Words for each state, read by screen readers. English by default. */
50
+ stateLabels?: Partial<Record<StepperStepState, string>>;
51
+ }
52
+ /** Declarative form of a `StepperStep`; its children are the step's content. */
53
+ interface StepperStepProps extends Omit<StepperStep$1, "content"> {
54
+ children?: ReactNode;
55
+ }
56
+
57
+ /**
58
+ * Declarative step. Renders nothing itself: `Stepper` reads its props as data
59
+ * and renders it through the same path as an entry in `steps`, so the two forms
60
+ * cannot drift apart in markup, states or handles. Its children are the step's
61
+ * content. It must be a DIRECT child of `Stepper` (not wrapped in another
62
+ * component) for the same reason `Breadcrumbs.Item` must.
63
+ */
64
+ declare function StepperStep(_props: StepperStepProps): null;
65
+ declare namespace StepperStep {
66
+ var displayName: string;
67
+ }
68
+ declare const Stepper: react.ForwardRefExoticComponent<StepperProps & react.RefAttributes<HTMLOListElement>> & {
69
+ Step: typeof StepperStep;
70
+ };
71
+
72
+ export { Stepper, type StepperOrientation, type StepperProps, type StepperStep$1 as StepperStep, type StepperStepProps, type StepperStepState };
@@ -0,0 +1,5 @@
1
+ export { Stepper } from './chunk-5EW47IH7.js';
2
+ import './chunk-EDYAXGUM.js';
3
+ import './chunk-MMW2JGKZ.js';
4
+ //# sourceMappingURL=stepper.js.map
5
+ //# sourceMappingURL=stepper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"stepper.js"}
package/dist/tooltip.cjs CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  var chunkOASSZI6M_cjs = require('./chunk-OASSZI6M.cjs');
4
4
  require('./chunk-I27K6NLX.cjs');
5
- require('./chunk-J2DI6RMR.cjs');
6
5
  require('./chunk-MKHYENKR.cjs');
6
+ require('./chunk-J2DI6RMR.cjs');
7
7
  require('./chunk-TI7D4QDM.cjs');
8
8
  require('./chunk-OUYC6EIL.cjs');
9
9
  require('./chunk-ZU5Q77OT.cjs');
package/dist/tooltip.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { Tooltip } from './chunk-GR2WKBER.js';
2
2
  import './chunk-SV5BW3IA.js';
3
- import './chunk-MQ6VGG62.js';
4
3
  import './chunk-5VMILVWD.js';
4
+ import './chunk-MQ6VGG62.js';
5
5
  import './chunk-RBCMKPBX.js';
6
6
  import './chunk-YX6FTJ6N.js';
7
7
  import './chunk-MMW2JGKZ.js';
@@ -34,8 +34,17 @@ import { Breadcrumbs } from "@particle-academy/react-fancy";
34
34
  |------|------|---------|-------------|
35
35
  | children | `ReactNode` | - | Item label |
36
36
  | href | `string` | - | Link URL (renders an anchor when provided) |
37
- | active | `boolean` | - | Mark as the current page (no link) |
37
+ | as | `ElementType` | - | Link component to render instead of `<a>`, e.g. a router's `<Link>` |
38
+ | onClick | `() => void` | - | Navigate by callback; renders a `<button>` when there is no `href` |
39
+ | active | `boolean` | - | Mark as the current page (no link, `aria-current="page"`) |
38
40
  | className | `string` | - | Additional CSS classes |
41
+ | ...HTML attributes | `HTMLAttributes<HTMLElement>` | - | `title`, `id`, `aria-*`, `style`, handlers: forwarded to the crumb's element. Only `title` is also carried into the mobile dropdown |
42
+
43
+ ```tsx
44
+ <Breadcrumbs.Item href="/projects/42" title="Quarterly planning for the platform team">
45
+ Quarterly planning…
46
+ </Breadcrumbs.Item>
47
+ ```
39
48
 
40
49
  ## Shrinkable Breadcrumbs
41
50
 
@@ -0,0 +1,84 @@
1
+ # CodeBlock
2
+
3
+ A display-only code block: `<pre><code>`, syntax-highlighted where a grammar exists, with an optional copy button. Use it for install commands, config snippets and setup instructions.
4
+
5
+ It contains **no `textarea`, `input`, `select` or `contenteditable` element**, with or without the copy button, so it is safe on pages that must never accept input (for example a provider-setup page that must not accept credentials). The only interactive element is the copy `<button>`, and `copyable={false}` removes that too.
6
+
7
+ For an editable source surface use [`CodeView`](./CodeView.md); for a full multi-language editor use `@particle-academy/fancy-code`'s `CodeEditor`.
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { CodeBlock } from "@particle-academy/react-fancy";
13
+ // or, just this component:
14
+ import { CodeBlock } from "@particle-academy/react-fancy/code-block";
15
+ ```
16
+
17
+ ## Basic Usage
18
+
19
+ ```tsx
20
+ <CodeBlock code="npm install @particle-academy/react-fancy" language="bash" />
21
+ ```
22
+
23
+ ## With a filename header and line numbers
24
+
25
+ ```tsx
26
+ <CodeBlock
27
+ title=".env"
28
+ language="env"
29
+ showLineNumbers
30
+ code={"OPENAI_API_KEY=your-key-here\nOPENAI_ORG=org-id"}
31
+ />
32
+ ```
33
+
34
+ With `title`, the copy button sits in the header with a visible "Copy" label. Without it, the button floats in the top-right corner of the code, icon-only until it shows its feedback.
35
+
36
+ ## Highlighting
37
+
38
+ Only **HTML** is highlighted (`language` of `"html"`, `"htm"`, `"xml"` or `"xhtml"`). It is the one grammar `@particle-academy/fancy-file-commons` ships. **Every other language, including `bash`, `json`, `env`, `php`, `typescript` and `python`, renders as plain, un-highlighted text** in the same font, size and palette. Unknown languages fall back the same way, and nothing throws. `language` is still reflected as `data-language`, so a page can style or target blocks by language today.
39
+
40
+ ## Props
41
+
42
+ Also accepts every `<div>` attribute (`id`, `aria-label`, `style`, `data-*`, ...), forwarded to the root element.
43
+
44
+ | Prop | Type | Default | Description |
45
+ |------|------|---------|-------------|
46
+ | code | `string` | - | The source to show. Rendered as text, never parsed as HTML |
47
+ | language | `string` | `"plaintext"` | Language id. Only HTML aliases are highlighted; everything else is plain text |
48
+ | copyable | `boolean` | `true` | Show the copy button |
49
+ | title | `ReactNode` | - | Header above the code (a filename, or a label like "Terminal") |
50
+ | showLineNumbers | `boolean` | `false` | Number each line in a gutter that is not part of the code text |
51
+ | wrap | `boolean` | `false` | Wrap long lines instead of scrolling horizontally |
52
+ | copyLabels | `{ copy?, copied?, failed? }` | `"Copy code"`, `"Copied"`, `"Copy failed"` | Words on the copy button, for translation |
53
+ | onCopyCode | `(event: { text: string; ok: boolean }) => void` | - | Called after every copy attempt |
54
+ | className | `string` | - | Additional CSS classes on the root element |
55
+
56
+ ## Copying
57
+
58
+ The button copies **exactly the `code` prop**: no highlight markup, no line numbers, no header text. It uses `navigator.clipboard.writeText`. When the Clipboard API is missing (server, insecure `http:` context, old browser) or the write is refused, nothing throws: the button shows "Copy failed" for two seconds, and `onCopyCode` receives `ok: false`. A successful copy shows "Copied" visibly, in the button's accessible name, and in a polite live region.
59
+
60
+ ## Theming
61
+
62
+ The same palette as `CodeView` (`LIGHT_COLORS` / `DARK_COLORS` from `fancy-file-commons`), so the two sit together. Dark is chosen when `<html>` has the `dark` class or the OS prefers dark. On the server, and during hydration, the light palette is used, then the real theme.
63
+
64
+ ## Security
65
+
66
+ Code is escaped before it reaches `dangerouslySetInnerHTML`: `highlightCode` escapes `&`, `<` and `>` in every slice it emits, highlighted or plain, and token colours pass an allow-list. `<script>` in `code` renders as the text `<script>`.
67
+
68
+ ## Server rendering
69
+
70
+ No `window`, `document` or `navigator` access during render. Tested with `renderToString` with all three undefined.
71
+
72
+ ## Agent handles
73
+
74
+ | Attribute | On | Value |
75
+ |-----------|----|-------|
76
+ | `data-react-fancy-code-block` | root `<div>` | - |
77
+ | `data-language` | root | the `language` prop |
78
+ | `data-wrap` | root | `true` / `false` |
79
+ | `data-react-fancy-code-block-header` / `-title` | the header and its title | only with `title` |
80
+ | `data-react-fancy-code-block-pre` / `-code` | the `<pre>` / `<code>` | - |
81
+ | `data-react-fancy-code-block-copy` | the copy `<button>` | - |
82
+ | `data-copy-state` | the copy `<button>` | `idle` / `copied` / `failed` |
83
+ | `data-react-fancy-code-block-line` | each line, with `showLineNumbers` | the line number |
84
+ | `data-react-fancy-code-block-line-number` / `-line-content` | each line's gutter / text | - |
@@ -0,0 +1,124 @@
1
+ # Stepper
2
+
3
+ An ordered list of steps, each with a title, an optional description and rich content, and a state: `upcoming`, `current`, `complete` or `error`. Use it for setup walkthroughs and multi-step guides. Data-driven (via the `steps` prop) or compound (`Stepper.Step`).
4
+
5
+ By default a Stepper is **pure content**: an `<ol>` with no buttons, inputs or form elements, so it is safe on pages that forbid interactive controls. Clickable steps are opt-in with `clickable`.
6
+
7
+ For in-app product tours, use `fancy-walkthrough`. For a record of past events, use `Timeline`.
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Stepper } from "@particle-academy/react-fancy";
13
+ ```
14
+
15
+ ## Basic Usage
16
+
17
+ ```tsx
18
+ <Stepper
19
+ aria-label="Connect your provider"
20
+ defaultCurrent={1}
21
+ steps={[
22
+ { id: "account", title: "Create an account", description: "At the provider", content: <p>Sign up at the provider's site.</p> },
23
+ { id: "key", title: "Copy the API key", content: <p>Open Settings, then API keys.</p> },
24
+ { id: "paste", title: "Paste it here", content: <p>Come back to this page.</p> },
25
+ ]}
26
+ />
27
+ ```
28
+
29
+ Steps before `current` are `complete`, the step at `current` is `current`, and steps after it are `upcoming`. A step's own `state` overrides that, which is how a step shows `error`.
30
+
31
+ ## Stepper Props
32
+
33
+ Also accepts every `<ol>` attribute (`id`, `aria-label`, `style`, `data-*`, ...), forwarded to the list.
34
+
35
+ | Prop | Type | Default | Description |
36
+ |------|------|---------|-------------|
37
+ | steps | `StepperStep[]` | - | The steps as data. Wins over `children` when both are given |
38
+ | children | `ReactNode` | - | `Stepper.Step` elements (direct children only) |
39
+ | current | `number` | - | Controlled index of the current step. `steps.length` means every step is complete |
40
+ | defaultCurrent | `number` | `0` | Uncontrolled starting index |
41
+ | onChange | `(index: number) => void` | - | Called with the chosen step's index. Only fires when `clickable` |
42
+ | orientation | `"vertical" \| "horizontal"` | `"vertical"` | Layout. Horizontal suits short content |
43
+ | clickable | `boolean` | `false` | Render each step's header as a `<button>` that makes it current |
44
+ | showContent | `"all" \| "current"` | `"all"` | Show every step's content, or only the current step's |
45
+ | stateLabels | `Partial<Record<StepperStepState, string>>` | English | Words for each state, read by screen readers |
46
+ | className | `string` | - | Additional CSS classes on the `<ol>` |
47
+
48
+ ## StepperStep (data-driven)
49
+
50
+ | Field | Type | Required | Description |
51
+ |-------|------|----------|-------------|
52
+ | title | `ReactNode` | yes | Step heading |
53
+ | id | `string` | no | Stable identity, rendered as `data-step-id` |
54
+ | description | `ReactNode` | no | Short line under the title |
55
+ | content | `ReactNode` | no | The step's body |
56
+ | state | `"upcoming" \| "current" \| "complete" \| "error"` | no | Overrides the state derived from `current` |
57
+ | disabled | `boolean` | no | With `clickable`, the step's button is disabled |
58
+
59
+ ## Stepper.Step Props
60
+
61
+ The same fields as `StepperStep`, with the step's content as `children`. `Stepper.Step` renders nothing by itself: `Stepper` reads it as data, so both forms produce identical markup.
62
+
63
+ ```tsx
64
+ <Stepper current={step} aria-label="Connect your provider">
65
+ <Stepper.Step title="Create an account" description="At the provider">
66
+ <p>Sign up at the provider's site.</p>
67
+ </Stepper.Step>
68
+ <Stepper.Step title="Copy the API key" state={keyRejected ? "error" : undefined}>
69
+ <p>Open Settings, then API keys.</p>
70
+ </Stepper.Step>
71
+ <Stepper.Step title="Paste it here" />
72
+ </Stepper>
73
+ ```
74
+
75
+ ## Clickable steps
76
+
77
+ ```tsx
78
+ const [step, setStep] = useState(0);
79
+
80
+ <Stepper
81
+ clickable
82
+ current={step}
83
+ onChange={setStep}
84
+ steps={[
85
+ { title: "Account" },
86
+ { title: "API key" },
87
+ { title: "Finish", disabled: step < 1 },
88
+ ]}
89
+ />
90
+ ```
91
+
92
+ With `clickable`, each step's indicator and title become a `type="button"`. The description and content stay outside the button, so links in them remain links. Enter and Space activate a button natively; the arrow keys (Up/Down, or Left/Right when horizontal) and Home/End move focus between enabled steps without changing the current step. Every button stays in the tab order. Clicking the step that is already current does not call `onChange`.
93
+
94
+ ## Horizontal
95
+
96
+ ```tsx
97
+ <Stepper orientation="horizontal" current={1} steps={[{ title: "Cart" }, { title: "Shipping" }, { title: "Pay" }]} />
98
+ ```
99
+
100
+ ## Content visibility
101
+
102
+ `showContent="current"` renders only the current step's content, for a wizard-style view. The default, `"all"`, renders every step's content, for a walkthrough read top to bottom.
103
+
104
+ ## Accessibility
105
+
106
+ - An `<ol>` of `<li>`s. Give the list an `aria-label`.
107
+ - The current step's `<li>` carries `aria-current="step"`.
108
+ - Each step's state is in text (visually hidden, before the title: "Completed: Create an account"), and the indicator's glyph differs per state (number, tick, "!"), so state never depends on colour alone. Translate the words with `stateLabels`.
109
+ - Server-renders with no `window` or `document` access.
110
+
111
+ ## Agent handles
112
+
113
+ | Attribute | On | Value |
114
+ |-----------|----|-------|
115
+ | `data-react-fancy-stepper` | `<ol>` | - |
116
+ | `data-orientation` | `<ol>` | `vertical` / `horizontal` |
117
+ | `data-current` | `<ol>` | current index |
118
+ | `data-react-fancy-stepper-step` | each `<li>` | - |
119
+ | `data-state` | each `<li>` | `upcoming` / `current` / `complete` / `error` |
120
+ | `data-index` | each `<li>` | the step's index |
121
+ | `data-step-id` | each `<li>` | the step's `id`, when given |
122
+ | `data-disabled` | each `<li>` | `true` when disabled |
123
+ | `data-react-fancy-stepper-trigger` | the step's `<button>` | only when `clickable` |
124
+ | `data-react-fancy-stepper-indicator` / `-title` / `-description` / `-content` / `-state` | the step's parts | - |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/react-fancy",
3
- "version": "6.2.0",
3
+ "version": "6.4.0",
4
4
  "description": "React UI component library for Human+ UX — controlled, agent-bridgeable primitives",
5
5
  "repository": {
6
6
  "type": "git",
@@ -203,6 +203,16 @@
203
203
  "default": "./dist/checkbox-group.cjs"
204
204
  }
205
205
  },
206
+ "./code-block": {
207
+ "import": {
208
+ "types": "./dist/code-block.d.ts",
209
+ "default": "./dist/code-block.js"
210
+ },
211
+ "require": {
212
+ "types": "./dist/code-block.d.cts",
213
+ "default": "./dist/code-block.cjs"
214
+ }
215
+ },
206
216
  "./code-view": {
207
217
  "import": {
208
218
  "types": "./dist/code-view.d.ts",
@@ -873,6 +883,16 @@
873
883
  "default": "./dist/stat-list.cjs"
874
884
  }
875
885
  },
886
+ "./stepper": {
887
+ "import": {
888
+ "types": "./dist/stepper.d.ts",
889
+ "default": "./dist/stepper.js"
890
+ },
891
+ "require": {
892
+ "types": "./dist/stepper.d.cts",
893
+ "default": "./dist/stepper.cjs"
894
+ }
895
+ },
876
896
  "./sticky-note": {
877
897
  "import": {
878
898
  "types": "./dist/sticky-note.d.ts",