@papernote/ui 1.7.2 → 1.7.4

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/dist/index.js CHANGED
@@ -4240,7 +4240,7 @@ function Stepper({ steps, activeStep, completedSteps = [], orientation = 'horizo
4240
4240
  `, children: steps.map((step, index) => renderStep(step, index)) }));
4241
4241
  }
4242
4242
 
4243
- function Calendar({ value, onChange, events = [], onEventClick, rangeMode = false, rangeValue, onRangeChange, minDate, maxDate, disabledDates = [], showWeekNumbers = false, firstDayOfWeek = 0, className = '', }) {
4243
+ function Calendar({ value, onChange, onMonthChange, events = [], onEventClick, rangeMode = false, rangeValue, onRangeChange, minDate, maxDate, disabledDates = [], showWeekNumbers = false, firstDayOfWeek = 0, className = '', }) {
4244
4244
  const [currentMonth, setCurrentMonth] = React.useState(value || new Date());
4245
4245
  const [hoverDate, setHoverDate] = React.useState(null);
4246
4246
  // Generate calendar grid for current month
@@ -4364,21 +4364,31 @@ function Calendar({ value, onChange, events = [], onEventClick, rangeMode = fals
4364
4364
  };
4365
4365
  // Navigate months
4366
4366
  const previousMonth = () => {
4367
- setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1));
4367
+ const newMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1);
4368
+ setCurrentMonth(newMonth);
4369
+ onMonthChange?.(newMonth);
4368
4370
  };
4369
4371
  const nextMonth = () => {
4370
- setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1));
4372
+ const newMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1);
4373
+ setCurrentMonth(newMonth);
4374
+ onMonthChange?.(newMonth);
4371
4375
  };
4372
4376
  // Navigate years
4373
4377
  const previousYear = () => {
4374
- setCurrentMonth(new Date(currentMonth.getFullYear() - 1, currentMonth.getMonth(), 1));
4378
+ const newMonth = new Date(currentMonth.getFullYear() - 1, currentMonth.getMonth(), 1);
4379
+ setCurrentMonth(newMonth);
4380
+ onMonthChange?.(newMonth);
4375
4381
  };
4376
4382
  const nextYear = () => {
4377
- setCurrentMonth(new Date(currentMonth.getFullYear() + 1, currentMonth.getMonth(), 1));
4383
+ const newMonth = new Date(currentMonth.getFullYear() + 1, currentMonth.getMonth(), 1);
4384
+ setCurrentMonth(newMonth);
4385
+ onMonthChange?.(newMonth);
4378
4386
  };
4379
4387
  // Go to today
4380
4388
  const goToToday = () => {
4381
- setCurrentMonth(new Date());
4389
+ const today = new Date();
4390
+ setCurrentMonth(today);
4391
+ onMonthChange?.(today);
4382
4392
  };
4383
4393
  // Day names
4384
4394
  const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
@@ -4391,7 +4401,7 @@ function Calendar({ value, onChange, events = [], onEventClick, rangeMode = fals
4391
4401
  error: 'bg-error-500',
4392
4402
  accent: 'bg-accent-500',
4393
4403
  };
4394
- return (jsxRuntime.jsxs("div", { className: `bg-white rounded-lg border border-paper-200 shadow-sm ${className}`, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 border-b border-paper-200", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsxs("button", { onClick: previousYear, className: "p-1.5 hover:bg-paper-100 rounded transition-colors", "aria-label": "Previous year", children: [jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4 text-ink-600" }), jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4 text-ink-600 -ml-3" })] }), jsxRuntime.jsx("button", { onClick: previousMonth, className: "p-1.5 hover:bg-paper-100 rounded transition-colors", "aria-label": "Previous month", children: jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4 text-ink-600" }) })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-ink-900", children: currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' }) }), jsxRuntime.jsx("button", { onClick: goToToday, className: "px-3 py-1 text-sm font-medium text-accent-700 hover:bg-accent-50 rounded transition-colors", children: "Today" })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("button", { onClick: nextMonth, className: "p-1.5 hover:bg-paper-100 rounded transition-colors", "aria-label": "Next month", children: jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-600" }) }), jsxRuntime.jsxs("button", { onClick: nextYear, className: "p-1.5 hover:bg-paper-100 rounded transition-colors", "aria-label": "Next year", children: [jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-600" }), jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-600 -ml-3" })] })] })] }), jsxRuntime.jsx("div", { className: "p-4", children: jsxRuntime.jsxs("div", { className: "grid grid-cols-7 gap-1", children: [showWeekNumbers && jsxRuntime.jsx("div", { className: "h-8" }), adjustedDayNames.map((day) => (jsxRuntime.jsx("div", { className: "h-8 flex items-center justify-center text-xs font-semibold text-ink-600", children: day }, day))), Array.from({ length: 6 }).map((_, weekIndex) => (jsxRuntime.jsxs(React.Fragment, { children: [showWeekNumbers && (jsxRuntime.jsx("div", { className: "flex items-center justify-center text-xs text-ink-500 font-medium", children: getWeekNumber(calendarDays[weekIndex * 7]) })), calendarDays.slice(weekIndex * 7, weekIndex * 7 + 7).map((date, dayIndex) => {
4404
+ return (jsxRuntime.jsxs("div", { className: `bg-white rounded-lg border border-paper-200 shadow-sm ${className}`, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 border-b border-paper-200", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("button", { onClick: previousYear, className: "p-1.5 hover:bg-paper-100 rounded transition-colors", "aria-label": "Previous year", children: jsxRuntime.jsx(lucideReact.ChevronsLeft, { className: "h-4 w-4 text-ink-600" }) }), jsxRuntime.jsx("button", { onClick: previousMonth, className: "p-1.5 hover:bg-paper-100 rounded transition-colors", "aria-label": "Previous month", children: jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4 text-ink-600" }) })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-ink-900", children: currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' }) }), jsxRuntime.jsx("button", { onClick: goToToday, className: "px-3 py-1 text-sm font-medium text-accent-700 hover:bg-accent-50 rounded transition-colors", children: "Today" })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("button", { onClick: nextMonth, className: "p-1.5 hover:bg-paper-100 rounded transition-colors", "aria-label": "Next month", children: jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-600" }) }), jsxRuntime.jsx("button", { onClick: nextYear, className: "p-1.5 hover:bg-paper-100 rounded transition-colors", "aria-label": "Next year", children: jsxRuntime.jsx(lucideReact.ChevronsRight, { className: "h-4 w-4 text-ink-600" }) })] })] }), jsxRuntime.jsx("div", { className: "p-4", children: jsxRuntime.jsxs("div", { className: "grid grid-cols-7 gap-1", children: [showWeekNumbers && jsxRuntime.jsx("div", { className: "h-8" }), adjustedDayNames.map((day) => (jsxRuntime.jsx("div", { className: "h-8 flex items-center justify-center text-xs font-semibold text-ink-600", children: day }, day))), Array.from({ length: 6 }).map((_, weekIndex) => (jsxRuntime.jsxs(React.Fragment, { children: [showWeekNumbers && (jsxRuntime.jsx("div", { className: "flex items-center justify-center text-xs text-ink-500 font-medium", children: getWeekNumber(calendarDays[weekIndex * 7]) })), calendarDays.slice(weekIndex * 7, weekIndex * 7 + 7).map((date, dayIndex) => {
4395
4405
  const dateEvents = getEventsForDate(date);
4396
4406
  const selected = isSelected(date);
4397
4407
  const inRange = isInRange(date);
@@ -5378,7 +5388,6 @@ function FormWizard({ steps, onComplete, onStepChange, showStepNumbers = true, a
5378
5388
  const [isSubmitting, setIsSubmitting] = React.useState(false);
5379
5389
  const isFirstStep = currentStep === 0;
5380
5390
  const isLastStep = currentStep === steps.length - 1;
5381
- const canGoNext = allowSkip || completedSteps.has(currentStep);
5382
5391
  // Go to specific step
5383
5392
  const goToStep = (stepIndex) => {
5384
5393
  if (stepIndex < 0 || stepIndex >= steps.length)
@@ -5450,7 +5459,7 @@ function FormWizard({ steps, onComplete, onStepChange, showStepNumbers = true, a
5450
5459
  ? 'bg-accent-500'
5451
5460
  : 'bg-paper-200'}
5452
5461
  ` }) }))] }, step.id));
