@knymbus/voxel-ui 1.0.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 (115) hide show
  1. package/.storybook/main.ts +17 -0
  2. package/.storybook/preview.ts +23 -0
  3. package/debug-storybook.log +40 -0
  4. package/dist/chunks/jsx-runtime-Boo2vksn.js +182 -0
  5. package/dist/chunks/resizable-ImB8dfG_.js +112 -0
  6. package/dist/chunks/tabs-MaVN00hJ.js +86 -0
  7. package/dist/components/button/Button.d.ts +31 -0
  8. package/dist/components/button/ButtonGroup.d.ts +12 -0
  9. package/dist/components/button/SplitActionButton.d.ts +2 -0
  10. package/dist/components/button/index.d.ts +5 -0
  11. package/dist/components/button/split-types.d.ts +16 -0
  12. package/dist/components/button/types.d.ts +9 -0
  13. package/dist/components/icons/AddIcon.d.ts +2 -0
  14. package/dist/components/icons/BlankDocIcon.d.ts +2 -0
  15. package/dist/components/icons/ChatIcon.d.ts +2 -0
  16. package/dist/components/icons/ChevronDownIcon.d.ts +2 -0
  17. package/dist/components/icons/CloseIcon.d.ts +2 -0
  18. package/dist/components/icons/CommentIcon.d.ts +2 -0
  19. package/dist/components/icons/DeleteChatIcon.d.ts +2 -0
  20. package/dist/components/icons/DocumentIcon.d.ts +2 -0
  21. package/dist/components/icons/ExpandIcon.d.ts +2 -0
  22. package/dist/components/icons/FolderIcon.d.ts +2 -0
  23. package/dist/components/icons/GroupIcon.d.ts +2 -0
  24. package/dist/components/icons/MinimizeIcon.d.ts +2 -0
  25. package/dist/components/icons/MinusIcon.d.ts +2 -0
  26. package/dist/components/icons/MoreIcon.d.ts +2 -0
  27. package/dist/components/icons/OpenFolderIcon.d.ts +2 -0
  28. package/dist/components/icons/PersonIcon.d.ts +2 -0
  29. package/dist/components/icons/PlusChatIcon.d.ts +2 -0
  30. package/dist/components/icons/PlusCommentIcon.d.ts +2 -0
  31. package/dist/components/icons/PlusDocBadgeIcon.d.ts +8 -0
  32. package/dist/components/icons/PlusDocIcon.d.ts +2 -0
  33. package/dist/components/icons/PlusPersonIcon.d.ts +2 -0
  34. package/dist/components/icons/RefreshIcon.d.ts +2 -0
  35. package/dist/components/icons/SearchIcon.d.ts +2 -0
  36. package/dist/components/icons/TerminalIcon.d.ts +2 -0
  37. package/dist/components/icons/TrashIcon.d.ts +2 -0
  38. package/dist/components/icons/TruckIcon.d.ts +2 -0
  39. package/dist/components/icons/index.d.ts +26 -0
  40. package/dist/components/icons/types.d.ts +5 -0
  41. package/dist/components/resizable/ResizablePanel.d.ts +10 -0
  42. package/dist/components/resizable/index.d.ts +1 -0
  43. package/dist/components/resizable/index.js +2 -0
  44. package/dist/components/search/SearchInput.d.ts +10 -0
  45. package/dist/components/search/index.d.ts +2 -0
  46. package/dist/components/search/types.d.ts +19 -0
  47. package/dist/components/tabs/TabButton.d.ts +12 -0
  48. package/dist/components/tabs/TabButtonGroup.d.ts +9 -0
  49. package/dist/components/tabs/TabPanel.d.ts +8 -0
  50. package/dist/components/tabs/TabPanelList.d.ts +11 -0
  51. package/dist/components/tabs/index.d.ts +5 -0
  52. package/dist/components/tabs/index.js +2 -0
  53. package/dist/components/tabs/types.d.ts +9 -0
  54. package/dist/components/tabs/useTab.d.ts +5 -0
  55. package/dist/index.d.ts +5 -0
  56. package/dist/index.js +1071 -0
  57. package/package.json +68 -0
  58. package/src/components/button/Button.stories.tsx +70 -0
  59. package/src/components/button/Button.tsx +108 -0
  60. package/src/components/button/ButtonGroup.stories.tsx +63 -0
  61. package/src/components/button/ButtonGroup.tsx +62 -0
  62. package/src/components/button/SplitActionButton.tsx +116 -0
  63. package/src/components/button/SplitButton.stories.tsx +55 -0
  64. package/src/components/button/index.ts +7 -0
  65. package/src/components/button/split-types.ts +18 -0
  66. package/src/components/button/types.ts +10 -0
  67. package/src/components/icons/AddIcon.tsx +10 -0
  68. package/src/components/icons/BlankDocIcon.tsx +10 -0
  69. package/src/components/icons/ChatIcon.tsx +9 -0
  70. package/src/components/icons/ChevronDownIcon.tsx +9 -0
  71. package/src/components/icons/CloseIcon.tsx +23 -0
  72. package/src/components/icons/CommentIcon.tsx +9 -0
  73. package/src/components/icons/DeleteChatIcon.tsx +10 -0
  74. package/src/components/icons/DocumentIcon.tsx +13 -0
  75. package/src/components/icons/ExpandIcon.tsx +12 -0
  76. package/src/components/icons/FolderIcon.tsx +9 -0
  77. package/src/components/icons/GroupIcon.tsx +12 -0
  78. package/src/components/icons/Icon.stories.tsx +122 -0
  79. package/src/components/icons/MinimizeIcon.tsx +12 -0
  80. package/src/components/icons/MinusIcon.tsx +9 -0
  81. package/src/components/icons/MoreIcon.tsx +11 -0
  82. package/src/components/icons/OpenFolderIcon.tsx +37 -0
  83. package/src/components/icons/PersonIcon.tsx +10 -0
  84. package/src/components/icons/PlusChatIcon.tsx +11 -0
  85. package/src/components/icons/PlusCommentIcon.tsx +11 -0
  86. package/src/components/icons/PlusDocBadgeIcon.tsx +74 -0
  87. package/src/components/icons/PlusDocIcon.tsx +12 -0
  88. package/src/components/icons/PlusPersonIcon.tsx +12 -0
  89. package/src/components/icons/RefreshIcon.tsx +9 -0
  90. package/src/components/icons/SearchIcon.tsx +10 -0
  91. package/src/components/icons/TerminalIcon.tsx +11 -0
  92. package/src/components/icons/TrashIcon.tsx +12 -0
  93. package/src/components/icons/TruckIcon.tsx +12 -0
  94. package/src/components/icons/index.ts +26 -0
  95. package/src/components/icons/types.ts +6 -0
  96. package/src/components/resizable/ResizablePanel.tsx +183 -0
  97. package/src/components/resizable/index.ts +1 -0
  98. package/src/components/search/SearchInput.stories.tsx +91 -0
  99. package/src/components/search/SearchInput.tsx +254 -0
  100. package/src/components/search/index.ts +2 -0
  101. package/src/components/search/types.ts +21 -0
  102. package/src/components/tabs/TabButton.tsx +56 -0
  103. package/src/components/tabs/TabButtonGroup.tsx +82 -0
  104. package/src/components/tabs/TabPanel.tsx +44 -0
  105. package/src/components/tabs/TabPanelList.tsx +31 -0
  106. package/src/components/tabs/Tabs.stories.tsx +71 -0
  107. package/src/components/tabs/index.ts +5 -0
  108. package/src/components/tabs/types.ts +10 -0
  109. package/src/components/tabs/useTab.ts +33 -0
  110. package/src/index.css +35 -0
  111. package/src/index.ts +5 -0
  112. package/src/vite-env.d.ts +5 -0
  113. package/tsconfig.json +47 -0
  114. package/vite.config.ts +64 -0
  115. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,82 @@
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { useTab } from './useTab';
3
+ import { TabVariant } from './types';
4
+ import TabButton from './TabButton'; // Imported to execute type-checking audits
5
+
6
+ interface TabButtonGroupProps {
7
+ children: React.ReactNode;
8
+ variant?: TabVariant;
9
+ scopeName?: string;
10
+ }
11
+
12
+ export default function TabButtonGroup({
13
+ children,
14
+ variant = 'underline',
15
+ scopeName = 'default'
16
+ }: TabButtonGroupProps) {
17
+ const containerRef = useRef<HTMLDivElement | null>(null);
18
+ const { activeTab } = useTab(scopeName);
19
+
20
+ const [lineStyles, setLineStyles] = useState<React.CSSProperties>({ left: 0, width: 0, opacity: 0 });
21
+ const [hoveredId, setHoveredId] = useState<string | null>(null);
22
+
23
+ // --- STRICT CHILDREN SUB-COMPONENT VALIDATION ENGINE LOOP ---
24
+ const validatedChildren = React.Children.map(children, (child) => {
25
+ if (!React.isValidElement(child)) return null;
26
+
27
+ // Verify if the child component reference maps directly to our TabButton signature
28
+ if (child.type !== TabButton) {
29
+ console.warn(
30
+ `[Voxel UI Validation Warning]: TabButtonGroup scope "${scopeName}" only accepts sub-children elements of type <TabButton />. Ignored invalid component node.`
31
+ );
32
+ return null;
33
+ }
34
+ return child;
35
+ });
36
+
37
+ useEffect(() => {
38
+ if (variant !== 'sliding-underline' || !containerRef.current) return;
39
+
40
+ const targetId = hoveredId || activeTab || 'tab1';
41
+ const targetElement = containerRef.current.querySelector(`[data-id="${targetId}"]`) as HTMLElement;
42
+
43
+ if (targetElement) {
44
+ setLineStyles({
45
+ left: `${targetElement.offsetLeft}px`,
46
+ width: `${targetElement.offsetWidth}px`,
47
+ opacity: 1,
48
+ backgroundColor: hoveredId && hoveredId !== activeTab ? 'var(--color-vsc-text)' : 'var(--color-vsc-accent)'
49
+ });
50
+ }
51
+ }, [activeTab, hoveredId, variant]);
52
+
53
+ const containerClasses = {
54
+ underline: 'flex items-center space-x-2 border-b border-vsc-border w-full bg-vsc-bg pb-[1px]',
55
+ 'sliding-underline': 'relative flex items-center border-b border-vsc-border w-full bg-vsc-bg pb-[2px]',
56
+ pill: 'flex items-center space-x-1.5 p-1 bg-vsc-sidebar rounded-full w-fit',
57
+ vscode: 'flex items-center h-9 bg-vsc-sidebar border-b border-vsc-border w-full overflow-hidden',
58
+ ghost: 'flex items-center space-x-1 p-1 bg-vsc-bg-input border border-vsc-border rounded'
59
+ }[variant];
60
+
61
+ return (
62
+ <div
63
+ ref={containerRef}
64
+ onMouseOver={(e) => {
65
+ const btn = (e.target as HTMLElement).closest('[data-id]');
66
+ if (btn) setHoveredId(btn.getAttribute('data-id'));
67
+ }}
68
+ onMouseLeave={() => setHoveredId(null)}
69
+ className={`${containerClasses} select-none`}
70
+ >
71
+ {/* Render exclusively the type-validated sub-nodes collection array */}
72
+ {validatedChildren}
73
+
74
+ {variant === 'sliding-underline' && (
75
+ <div
76
+ className="absolute bottom-0 h-0.5 rounded-t transition-all duration-200 ease-out pointer-events-none z-20"
77
+ style={lineStyles}
78
+ />
79
+ )}
80
+ </div>
81
+ );
82
+ }
@@ -0,0 +1,44 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { useTabListContext } from './TabPanelList';
3
+
4
+ interface TabPanelProps {
5
+ children: React.ReactNode;
6
+ id: string;
7
+ persist?: boolean;
8
+ }
9
+
10
+ export default function TabPanel({ children, id, persist = false }: TabPanelProps) {
11
+ const { activeTabId } = useTabListContext();
12
+ const isCurrent = activeTabId === id;
13
+
14
+ const [hasRenderedOnce, setHasRenderedOnce] = useState<boolean>(false);
15
+
16
+ useEffect(() => {
17
+ if (isCurrent && !hasRenderedOnce) {
18
+ setHasRenderedOnce(true);
19
+ }
20
+ }, [isCurrent, hasRenderedOnce]);
21
+
22
+ if (!hasRenderedOnce) return null;
23
+ if (!persist && !isCurrent) return null;
24
+
25
+ return (
26
+ <div
27
+ className={`absolute inset-0 w-full h-full bg-vsc-bg transition-all duration-300 ease-in-out ${
28
+ isCurrent
29
+ ? 'opacity-100 scale-100 z-10 pointer-events-auto visible'
30
+ : 'opacity-0 scale-[0.99] z-0 pointer-events-none invisible delay-75'
31
+ }`}
32
+ >
33
+ {/*
34
+ Inner layout wrapper applies a micro-blur and fine opacity mask cross-fade
35
+ to ensure background elements never clip through transparent gaps during transitions.
36
+ */}
37
+ <div className={`w-full h-full transition-opacity duration-300 ${
38
+ isCurrent ? 'opacity-100' : 'opacity-0'
39
+ }`}>
40
+ {children}
41
+ </div>
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,31 @@
1
+ import React, { useEffect, createContext, useContext } from 'react';
2
+ import { useTab } from './useTab';
3
+
4
+ interface TabPanelListProps {
5
+ children: React.ReactNode;
6
+ targetScopeName: string; // Ties this structural list panel block to a named useTab hook loop
7
+ defaultValue: string; // Initial focus viewport tab on render
8
+ }
9
+
10
+ const TabListContext = createContext<{ activeTabId: string | undefined }>({ activeTabId: undefined });
11
+
12
+ export const useTabListContext = () => useContext(TabListContext);
13
+
14
+ export default function TabPanelList({ children, targetScopeName, defaultValue }: TabPanelListProps) {
15
+ const { activeTab, registerDefault } = useTab(targetScopeName);
16
+
17
+ // Initialize defaultValue into state if it's the first execution pass
18
+ useEffect(() => {
19
+ registerDefault(defaultValue);
20
+ }, [defaultValue, registerDefault]);
21
+
22
+ const activeTabId = activeTab || defaultValue;
23
+
24
+ return (
25
+ <TabListContext.Provider value={{ activeTabId }}>
26
+ <div className="relative w-full h-full min-h-0 flex-1 overflow-hidden bg-vsc-bg">
27
+ {children}
28
+ </div>
29
+ </TabListContext.Provider>
30
+ );
31
+ }
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import TabPanelList from './TabPanelList';
4
+ import TabPanel from './TabPanel';
5
+ import TabButtonGroup from './TabButtonGroup';
6
+ import TabButton from './TabButton';
7
+
8
+ const meta: Meta = {
9
+ title: 'Navigation/VoxelTabsSuite',
10
+ parameters: {
11
+ layout: 'padded',
12
+ },
13
+ };
14
+ export default meta;
15
+
16
+ // Mock SVG icons to test start/end positioning layout slots
17
+ const BoxIcon = () => <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" /></svg>;
18
+ const CheckIcon = () => <svg className="w-3 h-3 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7" /></svg>;
19
+ const CrossIcon = () => <svg className="w-3 h-3 text-rose-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /></svg>;
20
+
21
+ const VariantSandboxShowcase = ({ variant }: { variant: 'underline' | 'pill' | 'vscode' | 'ghost' | 'sliding-underline' }) => {
22
+ const scopeId = `scope_variant_${variant}`;
23
+
24
+ return (
25
+ <div className="space-y-3 p-4 border border-vsc-border rounded bg-vsc-bg max-w-2xl mb-6 shadow-sm">
26
+ <div className="text-[10px] font-bold text-vsc-muted uppercase tracking-wider">
27
+ Style Profile Variant: <span className="text-vsc-accent">{variant}</span>
28
+ </div>
29
+
30
+ {/* Render the core active button groups panel elements */}
31
+ <TabButtonGroup variant={variant}>
32
+ <TabButton id="tab1" scopeName={scopeId} variant={variant} startIcon={<BoxIcon />}>
33
+ Manifest Data Cargo
34
+ </TabButton>
35
+ <TabButton id="tab2" scopeName={scopeId} variant={variant} endIcon={<CheckIcon />}>
36
+ Delivered Queue
37
+ </TabButton>
38
+ <TabButton id="tab3" scopeName={scopeId} variant={variant} endIcon={<CrossIcon />}>
39
+ Exceptions
40
+ </TabButton>
41
+ </TabButtonGroup>
42
+
43
+ {/* Render matching core content canvas wrappers */}
44
+ <div className="h-24 relative border border-vsc-border rounded-sm bg-vsc-bg-input p-3 overflow-hidden">
45
+ <TabPanelList targetScopeName={scopeId} defaultValue="tab1">
46
+ <TabPanel id="tab1" persist={true}>
47
+ <p className="text-xs text-vsc-text">📦 <b>Voxel Panel Alpha:</b> Staged database manifest streams active. Core inputs remain cached securely in background channels.</p>
48
+ </TabPanel>
49
+ <TabPanel id="tab2" persist={false}>
50
+ <p className="text-xs text-vsc-text">✨ <b>Voxel Panel Beta:</b> Real-time delivered telemetry nodes parsing clean. Data refreshes instantly on blur cycles.</p>
51
+ </TabPanel>
52
+ <TabPanel id="tab3" persist={false}>
53
+ <p className="text-xs text-vsc-text">⚠️ <b>Voxel Panel Gamma:</b> 3 logistics exceptions flagged across custom terminal checks loops corridors.</p>
54
+ </TabPanel>
55
+ </TabPanelList>
56
+ </div>
57
+ </div>
58
+ );
59
+ };
60
+
61
+ export const CombinedVoxelSuiteDemo: StoryObj = {
62
+ render: () => (
63
+ <div className="p-2 space-y-4 bg-vsc-sidebar min-h-screen">
64
+ <VariantSandboxShowcase variant="underline" />
65
+ <VariantSandboxShowcase variant="sliding-underline" />
66
+ <VariantSandboxShowcase variant="pill" />
67
+ <VariantSandboxShowcase variant="vscode" />
68
+ <VariantSandboxShowcase variant="ghost" />
69
+ </div>
70
+ ),
71
+ };
@@ -0,0 +1,5 @@
1
+ export { default as TabPanelList } from './TabPanelList';
2
+ export { default as TabPanel } from './TabPanel';
3
+ export { default as TabButton } from './TabButton';
4
+ export { useTab } from './useTab';
5
+ export * from './types';
@@ -0,0 +1,10 @@
1
+ export type TabVariant = 'underline' | 'pill' | 'vscode' | 'ghost' | 'sliding-underline';
2
+
3
+ export interface TabButtonProps {
4
+ id: string;
5
+ scopeName: string;
6
+ children: React.ReactNode;
7
+ variant?: TabVariant;
8
+ startIcon?: React.ReactNode;
9
+ endIcon?: React.ReactNode;
10
+ }
@@ -0,0 +1,33 @@
1
+ import { create } from 'zustand';
2
+
3
+ interface TabStateRegistry {
4
+ activeTabs: Record<string, string>; // Maps named scopes to their current active tab id
5
+ setActiveTab: (scopeName: string, tabId: string) => void;
6
+ initializeTab: (scopeName: string, defaultTabId: string) => void;
7
+ }
8
+
9
+ // Global lightweight store to handle cross-component communication links effortlessly
10
+ const useTabStore = create<TabStateRegistry>((set) => ({
11
+ activeTabs: {},
12
+ setActiveTab: (scopeName, tabId) =>
13
+ set((state) => ({
14
+ activeTabs: { ...state.activeTabs, [scopeName]: tabId }
15
+ })),
16
+ initializeTab: (scopeName, defaultTabId) =>
17
+ set((state) => {
18
+ if (state.activeTabs[scopeName]) return {}; // Don't wipe state if already initialized
19
+ return { activeTabs: { ...state.activeTabs, [scopeName]: defaultTabId } };
20
+ })
21
+ }));
22
+
23
+ export function useTab(scopeName: string) {
24
+ const activeTab = useTabStore((state) => state.activeTabs[scopeName]);
25
+ const setActiveTab = useTabStore((state) => state.setActiveTab);
26
+ const initializeTab = useTabStore((state) => state.initializeTab);
27
+
28
+ return {
29
+ activeTab,
30
+ changeTab: (tabId: string) => setActiveTab(scopeName, tabId),
31
+ registerDefault: (defaultTabId: string) => initializeTab(scopeName, defaultTabId)
32
+ };
33
+ }
package/src/index.css ADDED
@@ -0,0 +1,35 @@
1
+ @import "tailwindcss";
2
+
3
+
4
+ /* 🎛️ Tailwind v4 Theme Extension Configuration Panel */
5
+ @theme {
6
+ --color-vsc-bg: #ffffff;
7
+ --color-vsc-sidebar: #f3f3f3;
8
+ --color-vsc-border: #e4e4e7;
9
+ --color-vsc-accent: #007acc;
10
+ --color-vsc-accent-hover: #0062a3;
11
+ --color-vsc-hover: #e8e8e8;
12
+ --color-vsc-text: #333333;
13
+
14
+ --color-vsc-button-text: #ffffff;
15
+ --color-vsc-muted: #6a737d;
16
+ --color-vsc-bg-input: #f6f8fa;
17
+ }
18
+
19
+ /* ==========================================================================
20
+ DARK MODE OVERRIDES (Triggers when parent layout has the ".dark" class)
21
+ ========================================================================== */
22
+ @layer base {
23
+ .dark {
24
+ --color-vsc-bg: #1e1e1e;
25
+ --color-vsc-sidebar: #252526;
26
+ --color-vsc-border: #3c3c3c;
27
+ --color-vsc-accent: #007acc;
28
+ --color-vsc-accent-hover: #0062a3;
29
+ --color-vsc-hover: #2a2d2e;
30
+ --color-vsc-text: #cccccc;
31
+
32
+ --color-vsc-muted: #8b949e;
33
+ --color-vsc-bg-input: #1f1f1f;
34
+ }
35
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './components/resizable';
2
+ export * from './components/tabs';
3
+ export * from './components/button';
4
+ export * from './components/icons'
5
+ export * from './components/search';
@@ -0,0 +1,5 @@
1
+ // Explicitly declare that standard and nested style sheets are valid asset modules
2
+ declare module '*.css' {
3
+ const content: Record<string, string>;
4
+ export default content;
5
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "useDefineForClassFields": true,
5
+ "lib": [
6
+ "DOM",
7
+ "DOM.Iterable",
8
+ "ES2022"
9
+ ],
10
+ "module": "ESNext",
11
+ "skipLibCheck": true,
12
+ /* 🔬 Bundler & Composable Resolution Tuning */
13
+ "moduleResolution": "bundler",
14
+ "allowImportingTsExtensions": false,
15
+ "declaration": true,
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "noEmit": true, // Overridden by tsc in build scripts to output standalone declarations (.d.ts)
19
+ "jsx": "react-jsx",
20
+ /* 🛡️ Strict Quality Guardrails */
21
+ "strict": true,
22
+ "noUnusedLocals": true,
23
+ "noUnusedParameters": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "types": [
26
+ "node",
27
+ "vite/client"
28
+ ],
29
+ "ignoreDeprecations": "6.0",
30
+ /* 📦 Library Path Mapping Fallbacks */
31
+ "baseUrl": ".",
32
+ "paths": {
33
+ "@/*": [
34
+ "src/*"
35
+ ]
36
+ }
37
+ },
38
+ "include": [
39
+ "src"
40
+ ],
41
+ "exclude": [
42
+ "node_modules",
43
+ "dist",
44
+ "**/*.stories.tsx",
45
+ "**/*.test.ts"
46
+ ]
47
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,64 @@
1
+ /// <reference types="vitest/config" />
2
+ import { defineConfig } from 'vite';
3
+ import react from '@vitejs/plugin-react';
4
+ import dts from 'vite-plugin-dts';
5
+ import { resolve } from 'path';
6
+ import path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
9
+ import { playwright } from '@vitest/browser-playwright';
10
+ const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
11
+ import tailwindcss from '@tailwindcss/vite';
12
+
13
+ // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
14
+ export default defineConfig({
15
+ plugins: [
16
+ tailwindcss(),
17
+ react(),
18
+ // Auto-generates independent TypeScript type declaration files (.d.ts) matching paths
19
+ dts({
20
+ insertTypesEntry: true,
21
+ include: ['src']
22
+ })],
23
+ build: {
24
+ lib: {
25
+ entry: {
26
+ index: resolve(__dirname, 'src/index.ts'),
27
+ 'components/tabs/index': resolve(__dirname, 'src/components/tabs/index.ts'),
28
+ 'components/resizable/index': resolve(__dirname, 'src/components/resizable/index.ts')
29
+ },
30
+ formats: ['es'] // Output strictly as modern ES Modules for dead-code elimination (tree-shaking)
31
+ },
32
+ rollupOptions: {
33
+ // Externalize react dependencies so they aren't bundled directly into your code copies
34
+ external: ['react', 'react-dom', 'zustand'],
35
+ output: {
36
+ assetFileNames: 'assets/[name].[ext]',
37
+ entryFileNames: '[name].js',
38
+ chunkFileNames: 'chunks/[name]-[hash].js'
39
+ }
40
+ }
41
+ },
42
+ test: {
43
+ projects: [{
44
+ extends: true,
45
+ plugins: [
46
+ // The plugin will run tests for the stories defined in your Storybook config
47
+ // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
48
+ storybookTest({
49
+ configDir: path.join(dirname, '.storybook')
50
+ })],
51
+ test: {
52
+ name: 'storybook',
53
+ browser: {
54
+ enabled: true,
55
+ headless: true,
56
+ provider: playwright({}),
57
+ instances: [{
58
+ browser: 'chromium'
59
+ }]
60
+ }
61
+ }
62
+ }]
63
+ }
64
+ });
@@ -0,0 +1 @@
1
+ /// <reference types="@vitest/browser-playwright" />