@papernote/ui 1.0.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.
Files changed (84) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +455 -445
  3. package/dist/components/CurrencyInput.d.ts +52 -0
  4. package/dist/components/CurrencyInput.d.ts.map +1 -0
  5. package/dist/components/DataTable.d.ts +3 -1
  6. package/dist/components/DataTable.d.ts.map +1 -1
  7. package/dist/components/Modal.d.ts.map +1 -1
  8. package/dist/components/Page.d.ts +2 -0
  9. package/dist/components/Page.d.ts.map +1 -1
  10. package/dist/components/PageLayout.d.ts +5 -1
  11. package/dist/components/PageLayout.d.ts.map +1 -1
  12. package/dist/components/Spreadsheet.d.ts +129 -0
  13. package/dist/components/Spreadsheet.d.ts.map +1 -0
  14. package/dist/components/Tabs.d.ts +5 -1
  15. package/dist/components/Tabs.d.ts.map +1 -1
  16. package/dist/components/index.d.ts +6 -0
  17. package/dist/components/index.d.ts.map +1 -1
  18. package/dist/index.d.ts +336 -5
  19. package/dist/index.esm.js +51152 -174
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +51145 -143
  22. package/dist/index.js.map +1 -1
  23. package/dist/styles.css +1187 -11
  24. package/dist/utils/excelExport.d.ts +143 -0
  25. package/dist/utils/excelExport.d.ts.map +1 -0
  26. package/dist/utils/index.d.ts +2 -0
  27. package/dist/utils/index.d.ts.map +1 -1
  28. package/package.json +13 -3
  29. package/src/components/AdminModal.css +49 -49
  30. package/src/components/CurrencyInput.stories.tsx +290 -0
  31. package/src/components/CurrencyInput.tsx +193 -0
  32. package/src/components/DataTable.stories.tsx +87 -0
  33. package/src/components/DataTable.tsx +149 -37
  34. package/src/components/Modal.stories.tsx +64 -0
  35. package/src/components/Modal.tsx +15 -2
  36. package/src/components/Page.stories.tsx +76 -0
  37. package/src/components/Page.tsx +35 -3
  38. package/src/components/PageLayout.stories.tsx +75 -0
  39. package/src/components/PageLayout.tsx +28 -9
  40. package/src/components/RoleManager.css +10 -10
  41. package/src/components/Spreadsheet.css +216 -0
  42. package/src/components/Spreadsheet.stories.tsx +362 -0
  43. package/src/components/Spreadsheet.tsx +351 -0
  44. package/src/components/SpreadsheetSimple.stories.tsx +27 -0
  45. package/src/components/Tabs.stories.tsx +31 -0
  46. package/src/components/Tabs.tsx +28 -4
  47. package/src/components/TimePicker.tsx +1 -1
  48. package/src/components/Toast.tsx +9 -9
  49. package/src/components/__tests__/Input.test.tsx +22 -26
  50. package/src/components/index.ts +11 -2
  51. package/src/styles/index.css +44 -6
  52. package/src/utils/excelExport.stories.tsx +535 -0
  53. package/src/utils/excelExport.ts +225 -0
  54. package/src/utils/index.ts +3 -0
  55. package/src/utils/sqlToNaturalLanguage.ts +1 -1
  56. package/tailwind.config.js +253 -253
  57. package/dist/components/Button.stories.d.ts +0 -51
  58. package/dist/components/Button.stories.d.ts.map +0 -1
  59. package/dist/components/ChartVisualizationUI.d.ts +0 -21
  60. package/dist/components/ChartVisualizationUI.d.ts.map +0 -1
  61. package/dist/components/ChatUI.d.ts +0 -23
  62. package/dist/components/ChatUI.d.ts.map +0 -1
  63. package/dist/components/CommissionDashboardUI.d.ts +0 -25
  64. package/dist/components/CommissionDashboardUI.d.ts.map +0 -1
  65. package/dist/components/DataTable.stories.d.ts +0 -23
  66. package/dist/components/DataTable.stories.d.ts.map +0 -1
  67. package/dist/components/FormField.d.ts +0 -35
  68. package/dist/components/FormField.d.ts.map +0 -1
  69. package/dist/components/Input.stories.d.ts +0 -366
  70. package/dist/components/Input.stories.d.ts.map +0 -1
  71. package/dist/components/InsightsPanelUI.d.ts +0 -21
  72. package/dist/components/InsightsPanelUI.d.ts.map +0 -1
  73. package/dist/components/PaymentHistoryTimeline.d.ts +0 -34
  74. package/dist/components/PaymentHistoryTimeline.d.ts.map +0 -1
  75. package/dist/components/RelationshipManagerUI.d.ts +0 -60
  76. package/dist/components/RelationshipManagerUI.d.ts.map +0 -1
  77. package/dist/components/RoleManager.d.ts +0 -19
  78. package/dist/components/RoleManager.d.ts.map +0 -1
  79. package/dist/components/SplitCommissionBadge.d.ts +0 -18
  80. package/dist/components/SplitCommissionBadge.d.ts.map +0 -1
  81. package/dist/components/__tests__/Button.test.d.ts +0 -2
  82. package/dist/components/__tests__/Button.test.d.ts.map +0 -1
  83. package/dist/components/__tests__/Input.test.d.ts +0 -2
  84. package/dist/components/__tests__/Input.test.d.ts.map +0 -1