5453
- }) }) }), jsxRuntime.jsx("div", { className: "mb-8", children: steps.map((step, index) => (jsxRuntime.jsx("div", { hidden: index !== currentStep, children: step.content }, step.id))) }), jsxRuntime.jsxs("div", { className: "flex items-center justify-between pt-6 border-t border-paper-200", children: [jsxRuntime.jsx("button", { type: "button", onClick: prevStep, disabled: isFirstStep, className: "px-4 py-2 text-sm font-medium text-ink-700 bg-white border border-paper-300 rounded-lg hover:bg-paper-50 disabled:opacity-40 disabled:cursor-not-allowed transition-all", children: "Previous" }), jsxRuntime.jsxs("div", { className: "text-sm text-ink-600", children: ["Step ", currentStep + 1, " of ", steps.length] }), jsxRuntime.jsx("button", { type: "button", onClick: nextStep, disabled: !allowSkip && !canGoNext && !isLastStep || isSubmitting, className: "px-4 py-2 text-sm font-medium text-white bg-accent-500 rounded-lg hover:bg-accent-600 disabled:opacity-40 disabled:cursor-not-allowed transition-all", children: isSubmitting ? 'Submitting...' : isLastStep ? 'Complete' : 'Next' })] })] }));
5462
+ }) }) }), jsxRuntime.jsx("div", { className: "mb-8", children: steps.map((step, index) => (jsxRuntime.jsx("div", { hidden: index !== currentStep, children: step.content }, step.id))) }), jsxRuntime.jsxs("div", { className: "flex items-center justify-between pt-6 border-t border-paper-200", children: [jsxRuntime.jsx("button", { type: "button", onClick: prevStep, disabled: isFirstStep, className: "px-4 py-2 text-sm font-medium text-ink-700 bg-white border border-paper-300 rounded-lg hover:bg-paper-50 disabled:opacity-40 disabled:cursor-not-allowed transition-all", children: "Previous" }), jsxRuntime.jsxs("div", { className: "text-sm text-ink-600", children: ["Step ", currentStep + 1, " of ", steps.length] }), jsxRuntime.jsx("button", { type: "button", onClick: nextStep, disabled: isSubmitting, className: "px-4 py-2 text-sm font-medium text-white bg-accent-500 rounded-lg hover:bg-accent-600 disabled:opacity-40 disabled:cursor-not-allowed transition-all", children: isSubmitting ? 'Submitting...' : isLastStep ? 'Complete' : 'Next' })] })] }));
5454
5463
  }
