@pagamio/frontend-commons-lib 0.8.351 → 0.8.352
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/lib/components/ui/PagamioSearchableCombobox.d.ts +21 -1
- package/lib/components/ui/PagamioSearchableCombobox.js +15 -8
- package/lib/components/ui/TableDownload.js +1 -1
- package/lib/form-engine/components/inputs/searchable-combobox/SearchableComboboxInput.js +1 -1
- package/lib/form-engine/types/index.d.ts +11 -0
- package/lib/pagamio-table/data-table/TableDownload.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { UsePagamioComboboxReturn } from '../../shared/hooks/usePagamioCombobox';
|
|
3
|
+
/**
|
|
4
|
+
* Optional in-popover action — replaces the old "+ Create New X" sentinel
|
|
5
|
+
* option pattern that some `<Select>` callers used to inline a "create a
|
|
6
|
+
* new item" affordance. Rendered as a button row pinned to the top of the
|
|
7
|
+
* popover, above the options list. Clicking it closes the popover and
|
|
8
|
+
* fires `onClick` (typically opening a quick-create modal). The handler
|
|
9
|
+
* is responsible for the side effect; the combobox does NOT update its
|
|
10
|
+
* `value` automatically.
|
|
11
|
+
*/
|
|
12
|
+
export interface SearchableComboboxActionButton {
|
|
13
|
+
/** Label shown on the action button (e.g. "+ New category"). */
|
|
14
|
+
label: React.ReactNode;
|
|
15
|
+
onClick: () => void;
|
|
16
|
+
}
|
|
3
17
|
export interface PagamioSearchableComboboxProps<T extends {
|
|
4
18
|
id: string;
|
|
5
19
|
}> {
|
|
@@ -8,6 +22,12 @@ export interface PagamioSearchableComboboxProps<T extends {
|
|
|
8
22
|
/** Controlled selected id, or null when nothing is selected. */
|
|
9
23
|
value: string | null;
|
|
10
24
|
onChange: (id: string | null) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Optional action button rendered at the top of the popover. Used to
|
|
27
|
+
* surface a "+ Create new …" affordance inside the picker itself,
|
|
28
|
+
* matching where the old static-select sentinel option lived.
|
|
29
|
+
*/
|
|
30
|
+
actionButton?: SearchableComboboxActionButton;
|
|
11
31
|
/**
|
|
12
32
|
* Optional pre-resolved selected option. When set, the trigger shows its
|
|
13
33
|
* label without needing to fetch via `restoreIds`. If both this and the
|
|
@@ -39,4 +59,4 @@ export interface PagamioSearchableComboboxProps<T extends {
|
|
|
39
59
|
}
|
|
40
60
|
export declare function PagamioSearchableCombobox<T extends {
|
|
41
61
|
id: string;
|
|
42
|
-
}>({ combobox, value, onChange, selectedOption, placeholder, searchPlaceholder, emptyMessage, cappedMessage, loadingMessage, disabled, required, name, getLabel, renderOption, renderSelected, className, triggerClassName, contentClassName, }: PagamioSearchableComboboxProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
62
|
+
}>({ combobox, value, onChange, actionButton, selectedOption, placeholder, searchPlaceholder, emptyMessage, cappedMessage, loadingMessage, disabled, required, name, getLabel, renderOption, renderSelected, className, triggerClassName, contentClassName, }: PagamioSearchableComboboxProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -19,7 +19,7 @@ function defaultGetLabel(option) {
|
|
|
19
19
|
const o = option;
|
|
20
20
|
return o.name ?? option.id;
|
|
21
21
|
}
|
|
22
|
-
export function PagamioSearchableCombobox({ combobox, value, onChange, selectedOption, placeholder = 'Select…', searchPlaceholder = 'Search...', emptyMessage = 'No options found', cappedMessage = 'Showing top results — refine your search.', loadingMessage = 'Loading…', disabled, required, name, getLabel = defaultGetLabel, renderOption, renderSelected, className, triggerClassName, contentClassName, }) {
|
|
22
|
+
export function PagamioSearchableCombobox({ combobox, value, onChange, actionButton, selectedOption, placeholder = 'Select…', searchPlaceholder = 'Search...', emptyMessage = 'No options found', cappedMessage = 'Showing top results — refine your search.', loadingMessage = 'Loading…', disabled, required, name, getLabel = defaultGetLabel, renderOption, renderSelected, className, triggerClassName, contentClassName, }) {
|
|
23
23
|
const [open, setOpen] = React.useState(false);
|
|
24
24
|
const inputRef = React.useRef(null);
|
|
25
25
|
// Focus the search input when the popover opens — matches the Select's
|
|
@@ -52,11 +52,18 @@ export function PagamioSearchableCombobox({ combobox, value, onChange, selectedO
|
|
|
52
52
|
: placeholder }), _jsx(ChevronDownIcon, { className: "ml-2 h-4 w-4 opacity-50 shrink-0" })] }) }), _jsxs(PopoverContent, { align: "start", sideOffset: 4,
|
|
53
53
|
// Mirrors SelectContent: same shadow + animation classes, popover
|
|
54
54
|
// background, popover-foreground text. Width matches trigger.
|
|
55
|
-
className: cn('p-0 w-[var(--radix-popover-trigger-width)] min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md', contentClassName), children: [_jsx("div", { className: "p-2 border-b border-border", children: _jsx("input", { ref: inputRef, type: "text", placeholder: searchPlaceholder, value: combobox.search, onChange: (e) => combobox.setSearch(e.target.value), onKeyDown: (e) => e.stopPropagation(), className: "w-full px-2 py-1 text-sm border border-input rounded bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring" }) }),
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
className: cn('p-0 w-[var(--radix-popover-trigger-width)] min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md', contentClassName), children: [_jsx("div", { className: "p-2 border-b border-border", children: _jsx("input", { ref: inputRef, type: "text", placeholder: searchPlaceholder, value: combobox.search, onChange: (e) => combobox.setSearch(e.target.value), onKeyDown: (e) => e.stopPropagation(), className: "w-full px-2 py-1 text-sm border border-input rounded bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring" }) }), _jsxs("div", { className: "p-1 max-h-[200px] overflow-y-auto", children: [actionButton ? (_jsx("button", { type: "button", onClick: () => {
|
|
56
|
+
setOpen(false);
|
|
57
|
+
actionButton.onClick();
|
|
58
|
+
}, className: cn(
|
|
59
|
+
// Same row geometry as an option row so the picker reads
|
|
60
|
+
// as one consistent list. Primary-coloured label keeps it
|
|
61
|
+
// visually distinct from real options.
|
|
62
|
+
'relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none text-left font-medium text-primary', 'hover:bg-muted focus:bg-muted'), children: actionButton.label }, "__action__")) : null, combobox.isLoading && combobox.options.length === 0 ? (_jsx("div", { className: "px-2 py-1.5 text-sm text-muted-foreground", children: loadingMessage })) : combobox.error ? (_jsx("div", { className: "px-2 py-1.5 text-sm text-destructive", children: combobox.error.message || 'Failed to load options.' })) : combobox.options.length === 0 ? (_jsx("div", { className: "px-2 py-1.5 text-sm text-muted-foreground", children: emptyMessage })) : (_jsxs(_Fragment, { children: [combobox.options.map((option) => {
|
|
63
|
+
const isSelected = option.id === value;
|
|
64
|
+
return (_jsx("button", { type: "button", role: "option", "aria-selected": isSelected, onClick: () => handleSelect(option.id), className: cn(
|
|
65
|
+
// Mirrors SelectItem styling: padding, hover via
|
|
66
|
+
// focus:bg-muted, selected via bg-accent.
|
|
67
|
+
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none text-left', 'hover:bg-muted focus:bg-muted focus:text-foreground', isSelected && 'bg-accent text-foreground'), children: renderOption ? (renderOption(option, isSelected)) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "line-clamp-1", children: getLabel(option) }), isSelected ? (_jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(CheckIcon, { className: "h-4 w-4" }) })) : null] })) }, option.id));
|
|
68
|
+
}), combobox.isCapped ? (_jsx("div", { className: "mt-1 border-t px-2 py-1.5 text-xs text-muted-foreground", children: cappedMessage })) : null] }))] })] })] }), name ? _jsx("input", { type: "hidden", name: name, value: value ?? '' }) : null] }));
|
|
62
69
|
}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
3
|
import { Dropdown, DropdownItem } from 'flowbite-react';
|
|
4
4
|
import { jsPDF } from 'jspdf';
|
|
5
|
-
import
|
|
5
|
+
import autoTable from 'jspdf-autotable';
|
|
6
6
|
import { FiDownload } from 'react-icons/fi';
|
|
7
7
|
import * as XLSX from 'xlsx';
|
|
8
8
|
const TableDownload = ({ columns, data }) => {
|
|
@@ -34,7 +34,7 @@ const SearchableComboboxInput = forwardRef(({ field, value, onChange }, ref) =>
|
|
|
34
34
|
debounceMs: source.debounceMs,
|
|
35
35
|
restoreIds,
|
|
36
36
|
});
|
|
37
|
-
return (_jsxs("div", { ref: ref, children: [field.label && (_jsx("label", { htmlFor: field.name, className: "block text-sm font-medium text-foreground mb-1", children: field.label })), _jsx(PagamioSearchableCombobox, { combobox: combobox, value: value ?? null, onChange: (id) => onChange?.(id), placeholder: field.placeholder, disabled: field.disabled, required: field.validation?.required ? true : undefined, name: field.name, getLabel: source.getLabel })] }));
|
|
37
|
+
return (_jsxs("div", { ref: ref, children: [field.label && (_jsx("label", { htmlFor: field.name, className: "block text-sm font-medium text-foreground mb-1", children: field.label })), _jsx(PagamioSearchableCombobox, { combobox: combobox, value: value ?? null, onChange: (id) => onChange?.(id), actionButton: field.actionButton, placeholder: field.placeholder, disabled: field.disabled, required: field.validation?.required ? true : undefined, name: field.name, getLabel: source.getLabel })] }));
|
|
38
38
|
});
|
|
39
39
|
SearchableComboboxInput.displayName = 'SearchableComboboxInput';
|
|
40
40
|
export default SearchableComboboxInput;
|
|
@@ -215,6 +215,17 @@ export interface Field {
|
|
|
215
215
|
* Tells the form engine how to fetch lookup results.
|
|
216
216
|
*/
|
|
217
217
|
source?: ComboboxSourceSpec;
|
|
218
|
+
/**
|
|
219
|
+
* Optional in-picker action for `searchable-combobox`. Renders as the
|
|
220
|
+
* first row of the popover (above the options) — the same place a
|
|
221
|
+
* "+ Create new …" sentinel option used to live in the old static
|
|
222
|
+
* `<Select>`. Clicking it closes the popover and fires `onClick`; the
|
|
223
|
+
* handler owns the side effect (e.g. opens a quick-create modal).
|
|
224
|
+
*/
|
|
225
|
+
actionButton?: {
|
|
226
|
+
label: string;
|
|
227
|
+
onClick: () => void;
|
|
228
|
+
};
|
|
218
229
|
}
|
|
219
230
|
export interface DependentFieldUpdate {
|
|
220
231
|
field: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Dropdown, DropdownItem } from 'flowbite-react';
|
|
3
3
|
import { jsPDF } from 'jspdf';
|
|
4
|
-
import
|
|
4
|
+
import autoTable from 'jspdf-autotable';
|
|
5
5
|
import { FiDownload } from 'react-icons/fi';
|
|
6
6
|
import * as XLSX from 'xlsx';
|
|
7
7
|
const TableDownload = ({ columns, data }) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagamio/frontend-commons-lib",
|
|
3
3
|
"description": "Pagamio library for Frontend reusable components like the form engine and table container",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.352",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|