@socprime/react-ui 0.0.5

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 (153) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/LICENSE +21 -0
  3. package/README.md +537 -0
  4. package/attack-flow.d.ts +16 -0
  5. package/charts.d.ts +32 -0
  6. package/decorators/index.js +8 -0
  7. package/decorators/withRouter.js +10 -0
  8. package/decorators/withTheme.js +10 -0
  9. package/decorators.d.ts +10 -0
  10. package/domain.d.ts +23 -0
  11. package/editor.d.ts +25 -0
  12. package/index.d.ts +702 -0
  13. package/lib/cn.js +8 -0
  14. package/lib/theme.js +26 -0
  15. package/lib/useFullscreen.js +52 -0
  16. package/lib/useListenOnResizeDebounce.js +22 -0
  17. package/lib/useThemeColors.js +39 -0
  18. package/package.json +113 -0
  19. package/preset/createConfig.js +98 -0
  20. package/preset/createPreview.js +53 -0
  21. package/preset/index.js +6 -0
  22. package/preset/restoreNativeFocus.js +33 -0
  23. package/preset/types.js +0 -0
  24. package/preset.d.ts +27 -0
  25. package/theme-9m7j1UoI.d.ts +5 -0
  26. package/ui/Accordion/Accordion.js +82 -0
  27. package/ui/Accordion/AccordionSection.js +41 -0
  28. package/ui/Accordion/FolderTreeExpandTrigger.js +29 -0
  29. package/ui/Accordion/chevronVariants.js +31 -0
  30. package/ui/Accordion/index.js +16 -0
  31. package/ui/AnimatedDots/AnimatedDots.js +10 -0
  32. package/ui/AnimatedDots/index.js +4 -0
  33. package/ui/Aside/Aside.js +34 -0
  34. package/ui/Aside/index.js +4 -0
  35. package/ui/AttackFlow/AttackFlow.js +9 -0
  36. package/ui/AttackFlow/AttackFlowLayout.js +63 -0
  37. package/ui/AttackFlow/Controls.js +42 -0
  38. package/ui/AttackFlow/Node.js +47 -0
  39. package/ui/AttackFlow/OtherNode.js +44 -0
  40. package/ui/AttackFlow/index.js +4 -0
  41. package/ui/AttackFlow/prependData.js +153 -0
  42. package/ui/AttackFlow/types.js +0 -0
  43. package/ui/AttackFlow/useAttackFlow.js +193 -0
  44. package/ui/Badge/Badge.js +57 -0
  45. package/ui/Badge/index.js +5 -0
  46. package/ui/Button/Button.css +1 -0
  47. package/ui/Button/Button.js +109 -0
  48. package/ui/Button/index.js +5 -0
  49. package/ui/Charts/AreaChartWithGradient.js +79 -0
  50. package/ui/Charts/index.js +4 -0
  51. package/ui/Checkbox/Checkbox.js +31 -0
  52. package/ui/Checkbox/index.js +4 -0
  53. package/ui/ConditionalContent/ConditionalContent.js +10 -0
  54. package/ui/ConditionalContent/index.js +4 -0
  55. package/ui/CorrelationTimer/CorrelationTimer.js +62 -0
  56. package/ui/CorrelationTimer/index.js +4 -0
  57. package/ui/DeleteButtonConfirm/DeleteButtonConfirm.js +65 -0
  58. package/ui/DeleteButtonConfirm/index.js +4 -0
  59. package/ui/Dialog/ConfirmDialog.js +54 -0
  60. package/ui/Dialog/DefaultDialog.js +82 -0
  61. package/ui/Dialog/Dialog.js +120 -0
  62. package/ui/Dialog/index.js +32 -0
  63. package/ui/Dropdown/Dropdown.js +204 -0
  64. package/ui/Dropdown/DropdownsCheckbox.js +102 -0
  65. package/ui/Dropdown/DropdownsSelect.js +97 -0
  66. package/ui/Dropdown/index.js +38 -0
  67. package/ui/Editor/Editor.js +97 -0
  68. package/ui/Editor/index.js +4 -0
  69. package/ui/Editor/monacoSetup.js +38 -0
  70. package/ui/Editor/theme.js +50 -0
  71. package/ui/Editor/types.js +0 -0
  72. package/ui/EmptyState/EmptyState.js +26 -0
  73. package/ui/EmptyState/index.js +4 -0
  74. package/ui/Field/Field.js +204 -0
  75. package/ui/Field/index.js +24 -0
  76. package/ui/HelperText/HelperText.js +7 -0
  77. package/ui/HelperText/index.js +4 -0
  78. package/ui/Input/Input.js +40 -0
  79. package/ui/Input/index.js +4 -0
  80. package/ui/InputNumber/InputNumber.js +90 -0
  81. package/ui/InputNumber/index.js +4 -0
  82. package/ui/InputPassword/InputPassword.js +30 -0
  83. package/ui/InputPassword/index.js +4 -0
  84. package/ui/Label/Label.js +13 -0
  85. package/ui/Label/LabelInfo.js +14 -0
  86. package/ui/Label/index.js +6 -0
  87. package/ui/MultiSelect/MultiSelect.js +163 -0
  88. package/ui/MultiSelect/index.js +4 -0
  89. package/ui/PageHeader/PageHeader.js +51 -0
  90. package/ui/PageHeader/index.js +4 -0
  91. package/ui/Pagination/Pagination.js +97 -0
  92. package/ui/Pagination/PaginationWrap.js +149 -0
  93. package/ui/Pagination/index.js +20 -0
  94. package/ui/RadioGroup/RadioGroup.js +45 -0
  95. package/ui/RadioGroup/index.js +5 -0
  96. package/ui/ScrollArea/ScrollArea.js +57 -0
  97. package/ui/ScrollArea/index.js +5 -0
  98. package/ui/SearchInput/SearchInput.js +38 -0
  99. package/ui/SearchInput/index.js +4 -0
  100. package/ui/SearchInputFields/SearchInputFields.js +53 -0
  101. package/ui/SearchInputFields/index.js +4 -0
  102. package/ui/Select/Select.js +155 -0
  103. package/ui/Select/SelectDefault.js +43 -0
  104. package/ui/Select/index.js +26 -0
  105. package/ui/Separator/Separator.js +26 -0
  106. package/ui/Separator/index.js +4 -0
  107. package/ui/Severity/Severity.js +11 -0
  108. package/ui/Severity/index.js +4 -0
  109. package/ui/Severity/utils.js +53 -0
  110. package/ui/Skeleton/Skeleton.js +25 -0
  111. package/ui/Skeleton/index.js +5 -0
  112. package/ui/Slider/Slider.js +50 -0
  113. package/ui/Slider/index.js +4 -0
  114. package/ui/Spinner/Spinner.js +21 -0
  115. package/ui/Spinner/index.js +5 -0
  116. package/ui/SpinnerSquare/SpinnerSquare.css +1 -0
  117. package/ui/SpinnerSquare/SpinnerSquare.js +22 -0
  118. package/ui/SpinnerSquare/index.js +4 -0
  119. package/ui/StatisticCard/StatisticCard.js +27 -0
  120. package/ui/StatisticCard/index.js +4 -0
  121. package/ui/StatisticCard/types.js +0 -0
  122. package/ui/Suggestions/Suggestions.js +244 -0
  123. package/ui/Suggestions/index.js +4 -0
  124. package/ui/Switch/Switch.js +64 -0
  125. package/ui/Switch/index.js +4 -0
  126. package/ui/SyncProcessBar/SyncProcessBar.js +14 -0
  127. package/ui/SyncProcessBar/index.js +4 -0
  128. package/ui/Table/GroupHeaderRow.js +36 -0
  129. package/ui/Table/RowGrouped.js +19 -0
  130. package/ui/Table/ServerGroupedTableBody.js +89 -0
  131. package/ui/Table/SortableHeader.js +46 -0
  132. package/ui/Table/Table.js +110 -0
  133. package/ui/Table/TableWrap.js +124 -0
  134. package/ui/Table/columnStyle.js +14 -0
  135. package/ui/Table/index.js +28 -0
  136. package/ui/Tabs/Tabs.js +76 -0
  137. package/ui/Tabs/index.js +4 -0
  138. package/ui/TextTruncate/TextTruncate.js +107 -0
  139. package/ui/TextTruncate/index.js +4 -0
  140. package/ui/Textarea/Textarea.js +20 -0
  141. package/ui/Textarea/index.js +4 -0
  142. package/ui/ThemeToggle/ThemeToggle.js +23 -0
  143. package/ui/ThemeToggle/index.js +4 -0
  144. package/ui/Toast/Toast.js +23 -0
  145. package/ui/Toast/index.js +4 -0
  146. package/ui/Tooltip/Tooltip.js +17 -0
  147. package/ui/Tooltip/TooltipLayout.js +60 -0
  148. package/ui/Tooltip/index.js +14 -0
  149. package/ui/TreeGuide/TreeGuide.js +23 -0
  150. package/ui/TreeGuide/index.js +5 -0
  151. package/ui/entries/charts.js +2 -0
  152. package/ui/entries/domain.js +3 -0
  153. package/ui/index.js +45 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,56 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@socprime/react-ui` are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+
7
+ ## [0.0.5] - 2026-07-27
8
+
9
+ First release published to the npm registry. Earlier versions existed only as git tags and were installed directly from the repository, so this is the initial entry point for anyone consuming the package from npm.
10
+
11
+ ### Added
12
+
13
+ - Root export with product-agnostic UI primitives built on Radix UI, CVA and Tailwind CSS v4 — forms, dialogs, dropdowns, tables, pagination, tabs, accordions, tooltips, toasts, and theming helpers (`applyTheme`, `useDocumentTheme`, `ThemeToggle`).
14
+ - Subpath exports so consumers only pay for what they import: `/domain` (SOC Prime domain components), `/editor` (Monaco), `/charts` (recharts), `/attack-flow` (`@xyflow/react` + dagre).
15
+ - `/preset` and `/decorators` for teams building their own Storybook on top of the design system.
16
+ - TypeScript definitions for every entry point, with props exported under the `<Name>Props` convention.
17
+ - A `./package.json` export, so tooling that resolves a dependency's manifest (Tailwind, Storybook, bundler plugins) can reach it.
18
+ - Documentation of the full theme contract in the README — the CSS custom properties, `@theme` tokens, keyframes and base styles the host application must provide.
19
+
20
+ ### Notes for consumers
21
+
22
+ - The package is **ESM-only**. `require()` is not supported; use `import` or a dynamic `import()`.
23
+ - `dist/` is shipped as separate ESM modules rather than a single bundle, so importing one component does not pull in the rest. All relative imports are fully specified, which keeps the output valid under strict resolvers such as Node ESM and webpack 5 with `fullySpecified`.
24
+ - TypeScript consumers need `moduleResolution` set to `bundler` or `node16`; the legacy `"node"` mode ignores `exports` and resolves neither the subpath JavaScript nor its types.
25
+ - Required peer dependencies: `react`, `react-dom`, `react-router-dom`, `@tanstack/react-table`. Optional peers are listed in the README and are only needed for the matching subpath.
26
+
27
+ ### Import paths
28
+
29
+ - `Severity`, `CorrelationTimer` and `SyncProcessBar` moved out of the root export into `@socprime/react-ui/domain`. The root export is now reserved for components with no business-domain coupling.
30
+
31
+ ```diff
32
+ - import { Severity } from '@socprime/react-ui';
33
+ + import { Severity } from '@socprime/react-ui/domain';
34
+ ```
35
+
36
+ - `Editor`, `AreaChartWithGradient`, `StatisticCard` and `AttackFlow` moved to dedicated subpaths, so consumers who do not use them stop paying for Monaco, recharts and `@xyflow/react`.
37
+
38
+ ```diff
39
+ - import { Editor, StatisticCard, AttackFlow } from '@socprime/react-ui';
40
+ + import { Editor } from '@socprime/react-ui/editor';
41
+ + import { StatisticCard } from '@socprime/react-ui/charts';
42
+ + import { AttackFlow } from '@socprime/react-ui/attack-flow';
43
+ ```
44
+
45
+ - The `@socprime/react-ui/ui` alias was removed — use the root export.
46
+ - The Storybook preset is available only through `@socprime/react-ui/preset`, no longer from the root export or from a separate `@socprime/storybook` package.
47
+
48
+ ### Types
49
+
50
+ - `StatisticsGraphData` (`/charts`): fields `count_active` and `count_all` were renamed to `activeCount` and `totalCount`. The type no longer mirrors the backend response shape — map it at your API boundary.
51
+
52
+ ### Dependencies
53
+
54
+ - `react-router-dom`, `@tanstack/react-table`, `monaco-editor`, `@monaco-editor/react`, `@xyflow/react`, `dagre` and `recharts` are peer dependencies rather than direct dependencies. Install `react-router-dom` and `@tanstack/react-table` explicitly; the rest are optional and only required if you import `/editor`, `/charts` or `/attack-flow`.
55
+
56
+ `react-router-dom` is required rather than optional because `Button`, `PageHeader` and `Aside` use React Router internally — a second copy in the bundle would carry its own context, and links rendered by the library would not see your `<BrowserRouter>`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SOC Prime
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,537 @@
1
+ # @socprime/react-ui
2
+
3
+ React component library for SOC Prime products. Ships pre-built ESM modules with TypeScript definitions: generic UI primitives built on Radix UI, CVA and Tailwind CSS, plus a set of SOC Prime domain components behind separate entry points.
4
+
5
+ ## Requirements
6
+
7
+ | Requirement | Notes |
8
+ | --- | --- |
9
+ | React 19 | `react` and `react-dom` are peer dependencies |
10
+ | Tailwind CSS v4 | The library ships class names, not compiled utilities — your Tailwind build generates them |
11
+ | ESM-capable bundler | Vite, webpack 5, Next.js, Rollup, esbuild. The package is ESM-only; `require()` is not supported |
12
+ | TypeScript 5 (optional) | `moduleResolution` must be `bundler` or `node16` |
13
+ | Node.js 20+ | Only for the build/dev toolchain of your app |
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @socprime/react-ui
19
+ # or
20
+ yarn add @socprime/react-ui
21
+ ```
22
+
23
+ Install the required peer dependencies alongside it:
24
+
25
+ ```bash
26
+ npm install react react-dom react-router-dom @tanstack/react-table
27
+ ```
28
+
29
+ Optional peers are only needed for the corresponding subpath — see [Peer dependencies](#peer-dependencies).
30
+
31
+ ## Quick start
32
+
33
+ Adopting the library takes three steps. Skipping any of them produces components that render but look broken.
34
+
35
+ ### 1. Add the theme
36
+
37
+ The library styles itself entirely through CSS custom properties and Tailwind theme tokens that **your app must define**. Copy the [reference theme](#theme-contract) into your global stylesheet (for example `src/index.css`), then import it once at your entry point:
38
+
39
+ ```tsx
40
+ // src/main.tsx
41
+ import './index.css';
42
+ ```
43
+
44
+ ### 2. Point Tailwind at the package
45
+
46
+ Tailwind only generates utilities it can find in scanned sources. Classes like `rounded-xs` or `bg-btn-primary` exist only inside the library, so your Tailwind build must scan it:
47
+
48
+ ```css
49
+ /* src/index.css */
50
+ @import 'tailwindcss';
51
+ @source "../node_modules/@socprime/react-ui/**/*.js";
52
+ ```
53
+
54
+ Without this line every component renders unstyled.
55
+
56
+ ### 3. Set up the app shell
57
+
58
+ ```tsx
59
+ // src/App.tsx
60
+ import { BrowserRouter } from 'react-router-dom';
61
+ import { Button, Toaster, applyTheme } from '@socprime/react-ui';
62
+ import { useEffect } from 'react';
63
+
64
+ export function App() {
65
+ // Adds the `.dark` / `.light` class and `data-theme` attribute to <html>.
66
+ useEffect(() => applyTheme('dark'), []);
67
+
68
+ return (
69
+ <BrowserRouter>
70
+ <Button variant="primary" size="m" onClick={() => console.log('clicked')}>
71
+ Get started
72
+ </Button>
73
+
74
+ {/* Render once, anywhere in the tree — required for toast notifications. */}
75
+ <Toaster />
76
+ </BrowserRouter>
77
+ );
78
+ }
79
+ ```
80
+
81
+ `BrowserRouter` (or any React Router provider) is required if you render `Aside`, `PageHeader`, or a `Button` with the `to` prop — those use React Router internally. Everything else works without a router.
82
+
83
+ `Tooltip` provides its own context, so no extra provider is needed for it.
84
+
85
+ ## Entry points
86
+
87
+ The public API is deliberately narrow: seven entry points, no deep imports.
88
+
89
+ | Import path | Contents | Extra peers |
90
+ | --- | --- | --- |
91
+ | `@socprime/react-ui` | Generic, product-agnostic primitives | — |
92
+ | `@socprime/react-ui/domain` | SOC Prime domain components | — |
93
+ | `@socprime/react-ui/editor` | Monaco-based code editor | `monaco-editor`, `@monaco-editor/react` |
94
+ | `@socprime/react-ui/charts` | Charts and statistics cards | `recharts` |
95
+ | `@socprime/react-ui/attack-flow` | MITRE ATT&CK flow graph | `@xyflow/react`, `dagre` |
96
+ | `@socprime/react-ui/preset` | Storybook config factory | `@storybook/react-vite`, `vite`, `vite-plugin-svgr` |
97
+ | `@socprime/react-ui/decorators` | Storybook decorators | `@storybook/react-vite` |
98
+
99
+ Heavy modules live behind their own subpaths so that an app which never imports `/editor` does not pay for Monaco — neither in bundle size nor in installed dependencies.
100
+
101
+ ```tsx
102
+ import { Button, Table, Toaster } from '@socprime/react-ui';
103
+ import { Severity, type TSeverity } from '@socprime/react-ui/domain';
104
+ import { Editor } from '@socprime/react-ui/editor';
105
+ import { AreaChartWithGradient, StatisticCard } from '@socprime/react-ui/charts';
106
+ import { AttackFlow } from '@socprime/react-ui/attack-flow';
107
+ ```
108
+
109
+ Deep imports such as `@socprime/react-ui/dist/ui/Button` are blocked by the `exports` map. This is intentional — it keeps the internal layout of the package free to change without breaking consumers.
110
+
111
+ ## Components
112
+
113
+ ### Root export
114
+
115
+ **Forms**
116
+ `Field`, `FieldSet`, `FieldGroup`, `FieldLabel`, `FieldTitle`, `FieldDescription`, `FieldContent`, `FieldError`, `FieldLegend`, `FieldSeparator`, `Input`, `InputNumber`, `InputPassword`, `Textarea`, `Checkbox`, `RadioGroup`, `RadioGroupItem`, `Switch`, `Slider`, `Select`, `SelectDefault`, `SelectTrigger`, `SelectContent`, `SelectItem`, `SelectGroup`, `SelectLabel`, `SelectValue`, `SelectSeparator`, `SelectScrollUpButton`, `SelectScrollDownButton`, `MultiSelect`, `SearchInput`, `SearchInputFields`, `Suggestions`, `Label`, `LabelInfo`, `HelperText`
117
+
118
+ **Actions and overlays**
119
+ `Button`, `buttonVariants`, `DeleteButtonConfirm`, `Dialog`, `DialogTrigger`, `DialogContent`, `DialogHeader`, `DialogFooter`, `DialogTitle`, `DialogDescription`, `DialogOverlay`, `DialogPortal`, `DialogClose`, `DefaultDialog`, `ConfirmDeleteDialog`, `DropdownMenu` (with `Trigger`, `Content`, `Item`, `CheckboxItem`, `RadioGroup`, `RadioItem`, `Label`, `Group`, `Separator`, `Shortcut`, `Sub`, `SubTrigger`, `SubContent`, `Portal`), `DropdownsCheckbox`, `DropdownsSelect`, `Tooltip`, `TooltipTrigger`, `TooltipContent`, `TooltipProvider`, `TooltipParent`, `Toaster`
120
+
121
+ **Data display**
122
+ `Table`, `TableHeader`, `TableHead`, `TableBody`, `TableRow`, `TableCell`, `TableFooter`, `TableCaption`, `TableWrap`, `SortableHeader`, `GroupHeaderRow`, `ServerGroupedTableBody`, `SkeletonTable`, `Pagination`, `PaginationWrap`, `PaginationContent`, `PaginationItem`, `PaginationLink`, `PaginationNext`, `PaginationPrevious`, `PaginationEllipsis`, `Badge`, `badgeVariants`, `EmptyState`, `TextTruncate`
123
+
124
+ **Layout and navigation**
125
+ `Aside`, `PageHeader`, `Tabs`, `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent`, `AccordionSection`, `FolderTreeExpandTrigger`, `ScrollArea`, `ScrollBar`, `Separator`, `TreeGuide`, `TreeRow`
126
+
127
+ **Feedback and state**
128
+ `Spinner`, `SpinnerCustom`, `SpinnerSquare`, `AnimatedDots`, `Skeleton`, `ConditionalContent`
129
+
130
+ **Theming**
131
+ `ThemeToggle`, `applyTheme`, `useDocumentTheme`, `ThemeName`
132
+
133
+ Every component exports its props type under the `<Name>Props` convention — `ButtonProps`, `TableWrapProps`, and so on.
134
+
135
+ ### Subpath exports
136
+
137
+ | Entry point | Exports |
138
+ | --- | --- |
139
+ | `/domain` | `Severity`, `CorrelationTimer`, `SyncProcessBar`, `TSeverity` |
140
+ | `/editor` | `Editor`, `EditorProps`, `Theme` |
141
+ | `/charts` | `AreaChartWithGradient`, `StatisticCard`, `AreaChartDataPoint`, `StatisticsGraphData`, `StatisticsGraphDataPoint` |
142
+ | `/attack-flow` | `AttackFlow`, `AttackFlowProps`, `NodeData` |
143
+ | `/preset` | `createStorybookConfig`, `createStorybookPreview`, `StorybookHostOptions` |
144
+ | `/decorators` | `withTheme`, `withRouter`, `applyTheme`, `ThemeName` |
145
+
146
+ ## Theme contract
147
+
148
+ This is the part that most often goes wrong on first integration. The library never ships colors of its own — it references Tailwind theme tokens and CSS custom properties by name and expects the host application to define them.
149
+
150
+ You need three things in your global stylesheet:
151
+
152
+ 1. **CSS custom properties** for `:root`, `.light` and `.dark`.
153
+ 2. **A `@theme inline` block** mapping those properties onto Tailwind color tokens.
154
+ 3. **Keyframes, base styles and utilities** used by `Accordion`, `AnimatedDots`, `SyncProcessBar`, `Checkbox` and `TextTruncate`.
155
+
156
+ The `.light` / `.dark` classes are toggled on `<html>` by `applyTheme()` and by the `ThemeToggle` component.
157
+
158
+ <details>
159
+ <summary><strong>Reference theme — copy this into your global stylesheet</strong></summary>
160
+
161
+ ```css
162
+ @import 'tailwindcss';
163
+ @source "../node_modules/@socprime/react-ui/**/*.js";
164
+
165
+ @custom-variant dark (&:is(.dark *));
166
+ @custom-variant light (&:is(.light *));
167
+
168
+ :root {
169
+ --font-size: 1rem;
170
+ --font-weight-normal: 400;
171
+ --radius-xs: 0.3rem;
172
+ --radius-s: 0.4rem;
173
+ --radius-sm: 0.5rem;
174
+
175
+ --white: #ffffff;
176
+ --ring: #95c9b4;
177
+ --darkGray: #6b7280;
178
+
179
+ --btn-primary: #4ac18e;
180
+ --btn-primary-hover: #3bac7c;
181
+ --btn-primary-active: #329269;
182
+ --btn-primary-disabled: #333544;
183
+
184
+ --btn-secondary: #3b3d4f;
185
+ --btn-secondary-hover: #50536b;
186
+ --btn-secondary-active: #5b5e7a;
187
+ --btn-secondary-disabled: #333544;
188
+
189
+ --btn-destructive: #ee3523;
190
+ --btn-destructive-hover: #dc2311;
191
+ --btn-destructive-active: #ba1e0e;
192
+ --btn-destructive-disabled: #333544;
193
+
194
+ --border-primary: #95c9b4;
195
+ --border-disabled: #d2d5d8;
196
+ --border-critical: #fd5749;
197
+ --border-critical-disabled: #ffa7a3;
198
+
199
+ --bg-critical-light: #fd5749;
200
+ --red-violet: #c32181;
201
+ }
202
+
203
+ .light {
204
+ --btn-secondary: #cfd0d3;
205
+ --tooltip-white: #ffffff;
206
+ --tooltip-black: #000000;
207
+
208
+ --bg-primary: #f9f9f9;
209
+ --bg-secondary: #f9f9f9;
210
+ --bg-success: #4ac18e;
211
+ --bg-warning: #ee9d23;
212
+ --bg-purple: #c27aff;
213
+ --bg-light-blue: #51a2ff;
214
+ --bg-blue: #015bbb;
215
+ --bg-gray-chateau: #99a1af;
216
+ --bg-comet: #54556a;
217
+ --bg-critical: #ee3523;
218
+ --bg-hover: #cfd0d3;
219
+ --bg-yellow: #ffe824;
220
+
221
+ --foreground: #292c3d;
222
+ --border: #cfd0d3;
223
+ --btn-ghost: #cfd0d3;
224
+ --text-subdued: #292c3d;
225
+ --text-default: #1a1e2f;
226
+ --text-dark: #1a1e2f;
227
+ --text-warning: #ee9d23;
228
+ --text-critical: #ee3523;
229
+ --mirisk: #99a1af;
230
+ }
231
+
232
+ .dark {
233
+ --btn-secondary: #252838;
234
+ --tooltip-white: #000000;
235
+ --tooltip-black: #ffffff;
236
+
237
+ --bg-black: #ffffff;
238
+ --bg-primary: #1f2232;
239
+ --bg-secondary: #252838;
240
+ --bg-success: #4ac18e;
241
+ --bg-warning: #ee9d23;
242
+ --bg-purple: #c27aff;
243
+ --bg-light-blue: #51a2ff;
244
+ --bg-blue: #015bbb;
245
+ --bg-gray-chateau: #99a1af;
246
+ --bg-comet: #54556a;
247
+ --bg-critical: #ee3523;
248
+ --bg-hover: #3b3d4f;
249
+ --bg-yellow: #ffe824;
250
+
251
+ --foreground: #f9f9f9;
252
+ --border: #3b3d4f;
253
+ --btn-ghost: #3b3d4f;
254
+ --text-subdued: #cfd0d3;
255
+ --text-default: #f9f9f9;
256
+ --text-dark: #1a1e2f;
257
+ --text-warning: #ee9d23;
258
+ --text-critical: #ee3523;
259
+ --silver: #d1d5dc;
260
+ }
261
+
262
+ @theme inline {
263
+ --color-primary: var(--bg-primary);
264
+ --color-secondary: var(--bg-secondary);
265
+ --color-foreground: var(--foreground);
266
+ --color-border: var(--border);
267
+ --color-default: var(--text-default);
268
+ --color-subdued: var(--text-subdued);
269
+ --color-dark: var(--text-dark);
270
+ --color-white: var(--white);
271
+ --color-dark-gray: var(--darkGray);
272
+ --color-silver: var(--silver);
273
+ --color-ring: var(--ring);
274
+ --color-hover: var(--bg-hover);
275
+
276
+ --color-btn-primary: var(--btn-primary);
277
+ --color-btn-primary-hover: var(--btn-primary-hover);
278
+ --color-btn-primary-active: var(--btn-primary-active);
279
+ --color-btn-primary-disabled: var(--btn-primary-disabled);
280
+ --color-btn-secondary: var(--btn-secondary);
281
+ --color-btn-secondary-hover: var(--btn-secondary-hover);
282
+ --color-btn-secondary-active: var(--btn-secondary-active);
283
+ --color-btn-secondary-disabled: var(--btn-secondary-disabled);
284
+ --color-btn-destructive: var(--btn-destructive);
285
+ --color-btn-destructive-hover: var(--btn-destructive-hover);
286
+ --color-btn-destructive-active: var(--btn-destructive-active);
287
+ --color-btn-destructive-disabled: var(--btn-destructive-disabled);
288
+ --color-btn-ghost: var(--btn-ghost);
289
+
290
+ --color-success: var(--bg-success);
291
+ --color-warning: var(--bg-warning);
292
+ --color-critical: var(--bg-critical);
293
+ --color-critical-light: var(--bg-critical-light);
294
+ --color-purple: var(--bg-purple);
295
+ --color-light-blue: var(--bg-light-blue);
296
+ --color-blue: var(--bg-blue);
297
+ --color-yellow: var(--bg-yellow);
298
+ --color-gray-chateau: var(--bg-gray-chateau);
299
+ --color-comet: var(--bg-comet);
300
+ --color-red-violet: var(--red-violet);
301
+ --color-tooltip-white: var(--tooltip-white);
302
+ --color-tooltip-black: var(--tooltip-black);
303
+
304
+ --text-3xs: 0.625rem;
305
+ --text-2xs: 0.75rem;
306
+ --text-xs: 0.875rem;
307
+ --text-sm: 1rem;
308
+ --text-m: 1.125rem;
309
+ --text-l: 1.25rem;
310
+ --text-xl: 1.375rem;
311
+ --text-lg: 1.5rem;
312
+
313
+ --animate-accordion-down: accordion-down 0.2s ease-out;
314
+ --animate-accordion-up: accordion-up 0.2s ease-out;
315
+ }
316
+
317
+ @layer base {
318
+ html,
319
+ body {
320
+ font-size: var(--font-size);
321
+ font-weight: var(--font-weight-normal);
322
+ color: var(--foreground);
323
+ background-color: var(--bg-primary);
324
+ scrollbar-width: thin;
325
+ scrollbar-color: var(--border) var(--bg-primary);
326
+ }
327
+
328
+ input[type='checkbox'] {
329
+ appearance: none;
330
+ width: 1rem;
331
+ height: 1rem;
332
+ border-width: 1px;
333
+ border-radius: 0.25rem;
334
+ cursor: pointer;
335
+ position: relative;
336
+ flex-shrink: 0;
337
+ }
338
+
339
+ input[type='checkbox']:checked::before {
340
+ content: '';
341
+ position: absolute;
342
+ top: 50%;
343
+ left: 50%;
344
+ width: 0.375rem;
345
+ height: 0.625rem;
346
+ border: solid var(--white);
347
+ border-width: 0 2px 2px 0;
348
+ transform: translate(-50%, -60%) rotate(45deg);
349
+ }
350
+
351
+ input[type='checkbox']:focus,
352
+ input[type='checkbox']:focus-visible {
353
+ outline: none;
354
+ }
355
+ }
356
+
357
+ @keyframes accordion-down {
358
+ from { height: 0; opacity: 0; }
359
+ to { height: var(--radix-accordion-content-height); opacity: 1; }
360
+ }
361
+
362
+ @keyframes accordion-up {
363
+ from { height: var(--radix-accordion-content-height); opacity: 1; }
364
+ to { height: 0; opacity: 0; }
365
+ }
366
+
367
+ @keyframes sync-progress {
368
+ 0% { transform: translateX(-100%); }
369
+ 100% { transform: translateX(350%); }
370
+ }
371
+
372
+ @keyframes dot-loading-1 {
373
+ 0%, 100% { opacity: 1; }
374
+ }
375
+
376
+ @keyframes dot-loading-2 {
377
+ 0%, 33% { opacity: 0; }
378
+ 34%, 99% { opacity: 1; }
379
+ 100% { opacity: 0; }
380
+ }
381
+
382
+ @keyframes dot-loading-3 {
383
+ 0%, 66% { opacity: 0; }
384
+ 67%, 99% { opacity: 1; }
385
+ 100% { opacity: 0; }
386
+ }
387
+
388
+ @layer utilities {
389
+ .text-default { color: var(--text-default); }
390
+ .animate-progress {
391
+ animation: sync-progress 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
392
+ will-change: transform;
393
+ }
394
+ .animate-dot-loading-1 { animation: dot-loading-1 1.2s step-end infinite; }
395
+ .animate-dot-loading-2 { animation: dot-loading-2 1.2s step-end infinite; }
396
+ .animate-dot-loading-3 { animation: dot-loading-3 1.2s step-end infinite; }
397
+ .truncate-1 {
398
+ display: -webkit-box;
399
+ -webkit-box-orient: vertical;
400
+ -webkit-line-clamp: 1;
401
+ overflow: hidden;
402
+ }
403
+ }
404
+ ```
405
+
406
+ </details>
407
+
408
+ The palette above is the SOC Prime default. Override any custom property to rebrand — the components read tokens only, never hard-coded colors.
409
+
410
+ ### Component-level CSS
411
+
412
+ `Button` and `SpinnerSquare` ship a small compiled `.css` file each. They are imported by the components themselves, so no manual CSS import is needed; the package declares `sideEffects` so bundlers keep those imports while still tree-shaking unused components.
413
+
414
+ ## Peer dependencies
415
+
416
+ Required for every consumer:
417
+
418
+ ```json
419
+ {
420
+ "react": "^19.0.0",
421
+ "react-dom": "^19.0.0",
422
+ "react-router-dom": "^7.0.0",
423
+ "@tanstack/react-table": "^8.21.0"
424
+ }
425
+ ```
426
+
427
+ `react-router-dom` is required rather than optional: `Button`, `PageHeader` and `Aside` use React Router internally, and a second copy of the router in the bundle would carry its own context — links rendered by the library would not see your `<BrowserRouter>`.
428
+
429
+ Optional peers, needed only when you import the matching subpath:
430
+
431
+ | Package | Required for |
432
+ | --- | --- |
433
+ | `monaco-editor`, `@monaco-editor/react` | `@socprime/react-ui/editor` |
434
+ | `recharts` | `@socprime/react-ui/charts` |
435
+ | `@xyflow/react`, `dagre` | `@socprime/react-ui/attack-flow` |
436
+ | `@storybook/react-vite`, `vite`, `vite-plugin-svgr` | `@socprime/react-ui/preset`, `@socprime/react-ui/decorators` |
437
+
438
+ Everything else (`@radix-ui/*`, `lucide-react`, `class-variance-authority`, `clsx`, `tailwind-merge`, `motion`, `sonner`) is a regular dependency and installs automatically.
439
+
440
+ ## TypeScript
441
+
442
+ Types ship with the package — there is no separate `@types` package. Props types are exported as named type exports next to each component:
443
+
444
+ ```tsx
445
+ import { Button, type ButtonProps } from '@socprime/react-ui';
446
+
447
+ type SubmitButtonProps = Omit<ButtonProps, 'variant'> & { pending: boolean };
448
+ ```
449
+
450
+ Your `tsconfig.json` must use a resolution mode that understands `exports`:
451
+
452
+ ```json
453
+ {
454
+ "compilerOptions": {
455
+ "moduleResolution": "bundler"
456
+ }
457
+ }
458
+ ```
459
+
460
+ With the legacy `"node"` resolution, subpath imports resolve to neither JavaScript nor types.
461
+
462
+ ## Bundler notes
463
+
464
+ ### Tree shaking
465
+
466
+ `dist/` is built as separate ESM modules rather than one bundle, so importing `{ Button }` from the root export does not pull in `Table` or `Dropdown`. All relative imports are fully specified (`./Button/index.js`), which keeps the output valid for strict resolvers such as Node ESM and webpack 5 with `fullySpecified`.
467
+
468
+ ### Monaco Editor in Vite hosts
469
+
470
+ `@socprime/react-ui/editor` registers Monaco workers with `new Worker(new URL(specifier, import.meta.url), { type: 'module' })` rather than the Vite-specific `?worker` suffix. `?worker` is only understood by the full Vite pipeline; during dependency pre-bundling (`optimizeDeps`, which runs through bare esbuild) such imports fail with errors like `Cannot read file: .../ts.worker.js?worker`. The `new URL(...)` form is understood natively by Vite, webpack 5+ and esbuild alike.
471
+
472
+ ## Storybook preset
473
+
474
+ If your team maintains its own Storybook on top of this design system, the package provides a config factory and decorators.
475
+
476
+ ```ts
477
+ // .storybook/main.ts
478
+ import path from 'node:path';
479
+ import { createStorybookConfig, type StorybookHostOptions } from '@socprime/react-ui/preset';
480
+
481
+ const hostRoot = '/absolute/path/to/your/app';
482
+
483
+ export default createStorybookConfig({
484
+ hostRoot,
485
+ hostSrcDir: path.join(hostRoot, 'src'),
486
+ themeEntry: path.join(hostRoot, 'src/index.scss'),
487
+ packageRoot: path.resolve(import.meta.dirname, '..'),
488
+ appVersion: '1.0.0',
489
+ } satisfies StorybookHostOptions);
490
+ ```
491
+
492
+ ```tsx
493
+ // .storybook/preview.tsx
494
+ import { createStorybookPreview } from '@socprime/react-ui/preset';
495
+
496
+ import '@storybook-host/theme-entry';
497
+
498
+ export default createStorybookPreview();
499
+ ```
500
+
501
+ ### `StorybookHostOptions`
502
+
503
+ | Field | Description |
504
+ | --- | --- |
505
+ | `hostRoot` | Absolute path to the host app root. Its `public/` is mounted as static files |
506
+ | `hostSrcDir` | Absolute path to `host/src`, used as a Sass `loadPaths` entry |
507
+ | `themeEntry` | Absolute path to the global theme stylesheet, exposed as the `@storybook-host/theme-entry` alias |
508
+ | `packageRoot?` | Root of **your** package, the one that owns `stories/`. Required when `/preset` is consumed as an installed dependency — otherwise `createStorybookConfig` throws instead of silently finding zero stories |
509
+ | `appVersion?` | Injected into the build as `__APP_VERSION__` |
510
+ | `extraStories?` | Additional story globs, relative to `packageRoot` |
511
+
512
+ Decorators are available separately:
513
+
514
+ ```tsx
515
+ import { withTheme, withRouter } from '@socprime/react-ui/decorators';
516
+ ```
517
+
518
+ `withTheme` applies the `.light` / `.dark` class and adds a **Theme** toolbar toggle; `withRouter` wraps stories in a `MemoryRouter` so router-aware components work in isolation.
519
+
520
+ ## Troubleshooting
521
+
522
+ | Symptom | Cause |
523
+ | --- | --- |
524
+ | Components render completely unstyled | Missing `@source` directive, so Tailwind never generated the library's utilities |
525
+ | Colors are wrong or transparent | The theme custom properties are not defined, or `.light` / `.dark` is not set on `<html>` — call `applyTheme()` |
526
+ | `useHref() may be used only in the context of a <Router>` | `Aside`, `PageHeader` or `Button to=` rendered outside a React Router provider |
527
+ | `Cannot find module '@socprime/react-ui/charts'` in TS | `moduleResolution` is `"node"`; switch to `"bundler"` or `"node16"` |
528
+ | `require() of ES Module` | The package is ESM-only; use `import` or a dynamic `import()` |
529
+ | Toasts never appear | `<Toaster />` is not rendered anywhere in the tree |
530
+
531
+ ## Versioning
532
+
533
+ See [CHANGELOG.md](./CHANGELOG.md) for release history and breaking changes.
534
+
535
+ ## License
536
+
537
+ MIT
@@ -0,0 +1,16 @@
1
+ import { FC } from 'react';
2
+
3
+ interface NodeData {
4
+ content: string;
5
+ color?: string;
6
+ nodeClass?: string;
7
+ nodeId?: string;
8
+ }
9
+ interface IAttackFlow {
10
+ content: string;
11
+ className?: string;
12
+ }
13
+
14
+ declare const AttackFlow: FC<IAttackFlow>;
15
+
16
+ export { AttackFlow, type IAttackFlow as AttackFlowProps, type NodeData };
package/charts.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ import * as React$1 from 'react';
2
+
3
+ interface AreaChartDataPoint {
4
+ name: string;
5
+ value: number;
6
+ }
7
+ interface AreaChartWithGradientProps {
8
+ data: AreaChartDataPoint[];
9
+ color: string;
10
+ height?: number;
11
+ }
12
+ declare const AreaChartWithGradient: React$1.NamedExoticComponent<AreaChartWithGradientProps>;
13
+
14
+ interface StatisticsGraphDataPoint {
15
+ name: string;
16
+ value: number;
17
+ }
18
+ interface StatisticsGraphData {
19
+ name: string;
20
+ activeCount?: number | null;
21
+ totalCount: number;
22
+ points: StatisticsGraphDataPoint[];
23
+ }
24
+
25
+ interface StatisticCardProps {
26
+ title: string;
27
+ color: string;
28
+ data?: StatisticsGraphData;
29
+ }
30
+ declare const StatisticCard: React.FC<StatisticCardProps>;
31
+
32
+ export { type AreaChartDataPoint, AreaChartWithGradient, type AreaChartWithGradientProps, StatisticCard, type StatisticCardProps, type StatisticsGraphData, type StatisticsGraphDataPoint };
@@ -0,0 +1,8 @@
1
+ import { applyTheme } from "../lib/theme.js";
2
+ import { withRouter } from "./withRouter.js";
3
+ import { withTheme } from "./withTheme.js";
4
+ export {
5
+ applyTheme,
6
+ withRouter,
7
+ withTheme
8
+ };
@@ -0,0 +1,10 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { MemoryRouter } from "react-router-dom";
3
+ const withRouter = (Story, context) => {
4
+ const initialPath = context.parameters.initialPath;
5
+ const initialEntries = initialPath ? [initialPath] : ["/"];
6
+ return /* @__PURE__ */ jsx(MemoryRouter, { initialEntries, children: /* @__PURE__ */ jsx(Story, {}) });
7
+ };
8
+ export {
9
+ withRouter
10
+ };