@papernote/ui 1.1.0 → 1.2.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.
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/dist/components/CurrencyInput.d.ts +52 -0
- package/dist/components/CurrencyInput.d.ts.map +1 -0
- package/dist/components/DataTable.d.ts +3 -1
- package/dist/components/DataTable.d.ts.map +1 -1
- package/dist/components/Modal.d.ts.map +1 -1
- package/dist/components/Page.d.ts +2 -0
- package/dist/components/Page.d.ts.map +1 -1
- package/dist/components/PageLayout.d.ts +5 -1
- package/dist/components/PageLayout.d.ts.map +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +204 -4
- package/dist/index.esm.js +415 -88
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +413 -82
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2877 -2675
- package/dist/utils/excelExport.d.ts +143 -0
- package/dist/utils/excelExport.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/AdminModal.css +49 -49
- package/src/components/CurrencyInput.stories.tsx +290 -0
- package/src/components/CurrencyInput.tsx +193 -0
- package/src/components/DataTable.tsx +78 -14
- package/src/components/Modal.stories.tsx +64 -0
- package/src/components/Modal.tsx +15 -2
- package/src/components/Page.stories.tsx +76 -0
- package/src/components/Page.tsx +35 -3
- package/src/components/PageLayout.stories.tsx +75 -0
- package/src/components/PageLayout.tsx +28 -9
- package/src/components/RoleManager.css +10 -10
- package/src/components/Spreadsheet.css +216 -216
- package/src/components/Spreadsheet.stories.tsx +362 -362
- package/src/components/Spreadsheet.tsx +351 -351
- package/src/components/SpreadsheetSimple.stories.tsx +27 -27
- package/src/components/Tabs.tsx +152 -152
- package/src/components/index.ts +5 -0
- package/src/styles/index.css +41 -4
- package/src/utils/excelExport.stories.tsx +535 -0
- package/src/utils/excelExport.ts +225 -0
- package/src/utils/index.ts +3 -0
- package/tailwind.config.js +253 -253
- package/dist/components/Button.stories.d.ts +0 -51
- package/dist/components/Button.stories.d.ts.map +0 -1
- package/dist/components/ChartVisualizationUI.d.ts +0 -21
- package/dist/components/ChartVisualizationUI.d.ts.map +0 -1
- package/dist/components/ChatUI.d.ts +0 -23
- package/dist/components/ChatUI.d.ts.map +0 -1
- package/dist/components/CommissionDashboardUI.d.ts +0 -25
- package/dist/components/CommissionDashboardUI.d.ts.map +0 -1
- package/dist/components/DataTable.stories.d.ts +0 -23
- package/dist/components/DataTable.stories.d.ts.map +0 -1
- package/dist/components/FormField.d.ts +0 -35
- package/dist/components/FormField.d.ts.map +0 -1
- package/dist/components/Input.stories.d.ts +0 -366
- package/dist/components/Input.stories.d.ts.map +0 -1
- package/dist/components/InsightsPanelUI.d.ts +0 -21
- package/dist/components/InsightsPanelUI.d.ts.map +0 -1
- package/dist/components/PaymentHistoryTimeline.d.ts +0 -34
- package/dist/components/PaymentHistoryTimeline.d.ts.map +0 -1
- package/dist/components/RelationshipManagerUI.d.ts +0 -60
- package/dist/components/RelationshipManagerUI.d.ts.map +0 -1
- package/dist/components/RoleManager.d.ts +0 -19
- package/dist/components/RoleManager.d.ts.map +0 -1
- package/dist/components/SplitCommissionBadge.d.ts +0 -18
- package/dist/components/SplitCommissionBadge.d.ts.map +0 -1
- package/dist/components/Spreadsheet.css +0 -216
- package/dist/components/__tests__/Button.test.d.ts +0 -2
- package/dist/components/__tests__/Button.test.d.ts.map +0 -1
- package/dist/components/__tests__/Input.test.d.ts +0 -2
- package/dist/components/__tests__/Input.test.d.ts.map +0 -1
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import { Spreadsheet } from './Spreadsheet';
|
|
3
|
-
|
|
4
|
-
const meta: Meta<typeof Spreadsheet> = {
|
|
5
|
-
title: 'Components/Spreadsheet/Simple Test',
|
|
6
|
-
component: Spreadsheet,
|
|
7
|
-
parameters: {
|
|
8
|
-
docs: {
|
|
9
|
-
description: {
|
|
10
|
-
component: 'Simple test story for Spreadsheet component debugging.',
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export default meta;
|
|
17
|
-
type Story = StoryObj<typeof Spreadsheet>;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Minimal test - just render with defaults
|
|
21
|
-
*/
|
|
22
|
-
export const MinimalTest: Story = {
|
|
23
|
-
args: {
|
|
24
|
-
rows: 5,
|
|
25
|
-
columns: 3,
|
|
26
|
-
},
|
|
27
|
-
};
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Spreadsheet } from './Spreadsheet';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Spreadsheet> = {
|
|
5
|
+
title: 'Components/Spreadsheet/Simple Test',
|
|
6
|
+
component: Spreadsheet,
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component: 'Simple test story for Spreadsheet component debugging.',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story = StoryObj<typeof Spreadsheet>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Minimal test - just render with defaults
|
|
21
|
+
*/
|
|
22
|
+
export const MinimalTest: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
rows: 5,
|
|
25
|
+
columns: 3,
|
|
26
|
+
},
|
|
27
|
+
};
|
package/src/components/Tabs.tsx
CHANGED
|
@@ -1,152 +1,152 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
|
|
3
|
-
export interface Tab {
|
|
4
|
-
id: string;
|
|
5
|
-
label: string;
|
|
6
|
-
icon?: React.ReactNode;
|
|
7
|
-
content: React.ReactNode;
|
|
8
|
-
disabled?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface TabsProps {
|
|
12
|
-
tabs: Tab[];
|
|
13
|
-
/** Controlled mode: Currently active tab ID */
|
|
14
|
-
activeTab?: string;
|
|
15
|
-
/** Uncontrolled mode: Initial tab ID (ignored if activeTab is provided) */
|
|
16
|
-
defaultTab?: string;
|
|
17
|
-
variant?: 'underline' | 'pill';
|
|
18
|
-
/** Orientation of tabs (default: 'horizontal') */
|
|
19
|
-
orientation?: 'horizontal' | 'vertical';
|
|
20
|
-
/** Size of tabs (default: 'md') */
|
|
21
|
-
size?: 'sm' | 'md' | 'lg';
|
|
22
|
-
/** Called when tab changes (required for controlled mode) */
|
|
23
|
-
onChange?: (tabId: string) => void;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default function Tabs({ tabs, activeTab: controlledActiveTab, defaultTab, variant = 'underline', orientation = 'horizontal', size = 'md', onChange }: TabsProps) {
|
|
27
|
-
const [internalActiveTab, setInternalActiveTab] = useState(defaultTab || tabs[0]?.id);
|
|
28
|
-
|
|
29
|
-
// Controlled mode: use activeTab prop, Uncontrolled mode: use internal state
|
|
30
|
-
const isControlled = controlledActiveTab !== undefined;
|
|
31
|
-
const activeTab = isControlled ? controlledActiveTab : internalActiveTab;
|
|
32
|
-
|
|
33
|
-
// Ensure the activeTab exists in the current tabs array
|
|
34
|
-
// This handles the case where tabs array reference changes at the same time as activeTab
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
const tabExists = tabs.some(tab => tab.id === activeTab);
|
|
37
|
-
if (!tabExists && tabs.length > 0) {
|
|
38
|
-
// If the activeTab doesn't exist in the new tabs array, use the first tab
|
|
39
|
-
if (isControlled) {
|
|
40
|
-
onChange?.(tabs[0].id);
|
|
41
|
-
} else {
|
|
42
|
-
setInternalActiveTab(tabs[0].id);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}, [tabs, activeTab, isControlled, onChange]);
|
|
46
|
-
|
|
47
|
-
const handleTabChange = (tabId: string) => {
|
|
48
|
-
if (!isControlled) {
|
|
49
|
-
setInternalActiveTab(tabId);
|
|
50
|
-
}
|
|
51
|
-
onChange?.(tabId);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// Size-specific classes
|
|
55
|
-
const sizeClasses = {
|
|
56
|
-
sm: {
|
|
57
|
-
padding: 'px-3 py-1.5',
|
|
58
|
-
text: 'text-xs',
|
|
59
|
-
icon: 'h-3.5 w-3.5',
|
|
60
|
-
gap: orientation === 'vertical' ? 'gap-1.5' : 'gap-4',
|
|
61
|
-
minWidth: orientation === 'vertical' ? 'min-w-[150px]' : '',
|
|
62
|
-
spacing: orientation === 'vertical' ? 'mt-4' : 'mt-4',
|
|
63
|
-
},
|
|
64
|
-
md: {
|
|
65
|
-
padding: 'px-4 py-2.5',
|
|
66
|
-
text: 'text-sm',
|
|
67
|
-
icon: 'h-4 w-4',
|
|
68
|
-
gap: orientation === 'vertical' ? 'gap-2' : 'gap-6',
|
|
69
|
-
minWidth: orientation === 'vertical' ? 'min-w-[200px]' : '',
|
|
70
|
-
spacing: orientation === 'vertical' ? 'mt-6' : 'mt-6',
|
|
71
|
-
},
|
|
72
|
-
lg: {
|
|
73
|
-
padding: 'px-5 py-3',
|
|
74
|
-
text: 'text-base',
|
|
75
|
-
icon: 'h-5 w-5',
|
|
76
|
-
gap: orientation === 'vertical' ? 'gap-3' : 'gap-8',
|
|
77
|
-
minWidth: orientation === 'vertical' ? 'min-w-[250px]' : '',
|
|
78
|
-
spacing: orientation === 'vertical' ? 'mt-8' : 'mt-8',
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<div className={`w-full ${orientation === 'vertical' ? `flex ${sizeClasses[size].gap}` : ''}`}>
|
|
84
|
-
{/* Tab Headers */}
|
|
85
|
-
<div
|
|
86
|
-
className={`
|
|
87
|
-
flex ${orientation === 'vertical' ? 'flex-col' : ''}
|
|
88
|
-
${variant === 'underline'
|
|
89
|
-
? orientation === 'vertical'
|
|
90
|
-
? `border-r border-paper-200 ${sizeClasses[size].gap} pr-6`
|
|
91
|
-
: `border-b border-paper-200 ${sizeClasses[size].gap}`
|
|
92
|
-
: `${sizeClasses[size].gap} p-1 bg-paper-50 rounded-lg`
|
|
93
|
-
}
|
|
94
|
-
${sizeClasses[size].minWidth}
|
|
95
|
-
`}
|
|
96
|
-
role="tablist"
|
|
97
|
-
>
|
|
98
|
-
{tabs.map((tab) => {
|
|
99
|
-
const isActive = activeTab === tab.id;
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<button
|
|
103
|
-
key={tab.id}
|
|
104
|
-
role="tab"
|
|
105
|
-
aria-selected={isActive}
|
|
106
|
-
aria-controls={`panel-${tab.id}`}
|
|
107
|
-
disabled={tab.disabled}
|
|
108
|
-
onClick={() => !tab.disabled && handleTabChange(tab.id)}
|
|
109
|
-
className={`
|
|
110
|
-
flex items-center gap-2 ${sizeClasses[size].padding} ${sizeClasses[size].text} font-medium transition-all duration-200
|
|
111
|
-
${orientation === 'vertical' ? 'w-full justify-start' : ''}
|
|
112
|
-
${
|
|
113
|
-
variant === 'underline'
|
|
114
|
-
? isActive
|
|
115
|
-
? orientation === 'vertical'
|
|
116
|
-
? 'text-accent-900 border-r-2 border-accent-500 -mr-[1px]'
|
|
117
|
-
: 'text-accent-900 border-b-2 border-accent-500 -mb-[1px]'
|
|
118
|
-
: orientation === 'vertical'
|
|
119
|
-
? 'text-ink-600 hover:text-ink-900 border-r-2 border-transparent'
|
|
120
|
-
: 'text-ink-600 hover:text-ink-900 border-b-2 border-transparent'
|
|
121
|
-
: isActive
|
|
122
|
-
? 'bg-white text-accent-900 rounded-md shadow-xs'
|
|
123
|
-
: 'text-ink-600 hover:text-ink-900 hover:bg-white/50 rounded-md'
|
|
124
|
-
}
|
|
125
|
-
${tab.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
126
|
-
`}
|
|
127
|
-
>
|
|
128
|
-
{tab.icon && <span className={`flex-shrink-0 ${sizeClasses[size].icon}`}>{tab.icon}</span>}
|
|
129
|
-
<span>{tab.label}</span>
|
|
130
|
-
</button>
|
|
131
|
-
);
|
|
132
|
-
})}
|
|
133
|
-
</div>
|
|
134
|
-
|
|
135
|
-
{/* Tab Content */}
|
|
136
|
-
<div className={`${orientation === 'vertical' ? 'flex-1' : sizeClasses[size].spacing}`}>
|
|
137
|
-
{tabs.map((tab) => (
|
|
138
|
-
<div
|
|
139
|
-
key={tab.id}
|
|
140
|
-
id={`panel-${tab.id}`}
|
|
141
|
-
role="tabpanel"
|
|
142
|
-
aria-labelledby={tab.id}
|
|
143
|
-
hidden={activeTab !== tab.id}
|
|
144
|
-
className={activeTab === tab.id ? 'animate-fade-in' : ''}
|
|
145
|
-
>
|
|
146
|
-
{activeTab === tab.id && tab.content}
|
|
147
|
-
</div>
|
|
148
|
-
))}
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
);
|
|
152
|
-
}
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface Tab {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
icon?: React.ReactNode;
|
|
7
|
+
content: React.ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface TabsProps {
|
|
12
|
+
tabs: Tab[];
|
|
13
|
+
/** Controlled mode: Currently active tab ID */
|
|
14
|
+
activeTab?: string;
|
|
15
|
+
/** Uncontrolled mode: Initial tab ID (ignored if activeTab is provided) */
|
|
16
|
+
defaultTab?: string;
|
|
17
|
+
variant?: 'underline' | 'pill';
|
|
18
|
+
/** Orientation of tabs (default: 'horizontal') */
|
|
19
|
+
orientation?: 'horizontal' | 'vertical';
|
|
20
|
+
/** Size of tabs (default: 'md') */
|
|
21
|
+
size?: 'sm' | 'md' | 'lg';
|
|
22
|
+
/** Called when tab changes (required for controlled mode) */
|
|
23
|
+
onChange?: (tabId: string) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default function Tabs({ tabs, activeTab: controlledActiveTab, defaultTab, variant = 'underline', orientation = 'horizontal', size = 'md', onChange }: TabsProps) {
|
|
27
|
+
const [internalActiveTab, setInternalActiveTab] = useState(defaultTab || tabs[0]?.id);
|
|
28
|
+
|
|
29
|
+
// Controlled mode: use activeTab prop, Uncontrolled mode: use internal state
|
|
30
|
+
const isControlled = controlledActiveTab !== undefined;
|
|
31
|
+
const activeTab = isControlled ? controlledActiveTab : internalActiveTab;
|
|
32
|
+
|
|
33
|
+
// Ensure the activeTab exists in the current tabs array
|
|
34
|
+
// This handles the case where tabs array reference changes at the same time as activeTab
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const tabExists = tabs.some(tab => tab.id === activeTab);
|
|
37
|
+
if (!tabExists && tabs.length > 0) {
|
|
38
|
+
// If the activeTab doesn't exist in the new tabs array, use the first tab
|
|
39
|
+
if (isControlled) {
|
|
40
|
+
onChange?.(tabs[0].id);
|
|
41
|
+
} else {
|
|
42
|
+
setInternalActiveTab(tabs[0].id);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}, [tabs, activeTab, isControlled, onChange]);
|
|
46
|
+
|
|
47
|
+
const handleTabChange = (tabId: string) => {
|
|
48
|
+
if (!isControlled) {
|
|
49
|
+
setInternalActiveTab(tabId);
|
|
50
|
+
}
|
|
51
|
+
onChange?.(tabId);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Size-specific classes
|
|
55
|
+
const sizeClasses = {
|
|
56
|
+
sm: {
|
|
57
|
+
padding: 'px-3 py-1.5',
|
|
58
|
+
text: 'text-xs',
|
|
59
|
+
icon: 'h-3.5 w-3.5',
|
|
60
|
+
gap: orientation === 'vertical' ? 'gap-1.5' : 'gap-4',
|
|
61
|
+
minWidth: orientation === 'vertical' ? 'min-w-[150px]' : '',
|
|
62
|
+
spacing: orientation === 'vertical' ? 'mt-4' : 'mt-4',
|
|
63
|
+
},
|
|
64
|
+
md: {
|
|
65
|
+
padding: 'px-4 py-2.5',
|
|
66
|
+
text: 'text-sm',
|
|
67
|
+
icon: 'h-4 w-4',
|
|
68
|
+
gap: orientation === 'vertical' ? 'gap-2' : 'gap-6',
|
|
69
|
+
minWidth: orientation === 'vertical' ? 'min-w-[200px]' : '',
|
|
70
|
+
spacing: orientation === 'vertical' ? 'mt-6' : 'mt-6',
|
|
71
|
+
},
|
|
72
|
+
lg: {
|
|
73
|
+
padding: 'px-5 py-3',
|
|
74
|
+
text: 'text-base',
|
|
75
|
+
icon: 'h-5 w-5',
|
|
76
|
+
gap: orientation === 'vertical' ? 'gap-3' : 'gap-8',
|
|
77
|
+
minWidth: orientation === 'vertical' ? 'min-w-[250px]' : '',
|
|
78
|
+
spacing: orientation === 'vertical' ? 'mt-8' : 'mt-8',
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className={`w-full ${orientation === 'vertical' ? `flex ${sizeClasses[size].gap}` : ''}`}>
|
|
84
|
+
{/* Tab Headers */}
|
|
85
|
+
<div
|
|
86
|
+
className={`
|
|
87
|
+
flex ${orientation === 'vertical' ? 'flex-col' : ''}
|
|
88
|
+
${variant === 'underline'
|
|
89
|
+
? orientation === 'vertical'
|
|
90
|
+
? `border-r border-paper-200 ${sizeClasses[size].gap} pr-6`
|
|
91
|
+
: `border-b border-paper-200 ${sizeClasses[size].gap}`
|
|
92
|
+
: `${sizeClasses[size].gap} p-1 bg-paper-50 rounded-lg`
|
|
93
|
+
}
|
|
94
|
+
${sizeClasses[size].minWidth}
|
|
95
|
+
`}
|
|
96
|
+
role="tablist"
|
|
97
|
+
>
|
|
98
|
+
{tabs.map((tab) => {
|
|
99
|
+
const isActive = activeTab === tab.id;
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<button
|
|
103
|
+
key={tab.id}
|
|
104
|
+
role="tab"
|
|
105
|
+
aria-selected={isActive}
|
|
106
|
+
aria-controls={`panel-${tab.id}`}
|
|
107
|
+
disabled={tab.disabled}
|
|
108
|
+
onClick={() => !tab.disabled && handleTabChange(tab.id)}
|
|
109
|
+
className={`
|
|
110
|
+
flex items-center gap-2 ${sizeClasses[size].padding} ${sizeClasses[size].text} font-medium transition-all duration-200
|
|
111
|
+
${orientation === 'vertical' ? 'w-full justify-start' : ''}
|
|
112
|
+
${
|
|
113
|
+
variant === 'underline'
|
|
114
|
+
? isActive
|
|
115
|
+
? orientation === 'vertical'
|
|
116
|
+
? 'text-accent-900 border-r-2 border-accent-500 -mr-[1px]'
|
|
117
|
+
: 'text-accent-900 border-b-2 border-accent-500 -mb-[1px]'
|
|
118
|
+
: orientation === 'vertical'
|
|
119
|
+
? 'text-ink-600 hover:text-ink-900 border-r-2 border-transparent'
|
|
120
|
+
: 'text-ink-600 hover:text-ink-900 border-b-2 border-transparent'
|
|
121
|
+
: isActive
|
|
122
|
+
? 'bg-white text-accent-900 rounded-md shadow-xs'
|
|
123
|
+
: 'text-ink-600 hover:text-ink-900 hover:bg-white/50 rounded-md'
|
|
124
|
+
}
|
|
125
|
+
${tab.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
126
|
+
`}
|
|
127
|
+
>
|
|
128
|
+
{tab.icon && <span className={`flex-shrink-0 ${sizeClasses[size].icon}`}>{tab.icon}</span>}
|
|
129
|
+
<span>{tab.label}</span>
|
|
130
|
+
</button>
|
|
131
|
+
);
|
|
132
|
+
})}
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
{/* Tab Content */}
|
|
136
|
+
<div className={`${orientation === 'vertical' ? 'flex-1' : sizeClasses[size].spacing}`}>
|
|
137
|
+
{tabs.map((tab) => (
|
|
138
|
+
<div
|
|
139
|
+
key={tab.id}
|
|
140
|
+
id={`panel-${tab.id}`}
|
|
141
|
+
role="tabpanel"
|
|
142
|
+
aria-labelledby={tab.id}
|
|
143
|
+
hidden={activeTab !== tab.id}
|
|
144
|
+
className={activeTab === tab.id ? 'animate-fade-in' : ''}
|
|
145
|
+
>
|
|
146
|
+
{activeTab === tab.id && tab.content}
|
|
147
|
+
</div>
|
|
148
|
+
))}
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
);
|
|
152
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -309,6 +309,8 @@ export type {
|
|
|
309
309
|
// Display Components
|
|
310
310
|
export { default as CurrencyDisplay } from './CurrencyDisplay';
|
|
311
311
|
export type { CurrencyDisplayProps } from './CurrencyDisplay';
|
|
312
|
+
export { default as CurrencyInput } from './CurrencyInput';
|
|
313
|
+
export type { CurrencyInputProps } from './CurrencyInput';
|
|
312
314
|
|
|
313
315
|
export { default as DateDisplay } from './DateDisplay';
|
|
314
316
|
export type { DateDisplayProps } from './DateDisplay';
|
|
@@ -409,6 +411,9 @@ export {
|
|
|
409
411
|
} from '../utils/tableEnhancements';
|
|
410
412
|
export type { ColumnResize, ColumnOrder } from '../utils/tableEnhancements';
|
|
411
413
|
|
|
414
|
+
export { exportToExcel, exportDataTableToExcel, createMultiSheetExcel } from '../utils/excelExport';
|
|
415
|
+
export type { ExcelColumn, ExportToExcelOptions, DataTableExportOptions, MultiSheetExcelOptions } from '../utils/excelExport';
|
|
416
|
+
|
|
412
417
|
// Hooks
|
|
413
418
|
export { useColumnResize, useColumnReorder } from '../hooks/useTableEnhancements';
|
|
414
419
|
export type { UseColumnResizeOptions, UseColumnReorderOptions } from '../hooks/useTableEnhancements';
|
package/src/styles/index.css
CHANGED
|
@@ -172,16 +172,53 @@
|
|
|
172
172
|
@apply text-error-600;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
/* Notebook Page Container - Creates bounded page effect
|
|
175
|
+
/* Notebook Page Container - Creates bounded page effect
|
|
176
|
+
NOTE: This class is deprecated - Page component now handles responsive layout via props
|
|
177
|
+
Keeping for backward compatibility only */
|
|
176
178
|
.notebook-page {
|
|
177
179
|
@apply bg-white bg-subtle-grain rounded-sm shadow-lg border-l-4 border-paper-300;
|
|
178
180
|
max-width: 1400px;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
/* Responsive margins - fixed left/top, responsive right/bottom */
|
|
182
|
+
margin-top: 1rem;
|
|
183
|
+
margin-left: 1rem;
|
|
184
|
+
margin-right: 1rem;
|
|
185
|
+
margin-bottom: 1rem;
|
|
186
|
+
/* Responsive padding - fixed left/top, responsive right/bottom */
|
|
187
|
+
padding-top: 3rem;
|
|
188
|
+
padding-left: 5rem; /* Extra left padding for binding margin */
|
|
189
|
+
padding-right: 1rem;
|
|
190
|
+
padding-bottom: 1rem;
|
|
191
|
+
min-height: calc(100vh - 2rem);
|
|
182
192
|
position: relative;
|
|
183
193
|
}
|
|
184
194
|
|
|
195
|
+
/* Responsive padding/margin increases on larger screens */
|
|
196
|
+
@media (min-width: 640px) {
|
|
197
|
+
.notebook-page {
|
|
198
|
+
margin-right: 1.5rem;
|
|
199
|
+
margin-bottom: 2rem;
|
|
200
|
+
padding-right: 2rem;
|
|
201
|
+
padding-bottom: 2rem;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@media (min-width: 768px) {
|
|
206
|
+
.notebook-page {
|
|
207
|
+
margin-right: 2rem;
|
|
208
|
+
margin-bottom: 2rem;
|
|
209
|
+
padding-right: 3rem;
|
|
210
|
+
padding-bottom: 3rem;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
@media (min-width: 1024px) {
|
|
215
|
+
.notebook-page {
|
|
216
|
+
margin-right: auto; /* Center on large screens */
|
|
217
|
+
padding-right: 4rem;
|
|
218
|
+
padding-bottom: 4rem;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
185
222
|
/* Notebook binding effect on sidebar */
|
|
186
223
|
.notebook-binding {
|
|
187
224
|
position: relative;
|