@@ -30,6 +30,7 @@ export default function Modal({
30
30
  animation = 'scale',
31
31
  }: ModalProps) {
32
32
  const modalRef = useRef<HTMLDivElement>(null);
33
+ const mouseDownOnBackdrop = useRef(false);
33
34
  const titleId = useId();
34
35
 
35
36
  // Handle escape key
@@ -51,11 +52,22 @@ export default function Modal({
51
52
  };
52
53
  }, [isOpen, onClose]);
53
54
 
54
- // Handle click outside
55
- const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => {
55
+ // Track if mousedown originated on the backdrop
56
+ const handleBackdropMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
56
57
  if (e.target === e.currentTarget) {
58
+ mouseDownOnBackdrop.current = true;
59
+ } else {
60
+ mouseDownOnBackdrop.current = false;
61
+ }
62
+ };
63
+
64
+ // Handle click outside - only close if both mousedown and click happened on backdrop
65
+ const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => {
66
+ if (e.target === e.currentTarget && mouseDownOnBackdrop.current) {
57
67
  onClose();
58
68
  }
69
+ // Reset the flag after handling click
70
+ mouseDownOnBackdrop.current = false;
59
71
  };
60
72
 
61
73
  const getAnimationClass = () => {
@@ -80,6 +92,7 @@ export default function Modal({
80
92
  return (
81
93
  <div
82
94
  className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-ink-900 bg-opacity-50 backdrop-blur-sm animate-fade-in"
95
+ onMouseDown={handleBackdropMouseDown}
83
96
  onClick={handleBackdropClick}
84
97
  >
85
98
  <div
@@ -278,3 +278,79 @@ export const SettingsPage: Story = {
278
278
  </Page>
279
279
  ),
280
280
  };
281
+
282
+ export const ResponsiveLayout: Story = {
283
+ render: () => (
284
+ <Page>
285
+ <Card style={{ marginBottom: '1.5rem', backgroundColor: '#dbeafe', border: '1px solid #3b82f6' }}>
286
+ <CardContent>
287
+ <h3 style={{ fontWeight: 600, marginBottom: '0.75rem', fontSize: '0.875rem', color: '#1e40af' }}>
288
+ 📐 Responsive Layout (Default)
289
+ </h3>
290
+ <p style={{ fontSize: '0.875rem', marginBottom: '0.5rem' }}>
291
+ Try resizing your browser window! The page keeps <strong>left and top margins/padding fixed</strong>,
292
+ but <strong>right and bottom resize responsively</strong>:
293
+ </p>
294
+ <ul style={{ marginLeft: '1.5rem', fontSize: '0.875rem' }}>
295
+ <li>• Small screens: Minimal right/bottom padding for more content space</li>
296
+ <li>• Medium screens: Increased right/bottom padding</li>
297
+ <li>• Large screens (1024px+): Maximum spacing with centered layout</li>
298
+ </ul>
299
+ </CardContent>
300
+ </Card>
301
+ <Card>
302
+ <CardHeader>
303
+ <CardTitle>Content Adapts to Screen Size</CardTitle>
304
+ </CardHeader>
305
+ <CardContent>
306
+ <p style={{ marginBottom: '1rem' }}>
307
+ This is the default responsive behavior. The notebook aesthetic is maintained
308
+ across all screen sizes while optimizing for available space.
309
+ </p>
310
+ <p>
311
+ The left binding edge and top margin stay consistent (maintaining the notebook look),
312
+ while right and bottom spacing adjusts for comfort on different devices.
313
+ </p>
314
+ </CardContent>
315
+ </Card>
316
+ </Page>
317
+ ),
318
+ };
319
+
320
+ export const FixedLayout: Story = {
321
+ render: () => (
322
+ <Page fixed={true}>
323
+ <Card style={{ marginBottom: '1.5rem', backgroundColor: '#fef3c7', border: '1px solid #f59e0b' }}>
324
+ <CardContent>
325
+ <h3 style={{ fontWeight: 600, marginBottom: '0.75rem', fontSize: '0.875rem', color: '#92400e' }}>
326
+ 📌 Fixed Layout (fixed=true)
327
+ </h3>
328
+ <p style={{ fontSize: '0.875rem', marginBottom: '0.5rem' }}>
329
+ This page uses <code style={{ backgroundColor: '#fff', padding: '0.125rem 0.375rem', borderRadius: '0.25rem' }}>fixed=true</code>.
330
+ All margins and padding stay <strong>constant regardless of screen size</strong>:
331
+ </p>
332
+ <ul style={{ marginLeft: '1.5rem', fontSize: '0.875rem' }}>
333
+ <li>• Left, right, top, and bottom spacing never changes</li>
334
+ <li>• Consistent appearance on all devices</li>
335
+ <li>• May use more horizontal space on large screens</li>
336
+ </ul>
337
+ </CardContent>
338
+ </Card>
339
+ <Card>
340
+ <CardHeader>
341
+ <CardTitle>Consistent Spacing Everywhere</CardTitle>
342
+ </CardHeader>
343
+ <CardContent>
344
+ <p style={{ marginBottom: '1rem' }}>
345
+ Use the <code style={{ backgroundColor: '#f5f5f5', padding: '0.25rem 0.5rem', borderRadius: '0.25rem' }}>fixed</code> prop
346
+ when you need absolute consistency across all screen sizes, or when the responsive
347
+ behavior doesn't match your design requirements.
348
+ </p>
349
+ <p>
350
+ Try resizing your browser - the spacing around this page content remains identical.
351
+ </p>
352
+ </CardContent>
353
+ </Card>
354
+ </Page>
355
+ ),
356
+ };
@@ -12,6 +12,8 @@ export interface PageProps {
12
12
  className?: string;
13
13
  /** Padding size around the content (default: 'normal') */
14
14
  padding?: 'none' | 'sm' | 'normal' | 'lg';
15
+ /** Fix all margins/padding instead of responsive (default: false) */
16
+ fixed?: boolean;
15
17
  }
16
18
 
17
19
  /**
@@ -47,14 +49,44 @@ export interface PageProps {
47
49
  */
48
50
  export const Page: React.FC<PageProps> = ({
49
51
  children,
50
- maxWidth: _maxWidth = '7xl',
52
+ maxWidth = '7xl',
51
53
  className = '',
52
- padding: _padding = 'normal'
54
+ padding = 'normal',
55
+ fixed = false
53
56
  }) => {
57
+ // Max width classes
58
+ const maxWidthClasses = {
59
+ '4xl': 'max-w-4xl',
60
+ '5xl': 'max-w-5xl',
61
+ '6xl': 'max-w-6xl',
62
+ '7xl': 'max-w-7xl',
63
+ 'full': 'max-w-full',
64
+ };
65
+
66
+ // Padding classes - responsive (fixed left/top, responsive right/bottom) vs all fixed
67
+ const paddingClasses = {
68
+ none: fixed ? 'p-0' : 'pt-0 pl-0 pr-0 pb-0',
69
+ sm: fixed ? 'p-4' : 'pt-4 pl-4 pr-4 pb-4 sm:pr-6 md:pr-8 sm:pb-6 md:pb-8',
70
+ normal: fixed ? 'pt-12 pl-20 pr-16 pb-12' : 'pt-12 pl-20 pr-4 pb-4 sm:pr-8 md:pr-12 lg:pr-16 sm:pb-8 md:pb-12 lg:pb-16',
71
+ lg: fixed ? 'pt-16 pl-24 pr-20 pb-16' : 'pt-16 pl-24 pr-6 pb-6 sm:pr-12 md:pr-16 lg:pr-20 sm:pb-12 md:pb-16 lg:pb-20',
72
+ };
73
+
74
+ // Margin classes - responsive (fixed left/top, responsive right/bottom) vs all fixed
75
+ const marginClasses = fixed
76
+ ? 'mt-4 ml-4 mr-4 mb-4'
77
+ : 'mt-4 ml-4 mr-4 mb-4 sm:mr-6 md:mr-8 lg:mr-auto sm:mb-6 md:mb-8';
54
78
 
55
79
  return (
56
80
  <div className="min-h-screen bg-paper-100">
57
- <div className={`notebook-page notebook-margin notebook-ruled ${className}`}>
81
+ <div className={`
82
+ bg-white bg-subtle-grain rounded-sm shadow-lg border-l-4 border-paper-300
83
+ min-h-[calc(100vh-2rem)] relative
84
+ notebook-margin notebook-ruled
85
+ ${maxWidthClasses[maxWidth]}
86
+ ${paddingClasses[padding]}
87
+ ${marginClasses}
88
+ ${className}
89
+ `.trim().replace(/\s+/g, ' ')}>
58
90
  {children}
59
91
  </div>
60
92
  </div>
@@ -586,3 +586,78 @@ export const WithSidebarAndGutter: Story = {
586
586
  );
587
587
  },
588
588
  };
589
+
590
+ export const ResponsiveLayout: Story = {
591
+ render: () => (
592
+ <PageLayout
593
+ title="Responsive PageLayout"
594
+ description="Default responsive behavior - resize your browser to see the right and bottom padding adapt"
595
+ >
596
+ <Card style={{ marginBottom: '1.5rem', backgroundColor: '#dbeafe', border: '1px solid #3b82f6' }}>
597
+ <CardContent>
598
+ <h3 style={{ fontWeight: 600, marginBottom: '0.75rem', fontSize: '0.875rem', color: '#1e40af' }}>
599
+ 📐 Responsive Layout (Default)
600
+ </h3>
601
+ <p style={{ fontSize: '0.875rem', marginBottom: '0.5rem' }}>
602
+ Try resizing your browser window! PageLayout keeps <strong>left and top padding fixed</strong>,
603
+ but <strong>right and bottom resize responsively</strong>:
604
+ </p>
605
+ <ul style={{ marginLeft: '1.5rem', fontSize: '0.875rem' }}>
606
+ <li>• Small screens: Minimal right/bottom padding (pr-2 pb-8)</li>
607
+ <li>• Medium screens (640px+): Increased padding (pr-4 pb-12)</li>
608
+ <li>• Large screens (768px+): More padding (pr-6 pb-16)</li>
609
+ <li>• XL screens (1024px+): Maximum padding (pb-20)</li>
610
+ </ul>
611
+ </CardContent>
612
+ </Card>
613
+ <Card>
614
+ <CardHeader>
615
+ <CardTitle>Content Adapts to Screen Size</CardTitle>
616
+ </CardHeader>
617
+ <CardContent>
618
+ <p>
619
+ This is perfect for applications where you want the notebook aesthetic to be
620
+ maintained while optimizing for different device sizes.
621
+ </p>
622
+ </CardContent>
623
+ </Card>
624
+ </PageLayout>
625
+ ),
626
+ };
627
+
628
+ export const FixedLayout: Story = {
629
+ render: () => (
630
+ <PageLayout
631
+ title="Fixed PageLayout"
632
+ description="All padding remains constant regardless of screen size"
633
+ fixed={true}
634
+ >
635
+ <Card style={{ marginBottom: '1.5rem', backgroundColor: '#fef3c7', border: '1px solid #f59e0b' }}>
636
+ <CardContent>
637
+ <h3 style={{ fontWeight: 600, marginBottom: '0.75rem', fontSize: '0.875rem', color: '#92400e' }}>
638
+ 📌 Fixed Layout (fixed=true)
639
+ </h3>
640
+ <p style={{ fontSize: '0.875rem', marginBottom: '0.5rem' }}>
641
+ This page uses <code style={{ backgroundColor: '#fff', padding: '0.125rem 0.375rem', borderRadius: '0.25rem' }}>fixed=true</code>.
642
+ All padding stays <strong>constant regardless of screen size</strong>:
643
+ </p>
644
+ <ul style={{ marginLeft: '1.5rem', fontSize: '0.875rem' }}>
645
+ <li>• Same padding on mobile and desktop</li>
646
+ <li>• Predictable layout at all viewport sizes</li>
647
+ <li>• Use when you need absolute consistency</li>
648
+ </ul>
649
+ </CardContent>
650
+ </Card>
651
+ <Card>
652
+ <CardHeader>
653
+ <CardTitle>Consistent Everywhere</CardTitle>
654
+ </CardHeader>
655
+ <CardContent>
656
+ <p>
657
+ Try resizing your browser - the spacing remains identical at all screen sizes.
658
+ </p>
659
+ </CardContent>
660
+ </Card>
661
+ </PageLayout>
662
+ ),
663
+ };
@@ -12,6 +12,10 @@ export interface PageLayoutProps {
12
12
  className?: string;
13
13
  /** Optional content to render before the title (e.g., breadcrumbs, alerts, control bars) */
14
14
  headerContent?: ReactNode;
15
+ /** Maximum width constraint for the page content (default: '7xl' = 1400px) */
16
+ maxWidth?: '4xl' | '5xl' | '6xl' | '7xl' | 'full';
17
+ /** Fix all margins/padding instead of responsive (default: false) */
18
+ fixed?: boolean;
15
19
  }
16
20
 
17
21
  /**
@@ -51,19 +55,34 @@ export interface PageLayoutProps {
51
55
  * </Layout>
52
56
  * ```
53
57
  */
54
- export function PageLayout({
55
- title,
56
- description,
57
- children,
58
+ export function PageLayout({
59
+ title,
60
+ description,
61
+ children,
58
62
  className = '',
59
- headerContent
63
+ headerContent,
64
+ maxWidth = '7xl',
65
+ fixed = false
60
66
  }: PageLayoutProps) {
67
+ // Responsive padding classes - fixed left/top, responsive right/bottom
68
+ const paddingClasses = fixed
69
+ ? 'p-6 pb-20'
70
+ : 'pt-6 pl-6 pr-2 pb-8 sm:pr-4 md:pr-6 sm:pb-12 md:pb-16 lg:pb-20';
71
+
72
+ const maxWidthClasses = {
73
+ '4xl': 'max-w-4xl',
74
+ '5xl': 'max-w-5xl',
75
+ '6xl': 'max-w-6xl',
76
+ '7xl': 'max-w-7xl',
77
+ 'full': 'max-w-full',
78
+ };
79
+
61
80
  return (
62
- <Page>
81
+ <Page padding="none" maxWidth={maxWidth} fixed={fixed}>
63
82
  {/* Content before title (e.g., ControlBar) */}
64
83
  {headerContent}
65
-
66
- <div className={`p-6 max-w-7xl mx-auto pb-20 ${className}`}>
84
+
85
+ <div className={`${paddingClasses} ${maxWidthClasses[maxWidth]} mx-auto ${className}`}>
67
86
  {/* Header */}
68
87
  <div className="mb-8">
69
88
  <h1 className="text-3xl font-bold text-ink-900 mb-2">{title}</h1>
@@ -71,7 +90,7 @@ export function PageLayout({
71
90
  <p className="text-ink-600">{description}</p>
72
91
  )}
73
92
  </div>
74
-
93
+
75
94
  {children}
76
95
  </div>
77
96
  </Page>
@@ -1,10 +1,10 @@
1
- /* RoleManager.css - Styles for RoleManager component */
2
-
3
- .role-manager-permission-grid {
4
- grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
5
- }
6
-
7
- .role-manager-list {
8
- height: var(--role-manager-height, 400px);
9
- min-height: 200px;
10
- }
1
+ /* RoleManager.css - Styles for RoleManager component */
2
+
3
+ .role-manager-permission-grid {
4
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
5
+ }
6
+
7
+ .role-manager-list {
8
+ height: var(--role-manager-height, 400px);
9
+ min-height: 200px;
10
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Spreadsheet Component Styles
3
+ *
4
+ * Custom styling for react-spreadsheet to match notebook-ui's paper aesthetic
5
+ */
6
+
7
+ /* Container */
8
+ .spreadsheet-container {
9
+ width: 100%;
10
+ overflow: auto;
11
+ background-color: #fafaf9; /* paper-50 */
12
+ border-radius: 0.5rem;
13
+ border: 1px solid #e7e5e4; /* stone-200 */
14
+ }
15
+
16
+ /* Spreadsheet base */
17
+ .notebook-spreadsheet {
18
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
19
+ font-size: 0.875rem;
20
+ color: #1c1917; /* ink-900 */
21
+ }
22
+
23
+ /* Table styling */
24
+ .notebook-spreadsheet table {
25
+ border-collapse: separate;
26
+ border-spacing: 0;
27
+ background-color: #ffffff;
28
+ width: 100%;
29
+ }
30
+
31
+ /* Cell styling */
32
+ .notebook-spreadsheet td {
33
+ border: 1px solid #e7e5e4; /* stone-200 */
34
+ padding: 0;
35
+ background-color: #ffffff;
36
+ transition: background-color 0.15s ease;
37
+ }
38
+
39
+ /* Cell hover */
40
+ .notebook-spreadsheet td:hover {
41
+ background-color: #fafaf9; /* paper-50 */
42
+ }
43
+
44
+ /* Selected cell */
45
+ .notebook-spreadsheet td.Spreadsheet__active-cell {
46
+ border: 2px solid #334155; /* primary-700 */
47
+ box-shadow: 0 0 0 1px #334155;
48
+ background-color: #ffffff;
49
+ z-index: 10;
50
+ }
51
+
52
+ /* Header cells (row/column labels) */
53
+ .notebook-spreadsheet th {
54
+ background-color: #f5f5f4; /* stone-100 */
55
+ color: #57534e; /* ink-600 */
56
+ border: 1px solid #e7e5e4; /* stone-200 */
57
+ padding: 0.5rem;
58
+ font-weight: 600;
59
+ font-size: 0.75rem;
60
+ text-align: center;
61
+ position: sticky;
62
+ z-index: 5;
63
+ }
64
+
65
+ /* Column headers */
66
+ .notebook-spreadsheet thead th {
67
+ top: 0;
68
+ z-index: 10;
69
+ }
70
+
71
+ /* Row headers */
72
+ .notebook-spreadsheet tbody th {
73
+ left: 0;
74
+ z-index: 5;
75
+ }
76
+
77
+ /* Corner header (top-left cell) */
78
+ .notebook-spreadsheet thead th:first-child {
79
+ left: 0;
80
+ z-index: 15;
81
+ }
82
+
83
+ /* Cell input */
84
+ .notebook-spreadsheet .Spreadsheet__data-editor {
85
+ width: 100%;
86
+ height: 100%;
87
+ border: none;
88
+ outline: none;
89
+ padding: 0.5rem;
90
+ font-family: inherit;
91
+ font-size: inherit;
92
+ color: inherit;
93
+ background-color: #ffffff;
94
+ box-sizing: border-box;
95
+ }
96
+
97
+ .notebook-spreadsheet .Spreadsheet__data-editor:focus {
98
+ background-color: #ffffff;
99
+ border: 2px solid #334155; /* primary-700 */
100
+ padding: calc(0.5rem - 1px);
101
+ }
102
+
103
+ /* Cell with formula indicator */
104
+ .notebook-spreadsheet .Spreadsheet__cell--formula {
105
+ font-style: italic;
106
+ background-color: #f0fdf4; /* success-50 */
107
+ }
108
+
109
+ /* Read-only cells */
110
+ .notebook-spreadsheet .Spreadsheet__cell--readonly {
111
+ background-color: #f5f5f4; /* stone-100 */
112
+ color: #78716c; /* ink-500 */
113
+ }
114
+
115
+ /* Selection highlight */
116
+ .notebook-spreadsheet .Spreadsheet__cell--selected {
117
+ background-color: #e0f2fe; /* primary-100 */
118
+ }
119
+
120
+ /* Cell error state */
121
+ .notebook-spreadsheet .Spreadsheet__cell--error {
122
+ background-color: #fef2f2; /* error-50 */
123
+ color: #991b1b; /* error-800 */
124
+ }
125
+
126
+ /* Cell value display */
127
+ .notebook-spreadsheet .Spreadsheet__value {
128
+ padding: 0.5rem;
129
+ min-height: 2rem;
130
+ display: flex;
131
+ align-items: center;
132
+ }
133
+
134
+ /* Number cells - align right */
135
+ .notebook-spreadsheet .Spreadsheet__cell--number .Spreadsheet__value {
136
+ justify-content: flex-end;
137
+ font-variant-numeric: tabular-nums;
138
+ }
139
+
140
+ /* Empty cells */
141
+ .notebook-spreadsheet .Spreadsheet__cell--empty .Spreadsheet__value {
142
+ color: #a8a29e; /* ink-400 */
143
+ }
144
+
145
+ /* Copy/paste indicator */
146
+ .notebook-spreadsheet .Spreadsheet__floating-rect {
147
+ border: 2px dashed #334155; /* primary-700 */
148
+ background-color: rgba(51, 65, 85, 0.1);
149
+ pointer-events: none;
150
+ }
151
+
152
+ /* Scrollbar styling for webkit browsers */
153
+ .spreadsheet-container::-webkit-scrollbar {
154
+ width: 12px;
155
+ height: 12px;
156
+ }
157
+
158
+ .spreadsheet-container::-webkit-scrollbar-track {
159
+ background-color: #fafaf9; /* paper-50 */
160
+ border-radius: 0.5rem;
161
+ }
162
+
163
+ .spreadsheet-container::-webkit-scrollbar-thumb {
164
+ background-color: #d6d3d1; /* stone-300 */
165
+ border-radius: 0.5rem;
166
+ border: 2px solid #fafaf9;
167
+ }
168
+
169
+ .spreadsheet-container::-webkit-scrollbar-thumb:hover {
170
+ background-color: #a8a29e; /* ink-400 */
171
+ }
172
+
173
+ /* Loading state */
174
+ .spreadsheet-container.loading {
175
+ opacity: 0.6;
176
+ pointer-events: none;
177
+ }
178
+
179
+ /* Responsive adjustments */
180
+ @media (max-width: 768px) {
181
+ .notebook-spreadsheet {
182
+ font-size: 0.75rem;
183
+ }
184
+
185
+ .notebook-spreadsheet .Spreadsheet__value {
186
+ padding: 0.375rem;
187
+ min-height: 1.75rem;
188
+ }
189
+
190
+ .notebook-spreadsheet .Spreadsheet__data-editor {
191
+ padding: 0.375rem;
192
+ }
193
+
194
+ .notebook-spreadsheet th {
195
+ padding: 0.375rem;
196
+ font-size: 0.6875rem;
197
+ }
198
+ }
199
+
200
+ /* Print styles */
201
+ @media print {
202
+ .spreadsheet-container {
203
+ border: none;
204
+ overflow: visible;
205
+ }
206
+
207
+ .notebook-spreadsheet td,
208
+ .notebook-spreadsheet th {
209
+ border-color: #000;
210
+ }
211
+
212
+ .notebook-spreadsheet .Spreadsheet__active-cell {
213
+ border: 1px solid #000;
214
+ box-shadow: none;
215
+ }
216
+ }