@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.
- package/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/README.md +537 -0
- package/attack-flow.d.ts +16 -0
- package/charts.d.ts +32 -0
- package/decorators/index.js +8 -0
- package/decorators/withRouter.js +10 -0
- package/decorators/withTheme.js +10 -0
- package/decorators.d.ts +10 -0
- package/domain.d.ts +23 -0
- package/editor.d.ts +25 -0
- package/index.d.ts +702 -0
- package/lib/cn.js +8 -0
- package/lib/theme.js +26 -0
- package/lib/useFullscreen.js +52 -0
- package/lib/useListenOnResizeDebounce.js +22 -0
- package/lib/useThemeColors.js +39 -0
- package/package.json +113 -0
- package/preset/createConfig.js +98 -0
- package/preset/createPreview.js +53 -0
- package/preset/index.js +6 -0
- package/preset/restoreNativeFocus.js +33 -0
- package/preset/types.js +0 -0
- package/preset.d.ts +27 -0
- package/theme-9m7j1UoI.d.ts +5 -0
- package/ui/Accordion/Accordion.js +82 -0
- package/ui/Accordion/AccordionSection.js +41 -0
- package/ui/Accordion/FolderTreeExpandTrigger.js +29 -0
- package/ui/Accordion/chevronVariants.js +31 -0
- package/ui/Accordion/index.js +16 -0
- package/ui/AnimatedDots/AnimatedDots.js +10 -0
- package/ui/AnimatedDots/index.js +4 -0
- package/ui/Aside/Aside.js +34 -0
- package/ui/Aside/index.js +4 -0
- package/ui/AttackFlow/AttackFlow.js +9 -0
- package/ui/AttackFlow/AttackFlowLayout.js +63 -0
- package/ui/AttackFlow/Controls.js +42 -0
- package/ui/AttackFlow/Node.js +47 -0
- package/ui/AttackFlow/OtherNode.js +44 -0
- package/ui/AttackFlow/index.js +4 -0
- package/ui/AttackFlow/prependData.js +153 -0
- package/ui/AttackFlow/types.js +0 -0
- package/ui/AttackFlow/useAttackFlow.js +193 -0
- package/ui/Badge/Badge.js +57 -0
- package/ui/Badge/index.js +5 -0
- package/ui/Button/Button.css +1 -0
- package/ui/Button/Button.js +109 -0
- package/ui/Button/index.js +5 -0
- package/ui/Charts/AreaChartWithGradient.js +79 -0
- package/ui/Charts/index.js +4 -0
- package/ui/Checkbox/Checkbox.js +31 -0
- package/ui/Checkbox/index.js +4 -0
- package/ui/ConditionalContent/ConditionalContent.js +10 -0
- package/ui/ConditionalContent/index.js +4 -0
- package/ui/CorrelationTimer/CorrelationTimer.js +62 -0
- package/ui/CorrelationTimer/index.js +4 -0
- package/ui/DeleteButtonConfirm/DeleteButtonConfirm.js +65 -0
- package/ui/DeleteButtonConfirm/index.js +4 -0
- package/ui/Dialog/ConfirmDialog.js +54 -0
- package/ui/Dialog/DefaultDialog.js +82 -0
- package/ui/Dialog/Dialog.js +120 -0
- package/ui/Dialog/index.js +32 -0
- package/ui/Dropdown/Dropdown.js +204 -0
- package/ui/Dropdown/DropdownsCheckbox.js +102 -0
- package/ui/Dropdown/DropdownsSelect.js +97 -0
- package/ui/Dropdown/index.js +38 -0
- package/ui/Editor/Editor.js +97 -0
- package/ui/Editor/index.js +4 -0
- package/ui/Editor/monacoSetup.js +38 -0
- package/ui/Editor/theme.js +50 -0
- package/ui/Editor/types.js +0 -0
- package/ui/EmptyState/EmptyState.js +26 -0
- package/ui/EmptyState/index.js +4 -0
- package/ui/Field/Field.js +204 -0
- package/ui/Field/index.js +24 -0
- package/ui/HelperText/HelperText.js +7 -0
- package/ui/HelperText/index.js +4 -0
- package/ui/Input/Input.js +40 -0
- package/ui/Input/index.js +4 -0
- package/ui/InputNumber/InputNumber.js +90 -0
- package/ui/InputNumber/index.js +4 -0
- package/ui/InputPassword/InputPassword.js +30 -0
- package/ui/InputPassword/index.js +4 -0
- package/ui/Label/Label.js +13 -0
- package/ui/Label/LabelInfo.js +14 -0
- package/ui/Label/index.js +6 -0
- package/ui/MultiSelect/MultiSelect.js +163 -0
- package/ui/MultiSelect/index.js +4 -0
- package/ui/PageHeader/PageHeader.js +51 -0
- package/ui/PageHeader/index.js +4 -0
- package/ui/Pagination/Pagination.js +97 -0
- package/ui/Pagination/PaginationWrap.js +149 -0
- package/ui/Pagination/index.js +20 -0
- package/ui/RadioGroup/RadioGroup.js +45 -0
- package/ui/RadioGroup/index.js +5 -0
- package/ui/ScrollArea/ScrollArea.js +57 -0
- package/ui/ScrollArea/index.js +5 -0
- package/ui/SearchInput/SearchInput.js +38 -0
- package/ui/SearchInput/index.js +4 -0
- package/ui/SearchInputFields/SearchInputFields.js +53 -0
- package/ui/SearchInputFields/index.js +4 -0
- package/ui/Select/Select.js +155 -0
- package/ui/Select/SelectDefault.js +43 -0
- package/ui/Select/index.js +26 -0
- package/ui/Separator/Separator.js +26 -0
- package/ui/Separator/index.js +4 -0
- package/ui/Severity/Severity.js +11 -0
- package/ui/Severity/index.js +4 -0
- package/ui/Severity/utils.js +53 -0
- package/ui/Skeleton/Skeleton.js +25 -0
- package/ui/Skeleton/index.js +5 -0
- package/ui/Slider/Slider.js +50 -0
- package/ui/Slider/index.js +4 -0
- package/ui/Spinner/Spinner.js +21 -0
- package/ui/Spinner/index.js +5 -0
- package/ui/SpinnerSquare/SpinnerSquare.css +1 -0
- package/ui/SpinnerSquare/SpinnerSquare.js +22 -0
- package/ui/SpinnerSquare/index.js +4 -0
- package/ui/StatisticCard/StatisticCard.js +27 -0
- package/ui/StatisticCard/index.js +4 -0
- package/ui/StatisticCard/types.js +0 -0
- package/ui/Suggestions/Suggestions.js +244 -0
- package/ui/Suggestions/index.js +4 -0
- package/ui/Switch/Switch.js +64 -0
- package/ui/Switch/index.js +4 -0
- package/ui/SyncProcessBar/SyncProcessBar.js +14 -0
- package/ui/SyncProcessBar/index.js +4 -0
- package/ui/Table/GroupHeaderRow.js +36 -0
- package/ui/Table/RowGrouped.js +19 -0
- package/ui/Table/ServerGroupedTableBody.js +89 -0
- package/ui/Table/SortableHeader.js +46 -0
- package/ui/Table/Table.js +110 -0
- package/ui/Table/TableWrap.js +124 -0
- package/ui/Table/columnStyle.js +14 -0
- package/ui/Table/index.js +28 -0
- package/ui/Tabs/Tabs.js +76 -0
- package/ui/Tabs/index.js +4 -0
- package/ui/TextTruncate/TextTruncate.js +107 -0
- package/ui/TextTruncate/index.js +4 -0
- package/ui/Textarea/Textarea.js +20 -0
- package/ui/Textarea/index.js +4 -0
- package/ui/ThemeToggle/ThemeToggle.js +23 -0
- package/ui/ThemeToggle/index.js +4 -0
- package/ui/Toast/Toast.js +23 -0
- package/ui/Toast/index.js +4 -0
- package/ui/Tooltip/Tooltip.js +17 -0
- package/ui/Tooltip/TooltipLayout.js +60 -0
- package/ui/Tooltip/index.js +14 -0
- package/ui/TreeGuide/TreeGuide.js +23 -0
- package/ui/TreeGuide/index.js +5 -0
- package/ui/entries/charts.js +2 -0
- package/ui/entries/domain.js +3 -0
- package/ui/index.js +45 -0
package/lib/cn.js
ADDED
package/lib/theme.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
function applyTheme(theme) {
|
|
3
|
+
const root = document.documentElement;
|
|
4
|
+
root.classList.remove("dark", "light");
|
|
5
|
+
root.classList.add(theme);
|
|
6
|
+
root.setAttribute("data-theme", theme);
|
|
7
|
+
}
|
|
8
|
+
function getTheme() {
|
|
9
|
+
const theme = document.documentElement.getAttribute("data-theme");
|
|
10
|
+
return theme === "light" ? "light" : "dark";
|
|
11
|
+
}
|
|
12
|
+
function subscribe(onStoreChange) {
|
|
13
|
+
const observer = new MutationObserver(onStoreChange);
|
|
14
|
+
observer.observe(document.documentElement, {
|
|
15
|
+
attributes: true,
|
|
16
|
+
attributeFilter: ["data-theme"]
|
|
17
|
+
});
|
|
18
|
+
return () => observer.disconnect();
|
|
19
|
+
}
|
|
20
|
+
function useDocumentTheme() {
|
|
21
|
+
return useSyncExternalStore(subscribe, getTheme, () => "dark");
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
applyTheme,
|
|
25
|
+
useDocumentTheme
|
|
26
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
function useFullscreen(element, onFullscreenChange) {
|
|
3
|
+
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
4
|
+
const handleFullscreenChange = useCallback(() => {
|
|
5
|
+
const { fullscreenElement } = document;
|
|
6
|
+
const isCurrentlyFullscreen = !!fullscreenElement;
|
|
7
|
+
setIsFullscreen(isCurrentlyFullscreen);
|
|
8
|
+
onFullscreenChange?.(isCurrentlyFullscreen);
|
|
9
|
+
}, [onFullscreenChange]);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
|
12
|
+
return () => {
|
|
13
|
+
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
14
|
+
};
|
|
15
|
+
}, [handleFullscreenChange]);
|
|
16
|
+
const enterFullscreen = useCallback(async () => {
|
|
17
|
+
if (!element.current) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
await element.current.requestFullscreen();
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(error);
|
|
24
|
+
}
|
|
25
|
+
}, [element]);
|
|
26
|
+
const exitFullscreen = useCallback(async () => {
|
|
27
|
+
if (!document.fullscreenElement) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
await document.exitFullscreen();
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(error);
|
|
34
|
+
}
|
|
35
|
+
}, []);
|
|
36
|
+
const toggleFullscreen = useCallback(async () => {
|
|
37
|
+
if (document.fullscreenElement) {
|
|
38
|
+
await exitFullscreen();
|
|
39
|
+
} else {
|
|
40
|
+
await enterFullscreen();
|
|
41
|
+
}
|
|
42
|
+
}, [enterFullscreen, exitFullscreen]);
|
|
43
|
+
return {
|
|
44
|
+
isFullscreen,
|
|
45
|
+
toggleFullscreen,
|
|
46
|
+
enterFullscreen,
|
|
47
|
+
exitFullscreen
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
useFullscreen
|
|
52
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
const useListenOnResizeDebounce = (handleResize) => {
|
|
3
|
+
useEffect(() => {
|
|
4
|
+
let resizeTimeout;
|
|
5
|
+
const debouncedResize = () => {
|
|
6
|
+
if (resizeTimeout) {
|
|
7
|
+
clearTimeout(resizeTimeout);
|
|
8
|
+
}
|
|
9
|
+
resizeTimeout = setTimeout(handleResize, 200);
|
|
10
|
+
};
|
|
11
|
+
window.addEventListener("resize", debouncedResize);
|
|
12
|
+
return () => {
|
|
13
|
+
window.removeEventListener("resize", debouncedResize);
|
|
14
|
+
if (resizeTimeout) {
|
|
15
|
+
clearTimeout(resizeTimeout);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}, [handleResize]);
|
|
19
|
+
};
|
|
20
|
+
export {
|
|
21
|
+
useListenOnResizeDebounce
|
|
22
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
function colorsEqual(a, b) {
|
|
3
|
+
return a.primary === b.primary && a.secondary === b.secondary && a.success === b.success && a.lightBlue === b.lightBlue && a.purple === b.purple && a.default === b.default && a.subdued === b.subdued && a.warning === b.warning && a.critical === b.critical && a.border === b.border;
|
|
4
|
+
}
|
|
5
|
+
let cachedColors = null;
|
|
6
|
+
function getThemeColors() {
|
|
7
|
+
const styles = getComputedStyle(document.documentElement);
|
|
8
|
+
const nextColors = {
|
|
9
|
+
primary: styles.getPropertyValue("--bg-primary").trim(),
|
|
10
|
+
secondary: styles.getPropertyValue("--bg-secondary").trim(),
|
|
11
|
+
success: styles.getPropertyValue("--bg-success").trim(),
|
|
12
|
+
lightBlue: styles.getPropertyValue("--bg-light-blue").trim(),
|
|
13
|
+
purple: styles.getPropertyValue("--bg-purple").trim(),
|
|
14
|
+
default: styles.getPropertyValue("--text-default").trim(),
|
|
15
|
+
subdued: styles.getPropertyValue("--text-subdued").trim(),
|
|
16
|
+
warning: styles.getPropertyValue("--text-warning").trim(),
|
|
17
|
+
critical: styles.getPropertyValue("--text-critical").trim(),
|
|
18
|
+
border: styles.getPropertyValue("--border").trim()
|
|
19
|
+
};
|
|
20
|
+
if (cachedColors && colorsEqual(cachedColors, nextColors)) {
|
|
21
|
+
return cachedColors;
|
|
22
|
+
}
|
|
23
|
+
cachedColors = nextColors;
|
|
24
|
+
return cachedColors;
|
|
25
|
+
}
|
|
26
|
+
function subscribe(onStoreChange) {
|
|
27
|
+
const observer = new MutationObserver(onStoreChange);
|
|
28
|
+
observer.observe(document.documentElement, {
|
|
29
|
+
attributes: true,
|
|
30
|
+
attributeFilter: ["data-theme", "class"]
|
|
31
|
+
});
|
|
32
|
+
return () => observer.disconnect();
|
|
33
|
+
}
|
|
34
|
+
function useThemeColors() {
|
|
35
|
+
return useSyncExternalStore(subscribe, getThemeColors, getThemeColors);
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
useThemeColors
|
|
39
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@socprime/react-ui",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "SOC Prime React UI component library and Storybook design system.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"sideEffects": [
|
|
11
|
+
"**/*.css"
|
|
12
|
+
],
|
|
13
|
+
"main": "./ui/index.js",
|
|
14
|
+
"types": "./index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./index.d.ts",
|
|
18
|
+
"import": "./ui/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./editor": {
|
|
21
|
+
"types": "./editor.d.ts",
|
|
22
|
+
"import": "./ui/Editor/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./charts": {
|
|
25
|
+
"types": "./charts.d.ts",
|
|
26
|
+
"import": "./ui/entries/charts.js"
|
|
27
|
+
},
|
|
28
|
+
"./domain": {
|
|
29
|
+
"types": "./domain.d.ts",
|
|
30
|
+
"import": "./ui/entries/domain.js"
|
|
31
|
+
},
|
|
32
|
+
"./attack-flow": {
|
|
33
|
+
"types": "./attack-flow.d.ts",
|
|
34
|
+
"import": "./ui/AttackFlow/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./preset": {
|
|
37
|
+
"types": "./preset.d.ts",
|
|
38
|
+
"import": "./preset/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./decorators": {
|
|
41
|
+
"types": "./decorators.d.ts",
|
|
42
|
+
"import": "./decorators/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./package.json": "./package.json"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@monaco-editor/react": "^4.7.0",
|
|
48
|
+
"@storybook/react-vite": "^10.0.0",
|
|
49
|
+
"@tanstack/react-table": "^8.21.0",
|
|
50
|
+
"@xyflow/react": "^12.9.2",
|
|
51
|
+
"dagre": "^0.8.5",
|
|
52
|
+
"monaco-editor": "^0.55.1",
|
|
53
|
+
"react": "^19.0.0",
|
|
54
|
+
"react-dom": "^19.0.0",
|
|
55
|
+
"react-router-dom": "^7.0.0",
|
|
56
|
+
"recharts": "^3.8.1",
|
|
57
|
+
"vite": "^7.0.0",
|
|
58
|
+
"vite-plugin-svgr": "^4.0.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"@monaco-editor/react": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"@storybook/react-vite": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"@xyflow/react": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"dagre": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"monaco-editor": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"recharts": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"vite": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"vite-plugin-svgr": {
|
|
83
|
+
"optional": true
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"dependencies": {
|
|
87
|
+
"@radix-ui/react-accordion": "^1.2.12",
|
|
88
|
+
"@radix-ui/react-checkbox": "^1.3.3",
|
|
89
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
90
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
91
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
92
|
+
"@radix-ui/react-navigation-menu": "^1.2.14",
|
|
93
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
94
|
+
"@radix-ui/react-radio-group": "^1.3.8",
|
|
95
|
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
96
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
97
|
+
"@radix-ui/react-separator": "^1.1.8",
|
|
98
|
+
"@radix-ui/react-slider": "^1.3.6",
|
|
99
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
100
|
+
"@radix-ui/react-switch": "^1.2.6",
|
|
101
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
102
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
103
|
+
"class-variance-authority": "^0.7.1",
|
|
104
|
+
"clsx": "^2.1.1",
|
|
105
|
+
"lucide-react": "^0.552.0",
|
|
106
|
+
"motion": "^12.23.24",
|
|
107
|
+
"sonner": "^2.0.7",
|
|
108
|
+
"tailwind-merge": "^3.3.1"
|
|
109
|
+
},
|
|
110
|
+
"publishConfig": {
|
|
111
|
+
"access": "public"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { mergeConfig } from "vite";
|
|
5
|
+
import svgr from "vite-plugin-svgr";
|
|
6
|
+
const PACKAGE_NAME = "@socprime/react-ui";
|
|
7
|
+
function findPackageRoot(startDir) {
|
|
8
|
+
let dir = startDir;
|
|
9
|
+
while (!existsSync(path.join(dir, "package.json"))) {
|
|
10
|
+
const parent = path.dirname(dir);
|
|
11
|
+
if (parent === dir) {
|
|
12
|
+
throw new Error(`Could not locate a package.json above ${startDir}`);
|
|
13
|
+
}
|
|
14
|
+
dir = parent;
|
|
15
|
+
}
|
|
16
|
+
return dir;
|
|
17
|
+
}
|
|
18
|
+
function resolvePackageRoot(explicitPackageRoot) {
|
|
19
|
+
if (explicitPackageRoot) {
|
|
20
|
+
return explicitPackageRoot;
|
|
21
|
+
}
|
|
22
|
+
const presetDir = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
const root = findPackageRoot(presetDir);
|
|
24
|
+
const { name } = JSON.parse(readFileSync(path.join(root, "package.json"), "utf-8"));
|
|
25
|
+
if (name === PACKAGE_NAME) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`createStorybookConfig(): could not infer "packageRoot" because "${PACKAGE_NAME}/preset" is running from an installed dependency. Pass "packageRoot" explicitly \u2014 the root of your own Storybook package that owns the "stories/" directory.`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return root;
|
|
31
|
+
}
|
|
32
|
+
function createStorybookConfig(options) {
|
|
33
|
+
const packageRoot = resolvePackageRoot(options.packageRoot);
|
|
34
|
+
const storiesDir = path.join(packageRoot, "stories");
|
|
35
|
+
const stories = [
|
|
36
|
+
path.join(storiesDir, "**/*.stories.@(js|jsx|mjs|ts|tsx)"),
|
|
37
|
+
...options.extraStories?.map((glob) => path.join(packageRoot, glob)) ?? []
|
|
38
|
+
];
|
|
39
|
+
return {
|
|
40
|
+
stories,
|
|
41
|
+
addons: ["@storybook/addon-docs", "@storybook/addon-a11y"],
|
|
42
|
+
framework: "@storybook/react-vite",
|
|
43
|
+
features: {
|
|
44
|
+
changeDetection: false,
|
|
45
|
+
sidebarOnboardingChecklist: false,
|
|
46
|
+
menuOnboardingChecklist: false
|
|
47
|
+
},
|
|
48
|
+
staticDirs: [
|
|
49
|
+
{
|
|
50
|
+
from: path.join(options.hostRoot, "public"),
|
|
51
|
+
to: "/"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
async viteFinal(config) {
|
|
55
|
+
return mergeConfig(config, {
|
|
56
|
+
define: {
|
|
57
|
+
__APP_VERSION__: JSON.stringify(options.appVersion ?? "0.0.0")
|
|
58
|
+
},
|
|
59
|
+
resolve: {
|
|
60
|
+
alias: {
|
|
61
|
+
"@": packageRoot,
|
|
62
|
+
"@storybook-host/theme-entry": options.themeEntry
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
plugins: [
|
|
66
|
+
svgr({
|
|
67
|
+
svgrOptions: {
|
|
68
|
+
icon: true
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
],
|
|
72
|
+
css: {
|
|
73
|
+
preprocessorOptions: {
|
|
74
|
+
scss: {
|
|
75
|
+
loadPaths: [options.hostSrcDir],
|
|
76
|
+
additionalData: `@use 'assets/scss/palette' as palette;`
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
server: {
|
|
81
|
+
fs: {
|
|
82
|
+
allow: [options.hostRoot, packageRoot]
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
worker: {
|
|
86
|
+
format: "es"
|
|
87
|
+
},
|
|
88
|
+
optimizeDeps: {
|
|
89
|
+
include: ["monaco-editor"],
|
|
90
|
+
exclude: ["@monaco-editor/react"]
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
createStorybookConfig
|
|
98
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { withRouter, withTheme } from "../decorators/index.js";
|
|
3
|
+
import { Toaster } from "../ui/index.js";
|
|
4
|
+
import { restoreNativeFocus } from "./restoreNativeFocus.js";
|
|
5
|
+
function createStorybookPreview() {
|
|
6
|
+
return {
|
|
7
|
+
globalTypes: {
|
|
8
|
+
theme: {
|
|
9
|
+
description: "Host color theme (CSS tokens from theme entry)",
|
|
10
|
+
toolbar: {
|
|
11
|
+
title: "Theme",
|
|
12
|
+
icon: "circlehollow",
|
|
13
|
+
items: [
|
|
14
|
+
{ value: "dark", title: "Dark", icon: "moon" },
|
|
15
|
+
{ value: "light", title: "Light", icon: "sun" }
|
|
16
|
+
],
|
|
17
|
+
dynamicTitle: true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
initialGlobals: {
|
|
22
|
+
theme: "dark"
|
|
23
|
+
},
|
|
24
|
+
parameters: {
|
|
25
|
+
layout: "centered",
|
|
26
|
+
controls: {
|
|
27
|
+
matchers: {
|
|
28
|
+
color: /(background|color)$/i,
|
|
29
|
+
date: /Date$/i
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
backgrounds: { disable: true },
|
|
33
|
+
a11y: {
|
|
34
|
+
// Fails interaction/test-runner runs when violations are found.
|
|
35
|
+
test: "error"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
decorators: [
|
|
39
|
+
withRouter,
|
|
40
|
+
withTheme,
|
|
41
|
+
(Story) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42
|
+
/* @__PURE__ */ jsx(Story, {}),
|
|
43
|
+
/* @__PURE__ */ jsx(Toaster, {})
|
|
44
|
+
] })
|
|
45
|
+
],
|
|
46
|
+
beforeEach() {
|
|
47
|
+
restoreNativeFocus();
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
createStorybookPreview
|
|
53
|
+
};
|
package/preset/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
let cachedNativeFocus = null;
|
|
2
|
+
function getNativeFocus() {
|
|
3
|
+
if (cachedNativeFocus) {
|
|
4
|
+
return cachedNativeFocus;
|
|
5
|
+
}
|
|
6
|
+
const iframe = document.createElement("iframe");
|
|
7
|
+
iframe.style.display = "none";
|
|
8
|
+
document.body.appendChild(iframe);
|
|
9
|
+
const contentWindow = iframe.contentWindow;
|
|
10
|
+
if (!contentWindow) {
|
|
11
|
+
throw new Error("Unable to access iframe content window");
|
|
12
|
+
}
|
|
13
|
+
const { focus } = contentWindow.HTMLElement.prototype;
|
|
14
|
+
document.body.removeChild(iframe);
|
|
15
|
+
cachedNativeFocus = focus;
|
|
16
|
+
return focus;
|
|
17
|
+
}
|
|
18
|
+
function restoreNativeFocus() {
|
|
19
|
+
if (typeof HTMLElement === "undefined") {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const nativeFocus = getNativeFocus();
|
|
23
|
+
Object.defineProperty(HTMLElement.prototype, "focus", {
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: function focus(options) {
|
|
27
|
+
return nativeFocus.call(this, options);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
restoreNativeFocus
|
|
33
|
+
};
|
package/preset/types.js
ADDED
|
File without changes
|
package/preset.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { StorybookConfig, Preview } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
interface StorybookHostOptions {
|
|
4
|
+
/** Absolute path to the host application root (Vite `server.fs.allow`). */
|
|
5
|
+
hostRoot: string;
|
|
6
|
+
/** Absolute path to the host `src/` directory (Sass load path for palette tokens). */
|
|
7
|
+
hostSrcDir: string;
|
|
8
|
+
/** Absolute path to the host global theme entry SCSS (e.g. `src/index.scss`). */
|
|
9
|
+
themeEntry: string;
|
|
10
|
+
/** Absolute path to the package root where `stories/` lives. Defaults to the preset package root. */
|
|
11
|
+
packageRoot?: string;
|
|
12
|
+
/** Injected as `__APP_VERSION__` in Storybook builds. */
|
|
13
|
+
appVersion?: string;
|
|
14
|
+
/** Additional story globs relative to `packageRoot`. */
|
|
15
|
+
extraStories?: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates a Storybook config for a UI component catalog.
|
|
20
|
+
* Component code under `ui/` must not import from the host `src/` —
|
|
21
|
+
* `@/` resolves only within this package root.
|
|
22
|
+
*/
|
|
23
|
+
declare function createStorybookConfig(options: StorybookHostOptions): StorybookConfig;
|
|
24
|
+
|
|
25
|
+
declare function createStorybookPreview(): Preview;
|
|
26
|
+
|
|
27
|
+
export { type StorybookHostOptions, createStorybookConfig, createStorybookPreview };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
|
3
|
+
import { ChevronDownIcon } from "lucide-react";
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
import {
|
|
6
|
+
accordionChevronVariants,
|
|
7
|
+
resolveAccordionChevronVariant
|
|
8
|
+
} from "./chevronVariants.js";
|
|
9
|
+
const Accordion = ({ children, ...props }) => {
|
|
10
|
+
return /* @__PURE__ */ jsx(AccordionPrimitive.Root, { "data-slot": "accordion", ...props, children });
|
|
11
|
+
};
|
|
12
|
+
const AccordionItem = ({ className, children, ...props }) => {
|
|
13
|
+
return /* @__PURE__ */ jsx(
|
|
14
|
+
AccordionPrimitive.Item,
|
|
15
|
+
{
|
|
16
|
+
"data-slot": "accordion-item",
|
|
17
|
+
className: cn("border-border border-b last:border-b-0", className),
|
|
18
|
+
...props,
|
|
19
|
+
children
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
const AccordionTrigger = ({
|
|
24
|
+
className,
|
|
25
|
+
children,
|
|
26
|
+
chevronPosition,
|
|
27
|
+
chevronVariant,
|
|
28
|
+
...props
|
|
29
|
+
}) => {
|
|
30
|
+
const resolvedVariant = resolveAccordionChevronVariant(chevronPosition, chevronVariant);
|
|
31
|
+
const showChevron = Boolean(chevronPosition) && resolvedVariant !== "none";
|
|
32
|
+
const isChevronLeft = chevronPosition === "left";
|
|
33
|
+
const variantConfig = resolvedVariant !== "none" ? accordionChevronVariants[resolvedVariant] : void 0;
|
|
34
|
+
const chevron = showChevron ? /* @__PURE__ */ jsx(
|
|
35
|
+
ChevronDownIcon,
|
|
36
|
+
{
|
|
37
|
+
className: cn(
|
|
38
|
+
"text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200",
|
|
39
|
+
variantConfig?.icon
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
) : null;
|
|
43
|
+
return /* @__PURE__ */ jsx(AccordionPrimitive.Header, { className: "flex", children: /* @__PURE__ */ jsxs(
|
|
44
|
+
AccordionPrimitive.Trigger,
|
|
45
|
+
{
|
|
46
|
+
"data-slot": "accordion-trigger",
|
|
47
|
+
className: cn(
|
|
48
|
+
"group/accordion-trigger flex flex-1 items-start gap-2 px-2 py-4 text-left text-sm font-medium transition-all outline-none disabled:pointer-events-none disabled:opacity-50",
|
|
49
|
+
!isChevronLeft && "justify-between",
|
|
50
|
+
variantConfig?.trigger,
|
|
51
|
+
className
|
|
52
|
+
),
|
|
53
|
+
...props,
|
|
54
|
+
children: [
|
|
55
|
+
isChevronLeft && chevron,
|
|
56
|
+
children,
|
|
57
|
+
!isChevronLeft && chevron
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
) });
|
|
61
|
+
};
|
|
62
|
+
const AccordionContent = ({
|
|
63
|
+
className,
|
|
64
|
+
children,
|
|
65
|
+
...props
|
|
66
|
+
}) => {
|
|
67
|
+
return /* @__PURE__ */ jsx(
|
|
68
|
+
AccordionPrimitive.Content,
|
|
69
|
+
{
|
|
70
|
+
"data-slot": "accordion-content",
|
|
71
|
+
className: "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-xs",
|
|
72
|
+
...props,
|
|
73
|
+
children: /* @__PURE__ */ jsx("div", { className, children })
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
export {
|
|
78
|
+
Accordion,
|
|
79
|
+
AccordionContent,
|
|
80
|
+
AccordionItem,
|
|
81
|
+
AccordionTrigger
|
|
82
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/cn.js";
|
|
3
|
+
import { AccordionContent, AccordionItem, AccordionTrigger } from "./Accordion.js";
|
|
4
|
+
const AccordionSection = ({
|
|
5
|
+
value,
|
|
6
|
+
title,
|
|
7
|
+
description,
|
|
8
|
+
children,
|
|
9
|
+
itemClassName,
|
|
10
|
+
triggerClassName,
|
|
11
|
+
contentClassName
|
|
12
|
+
}) => {
|
|
13
|
+
return /* @__PURE__ */ jsxs(
|
|
14
|
+
AccordionItem,
|
|
15
|
+
{
|
|
16
|
+
value,
|
|
17
|
+
className: cn(
|
|
18
|
+
"border-border bg-primary overflow-hidden rounded-sm border last:border-b-1",
|
|
19
|
+
itemClassName
|
|
20
|
+
),
|
|
21
|
+
children: [
|
|
22
|
+
/* @__PURE__ */ jsx(
|
|
23
|
+
AccordionTrigger,
|
|
24
|
+
{
|
|
25
|
+
className: cn("hover:bg-secondary items-center justify-start gap-4 px-4 py-2", triggerClassName),
|
|
26
|
+
chevronPosition: "left",
|
|
27
|
+
chevronVariant: "section",
|
|
28
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-2", children: [
|
|
29
|
+
typeof title === "string" ? /* @__PURE__ */ jsx("h6", { className: "text-default text-xs font-medium", children: title }) : title,
|
|
30
|
+
description != null && (typeof description === "string" ? /* @__PURE__ */ jsx("p", { className: "text-gray-chateau text-2xs", children: description }) : description)
|
|
31
|
+
] })
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
/* @__PURE__ */ jsx(AccordionContent, { className: cn("border-border bg-secondary border-t", contentClassName), children })
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
export {
|
|
40
|
+
AccordionSection
|
|
41
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/cn.js";
|
|
3
|
+
import { AccordionTrigger } from "./Accordion.js";
|
|
4
|
+
const FolderTreeExpandTrigger = ({
|
|
5
|
+
label,
|
|
6
|
+
className,
|
|
7
|
+
chevronVariant = "tree",
|
|
8
|
+
...props
|
|
9
|
+
}) => {
|
|
10
|
+
return /* @__PURE__ */ jsx(
|
|
11
|
+
AccordionTrigger,
|
|
12
|
+
{
|
|
13
|
+
className: cn(
|
|
14
|
+
"text-subdued shrink-0 rounded-xs p-0 text-xs font-normal hover:cursor-pointer hover:no-underline",
|
|
15
|
+
className
|
|
16
|
+
),
|
|
17
|
+
chevronPosition: "left",
|
|
18
|
+
chevronVariant,
|
|
19
|
+
...props,
|
|
20
|
+
children: /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
21
|
+
"Expand ",
|
|
22
|
+
label
|
|
23
|
+
] })
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
export {
|
|
28
|
+
FolderTreeExpandTrigger
|
|
29
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const accordionChevronVariants = {
|
|
2
|
+
down: {
|
|
3
|
+
trigger: "[&[data-state=open]>svg]:rotate-180",
|
|
4
|
+
icon: ""
|
|
5
|
+
},
|
|
6
|
+
section: {
|
|
7
|
+
trigger: "",
|
|
8
|
+
icon: "rotate-[-90deg] group-data-[state=open]/accordion-trigger:rotate-0"
|
|
9
|
+
},
|
|
10
|
+
tree: {
|
|
11
|
+
trigger: "",
|
|
12
|
+
icon: "size-3 translate-y-0 rotate-[-90deg] group-data-[state=open]/accordion-trigger:rotate-0"
|
|
13
|
+
},
|
|
14
|
+
"tree-sm": {
|
|
15
|
+
trigger: "",
|
|
16
|
+
icon: "mb-1 size-3.5 rotate-[-90deg] group-data-[state=open]/accordion-trigger:rotate-0"
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function resolveAccordionChevronVariant(chevronPosition, chevronVariant) {
|
|
20
|
+
if (chevronVariant) {
|
|
21
|
+
return chevronVariant;
|
|
22
|
+
}
|
|
23
|
+
if (chevronPosition) {
|
|
24
|
+
return "down";
|
|
25
|
+
}
|
|
26
|
+
return "none";
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
accordionChevronVariants,
|
|
30
|
+
resolveAccordionChevronVariant
|
|
31
|
+
};
|