5455
5464
 
5456
5465
  function InfiniteScroll({ loadMore, hasMore, loading = false, children, threshold = 200, loader, scrollContainer, reverse = false, className = '', }) {
@@ -7283,6 +7292,9 @@ function Hide({ children, above, below, only, className = '' }) {
7283
7292
  * Hook to detect breadcrumb navigation and trigger callbacks.
7284
7293
  * Use this in host components to reset state when a breadcrumb is clicked.
7285
7294
  *
7295
+ * Note: This hook requires React Router context. If used outside a Router,
7296
+ * it will be a no-op (the callback will never be called).
7297
+ *
7286
7298
  * @param onReset - Callback fired when breadcrumb navigation is detected
7287
7299
  *
7288
7300
  * @example
@@ -7296,15 +7308,19 @@ function Hide({ children, above, below, only, className = '' }) {
7296
7308
  * }
7297
7309
  */
7298
7310
  function useBreadcrumbReset(onReset) {
7299
- const location = reactRouterDom.useLocation();
7311
+ const inRouter = reactRouterDom.useInRouterContext();
7300
7312
  const lastResetRef = React.useRef(null);
7313
+ // Only use useLocation when inside Router context
7314
+ const location = inRouter ? reactRouterDom.useLocation() : null;
7301
7315
  React.useEffect(() => {
7316
+ if (!location)
7317
+ return;
7302
7318
  const state = location.state;
7303
7319
  if (state?.breadcrumbReset && state.breadcrumbReset !== lastResetRef.current) {
7304
7320
  lastResetRef.current = state.breadcrumbReset;
7305
7321
  onReset();
7306
7322
  }
7307
- }, [location.state, onReset]);
7323
+ }, [location?.state, onReset, location]);
7308
7324
  }
7309
7325
  /**
7310
7326
  * Breadcrumbs navigation component.
@@ -7339,8 +7355,10 @@ function useBreadcrumbReset(onReset) {
7339
7355
  * }
7340
7356
  */
