@pk-design/react-tailwind 1.13.0 → 1.13.2
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/cjs/components/Button/Button.js +34 -14
- package/dist/cjs/components/Button/Button.js.map +1 -1
- package/dist/cjs/components/Drawer/Drawer.js +42 -6
- package/dist/cjs/components/Drawer/Drawer.js.map +1 -1
- package/dist/cjs/components/QuantityStepper/QuantityStepper.js +1 -1
- package/dist/cjs/components/QuantityStepper/QuantityStepper.js.map +1 -1
- package/dist/cjs/components/SelectBox/SelectBox.js +1 -1
- package/dist/cjs/components/SelectBox/SelectBox.js.map +1 -1
- package/dist/es/components/Button/Button.js +34 -14
- package/dist/es/components/Button/Button.js.map +1 -1
- package/dist/es/components/Drawer/Drawer.js +42 -6
- package/dist/es/components/Drawer/Drawer.js.map +1 -1
- package/dist/es/components/QuantityStepper/QuantityStepper.js +1 -1
- package/dist/es/components/QuantityStepper/QuantityStepper.js.map +1 -1
- package/dist/es/components/SelectBox/SelectBox.js +1 -1
- package/dist/es/components/SelectBox/SelectBox.js.map +1 -1
- package/dist/react-tailwind.cjs.js +78 -22
- package/dist/react-tailwind.cjs.js.map +1 -1
- package/dist/react-tailwind.es.js +78 -22
- package/dist/react-tailwind.es.js.map +1 -1
- package/package.json +1 -1
|
@@ -167,27 +167,36 @@ const THEMED_BTN_CLASS = {
|
|
|
167
167
|
plain: 'text-[var(--ui-danger-text)] hover:bg-current/10 active:bg-current/15 focus-visible:outline-[var(--ui-danger-ring)]',
|
|
168
168
|
},
|
|
169
169
|
secondary: {
|
|
170
|
-
default: 'text-gray-
|
|
171
|
-
outlined: 'text-gray-
|
|
170
|
+
default: 'text-gray-800 bg-gray-200 hover:bg-gray-300 active:bg-gray-300 dark:text-white dark:bg-gray-700 dark:hover:bg-gray-600 dark:active:bg-gray-600 focus-visible:outline-[var(--ui-focus-ring)]',
|
|
171
|
+
outlined: 'text-gray-800 bg-white border border-gray-300 shadow-xs hover:bg-gray-100 active:bg-gray-200 dark:text-gray-100 dark:bg-transparent dark:border-gray-600 dark:shadow-none dark:hover:bg-white/10 dark:active:bg-white/15 focus-visible:outline-[var(--ui-focus-ring)]',
|
|
172
172
|
plain: 'text-gray-700 hover:bg-current/10 active:bg-current/15 dark:text-gray-200 focus-visible:outline-[var(--ui-focus-ring)]',
|
|
173
173
|
},
|
|
174
174
|
success: {
|
|
175
|
-
default: 'text-white bg-emerald-
|
|
176
|
-
outlined: 'text-emerald-700 hover:text-white border border-emerald-
|
|
175
|
+
default: 'text-white bg-emerald-700 hover:bg-emerald-800 focus-visible:outline-emerald-500',
|
|
176
|
+
outlined: 'text-emerald-700 hover:text-white border border-emerald-700 hover:bg-emerald-700 dark:text-emerald-400 dark:border-emerald-500 focus-visible:outline-emerald-500',
|
|
177
177
|
plain: 'text-emerald-700 hover:bg-current/10 active:bg-current/15 dark:text-emerald-400 focus-visible:outline-emerald-500',
|
|
178
178
|
},
|
|
179
179
|
warning: {
|
|
180
|
-
default: 'text-
|
|
181
|
-
outlined: 'text-amber-700 hover:text-
|
|
180
|
+
default: 'text-gray-900 bg-amber-500 hover:bg-amber-400 focus-visible:outline-amber-500',
|
|
181
|
+
outlined: 'text-amber-700 hover:text-gray-900 border border-amber-500 hover:bg-amber-500 dark:text-amber-400 dark:border-amber-500 focus-visible:outline-amber-500',
|
|
182
182
|
plain: 'text-amber-700 hover:bg-current/10 active:bg-current/15 dark:text-amber-400 focus-visible:outline-amber-500',
|
|
183
183
|
},
|
|
184
184
|
};
|
|
185
185
|
const SIZE_CLASSES = {
|
|
186
|
-
xs: {
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
xs: {
|
|
187
|
+
normal: 'min-h-7 px-2.5 py-1 rounded-sm gap-1 text-xs',
|
|
188
|
+
iconOnly: 'h-7 w-7 p-1 rounded-sm text-xs',
|
|
189
|
+
},
|
|
190
|
+
sm: {
|
|
191
|
+
normal: 'min-h-8 px-3 py-1 rounded gap-1.5 text-sm',
|
|
192
|
+
iconOnly: 'h-8 w-8 p-1.5 rounded text-sm',
|
|
193
|
+
},
|
|
194
|
+
md: {
|
|
195
|
+
normal: 'min-h-9 px-4 py-1.5 rounded-md gap-2 text-sm',
|
|
196
|
+
iconOnly: 'h-9 w-9 p-2 rounded-md text-sm',
|
|
197
|
+
},
|
|
189
198
|
lg: {
|
|
190
|
-
normal: 'h-10 px-5 rounded-lg gap-2 text-base',
|
|
199
|
+
normal: 'min-h-10 px-5 py-2 rounded-lg gap-2 text-base',
|
|
191
200
|
iconOnly: 'h-10 w-10 p-2.5 rounded-lg text-base',
|
|
192
201
|
},
|
|
193
202
|
};
|
|
@@ -202,12 +211,18 @@ const LOADER_SIZE = {
|
|
|
202
211
|
*
|
|
203
212
|
* Disabled styling is keyed off both the native `disabled` attribute and
|
|
204
213
|
* `aria-disabled`, so non-button elements rendered via `as` look disabled too.
|
|
214
|
+
*
|
|
215
|
+
* On touch screens an invisible layer makes the tappable area at least 44px,
|
|
216
|
+
* whatever the button's size, without changing how it looks.
|
|
205
217
|
*/
|
|
206
|
-
const BASE_BTN_CLASS = 'font-medium inline-flex items-center justify-center shrink-0 cursor-pointer select-none ' +
|
|
218
|
+
const BASE_BTN_CLASS = 'relative font-medium inline-flex items-center justify-center text-center shrink-0 cursor-pointer select-none ' +
|
|
207
219
|
'transition-[color,background-color,border-color,box-shadow,opacity,transform] duration-150 ease-out ' +
|
|
208
220
|
'active:scale-[0.98] focus:outline-none ' +
|
|
209
221
|
'disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none ' +
|
|
210
|
-
'aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:shadow-none'
|
|
222
|
+
'aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:shadow-none ' +
|
|
223
|
+
'pointer-coarse:after:absolute pointer-coarse:after:top-1/2 pointer-coarse:after:left-1/2 ' +
|
|
224
|
+
'pointer-coarse:after:-translate-x-1/2 pointer-coarse:after:-translate-y-1/2 ' +
|
|
225
|
+
'pointer-coarse:after:w-full pointer-coarse:after:min-w-11 pointer-coarse:after:h-full pointer-coarse:after:min-h-11';
|
|
211
226
|
const Button = React.forwardRef(({ as, type, ...props }, ref) => {
|
|
212
227
|
const { className = '', children, theme = 'primary', variant = 'default', size = 'md', leftIcon, rightIcon, fullWidth = false, loading = false, loadingText = '', rounded = false, disabled, iconOnly = false, noOutlineOnFocus = false, active, onClick, ...restProps } = props;
|
|
213
228
|
const Component = as || 'button';
|
|
@@ -259,7 +274,10 @@ const Button = React.forwardRef(({ as, type, ...props }, ref) => {
|
|
|
259
274
|
const elementProps = isNativeButton
|
|
260
275
|
? {
|
|
261
276
|
type: type !== null && type !== void 0 ? type : 'button',
|
|
262
|
-
disabled:
|
|
277
|
+
// Not `disabled` while loading: that would drop keyboard focus from the
|
|
278
|
+
// button just pressed. handleClick ignores presses until it's done.
|
|
279
|
+
disabled: Boolean(disabled),
|
|
280
|
+
'aria-disabled': loading && !disabled ? true : undefined,
|
|
263
281
|
role,
|
|
264
282
|
tabIndex,
|
|
265
283
|
onClick: handleClick,
|
|
@@ -289,7 +307,9 @@ const Button = React.forwardRef(({ as, type, ...props }, ref) => {
|
|
|
289
307
|
return buildClassName(BASE_BTN_CLASS, ((_a = THEMED_BTN_CLASS[theme]) === null || _a === void 0 ? void 0 : _a[variant]) || THEMED_BTN_CLASS.primary.default, iconOnly ? sizeObj.iconOnly : sizeObj.normal,
|
|
290
308
|
// An outline (not a ring) so the offset gap stays transparent on any surface/mode.
|
|
291
309
|
!noOutlineOnFocus &&
|
|
292
|
-
'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid', rounded && 'rounded-full', fullWidth && 'w-full',
|
|
310
|
+
'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid', rounded && 'rounded-full', fullWidth && 'w-full',
|
|
311
|
+
// Secondary default is a flat grey fill; a shadow would bring back the outlined look.
|
|
312
|
+
variant === 'default' && theme !== 'secondary' && 'shadow-xs hover:shadow-none', active && 'ring-2 ring-current', className);
|
|
293
313
|
}, [theme, variant, sizeObj, iconOnly, noOutlineOnFocus, rounded, fullWidth, active, className]);
|
|
294
314
|
// The spinner and loading text inherit the button's text colour.
|
|
295
315
|
const loaderIcon = (jsxRuntime.jsx(Loader, { "data-testid": "btn-loader-icon", size: LOADER_SIZE[size] || 'xs', className: "text-current" }));
|
|
@@ -392,8 +412,10 @@ const panelAlignmentMap = {
|
|
|
392
412
|
start: 'data-[closed]:-translate-x-1/2 rounded-r-2xl',
|
|
393
413
|
end: 'data-[closed]:translate-x-1/2 rounded-l-2xl',
|
|
394
414
|
top: 'data-[closed]:-translate-y-1/2 rounded-b-2xl',
|
|
395
|
-
// Bottom sheets clear the home indicator on notched phones (0 elsewhere).
|
|
396
|
-
|
|
415
|
+
// Bottom sheets clear the home indicator on notched phones (0 elsewhere). Never
|
|
416
|
+
// taller than the container: with the keyboard up it's shorter than 88dvh, and a
|
|
417
|
+
// bottom-anchored panel past its top is off screen and can't be scrolled to.
|
|
418
|
+
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)]',
|
|
397
419
|
};
|
|
398
420
|
const panelSizeMap = {
|
|
399
421
|
xs: 'max-w-xs',
|
|
@@ -476,6 +498,31 @@ const Drawer = ({ isOpen, onClose = () => { }, closeOnOutsideClick = true, align
|
|
|
476
498
|
: [panelAlignmentMap[align], panelSizeMap[size], panelClass])), "data-layout": fullscreen ? 'fullscreen' : undefined, children: [shouldShowDragHandle && (jsxRuntime.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 && (jsxRuntime.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: [jsxRuntime.jsx(Button, { iconOnly: true, "aria-label": "Close", variant: "plain", theme: "secondary", onClick: onClose, className: "shrink-0", children: jsxRuntime.jsx(SvgX, { className: "size-5" }) }), title && (jsxRuntime.jsx(react.DialogTitle, { as: "h3", className: "min-w-0 flex-1 truncate text-base font-semibold text-gray-900 dark:text-white", children: title })), headerAction && jsxRuntime.jsx("div", { className: "ml-auto shrink-0", children: headerAction })] })), !fullscreen && showTitleSection && (jsxRuntime.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: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 min-w-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [showBackButton && (jsxRuntime.jsx(Button, { iconOnly: true, "aria-label": "Back", variant: "plain", theme: "secondary", size: "xs", onClick: onClose, children: jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" }) })), title && (jsxRuntime.jsx(react.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 && (jsxRuntime.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: jsxRuntime.jsx(SvgX, { className: "size-4" }) }))] }), description && (jsxRuntime.jsx("p", { className: buildClassName('text-sm text-gray-500 dark:text-gray-400 font-normal truncate', descriptionClass), children: description }))] })), jsxRuntime.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 && (jsxRuntime.jsx("p", { className: buildClassName('text-sm text-gray-500 dark:text-gray-400', descriptionClass), children: description })), children] }), !fullscreen && footer && (jsxRuntime.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 }))] }) }) })] }));
|
|
477
499
|
};
|
|
478
500
|
Drawer.displayName = 'Drawer';
|
|
501
|
+
// history.back() lands later, so a drawer opening meanwhile (one replacing another,
|
|
502
|
+
// or React re-running effects under StrictMode) would have its new entry removed
|
|
503
|
+
// instead, and close at once. Removals are counted, and an opening drawer waits for them.
|
|
504
|
+
let pendingBacks = 0;
|
|
505
|
+
const afterBacks = [];
|
|
506
|
+
function settleBack() {
|
|
507
|
+
pendingBacks = Math.max(0, pendingBacks - 1);
|
|
508
|
+
if (pendingBacks === 0)
|
|
509
|
+
afterBacks.splice(0).forEach((run) => run());
|
|
510
|
+
}
|
|
511
|
+
function removeEntry() {
|
|
512
|
+
pendingBacks += 1;
|
|
513
|
+
let settled = false;
|
|
514
|
+
const settle = () => {
|
|
515
|
+
if (settled)
|
|
516
|
+
return;
|
|
517
|
+
settled = true;
|
|
518
|
+
window.removeEventListener('popstate', settle);
|
|
519
|
+
settleBack();
|
|
520
|
+
};
|
|
521
|
+
window.addEventListener('popstate', settle);
|
|
522
|
+
// A back that never reports (nothing to go back to) mustn't hold others up.
|
|
523
|
+
window.setTimeout(settle, 500);
|
|
524
|
+
window.history.back();
|
|
525
|
+
}
|
|
479
526
|
/**
|
|
480
527
|
* While `active`, the browser's back button (and Android's back gesture)
|
|
481
528
|
* closes the drawer instead of leaving the page: opening adds a history entry
|
|
@@ -493,8 +540,7 @@ function useCloseOnBack(active, onClose) {
|
|
|
493
540
|
if (!active || typeof window === 'undefined')
|
|
494
541
|
return;
|
|
495
542
|
const pushEntry = () => { var _a; return window.history.pushState({ ...((_a = window.history.state) !== null && _a !== void 0 ? _a : {}), drawer: token }, ''); };
|
|
496
|
-
|
|
497
|
-
let entryPresent = true;
|
|
543
|
+
let entryPresent = false;
|
|
498
544
|
let disposed = false;
|
|
499
545
|
const handlePop = () => {
|
|
500
546
|
var _a;
|
|
@@ -511,13 +557,23 @@ function useCloseOnBack(active, onClose) {
|
|
|
511
557
|
entryPresent = true;
|
|
512
558
|
}, 0);
|
|
513
559
|
};
|
|
514
|
-
|
|
560
|
+
const start = () => {
|
|
561
|
+
if (disposed)
|
|
562
|
+
return;
|
|
563
|
+
pushEntry();
|
|
564
|
+
entryPresent = true;
|
|
565
|
+
window.addEventListener('popstate', handlePop);
|
|
566
|
+
};
|
|
567
|
+
if (pendingBacks > 0)
|
|
568
|
+
afterBacks.push(start);
|
|
569
|
+
else
|
|
570
|
+
start();
|
|
515
571
|
return () => {
|
|
516
572
|
var _a;
|
|
517
573
|
disposed = true;
|
|
518
574
|
window.removeEventListener('popstate', handlePop);
|
|
519
575
|
if (entryPresent && ((_a = window.history.state) === null || _a === void 0 ? void 0 : _a.drawer) === token)
|
|
520
|
-
|
|
576
|
+
removeEntry();
|
|
521
577
|
};
|
|
522
578
|
}, [active, token]);
|
|
523
579
|
}
|
|
@@ -4359,7 +4415,7 @@ const SelectBox = React.forwardRef((props, forwardedRef) => {
|
|
|
4359
4415
|
const isOptSelected = selectedValueSet.has(optVal);
|
|
4360
4416
|
return (jsxRuntime.jsx(react.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))) : (jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 text-gray-900 dark:text-white group-data-[selected]:text-blue-600", children: [jsxRuntime.jsx("span", { className: "text-sm/6", children: getDisplayValue(option) }), jsxRuntime.jsx(SvgCheck, { className: "invisible size-5 dark:stroke-gray-300 group-data-[selected]:visible" })] })) }, optVal));
|
|
4361
4417
|
};
|
|
4362
|
-
return (jsxRuntime.jsxs("div", { className: buildClassName('group
|
|
4418
|
+
return (jsxRuntime.jsxs("div", { className: buildClassName('group', hasError && 'has-error', containerClass), ref: containerRef, children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-1.5', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint && jsxRuntime.jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxRuntime.jsxs(react.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 ? (jsxRuntime.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 && (jsxRuntime.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) &&
|
|
4363
4419
|
(normalizedSelected === null || normalizedSelected === void 0 ? void 0 : normalizedSelected.length) > 0 &&
|
|
4364
4420
|
normalizedSelected.map((option, idx) => (jsxRuntime.jsx(Badge, { theme: "secondary", size: currentSize.badgeSize, removable: !disabled, onRemove: () => removeSelection(idx), children: getDisplayValue(option) }, `${getValue(option)}-${idx}`))), jsxRuntime.jsx(react.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) => {
|
|
4365
4421
|
const val = e.target.value;
|
|
@@ -4490,7 +4546,7 @@ const QuantityStepper = React.forwardRef((props, ref) => {
|
|
|
4490
4546
|
};
|
|
4491
4547
|
const isAtMin = disabled || value <= min;
|
|
4492
4548
|
const isAtMax = disabled || value >= max;
|
|
4493
|
-
return (jsxRuntime.jsxs("div", { className: buildClassName('flex flex-col gap-1 inline-flex', className), children: [label && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsxRuntime.jsx(Label, { htmlFor: stepperId, className: disabled ? 'opacity-70 cursor-not-allowed' : '', children: label }), labelHint && jsxRuntime.jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxRuntime.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
|
|
4549
|
+
return (jsxRuntime.jsxs("div", { className: buildClassName('flex flex-col gap-1.5 inline-flex', className), children: [label && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsxRuntime.jsx(Label, { htmlFor: stepperId, className: disabled ? 'opacity-70 cursor-not-allowed' : '', children: label }), labelHint && jsxRuntime.jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxRuntime.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
|
|
4494
4550
|
? '!outline-red-500 !ring-1 !ring-red-500/50 dark:!outline-red-500'
|
|
4495
4551
|
: 'outline-[var(--ui-border)]', disabled
|
|
4496
4552
|
? 'pointer-events-none bg-gray-100 dark:bg-gray-800 outline-[var(--ui-border-muted)]'
|