@papernote/ui 1.14.0 → 2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@papernote/ui",
3
- "version": "1.14.0",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "description": "A modern React component library with a paper notebook aesthetic - minimal, professional, and expressive",
6
6
  "main": "dist/index.js",
@@ -20,6 +20,8 @@
20
20
  },
21
21
  "./styles": "./dist/styles.css",
22
22
  "./styles.css": "./dist/styles.css",
23
+ "./theme": "./src/styles/theme.css",
24
+ "./theme.css": "./src/styles/theme.css",
23
25
  "./tailwind-config": "./tailwind.config.js"
24
26
  },
25
27
  "scripts": {
@@ -60,7 +62,8 @@
60
62
  "@types/react-dom": "^19.2.2",
61
63
  "@typescript-eslint/eslint-plugin": "^6.0.0",
62
64
  "@typescript-eslint/parser": "^6.0.0",
63
- "autoprefixer": "^10.4.0",
65
+ "@tailwindcss/postcss": "^4.0.0",
66
+ "@tailwindcss/vite": "^4.0.0",
64
67
  "eslint": "^8.0.0",
65
68
  "eslint-plugin-react": "^7.0.0",
66
69
  "eslint-plugin-react-hooks": "^4.0.0",
@@ -69,7 +72,6 @@
69
72
  "jest-environment-jsdom": "^30.2.0",
70
73
  "lucide-react": "^0.554.0",
71
74
  "postcss": "^8.4.0",
72
- "postcss-import": "^16.1.1",
73
75
  "react": "^19.2.0",
74
76
  "react-dom": "^19.2.0",
75
77
  "react-router-dom": "^7.9.6",
@@ -78,7 +80,7 @@
78
80
  "rollup-plugin-peer-deps-external": "^2.2.4",
79
81
  "rollup-plugin-postcss": "^4.0.0",
80
82
  "storybook": "^10.1.11",
81
- "tailwindcss": "^3.4.0",
83
+ "tailwindcss": "^4.0.0",
82
84
  "ts-jest": "^29.4.5",
83
85
  "tslib": "^2.6.0",
84
86
  "typescript": "^5.0.0",
@@ -63,7 +63,7 @@ export function AdminModal({
63
63
  };
64
64
 
65
65
  return (
66
- <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4 admin-modal-overlay">
66
+ <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 admin-modal-overlay">
67
67
  <div
68
68
  className={`bg-white rounded-lg w-full ${sizeClasses[size]} flex flex-col overflow-hidden shadow-2xl admin-modal-content`}
69
69
  style={{ height: height }}
@@ -301,7 +301,7 @@ const Autocomplete = forwardRef<AutocompleteHandle, AutocompleteProps>(({
301
301
  disabled={disabled}
302
302
  className={`
303
303
  w-full pl-9 pr-9 py-2
304
- text-sm text-ink-900 placeholder-ink-400
304
+ text-sm text-ink-900 placeholder:text-ink-400
305
305
  bg-white border rounded-lg
306
306
  focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400
307
307
  disabled:bg-paper-100 disabled:cursor-not-allowed
@@ -167,7 +167,7 @@ export default function CommandPalette({
167
167
  <div className="fixed inset-0 z-50 flex items-start justify-center pt-[20vh] animate-fade-in">
168
168
  {/* Backdrop */}
169
169
  <div
170
- className="absolute inset-0 bg-ink-900 bg-opacity-50 backdrop-blur-sm"
170
+ className="absolute inset-0 bg-ink-900/50 backdrop-blur-sm"
171
171
  onClick={() => onOpenChange(false)}
172
172
  />
173
173
 
@@ -185,7 +185,7 @@ export default function CommandPalette({
185
185
  setSelectedIndex(0);
186
186
  }}
187
187
  placeholder={placeholder}
188
- className="flex-1 text-base text-ink-900 placeholder-ink-400 bg-transparent border-none outline-none"
188
+ className="flex-1 text-base text-ink-900 placeholder:text-ink-400 bg-transparent border-none outline-none"
189
189
  />
190
190
  {trigger && (
191
191
  <kbd className="hidden sm:inline-block px-2 py-1 text-xs font-mono text-ink-500 bg-paper-100 border border-paper-300 rounded">
@@ -1646,7 +1646,7 @@ export default function DataTable<T extends BaseDataItem = BaseDataItem>({
1646
1646
  {/* Loading overlay for when data is being refreshed */}
1647
1647
  {loading && data.length > 0 && (
1648
1648
  <div
1649
- className="absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center z-20"
1649
+ className="absolute inset-0 bg-white/75 flex items-center justify-center z-20"
1650
1650
  style={{ backdropFilter: 'blur(2px)' }}
1651
1651
  >
1652
1652
  <div className="flex flex-col items-center gap-3">
@@ -131,7 +131,7 @@ export default function Drawer({
131
131
  {/* Overlay */}
132
132
  {showOverlay && (
133
133
  <div
134
- className="fixed inset-0 bg-ink-900 bg-opacity-50 backdrop-blur-sm animate-fade-in"
134
+ className="fixed inset-0 bg-ink-900/50 backdrop-blur-sm animate-fade-in"
135
135
  onClick={handleOverlayClick}
136
136
  aria-hidden="true"
137
137
  />
@@ -187,7 +187,7 @@ export default function MarkdownEditor({
187
187
  disabled={disabled}
188
188
  className={`
189
189
  w-full p-3 outline-none resize-none
190
- text-sm text-ink-900 font-mono placeholder-ink-400
190
+ text-sm text-ink-900 font-mono placeholder:text-ink-400
191
191
  ${disabled ? 'bg-paper-100 cursor-not-allowed' : 'bg-white'}
192
192
  `}
193
193
  style={{ minHeight, maxHeight }}
@@ -161,7 +161,7 @@ const MaskedInput = forwardRef<MaskedInputHandle, MaskedInputProps>(({
161
161
  disabled={disabled}
162
162
  className={`
163
163
  w-full px-3 py-2
164
- text-sm text-ink-900 placeholder-ink-400
164
+ text-sm text-ink-900 placeholder:text-ink-400
165
165
  bg-white border rounded-lg
166
166
  focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400
167
167
  disabled:bg-paper-100 disabled:cursor-not-allowed
@@ -259,7 +259,7 @@ export default function Modal({
259
259
  // Render as standard modal on desktop
260
260
  const modalContent = (
261
261
  <div
262
- 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"
262
+ className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-ink-900/50 backdrop-blur-sm animate-fade-in"
263
263
  onMouseDown={handleBackdropMouseDown}
264
264
  onClick={handleBackdropClick}
265
265
  >
@@ -54,7 +54,7 @@ export default function NotificationBar({ notifications, onDismiss }: Notificati
54
54
  className={`border-2 rounded-xl p-4 backdrop-blur-sm transform transition-all duration-300 ease-in-out animate-slide-in ${notificationStyles[notification.type]}`}
55
55
  >
56
56
  <div className="flex items-start space-x-3">
57
- <div className={`flex-shrink-0 p-1 rounded-full bg-white bg-opacity-50 ${iconStyles[notification.type]}`}>
57
+ <div className={`flex-shrink-0 p-1 rounded-full bg-white/50 ${iconStyles[notification.type]}`}>
58
58
  <IconComponent className="h-5 w-5" />
59
59
  </div>
60
60
  <div className="flex-1 min-w-0">
@@ -68,7 +68,7 @@ export default function NotificationBar({ notifications, onDismiss }: Notificati
68
68
  {notification.dismissible && onDismiss && (
69
69
  <button
70
70
  onClick={() => onDismiss(notification.id)}
71
- className={`flex-shrink-0 p-1.5 hover:bg-white hover:bg-opacity-60 rounded-full transition-all duration-200 ${iconStyles[notification.type]} hover:scale-110`}
71
+ className={`flex-shrink-0 p-1.5 hover:bg-white/60 rounded-full transition-all duration-200 ${iconStyles[notification.type]} hover:scale-110`}
72
72
  title="Dismiss notification"
73
73
  >
74
74
  <X className="h-4 w-4" />
@@ -164,7 +164,7 @@ const PasswordInput = forwardRef<PasswordInputHandle, PasswordInputProps>(({
164
164
  disabled={disabled}
165
165
  className={`
166
166
  w-full px-3 py-2 pr-10
167
- text-sm text-ink-900 placeholder-ink-400
167
+ text-sm text-ink-900 placeholder:text-ink-400
168
168
  bg-white border rounded-lg
169
169
  focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400
170
170
  disabled:bg-paper-100 disabled:cursor-not-allowed
@@ -35,7 +35,7 @@ export default function SearchBar({
35
35
  onChange={(e) => onChange(e.target.value)}
36
36
  onKeyDown={handleKeyDown}
37
37
  disabled={disabled}
38
- className="block w-full pl-11 pr-4 py-3 border border-paper-300 rounded-lg leading-5 bg-white placeholder-ink-400 text-ink-800 focus:outline-none focus:placeholder-ink-300 focus:ring-2 focus:ring-accent-400 focus:border-accent-400 hover:border-paper-400 transition-all sm:text-sm disabled:bg-paper-100 disabled:cursor-not-allowed"
38
+ className="block w-full pl-11 pr-4 py-3 border border-paper-300 rounded-lg leading-5 bg-white placeholder:text-ink-400 text-ink-800 focus:outline-none focus:placeholder:text-ink-300 focus:ring-2 focus:ring-accent-400 focus:border-accent-400 hover:border-paper-400 transition-all sm:text-sm disabled:bg-paper-100 disabled:cursor-not-allowed"
39
39
  placeholder={placeholder}
40
40
  />
41
41
  </div>
@@ -177,7 +177,7 @@ const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
177
177
  rows={autoExpand ? minRows : rows}
178
178
  enterKeyHint={enterKeyHint}
179
179
  className={`
180
- block w-full border rounded-lg text-ink-800 placeholder-ink-400
180
+ block w-full border rounded-lg text-ink-800 placeholder:text-ink-400
181
181
  bg-white bg-subtle-grain transition-all duration-200
182
182
  focus:outline-none focus:ring-2 ${getResizeClass()}
183
183
  disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
@@ -3,9 +3,12 @@
3
3
  /* Component styles */
4
4
  @import '../components/Spreadsheet.css';
5
5
 
6
- @tailwind base;
7
- @tailwind components;
8
- @tailwind utilities;
6
+ @import "tailwindcss";
7
+ @import "./theme.css";
8
+
9
+ /* Content sources for class detection */
10
+ @source "../components/**/*.{tsx,ts}";
11
+ @source inline("bg-sky-100 bg-sky-50 bg-sky-100/50 bg-amber-100 bg-amber-50 bg-amber-100/50 bg-emerald-100 bg-emerald-50 bg-emerald-100/50 bg-pink-100 bg-pink-50 bg-pink-100/50");
9
12
 
10
13
  @layer base {
11
14
  body {
@@ -47,7 +50,7 @@
47
50
 
48
51
  /* Input Styles - Comfortable & Clear */
49
52
  .input {
50
- @apply block w-full px-4 py-2.5 border border-paper-300 rounded-lg text-sm text-ink-800 placeholder-ink-400 bg-white transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400 hover:border-paper-400;
53
+ @apply block w-full px-4 py-2.5 border border-paper-300 rounded-lg text-sm text-ink-800 placeholder:text-ink-400 bg-white transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400 hover:border-paper-400;
51
54
  }
52
55
 
53
56
  .label {
@@ -84,27 +87,6 @@
84
87
  @apply bg-primary-50 text-primary-700 border border-primary-200;
85
88
  }
86
89
 
87
- /* Table Styles - Clean & Minimal */
88
- .table {
89
- @apply min-w-full divide-y divide-paper-200;
90
- }
91
-
92
- .table-header {
93
- @apply bg-paper-50;
94
- }
95
-
96
- .table-header-cell {
97
- @apply px-6 py-3 text-left text-xs font-medium text-ink-500 uppercase tracking-wider;
98
- }
99
-
100
- .table-cell {
101
- @apply px-6 py-4 whitespace-nowrap text-sm text-ink-700;
102
- }
103
-
104
- .table-row {
105
- @apply hover:bg-paper-50 transition-colors duration-150;
106
- }
107
-
108
90
  /* Navigation Styles - Notebook-like */
109
91
  .nav-link {
110
92
  @apply flex items-center px-3 py-2.5 text-sm font-medium rounded-lg transition-all duration-200;
@@ -140,7 +122,7 @@
140
122
  }
141
123
 
142
124
  input:checked + .slider:before {
143
- @apply transform translate-x-5;
125
+ @apply translate-x-5;
144
126
  }
145
127
 
146
128
  /* Stat Card Styles - Paper-like */
@@ -316,56 +298,33 @@
316
298
  }
317
299
  }
318
300
 
319
- @layer utilities {
320
- .line-clamp-1 {
321
- overflow: hidden;
322
- display: -webkit-box;
323
- -webkit-box-orient: vertical;
324
- -webkit-line-clamp: 1;
325
- }
326
-
327
- .line-clamp-2 {
328
- overflow: hidden;
329
- display: -webkit-box;
330
- -webkit-box-orient: vertical;
331
- -webkit-line-clamp: 2;
332
- }
333
-
334
- .line-clamp-3 {
335
- overflow: hidden;
336
- display: -webkit-box;
337
- -webkit-box-orient: vertical;
338
- -webkit-line-clamp: 3;
339
- }
340
-
341
- .scrollbar-hide {
342
- -ms-overflow-style: none;
343
- scrollbar-width: none;
344
- }
345
-
346
- .scrollbar-hide::-webkit-scrollbar {
301
+ /* Custom utilities */
302
+ @utility scrollbar-hide {
303
+ -ms-overflow-style: none;
304
+ scrollbar-width: none;
305
+ &::-webkit-scrollbar {
347
306
  display: none;
348
307
  }
308
+ }
349
309
 
350
- .text-shadow {
351
- text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
352
- }
310
+ @utility text-shadow {
311
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
312
+ }
353
313
 
354
- .bg-gradient-primary {
355
- background: linear-gradient(135deg, #64748b, #475569);
356
- }
314
+ @utility bg-gradient-primary {
315
+ background: linear-gradient(135deg, #64748b, #475569);
316
+ }
357
317
 
358
- .bg-gradient-success {
359
- background: linear-gradient(135deg, #10b981, #059669);
360
- }
318
+ @utility bg-gradient-success {
319
+ background: linear-gradient(135deg, #10b981, #059669);
320
+ }
361
321
 
362
- .bg-gradient-warning {
363
- background: linear-gradient(135deg, #f59e0b, #d97706);
364
- }
322
+ @utility bg-gradient-warning {
323
+ background: linear-gradient(135deg, #f59e0b, #d97706);
324
+ }
365
325
 
366
- .bg-gradient-accent {
367
- background: linear-gradient(135deg, #f59e0b, #d97706);
368
- }
326
+ @utility bg-gradient-accent {
327
+ background: linear-gradient(135deg, #f59e0b, #d97706);
369
328
  }
370
329
 
371
330
  /* Custom scrollbar - Subtle paper aesthetic */
@@ -388,21 +347,7 @@
388
347
  background: #a8a29e;
389
348
  }
390
349
 
391
- /* Loading animations */
392
- @keyframes pulse {
393
- 0%, 100% {
394
- opacity: 1;
395
- }
396
- 50% {
397
- opacity: .5;
398
- }
399
- }
400
-
401
- .animate-pulse {
402
- animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
403
- }
404
-
405
- /* Table styles - Clean & minimal */
350
+ /* Table styles - Clean & minimal (un-layered for higher specificity) */
406
351
  .table {
407
352
  @apply min-w-full divide-y divide-paper-200;
408
353
  }
@@ -429,35 +374,33 @@
429
374
  }
430
375
 
431
376
  .table-stable {
432
- @apply table-fixed;
433
- /* Removed min-height to allow content-based sizing for two-row layout */
377
+ table-layout: fixed !important;
434
378
  }
435
379
 
436
- .table-stable thead {
437
- height: auto !important;
438
- }
380
+ .table-stable thead {
381
+ height: auto !important;
382
+ }
439
383
 
440
- .table-stable thead th {
441
- position: sticky;
442
- top: 0;
443
- z-index: 10;
444
- background-color: #fafaf9;
445
- backdrop-filter: blur(8px);
446
- /* padding controlled by component density classes (currentDensity.header) */
447
- height: 28px !important;
448
- min-height: 28px !important;
449
- max-height: 28px !important;
450
- line-height: 1 !important;
451
- vertical-align: middle !important;
452
- overflow: hidden !important;
453
- box-sizing: border-box !important;
454
- font-size: 0.75rem !important;
455
- border-bottom: 1px solid #e7e5e4;
456
- }
384
+ .table-stable thead th {
385
+ position: sticky;
386
+ top: 0;
387
+ z-index: 10;
388
+ background-color: #fafaf9;
389
+ backdrop-filter: blur(8px);
390
+ height: 28px !important;
391
+ min-height: 28px !important;
392
+ max-height: 28px !important;
393
+ line-height: 1 !important;
394
+ vertical-align: middle !important;
395
+ overflow: hidden !important;
396
+ box-sizing: border-box !important;
397
+ font-size: 0.75rem !important;
398
+ border-bottom: 1px solid #e7e5e4;
399
+ }
457
400
 
458
401
  /* Primary rows with normal content */
459
402
  .table-stable tbody tr {
460
- height: auto; /* Allow content-based sizing for two-row layout */
403
+ height: auto;
461
404
  }
462
405
 
463
406
  /* Secondary rows should be compact */
@@ -534,59 +477,6 @@
534
477
  overflow: hidden;
535
478
  }
536
479
 
537
- /* Drawer Slide Animations */
538
- @keyframes slideInLeft {
539
- from {
540
- transform: translateX(-100%);
541
- }
542
- to {
543
- transform: translateX(0);
544
- }
545
- }
546
-
547
- @keyframes slideInRight {
548
- from {
549
- transform: translateX(100%);
550
- }
551
- to {
552
- transform: translateX(0);
553
- }
554
- }
555
-
556
- @keyframes slideInTop {
557
- from {
558
- transform: translateY(-100%);
559
- }
560
- to {
561
- transform: translateY(0);
562
- }
563
- }
564
-
565
- @keyframes slideInBottom {
566
- from {
567
- transform: translateY(100%);
568
- }
569
- to {
570
- transform: translateY(0);
571
- }
572
- }
573
-
574
- .animate-slide-in-left {
575
- animation: slideInLeft 0.3s ease-out;
576
- }
577
-
578
- .animate-slide-in-right {
579
- animation: slideInRight 0.3s ease-out;
580
- }
581
-
582
- .animate-slide-in-top {
583
- animation: slideInTop 0.3s ease-out;
584
- }
585
-
586
- .animate-slide-in-bottom {
587
- animation: slideInBottom 0.3s ease-out;
588
- }
589
-
590
480
  /* Touch-friendly sizing for coarse pointer devices (touch screens) */
591
481
  @media (pointer: coarse) {
592
482
  /* Ensure buttons meet 48px minimum touch target on touch devices */