7341
7357
  function Breadcrumbs({ items, showHome = true }) {
7342
- const navigate = reactRouterDom.useNavigate();
7343
- const location = reactRouterDom.useLocation();
7358
+ const inRouter = reactRouterDom.useInRouterContext();
7359
+ // Only use router hooks when inside Router context
7360
+ const navigate = inRouter ? reactRouterDom.useNavigate() : null;
7361
+ const location = inRouter ? reactRouterDom.useLocation() : null;
7344
7362
  /**
7345
7363
  * Handle breadcrumb click with same-route detection.
7346
7364
  * When clicking a breadcrumb that points to the current route,
@@ -7349,6 +7367,9 @@ function Breadcrumbs({ items, showHome = true }) {
7349
7367
  const handleBreadcrumbClick = (e, href, onClick) => {
7350
7368
  // Always call onClick if provided (for custom actions)
7351
7369
  onClick?.();
7370
+ // If not in router context, let the browser handle navigation naturally
7371
+ if (!navigate || !location)
7372
+ return;
7352
7373
  // Check if we're navigating to the same base path
7353
7374
  const targetPath = href.split('?')[0].split('#')[0];
7354
7375
  const currentPath = location.pathname;
@@ -7365,7 +7386,16 @@ function Breadcrumbs({ items, showHome = true }) {
7365
7386
  }
7366
7387
  // Different route - let the Link handle it normally
7367
7388
  };
7368
- return (jsxRuntime.jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center space-x-2 text-sm", children: [showHome && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactRouterDom.Link, { to: "/", className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": "Home", onClick: (e) => handleBreadcrumbClick(e, '/'), children: jsxRuntime.jsx(lucideReact.Home, { className: "h-4 w-4" }) }), items.length > 0 && jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-400" })] })), items.map((item, index) => {
7389
+ // Helper to render a link - uses Link when in router, <a> when not
7390
+ const renderLink = (href, children, className, onClick, ariaLabel) => {
7391
+ if (inRouter) {
7392
+ return (jsxRuntime.jsx(reactRouterDom.Link, { to: href, className: className, onClick: onClick, "aria-label": ariaLabel, children: children }));
7393
+ }
7394
+ return (jsxRuntime.jsx("a", { href: href, className: className, onClick: (e) => {
7395
+ onClick?.(e);
7396
+ }, "aria-label": ariaLabel, children: children }));
7397
+ };
7398
+ return (jsxRuntime.jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center space-x-2 text-sm", children: [showHome && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderLink('/', jsxRuntime.jsx(lucideReact.Home, { className: "h-4 w-4" }), 'text-ink-500 hover:text-ink-900 transition-colors', (e) => handleBreadcrumbClick(e, '/'), 'Home'), items.length > 0 && jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-400" })] })), items.map((item, index) => {
7369
7399
  const isLast = index === items.length - 1;
7370
7400
  const isActive = isLast;
7371
7401
  const content = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [item.icon && jsxRuntime.jsx("span", { className: "flex-shrink-0", children: item.icon }), jsxRuntime.jsx("span", { children: item.label })] }));
@@ -7374,9 +7404,9 @@ function Breadcrumbs({ items, showHome = true }) {
7374
7404
  if (isActive) {
7375
7405
  return (jsxRuntime.jsx("span", { className: "flex items-center gap-2 px-2 py-1 rounded-md bg-accent-50 text-accent-900 font-semibold transition-colors", "aria-current": "page", children: content }));
7376
7406
  }
7377
- // Has href - render as Link with same-route detection
7407
+ // Has href - render as Link (or <a> if no router) with same-route detection
7378
7408
  if (item.href) {
7379
- return (jsxRuntime.jsx(reactRouterDom.Link, { to: item.href, onClick: (e) => handleBreadcrumbClick(e, item.href, item.onClick), className: "flex items-center gap-2 text-ink-500 hover:text-ink-900 hover:underline transition-colors", children: content }));
7409
+ return renderLink(item.href, content, 'flex items-center gap-2 text-ink-500 hover:text-ink-900 hover:underline transition-colors', (e) => handleBreadcrumbClick(e, item.href, item.onClick));
7380
7410
  }
7381
7411
  // Only onClick (no href) - render as button
7382
7412
  if (item.onClick) {