@pk-design/react-tailwind 1.13.0 → 1.13.1

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.
@@ -372,8 +372,10 @@ const panelAlignmentMap = {
372
372
  start: 'data-[closed]:-translate-x-1/2 rounded-r-2xl',
373
373
  end: 'data-[closed]:translate-x-1/2 rounded-l-2xl',
374
374
  top: 'data-[closed]:-translate-y-1/2 rounded-b-2xl',
375
- // Bottom sheets clear the home indicator on notched phones (0 elsewhere).
376
- bottom: 'data-[closed]:translate-y-full rounded-t-2xl md:rounded-t-3xl max-h-[88vh] max-h-[88dvh] pb-[env(safe-area-inset-bottom,0px)]',
375
+ // Bottom sheets clear the home indicator on notched phones (0 elsewhere). Never
376
+ // taller than the container: with the keyboard up it's shorter than 88dvh, and a
377
+ // bottom-anchored panel past its top is off screen and can't be scrolled to.
378
+ bottom: 'data-[closed]:translate-y-full rounded-t-2xl md:rounded-t-3xl max-h-[min(88dvh,100%)] pb-[env(safe-area-inset-bottom,0px)]',
377
379
  };
378
380
  const panelSizeMap = {
379
381
  xs: 'max-w-xs',
@@ -456,6 +458,31 @@ const Drawer = ({ isOpen, onClose = () => { }, closeOnOutsideClick = true, align
456
458
  : [panelAlignmentMap[align], panelSizeMap[size], panelClass])), "data-layout": fullscreen ? 'fullscreen' : undefined, children: [shouldShowDragHandle && (jsx("div", { className: "w-12 h-1.5 rounded-full bg-gray-300 dark:bg-gray-600 mx-auto my-2.5 shrink-0 cursor-grab", "data-testid": "drawer-drag-handle" })), fullscreen && (jsxs("div", { className: "sticky top-0 z-10 flex h-14 shrink-0 items-center gap-1 border-b border-[var(--ui-border)] bg-white pl-1 pr-3 pt-[env(safe-area-inset-top,0px)] box-content dark:bg-gray-800", children: [jsx(Button, { iconOnly: true, "aria-label": "Close", variant: "plain", theme: "secondary", onClick: onClose, className: "shrink-0", children: jsx(SvgX, { className: "size-5" }) }), title && (jsx(DialogTitle, { as: "h3", className: "min-w-0 flex-1 truncate text-base font-semibold text-gray-900 dark:text-white", children: title })), headerAction && jsx("div", { className: "ml-auto shrink-0", children: headerAction })] })), !fullscreen && showTitleSection && (jsxs("div", { className: buildClassName('space-y-1 py-3 px-4 md:px-6 flex flex-col border-b border-[var(--ui-border)] shrink-0', titleSticky && 'sticky top-0 bg-white dark:bg-gray-800 z-10'), children: [jsxs("div", { className: "flex items-center justify-between gap-3 min-w-0", children: [jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [showBackButton && (jsx(Button, { iconOnly: true, "aria-label": "Back", variant: "plain", theme: "secondary", size: "xs", onClick: onClose, children: jsx(SvgChevronLeft, { className: "size-4" }) })), title && (jsx(DialogTitle, { as: "h3", className: buildClassName('text-lg font-semibold text-gray-900 dark:text-white truncate tracking-tight min-w-0', titleClass), children: title }))] }), showCloseButton && (jsx(Button, { iconOnly: true, "aria-label": "Close drawer", variant: "plain", theme: "secondary", size: "xs", onClick: onClose, className: "rounded-full text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 shrink-0", children: jsx(SvgX, { className: "size-4" }) }))] }), description && (jsx("p", { className: buildClassName('text-sm text-gray-500 dark:text-gray-400 font-normal truncate', descriptionClass), children: description }))] })), jsxs("div", { className: buildClassName('flex-1 p-4 md:p-6 space-y-4 min-w-0', contentClass, fullscreen && 'pb-[calc(1rem+env(safe-area-inset-bottom,0px))]'), children: [fullscreen && description && (jsx("p", { className: buildClassName('text-sm text-gray-500 dark:text-gray-400', descriptionClass), children: description })), children] }), !fullscreen && footer && (jsx("div", { className: buildClassName('p-4 border-t border-[var(--ui-border-muted)] bg-white dark:bg-gray-800 shrink-0 min-w-0', footerSticky && 'sticky bottom-0 z-10'), children: footer }))] }) }) })] }));
