@pk-design/react-tailwind 1.4.2 → 1.4.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.
|
@@ -122,8 +122,8 @@ const loaderSizeMap = {
|
|
|
122
122
|
md: 'size-8',
|
|
123
123
|
lg: 'size-10',
|
|
124
124
|
};
|
|
125
|
-
const Loader = ({ className = '
|
|
126
|
-
return (jsx("svg", { className: buildClassName(loaderSizeMap[size], className, 'spinner'), viewBox: "0 0 50 50", ...props, children: jsx("circle", { className: "path", cx: "25", cy: "25", r: "20", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "5" }) }));
|
|
125
|
+
const Loader = ({ className = '', size = 'md', ...props }) => {
|
|
126
|
+
return (jsx("svg", { className: buildClassName('text-blue-600 dark:text-white', loaderSizeMap[size], className, 'spinner'), viewBox: "0 0 50 50", ...props, children: jsx("circle", { className: "path", cx: "25", cy: "25", r: "20", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "5" }) }));
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
const TextContent = forwardRef((props, ref) => {
|
|
@@ -156,6 +156,23 @@ const THEMED_BTN_CLASS = {
|
|
|
156
156
|
plain: 'text-gray-700 hover:bg-black/5 dark:text-gray-200 dark:hover:bg-gray-700 focus:outline-[var(--ui-focus-ring)] disabled:text-gray-400',
|
|
157
157
|
},
|
|
158
158
|
};
|
|
159
|
+
const LOADER_TEXT_CLASS = {
|
|
160
|
+
primary: {
|
|
161
|
+
default: 'text-white',
|
|
162
|
+
outlined: 'text-[var(--ui-primary-text)]',
|
|
163
|
+
plain: 'text-[var(--ui-primary-text)]',
|
|
164
|
+
},
|
|
165
|
+
danger: {
|
|
166
|
+
default: 'text-white',
|
|
167
|
+
outlined: 'text-[var(--ui-danger-text)]',
|
|
168
|
+
plain: 'text-[var(--ui-danger-text)]',
|
|
169
|
+
},
|
|
170
|
+
secondary: {
|
|
171
|
+
default: 'text-gray-700 dark:text-white',
|
|
172
|
+
outlined: 'text-gray-700 dark:text-gray-200',
|
|
173
|
+
plain: 'text-gray-700 dark:text-gray-200',
|
|
174
|
+
},
|
|
175
|
+
};
|
|
159
176
|
/**
|
|
160
177
|
* Generate size classes.
|
|
161
178
|
*/
|
|
@@ -205,7 +222,7 @@ const Button = forwardRef(({ as, type, ...props }, ref) => {
|
|
|
205
222
|
if (loading && iconOnly) {
|
|
206
223
|
return (jsx(Component, { ref: ref, className: classes, ...buttonSpecificProps, ...cleanRest, children: jsx(Loader, { "data-testid": "btn-loader-icon", size: "xs" }) }));
|
|
207
224
|
}
|
|
208
|
-
return (jsx(Component, { ref: ref, className: classes, ...buttonSpecificProps, ...cleanRest, children: loading ? (jsxs("span", { className: "flex items-center gap-2", "aria-live": "polite", children: [jsx(Loader, { "data-testid": "btn-loader-icon", size: "xs" }), loadingText && jsx(TextContent, { children: loadingText })] })) : (children) }));
|
|
225
|
+
return (jsx(Component, { ref: ref, className: classes, ...buttonSpecificProps, ...cleanRest, children: loading ? (jsxs("span", { className: "flex items-center gap-2", "aria-live": "polite", children: [jsx(Loader, { "data-testid": "btn-loader-icon", size: "xs", className: buildClassName(LOADER_TEXT_CLASS[theme][variant]) }), loadingText && (jsx(TextContent, { className: buildClassName(LOADER_TEXT_CLASS[theme][variant]), children: loadingText }))] })) : (children) }));
|
|
209
226
|
});
|
|
210
227
|
Button.displayName = 'Button';
|
|
211
228
|
|
|
@@ -785,11 +802,11 @@ function DataTable({ items, columns, sorting = {}, onSort, loading, pagination,
|
|
|
785
802
|
}
|
|
786
803
|
DataTable.displayName = 'DataTable';
|
|
787
804
|
|
|
788
|
-
const Title = ({ children, className }) => (jsx("h1", { className: buildClassName('text-3xl font-bold', className), children: children }));
|
|
789
|
-
const SubTitle = ({ children, className }) => (jsx("h2", { className: buildClassName('text-2xl font-semibold', className), children: children }));
|
|
790
|
-
const SubTitle2 = ({ children, className }) => (jsx("h3", { className: buildClassName('text-xl font-semibold', className), children: children }));
|
|
791
|
-
const SubTitle3 = ({ children, className }) => (jsx("h4", { className: buildClassName('text-lg font-medium', className), children: children }));
|
|
792
|
-
const SubTitle4 = ({ children, className }) => (jsx("h5", { className: buildClassName('text-base font-medium', className), children: children }));
|
|
805
|
+
const Title = ({ children, className }) => (jsx("h1", { className: buildClassName('text-3xl font-bold text-gray-900 dark:text-white', className), children: children }));
|
|
806
|
+
const SubTitle = ({ children, className }) => (jsx("h2", { className: buildClassName('text-2xl font-semibold text-gray-900 dark:text-white', className), children: children }));
|
|
807
|
+
const SubTitle2 = ({ children, className }) => (jsx("h3", { className: buildClassName('text-xl font-semibold text-gray-900 dark:text-white', className), children: children }));
|
|
808
|
+
const SubTitle3 = ({ children, className }) => (jsx("h4", { className: buildClassName('text-lg font-medium text-gray-900 dark:text-white', className), children: children }));
|
|
809
|
+
const SubTitle4 = ({ children, className }) => (jsx("h5", { className: buildClassName('text-base font-medium text-gray-900 dark:text-white', className), children: children }));
|
|
793
810
|
const HeadingText = {
|
|
794
811
|
Title,
|
|
795
812
|
SubTitle,
|
|
@@ -1185,7 +1202,7 @@ var SvgCirclePlus = function SvgCirclePlus(props) {
|
|
|
1185
1202
|
|
|
1186
1203
|
const constructInputClass = (disabled) => buildInputClass('', { disabled });
|
|
1187
1204
|
const SelectBox = forwardRef((props, forwardedRef) => {
|
|
1188
|
-
const { labelKey = 'label', valueKey = 'value', name, id = name, options, selected, label = null, labelWrapperClass = '', labelClass = '', labelHint = null, disabled = false, containerClass = '', onChange = () => { }, placeholder, dropdownContainerClass = 'z-20', multiple = false, maxSelection, immediate = true, showErrorMessage = true, error = null, async = false, searchable = true, required = false, allowAdd = false, addNewText = 'Create', onAdd = () => { }, allowClear = false, } = props;
|
|
1205
|
+
const { labelKey = 'label', valueKey = 'value', name, id = name, options, selected, label = null, labelWrapperClass = '', labelClass = '', labelHint = null, disabled = false, containerClass = '', onChange = () => { }, placeholder, dropdownContainerClass = 'z-20', multiple = false, maxSelection, immediate = true, showErrorMessage = true, error = null, async = false, searchable = true, required = false, allowAdd = false, addNewText = 'Create', onAdd = () => { }, allowClear = false, modalDropdown = false, } = props;
|
|
1189
1206
|
const hasError = Boolean(error);
|
|
1190
1207
|
const [query, setQuery] = useState('');
|
|
1191
1208
|
const debouncedQuery = useDebounce(query, 500);
|
|
@@ -1280,11 +1297,18 @@ const SelectBox = forwardRef((props, forwardedRef) => {
|
|
|
1280
1297
|
console.error('onAdd handler error', err);
|
|
1281
1298
|
}
|
|
1282
1299
|
}, [onAdd, handleOnChangeInternal]);
|
|
1300
|
+
// Kept in a ref so `handleSearch` stays referentially stable even when the
|
|
1301
|
+
// caller passes a non-memoized `onSearch` — otherwise the effect below would
|
|
1302
|
+
// re-fire (and re-search) on every render instead of only on query changes.
|
|
1303
|
+
const onSearchRef = useRef(props.onSearch);
|
|
1304
|
+
useEffect(() => {
|
|
1305
|
+
onSearchRef.current = props.onSearch;
|
|
1306
|
+
}, [props.onSearch]);
|
|
1283
1307
|
const handleSearch = useCallback(async (searchString) => {
|
|
1284
1308
|
var _a;
|
|
1285
1309
|
try {
|
|
1286
1310
|
setOptionsLoading(true);
|
|
1287
|
-
await ((_a =
|
|
1311
|
+
await ((_a = onSearchRef.current) === null || _a === void 0 ? void 0 : _a.call(onSearchRef, searchString));
|
|
1288
1312
|
}
|
|
1289
1313
|
catch (err) {
|
|
1290
1314
|
console.error('Error loading options:', err);
|
|
@@ -1292,7 +1316,7 @@ const SelectBox = forwardRef((props, forwardedRef) => {
|
|
|
1292
1316
|
finally {
|
|
1293
1317
|
setOptionsLoading(false);
|
|
1294
1318
|
}
|
|
1295
|
-
}, [
|
|
1319
|
+
}, []);
|
|
1296
1320
|
useEffect(() => {
|
|
1297
1321
|
if (async && debouncedQuery)
|
|
1298
1322
|
handleSearch(debouncedQuery);
|
|
@@ -1305,7 +1329,7 @@ const SelectBox = forwardRef((props, forwardedRef) => {
|
|
|
1305
1329
|
removeSelection(selected.length - 1);
|
|
1306
1330
|
}
|
|
1307
1331
|
}
|
|
1308
|
-
}, "data-testid": "combobox-input" }), jsx(ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5", "data-testid": "combobox-button", children: jsx(SvgChevronDown, { className: chevronIconClass }) })] })) : (jsxs("div", { className: "relative", ref: forwardedRef, children: [jsx(ComboboxInput, { "aria-label": name, displayValue: (option) => (option ? getDisplayValue(option) : null), autoComplete: "off", placeholder: placeholder, onChange: (event) => setQuery(event.target.value), className: inputClass, disabled: disabled, id: id, readOnly: !searchable, ref: inputRef, "data-testid": "combobox-input" }), allowClear && !isEmpty(selected) && (jsx(Button, { size: "xs", iconOnly: true, "aria-label": "Clear selection", theme: "secondary", variant: "plain", className: "group absolute inset-y-0 right-8 h-6 top-2", onClick: () => handleOnChangeInternal(multiple ? [] : null), disabled: disabled, "data-testid": "combobox-clear-button", noOutlineOnFocus: true, children: jsx(SvgX, { className: "size-4 stroke-gray-500" }) })), jsx(ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5", "data-testid": "combobox-button", children: jsx(SvgChevronDown, { className: chevronIconClass }) })] })), jsx(ComboboxOptions, { anchor: { to: 'bottom', gap: 5 }, as: "div", className: buildClassName('w-[var(--input-width)] rounded-lg border border-gray-200 dark:border-white/5 bg-white dark:bg-gray-800 p-1 [--anchor-gap:var(--spacing-1)]', '[--anchor-max-height:20rem]', 'origin-top border transition duration-200 ease-[cubic-bezier(0.4, 0.0, 0.2, 1)] data-[closed]:translate-y-[-15%] data-[closed]:opacity-0', dropdownContainerClass), transition: true, "data-testid": "combobox-options", children: optionsLoading ? (jsx(
|
|
1332
|
+
}, "data-testid": "combobox-input" }), jsx(ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5", "data-testid": "combobox-button", children: jsx(SvgChevronDown, { className: chevronIconClass }) })] })) : (jsxs("div", { className: "relative", ref: forwardedRef, children: [jsx(ComboboxInput, { "aria-label": name, displayValue: (option) => (option ? getDisplayValue(option) : null), autoComplete: "off", placeholder: placeholder, onChange: (event) => setQuery(event.target.value), className: inputClass, disabled: disabled, id: id, readOnly: !searchable, ref: inputRef, "data-testid": "combobox-input" }), allowClear && !isEmpty(selected) && (jsx(Button, { size: "xs", iconOnly: true, "aria-label": "Clear selection", theme: "secondary", variant: "plain", className: "group absolute inset-y-0 right-8 h-6 top-2", onClick: () => handleOnChangeInternal(multiple ? [] : null), disabled: disabled, "data-testid": "combobox-clear-button", noOutlineOnFocus: true, children: jsx(SvgX, { className: "size-4 stroke-gray-500 dark:stroke-gray-300" }) })), jsx(ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5", "data-testid": "combobox-button", children: jsx(SvgChevronDown, { className: chevronIconClass }) })] })), jsx(ComboboxOptions, { anchor: { to: 'bottom', gap: 5 }, as: "div", modal: modalDropdown, className: buildClassName('w-[var(--input-width)] rounded-lg border border-gray-200 dark:border-white/5 bg-white dark:bg-gray-800 p-1 [--anchor-gap:var(--spacing-1)]', '[--anchor-max-height:20rem]', 'origin-top border transition duration-200 ease-[cubic-bezier(0.4, 0.0, 0.2, 1)] data-[closed]:translate-y-[-15%] data-[closed]:opacity-0', dropdownContainerClass), transition: true, "data-testid": "combobox-options", children: optionsLoading ? (jsx(BodyText, { "data-testid": "options-loading", className: "flex items-center justify-center py-2 px-3 select-none", children: jsx(Loader, { size: "sm" }) })) : shouldShowTypeToSearch ? (jsx(BodyText, { className: "flex items-center justify-between py-2 px-3 select-none", children: "Type to search..." })) : (jsxs("div", { children: [filteredOptions.map((option) => (jsx(ComboboxOption, { disabled: option.disabled, value: option, className: "group rounded-lg py-1.5 px-3 select-none data-[focus]:bg-black/3 dark:data-[focus]:bg-white/10 data-disabled:opacity-50 cursor-pointer data-disabled:pointer-events-none", children: jsxs("div", { className: "flex items-center justify-between gap-2 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" })] }) }, getValue(option)))), filteredOptions.length === 0 && query && !optionsLoading && (jsxs("div", { "data-testid": "no-result-found", className: "flex items-center gap-2 py-1.5 px-3 select-none text-gray-500 dark:text-gray-400", children: ["No results found for ", jsx("span", { className: "font-semibold", children: query })] })), allowAdd && (jsx(ComboboxOption, { value: query, className: "group rounded-lg py-1.5 px-3 cursor-pointer text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700", onClick: () => void handleAddAndSelect(query), children: jsxs("div", { className: "flex items-center gap-2", children: [jsx(SvgCirclePlus, { className: "size-4.5" }), jsxs(TextContent, { children: [addNewText, " \"", query, "\""] })] }) }))] })) })] }), showErrorMessage && error && (jsx("div", { className: "mt-1", children: jsx(TextContent, { error: true, small: true, children: error }) }))] }));
|
|
1309
1333
|
});
|
|
1310
1334
|
|
|
1311
1335
|
const Tabs = ({ tabs, defaultIndex = 0, selectedIndex, onChange, variant = 'underline', orientation = 'horizontal', stretch = false, className = '', listClass = '', panelsClass = '', }) => {
|