457
459
  };
458
460
  Drawer.displayName = 'Drawer';
461
+ // history.back() lands later, so a drawer opening meanwhile (one replacing another,
462
+ // or React re-running effects under StrictMode) would have its new entry removed
463
+ // instead, and close at once. Removals are counted, and an opening drawer waits for them.
464
+ let pendingBacks = 0;
465
+ const afterBacks = [];
466
+ function settleBack() {
467
+ pendingBacks = Math.max(0, pendingBacks - 1);
468
+ if (pendingBacks === 0)
469
+ afterBacks.splice(0).forEach((run) => run());
470
+ }
471
+ function removeEntry() {
472
+ pendingBacks += 1;
473
+ let settled = false;
474
+ const settle = () => {
475
+ if (settled)
476
+ return;
477
+ settled = true;
478
+ window.removeEventListener('popstate', settle);
479
+ settleBack();
480
+ };
481
+ window.addEventListener('popstate', settle);
482
+ // A back that never reports (nothing to go back to) mustn't hold others up.
483
+ window.setTimeout(settle, 500);
484
+ window.history.back();
485
+ }
459
486
  /**
460
487
  * While `active`, the browser's back button (and Android's back gesture)
461
488
  * closes the drawer instead of leaving the page: opening adds a history entry
@@ -473,8 +500,7 @@ function useCloseOnBack(active, onClose) {
473
500
  if (!active || typeof window === 'undefined')
474
501
  return;
475
502
  const pushEntry = () => { var _a; return window.history.pushState({ ...((_a = window.history.state) !== null && _a !== void 0 ? _a : {}), drawer: token }, ''); };
476
- pushEntry();
477
- let entryPresent = true;
503
+ let entryPresent = false;
478
504
  let disposed = false;
479
505
  const handlePop = () => {
480
506
  var _a;
@@ -491,13 +517,23 @@ function useCloseOnBack(active, onClose) {
491
517
  entryPresent = true;
492
518
  }, 0);
493
519
  };
494
- window.addEventListener('popstate', handlePop);
520
+ const start = () => {
521
+ if (disposed)
522
+ return;
523
+ pushEntry();
524
+ entryPresent = true;
525
+ window.addEventListener('popstate', handlePop);
526
+ };
527
+ if (pendingBacks > 0)
528
+ afterBacks.push(start);
529
+ else
530
+ start();
495
531
  return () => {
496
532
  var _a;
497
533
  disposed = true;
498
534
  window.removeEventListener('popstate', handlePop);
499
535
  if (entryPresent && ((_a = window.history.state) === null || _a === void 0 ? void 0 : _a.drawer) === token)
500
- window.history.back();
536
+ removeEntry();
501
537
  };
502
538
  }, [active, token]);
503
539
  }
@@ -4339,7 +4375,7 @@ const SelectBox = forwardRef((props, forwardedRef) => {
4339
4375
  const isOptSelected = selectedValueSet.has(optVal);
4340
4376
  return (jsx(ComboboxOption, { disabled: option.disabled, value: option, className: "group rounded-lg py-1.5 px-3 select-none data-[focus]:bg-gray-100 dark:data-[focus]:bg-white/10 data-disabled:opacity-50 cursor-pointer data-disabled:pointer-events-none", children: renderOption ? (renderOption(option, Boolean(isOptSelected))) : (jsxs("div", { className: "flex items-center justify-between gap-2 text-gray-900 dark:text-white group-data-[selected]:text-blue-600", children: [jsx("span", { className: "text-sm/6", children: getDisplayValue(option) }), jsx(SvgCheck, { className: "invisible size-5 dark:stroke-gray-300 group-data-[selected]:visible" })] })) }, optVal));
4341
4377
  };
4342
- return (jsxs("div", { className: buildClassName('group space-y-2', hasError && 'has-error', containerClass), ref: containerRef, children: [label && (jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint && jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxs(Combobox, { multiple: multiple, immediate: immediate, name: name, value: normalizedSelected, onChange: comboboxOnChangeWrapper, onClose: () => setQuery(''), disabled: disabled, by: (a, b) => (a && b ? getValue(a) === getValue(b) : a === b), children: [multiple ? (jsxs("div", { className: buildClassName(baseInputClass, 'flex flex-wrap gap-2 peer relative', rightPaddingClass, hasLeftGroup ? (size === 'lg' ? 'ps-12' : size === 'sm' ? 'ps-8' : 'ps-10') : ''), ref: forwardedRef, children: [hasLeftGroup && (jsx("span", { className: buildClassName('absolute left-0 top-0 h-full flex items-center justify-center text-gray-400 dark:text-gray-500', currentSize.group), children: leftGroup })), isArray(normalizedSelected) &&
4378
+ return (jsxs("div", { className: buildClassName('group', hasError && 'has-error', containerClass), ref: containerRef, children: [label && (jsxs("div", { className: buildClassName('flex items-center justify-between mb-1.5', labelWrapperClass), children: [jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint && jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxs(Combobox, { multiple: multiple, immediate: immediate, name: name, value: normalizedSelected, onChange: comboboxOnChangeWrapper, onClose: () => setQuery(''), disabled: disabled, by: (a, b) => (a && b ? getValue(a) === getValue(b) : a === b), children: [multiple ? (jsxs("div", { className: buildClassName(baseInputClass, 'flex flex-wrap gap-2 peer relative', rightPaddingClass, hasLeftGroup ? (size === 'lg' ? 'ps-12' : size === 'sm' ? 'ps-8' : 'ps-10') : ''), ref: forwardedRef, children: [hasLeftGroup && (jsx("span", { className: buildClassName('absolute left-0 top-0 h-full flex items-center justify-center text-gray-400 dark:text-gray-500', currentSize.group), children: leftGroup })), isArray(normalizedSelected) &&
4343
4379
  (normalizedSelected === null || normalizedSelected === void 0 ? void 0 : normalizedSelected.length) > 0 &&
4344
4380
  normalizedSelected.map((option, idx) => (jsx(Badge, { theme: "secondary", size: currentSize.badgeSize, removable: !disabled, onRemove: () => removeSelection(idx), children: getDisplayValue(option) }, `${getValue(option)}-${idx}`))), jsx(ComboboxInput, { className: "outline-none flex-1 dark:placeholder-gray-400 placeholder-gray-400 bg-transparent", "aria-label": name, value: query, autoComplete: "off", placeholder: (normalizedSelected === null || normalizedSelected === void 0 ? void 0 : normalizedSelected.length) ? '' : placeholder, onChange: (e) => {
4345
4381
  const val = e.target.value;
@@ -4470,7 +4506,7 @@ const QuantityStepper = forwardRef((props, ref) => {
4470
4506
  };
4471
4507
  const isAtMin = disabled || value <= min;
4472
4508
  const isAtMax = disabled || value >= max;
4473
- return (jsxs("div", { className: buildClassName('flex flex-col gap-1 inline-flex', className), children: [label && (jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsx(Label, { htmlFor: stepperId, className: disabled ? 'opacity-70 cursor-not-allowed' : '', children: label }), labelHint && jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxs("div", { className: buildClassName('inline-flex items-center rounded-lg shadow-2xs transition-all duration-150', 'outline outline-1 -outline-offset-1', CONTAINER_SIZE_CLASS[size], hasError
4509
+ return (jsxs("div", { className: buildClassName('flex flex-col gap-1.5 inline-flex', className), children: [label && (jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsx(Label, { htmlFor: stepperId, className: disabled ? 'opacity-70 cursor-not-allowed' : '', children: label }), labelHint && jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxs("div", { className: buildClassName('inline-flex items-center rounded-lg shadow-2xs transition-all duration-150', 'outline outline-1 -outline-offset-1', CONTAINER_SIZE_CLASS[size], hasError
4474
4510
  ? '!outline-red-500 !ring-1 !ring-red-500/50 dark:!outline-red-500'
4475
4511
  : 'outline-[var(--ui-border)]', disabled
4476
4512
  ? 'pointer-events-none bg-gray-100 dark:bg-gray-800 outline-[var(--ui-border-muted)]'