@pallasoft/ps-input-components 3.9.1 → 3.10.0

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.
Files changed (60) hide show
  1. package/dist/components/ps-cascader-input.d.ts +2 -1
  2. package/dist/components/ps-cascader-input.js +11 -7
  3. package/dist/components/ps-checkbox-matrix.js +1 -1
  4. package/dist/components/ps-combobox-input.d.ts +3 -1
  5. package/dist/components/ps-combobox-input.js +7 -3
  6. package/dist/components/ps-date-input.d.ts +3 -1
  7. package/dist/components/ps-date-input.js +3 -2
  8. package/dist/components/ps-grouped-switcher.js +2 -2
  9. package/dist/components/ps-multi-select-input.js +1 -1
  10. package/dist/components/ps-percent-input.js +1 -1
  11. package/dist/components/ps-phone-input.js +2 -2
  12. package/dist/components/ps-select-input.d.ts +3 -1
  13. package/dist/components/ps-select-input.js +6 -2
  14. package/dist/components/ps-select-option-item.js +1 -1
  15. package/dist/components/ps-select-with-create.d.ts +3 -1
  16. package/dist/components/ps-select-with-create.js +2 -2
  17. package/dist/components/ps-suggested-tag.d.ts +6 -0
  18. package/dist/components/ps-suggested-tag.js +8 -0
  19. package/dist/components/ps-tag-input.js +1 -1
  20. package/dist/components/ps-text-input.d.ts +3 -1
  21. package/dist/components/ps-text-input.js +4 -3
  22. package/dist/constants/ps-portable-text-editor-config.d.ts +1 -1
  23. package/dist/constants/ps-portable-text-editor-config.js +1 -1
  24. package/dist/esm/components/ps-cascader-input.js +11 -7
  25. package/dist/esm/components/ps-checkbox-matrix.js +1 -1
  26. package/dist/esm/components/ps-combobox-input.js +7 -3
  27. package/dist/esm/components/ps-date-input.js +3 -2
  28. package/dist/esm/components/ps-grouped-switcher.js +2 -2
  29. package/dist/esm/components/ps-multi-select-input.js +1 -1
  30. package/dist/esm/components/ps-percent-input.js +1 -1
  31. package/dist/esm/components/ps-phone-input.js +2 -2
  32. package/dist/esm/components/ps-select-input.js +6 -2
  33. package/dist/esm/components/ps-select-option-item.js +1 -1
  34. package/dist/esm/components/ps-select-with-create.js +2 -2
  35. package/dist/esm/components/ps-suggested-tag.js +4 -0
  36. package/dist/esm/components/ps-tag-input.js +1 -1
  37. package/dist/esm/components/ps-text-input.js +4 -3
  38. package/dist/esm/constants/ps-portable-text-editor-config.js +1 -1
  39. package/dist/esm/form/components/ps-form-cascader-field.js +1 -1
  40. package/dist/esm/form/components/ps-form-date-field.js +1 -1
  41. package/dist/esm/form/components/ps-form-money-field.js +2 -2
  42. package/dist/esm/form/components/ps-form-select-field.js +2 -2
  43. package/dist/esm/form/components/ps-form-text-field.js +3 -1
  44. package/dist/esm/index.js +2 -0
  45. package/dist/esm/services/ps-suggested-tag-service.js +5 -0
  46. package/dist/form/components/ps-form-cascader-field.d.ts +3 -1
  47. package/dist/form/components/ps-form-cascader-field.js +1 -1
  48. package/dist/form/components/ps-form-date-field.d.ts +3 -1
  49. package/dist/form/components/ps-form-date-field.js +1 -1
  50. package/dist/form/components/ps-form-money-field.d.ts +3 -1
  51. package/dist/form/components/ps-form-money-field.js +2 -2
  52. package/dist/form/components/ps-form-select-field.d.ts +3 -1
  53. package/dist/form/components/ps-form-select-field.js +2 -2
  54. package/dist/form/components/ps-form-text-field.d.ts +3 -1
  55. package/dist/form/components/ps-form-text-field.js +3 -1
  56. package/dist/index.d.ts +2 -0
  57. package/dist/index.js +2 -0
  58. package/dist/services/ps-suggested-tag-service.d.ts +3 -0
  59. package/dist/services/ps-suggested-tag-service.js +9 -0
  60. package/package.json +1 -1
@@ -4,15 +4,19 @@ import { PsSpinner } from '@pallasoft/ps-core-components';
4
4
  import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
5
5
  import { ComboBox, Label, ListBox, ListBoxItem, Popover } from 'react-aria-components';
6
6
  import { PsComboboxInputService } from '../services/ps-combobox-input-service';
7
+ import { PsSuggestedTagService } from '../services/ps-suggested-tag-service';
7
8
  import { PsComboboxCloseBridge } from './ps-combobox-close-bridge';
8
9
  import { PsComboboxScanInput } from './ps-combobox-scan-input';
9
10
  import { PsRequiredMark } from './ps-required-mark';
10
- export const PsComboboxInput = ({ className, emptyText, getItemKey, getItemLabel, hideLabel = false, inputValue, isDisabled = false, isLoading = false, items, label, menuTrigger = 'input', onInputChange, onScan, onSelectionChange, placeholder, renderItem, required, selectedKey, }) => {
11
+ import { PsSuggestedTag } from './ps-suggested-tag';
12
+ export const PsComboboxInput = ({ className, emptyText, getItemKey, getItemLabel, hideLabel = false, inputValue, isDisabled = false, isLoading = false, isSuggested = false, items, label, menuTrigger = 'input', onInputChange, onScan, onSelectionChange, placeholder, renderItem, required, selectedKey, suggestedLabel, }) => {
11
13
  const itemsByKey = new Map(items.map((item) => [getItemKey(item), item]));
12
14
  const closeRef = useRef(null);
13
- return (_jsxs(ComboBox, { allowsEmptyCollection: true, "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), defaultFilter: () => true, inputValue: inputValue, isDisabled: isDisabled, items: items, menuTrigger: menuTrigger, onInputChange: onInputChange, selectedKey: selectedKey, onSelectionChange: (key) => {
15
+ return (_jsxs(ComboBox, { allowsEmptyCollection: true, "aria-label": hideLabel && label !== undefined
16
+ ? PsSuggestedTagService.accessibleLabel(label, isSuggested, suggestedLabel)
17
+ : undefined, className: PallasoftClassNameService.merge('block', className), defaultFilter: () => true, inputValue: inputValue, isDisabled: isDisabled, items: items, menuTrigger: menuTrigger, onInputChange: onInputChange, selectedKey: selectedKey, onSelectionChange: (key) => {
14
18
  onSelectionChange?.(key === null ? null : PsComboboxInputService.getItem(itemsByKey, key));
15
19
  if (key !== null && closeRef.current !== null)
16
20
  closeRef.current();
17
- }, children: [_jsx(PsComboboxCloseBridge, { closeRef: closeRef }), label && !hideLabel ? (_jsxs(Label, { className: 'ps-input-label', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })) : null, _jsx("span", { className: hideLabel || !label ? 'relative block' : 'relative mt-2 block', children: _jsx(PsComboboxScanInput, { className: 'ps-input-control ps-focus-ring w-full text-sm font-semibold', onScan: onScan, placeholder: placeholder }) }), _jsx(Popover, { className: 'w-[--trigger-width] rounded-2xl border border-line bg-surface p-1.5 shadow-lg', children: isLoading && items.length === 0 ? (_jsx("div", { className: 'flex items-center justify-center py-4', children: _jsx(PsSpinner, { label: 'Loading results', size: 'small' }) })) : (_jsx(ListBox, { "aria-busy": isLoading, className: 'max-h-72 overflow-y-auto outline-none', items: items, renderEmptyState: () => emptyText ? _jsx("div", { className: 'px-3 py-2 text-sm text-ink/55', children: emptyText }) : null, children: (item) => (_jsx(ListBoxItem, { className: 'ps-focus-ring cursor-pointer rounded-ps-control px-3 py-2 text-sm font-semibold text-ink selected:bg-primary-soft selected:text-primary hover:bg-mist focused:bg-mist', id: getItemKey(item), textValue: getItemLabel(item), children: renderItem ? renderItem(item) : getItemLabel(item) })) })) })] }));
21
+ }, children: [_jsx(PsComboboxCloseBridge, { closeRef: closeRef }), label && !hideLabel ? (_jsxs(Label, { className: 'ps-input-label', children: [label, _jsx(PsRequiredMark, { isRequired: required }), _jsx(PsSuggestedTag, { isSuggested: isSuggested, label: suggestedLabel })] })) : null, _jsx("span", { className: hideLabel || !label ? 'relative block' : 'relative mt-2 block', children: _jsx(PsComboboxScanInput, { className: 'ps-input-control ps-focus-ring w-full text-sm font-semibold', onScan: onScan, placeholder: placeholder }) }), _jsx(Popover, { className: 'w-[--trigger-width] rounded-2xl border border-line bg-surface p-1.5 shadow-lg', children: isLoading && items.length === 0 ? (_jsx("div", { className: 'flex items-center justify-center py-4', children: _jsx(PsSpinner, { label: 'Loading results', size: 'small' }) })) : (_jsx(ListBox, { "aria-busy": isLoading, className: 'max-h-72 overflow-y-auto outline-none', items: items, renderEmptyState: () => emptyText ? _jsx("div", { className: 'px-3 py-2 text-sm text-muted', children: emptyText }) : null, children: (item) => (_jsx(ListBoxItem, { className: 'ps-focus-ring cursor-pointer rounded-ps-control px-3 py-2 text-sm font-semibold text-ink selected:bg-primary-soft selected:text-primary hover:bg-mist focused:bg-mist', id: getItemKey(item), textValue: getItemLabel(item), children: renderItem ? renderItem(item) : getItemLabel(item) })) })) })] }));
18
22
  };
@@ -12,7 +12,8 @@ import { PsDatePickerFallback } from './ps-date-picker-fallback';
12
12
  import { PsFieldSkeleton } from './ps-field-skeleton';
13
13
  import { PsLazyDatePicker } from './ps-lazy-date-picker';
14
14
  import { PsRequiredMark } from './ps-required-mark';
15
- export const PsDateInput = ({ className, defaultValue, disabled, helperText, hideLabel, isLoading = false, label, max, min, name, onChange, placeholder = PsDateInputConfig.placeholder, required, value, }) => {
15
+ import { PsSuggestedTag } from './ps-suggested-tag';
16
+ export const PsDateInput = ({ className, defaultValue, disabled, helperText, hideLabel, isLoading = false, isSuggested = false, label, max, min, name, onChange, placeholder = PsDateInputConfig.placeholder, required, suggestedLabel, value, }) => {
16
17
  if (isLoading)
17
18
  return _jsx(PsFieldSkeleton, { className: className, hideLabel: hideLabel, label: label });
18
19
  const inputId = useId();
@@ -42,5 +43,5 @@ export const PsDateInput = ({ className, defaultValue, disabled, helperText, hid
42
43
  onChange?.(nextValue);
43
44
  };
44
45
  const fallback = (_jsx(PsDatePickerFallback, { disabled: disabled, id: inputId, placeholder: placeholder, required: required, text: PsDateInputService.display(currentValue) }));
45
- return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label block', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: hideLabel ? 'relative' : 'relative mt-2', children: [isHydrated ? (_jsx(Suspense, { fallback: fallback, children: _jsx(PsLazyDatePicker, { autoComplete: 'off', calendarClassName: PallasoftClassNameService.merge('ps-floating-panel ps-datepicker', view === PsCalendarView.day ? undefined : PsDateInputConfig.pickingClassName), className: PsDatePickerClasses.control, dateFormat: [...PsDateInputConfig.inputFormats], disabled: disabled, id: inputId, maxDate: maxDate, minDate: minDate, onCalendarClose: () => setView(PsCalendarView.day), onChange: handleChange, placeholderText: placeholder, popperClassName: 'ps-datepicker-popper', popperPlacement: 'bottom-start', popperProps: { strategy: 'fixed' }, portalId: portalId, renderCustomHeader: (headerProps) => (_jsx(PsCalendarHeader, { ...headerProps, maxDate: maxDate, minDate: minDate, onViewChange: setView, view: view })), required: required, selected: PsDateInputService.parse(currentValue), showPopperArrow: false, wrapperClassName: PsDatePickerClasses.wrapperOption }) })) : (fallback), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-ink/50', iconKey: PsIconKey.Calendar }), name ? _jsx("input", { name: name, type: 'hidden', value: currentValue }) : null] }), helperText ? _jsx("span", { className: 'ps-input-helper', children: helperText }) : null] }));
46
+ return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label block', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required }), _jsx(PsSuggestedTag, { isSuggested: isSuggested, label: suggestedLabel })] }), _jsxs("div", { className: hideLabel ? 'relative' : 'relative mt-2', children: [isHydrated ? (_jsx(Suspense, { fallback: fallback, children: _jsx(PsLazyDatePicker, { autoComplete: 'off', calendarClassName: PallasoftClassNameService.merge('ps-floating-panel ps-datepicker', view === PsCalendarView.day ? undefined : PsDateInputConfig.pickingClassName), className: PsDatePickerClasses.control, dateFormat: [...PsDateInputConfig.inputFormats], disabled: disabled, id: inputId, maxDate: maxDate, minDate: minDate, onCalendarClose: () => setView(PsCalendarView.day), onChange: handleChange, placeholderText: placeholder, popperClassName: 'ps-datepicker-popper', popperPlacement: 'bottom-start', popperProps: { strategy: 'fixed' }, portalId: portalId, renderCustomHeader: (headerProps) => (_jsx(PsCalendarHeader, { ...headerProps, maxDate: maxDate, minDate: minDate, onViewChange: setView, view: view })), required: required, selected: PsDateInputService.parse(currentValue), showPopperArrow: false, wrapperClassName: PsDatePickerClasses.wrapperOption }) })) : (fallback), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-ink/50', iconKey: PsIconKey.Calendar }), name ? _jsx("input", { name: name, type: 'hidden', value: currentValue }) : null] }), helperText ? _jsx("span", { className: 'ps-input-helper', children: helperText }) : null] }));
46
47
  };
@@ -42,11 +42,11 @@ export const PsGroupedSwitcher = ({ allOption, ariaLabel, className, emptyText,
42
42
  setIsOpen(next);
43
43
  if (!next)
44
44
  setQuery('');
45
- }, children: [_jsxs(Button, { "aria-label": ariaLabel, className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex w-full min-w-0 items-center pr-10 text-left text-sm font-semibold', className), children: [_jsx("span", { className: 'min-w-0 flex-1', children: renderSelected(isAllSelected ? null : selected) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), _jsx(Popover, { className: 'ps-floating-panel w-[max(var(--trigger-width),min(32rem,calc(100vw-2rem)))] min-w-[var(--trigger-width)] overflow-hidden p-0 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(Dialog, { "aria-label": ariaLabel, className: 'flex max-h-[min(34rem,75vh)] flex-col outline-none', children: _jsxs(Autocomplete, { filter: () => true, inputValue: query, onInputChange: setQuery, children: [_jsxs(SearchField, { "aria-label": searchPlaceholder, autoFocus: true, className: 'relative block border-b border-line p-2', children: [_jsx(Input, { className: 'ps-input-control ps-focus-ring w-full pl-10 text-sm font-semibold', placeholder: searchPlaceholder }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute left-5 top-1/2 h-4 w-4 -translate-y-1/2 text-ink/45', iconKey: PsIconKey.Search })] }), _jsxs(ListBox, { "aria-label": ariaLabel, className: 'ps-scrollbar-hidden min-h-0 flex-1 overflow-y-auto p-1.5 outline-none', onSelectionChange: onSelectionChange, renderEmptyState: () => (_jsx("div", { className: 'px-3 py-6 text-center text-sm text-ink/55', children: emptyText })), selectedKeys: [
45
+ }, children: [_jsxs(Button, { "aria-label": ariaLabel, className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex w-full min-w-0 items-center pr-10 text-left text-sm font-semibold', className), children: [_jsx("span", { className: 'min-w-0 flex-1', children: renderSelected(isAllSelected ? null : selected) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), _jsx(Popover, { className: 'ps-floating-panel w-[max(var(--trigger-width),min(32rem,calc(100vw-2rem)))] min-w-[var(--trigger-width)] overflow-hidden p-0 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(Dialog, { "aria-label": ariaLabel, className: 'flex max-h-[min(34rem,75vh)] flex-col outline-none', children: _jsxs(Autocomplete, { filter: () => true, inputValue: query, onInputChange: setQuery, children: [_jsxs(SearchField, { "aria-label": searchPlaceholder, autoFocus: true, className: 'relative block border-b border-line p-2', children: [_jsx(Input, { className: 'ps-input-control ps-focus-ring w-full pl-10 text-sm font-semibold', placeholder: searchPlaceholder }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute left-5 top-1/2 h-4 w-4 -translate-y-1/2 text-ink/45', iconKey: PsIconKey.Search })] }), _jsxs(ListBox, { "aria-label": ariaLabel, className: 'ps-scrollbar-hidden min-h-0 flex-1 overflow-y-auto p-1.5 outline-none', onSelectionChange: onSelectionChange, renderEmptyState: () => (_jsx("div", { className: 'px-3 py-6 text-center text-sm text-muted', children: emptyText })), selectedKeys: [
46
46
  isAllSelected
47
47
  ? PsGroupedSwitcherConfig.allKey
48
48
  : PsGroupedSwitcherService.selectedOptionId(sections, selectedKey, getItemKey),
49
- ], selectionMode: 'single', children: [showAll ? (_jsx(ListBoxSection, { children: _jsx(ListBoxItem, { className: 'ps-floating-option min-h-12 text-ink', id: PsGroupedSwitcherConfig.allKey, textValue: 'all', children: allOption.content }) })) : null, sections.map((section) => (_jsxs(ListBoxSection, { id: section.key, children: [_jsx(Header, { className: 'px-3 pb-1 pt-3 text-xs font-semibold tracking-wide text-ink/50 uppercase', children: renderSectionLabel === undefined
49
+ ], selectionMode: 'single', children: [showAll ? (_jsx(ListBoxSection, { children: _jsx(ListBoxItem, { className: 'ps-floating-option min-h-12 text-ink', id: PsGroupedSwitcherConfig.allKey, textValue: 'all', children: allOption.content }) })) : null, sections.map((section) => (_jsxs(ListBoxSection, { id: section.key, children: [_jsx(Header, { className: 'px-3 pb-1 pt-3 text-xs font-semibold tracking-wide text-muted uppercase', children: renderSectionLabel === undefined
50
50
  ? section.label
51
51
  : renderSectionLabel(section.key, section.label) }), section.items.map((item) => {
52
52
  const key = getItemKey(item);
@@ -20,7 +20,7 @@ export const PsMultiSelectInput = ({ className, defaultValue, disabled, helperTe
20
20
  setUncontrolledValue(nextValue);
21
21
  onChange?.(nextValue);
22
22
  };
23
- return (_jsxs(Select, { "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), isDisabled: disabled, isRequired: required, name: name, onChange: handleChange, placeholder: placeholder, selectionMode: 'multiple', value: currentValue.filter((selected) => labelByValue.has(selected)), children: [hideLabel ? null : (_jsxs(Label, { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(Button, { className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex w-full items-center py-1.5 pr-10 text-left text-sm font-semibold disabled:cursor-not-allowed disabled:opacity-60', hideLabel ? '' : 'mt-2'), children: [_jsx(SelectValue, { className: 'flex min-w-0 flex-1 flex-wrap gap-1.5', children: ({ isPlaceholder }) => isPlaceholder ? (_jsx("span", { className: 'font-medium text-ink/45', children: placeholder })) : (currentValue
23
+ return (_jsxs(Select, { "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), isDisabled: disabled, isRequired: required, name: name, onChange: handleChange, placeholder: placeholder, selectionMode: 'multiple', value: currentValue.filter((selected) => labelByValue.has(selected)), children: [hideLabel ? null : (_jsxs(Label, { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(Button, { className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex w-full items-center py-1.5 pr-10 text-left text-sm font-semibold disabled:cursor-not-allowed disabled:opacity-60', hideLabel ? '' : 'mt-2'), children: [_jsx(SelectValue, { className: 'flex min-w-0 flex-1 flex-wrap gap-1.5', children: ({ isPlaceholder }) => isPlaceholder ? (_jsx("span", { className: 'font-medium text-subtle', children: placeholder })) : (currentValue
24
24
  .filter((selected) => labelByValue.has(selected))
25
25
  .map((selected) => (_jsx("span", { className: 'inline-flex max-w-full items-center rounded-ps-control bg-primary/12 px-2.5 py-0.5 text-xs font-semibold text-ink', children: _jsx("span", { className: 'truncate', children: labelByValue.get(selected) }) }, selected)))) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), helperText ? (_jsx(Text, { className: 'ps-input-helper', slot: 'description', children: helperText })) : null, _jsx(Popover, { className: 'ps-floating-panel ps-scrollbar-hidden max-h-72 min-w-[var(--trigger-width)] overflow-y-auto p-1.5 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(ListBox, { className: 'outline-none', items: options.map((option) => ({ ...option, id: option.value })), children: (option) => _jsx(PsSelectOptionItem, { option: option }) }) })] }));
26
26
  };
@@ -9,4 +9,4 @@ export const PsPercentInput = ({ className, onChange, ...props }) => (_jsxs("div
9
9
  event.target.value = normalised;
10
10
  if (onChange)
11
11
  onChange(event);
12
- }, type: 'text' }), _jsx("span", { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 bottom-3 text-sm text-ink/50', children: PsTextFormatConfig.percentSuffix })] }));
12
+ }, type: 'text' }), _jsx("span", { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 bottom-3 text-sm text-muted', children: PsTextFormatConfig.percentSuffix })] }));
@@ -34,9 +34,9 @@ export const PsPhoneInput = ({ className, defaultCountry = PsPhoneInputConfig.de
34
34
  emit(national, code);
35
35
  document.getElementById(inputId)?.focus();
36
36
  };
37
- return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: PallasoftClassNameService.merge('ps-input-control flex items-stretch overflow-hidden p-0 focus-within:border-primary focus-within:shadow-[0_0_0_1px_rgb(var(--ps-color-primary-rgb))]', hideLabel ? '' : 'mt-2', isInvalid ? 'border-danger bg-danger/5' : '', disabled ? 'opacity-60' : ''), children: [_jsxs(DialogTrigger, { isOpen: isOpen, onOpenChange: setIsOpen, children: [_jsxs(Button, { "aria-label": PsPhoneInputConfig.countryLabel, className: 'flex shrink-0 items-center gap-1.5 border-r border-line px-3 outline-none focus-visible:bg-primary/10 text-sm font-semibold text-ink', isDisabled: disabled, children: [country, _jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-3.5 w-3.5 text-ink/45', iconKey: PsIconKey.Chevron })] }), _jsx(Popover, { className: 'ps-floating-panel w-72 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsxs(Dialog, { "aria-label": PsPhoneInputConfig.countryLabel, className: 'flex flex-col outline-none', children: [_jsx("div", { className: 'border-b border-line p-2', children: _jsx("input", { "aria-label": PsPhoneInputConfig.searchPlaceholder, autoFocus: true, className: 'ps-input-control ps-control-compact ps-focus-ring w-full text-sm', onChange: (event) => setQuery(event.target.value), placeholder: PsPhoneInputConfig.searchPlaceholder, type: 'search', value: query }) }), _jsx("ul", { className: 'ps-scrollbar-hidden max-h-64 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? (_jsx("li", { className: 'px-3 py-2.5 text-sm text-ink/50', children: PsPhoneInputConfig.emptyMessage })) : (matches.map((option) => (_jsx("li", { role: 'none', children: _jsxs("button", { "aria-selected": option.code === country, className: PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center justify-between gap-3 rounded-ps-control px-3 py-2.5 text-left text-sm', option.code === country
37
+ return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: PallasoftClassNameService.merge('ps-input-control flex items-stretch overflow-hidden p-0 focus-within:border-primary focus-within:shadow-[0_0_0_1px_rgb(var(--ps-color-primary-rgb))]', hideLabel ? '' : 'mt-2', isInvalid ? 'border-danger bg-danger/5' : '', disabled ? 'opacity-60' : ''), children: [_jsxs(DialogTrigger, { isOpen: isOpen, onOpenChange: setIsOpen, children: [_jsxs(Button, { "aria-label": PsPhoneInputConfig.countryLabel, className: 'flex shrink-0 items-center gap-1.5 border-r border-line px-3 outline-none focus-visible:bg-primary/10 text-sm font-semibold text-ink', isDisabled: disabled, children: [country, _jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-3.5 w-3.5 text-ink/45', iconKey: PsIconKey.Chevron })] }), _jsx(Popover, { className: 'ps-floating-panel w-72 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsxs(Dialog, { "aria-label": PsPhoneInputConfig.countryLabel, className: 'flex flex-col outline-none', children: [_jsx("div", { className: 'border-b border-line p-2', children: _jsx("input", { "aria-label": PsPhoneInputConfig.searchPlaceholder, autoFocus: true, className: 'ps-input-control ps-control-compact ps-focus-ring w-full text-sm', onChange: (event) => setQuery(event.target.value), placeholder: PsPhoneInputConfig.searchPlaceholder, type: 'search', value: query }) }), _jsx("ul", { className: 'ps-scrollbar-hidden max-h-64 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? (_jsx("li", { className: 'px-3 py-2.5 text-sm text-muted', children: PsPhoneInputConfig.emptyMessage })) : (matches.map((option) => (_jsx("li", { role: 'none', children: _jsxs("button", { "aria-selected": option.code === country, className: PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center justify-between gap-3 rounded-ps-control px-3 py-2.5 text-left text-sm', option.code === country
38
38
  ? 'bg-primary/10 text-ink'
39
- : 'text-ink/80 hover:bg-mist/60 hover:text-ink'), onClick: () => choose(option.code), role: 'option', type: 'button', children: [_jsx("span", { className: 'min-w-0 truncate', children: PsPhoneInputService.highlight(option.label, query).map((part, index) => part.isMatch ? (_jsx("strong", { className: 'font-semibold text-ink', children: part.text }, index)) : (_jsx("span", { children: part.text }, index))) }), _jsxs("span", { className: 'shrink-0 text-xs text-ink/50', children: ["+", option.callingCode] })] }) }, option.code)))) })] }) })] }), _jsxs("span", { "aria-hidden": 'true', className: 'flex items-center pl-3 text-sm text-ink/45', children: [PsPhoneInputConfig.plus, PsPhoneInputService.callingCode(country)] }), _jsx("input", { "aria-invalid": isInvalid, autoComplete: 'tel-national', className: 'min-w-0 flex-1 bg-transparent px-2 text-sm text-ink outline-none', disabled: disabled, id: inputId, inputMode: 'tel', name: name, onBlur: () => {
39
+ : 'text-ink/80 hover:bg-mist/60 hover:text-ink'), onClick: () => choose(option.code), role: 'option', type: 'button', children: [_jsx("span", { className: 'min-w-0 truncate', children: PsPhoneInputService.highlight(option.label, query).map((part, index) => part.isMatch ? (_jsx("strong", { className: 'font-semibold text-ink', children: part.text }, index)) : (_jsx("span", { children: part.text }, index))) }), _jsxs("span", { className: 'shrink-0 text-xs text-muted', children: ["+", option.callingCode] })] }) }, option.code)))) })] }) })] }), _jsxs("span", { "aria-hidden": 'true', className: 'flex items-center pl-3 text-sm text-subtle', children: [PsPhoneInputConfig.plus, PsPhoneInputService.callingCode(country)] }), _jsx("input", { "aria-invalid": isInvalid, autoComplete: 'tel-national', className: 'min-w-0 flex-1 bg-transparent px-2 text-sm text-ink outline-none', disabled: disabled, id: inputId, inputMode: 'tel', name: name, onBlur: () => {
40
40
  setIsTouched(true);
41
41
  if (onBlur)
42
42
  onBlur();
@@ -6,10 +6,12 @@ import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
6
6
  import { Button, Label, ListBox, Popover, Select, SelectValue, Text, } from 'react-aria-components';
7
7
  import { PsInputSizeClassNames } from '../constants/ps-input-size-class-names';
8
8
  import { PsSelectInputService } from '../services/ps-select-input-service';
9
+ import { PsSuggestedTagService } from '../services/ps-suggested-tag-service';
9
10
  import { PsFieldSkeleton } from './ps-field-skeleton';
10
11
  import { PsRequiredMark } from './ps-required-mark';
11
12
  import { PsSelectOptionItem } from './ps-select-option-item';
12
- export const PsSelectInput = ({ className, defaultValue, disabled, helperText, hideLabel, isLoading = false, label, name, onChange, options, placeholder = 'Select an option', required, controlSize = 'default', value, }) => {
13
+ import { PsSuggestedTag } from './ps-suggested-tag';
14
+ export const PsSelectInput = ({ className, defaultValue, disabled, helperText, hideLabel, isLoading = false, isSuggested = false, label, name, onChange, options, placeholder = 'Select an option', required, suggestedLabel, controlSize = 'default', value, }) => {
13
15
  if (isLoading)
14
16
  return _jsx(PsFieldSkeleton, { className: className, hideLabel: hideLabel, label: label });
15
17
  const [uncontrolledValue, setUncontrolledValue] = useState(() => PsSelectInputService.getDefaultValue(defaultValue, options));
@@ -22,5 +24,7 @@ export const PsSelectInput = ({ className, defaultValue, disabled, helperText, h
22
24
  setUncontrolledValue(nextValue);
23
25
  onChange?.(nextValue);
24
26
  };
25
- return (_jsxs(Select, { "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), isDisabled: disabled, isRequired: required, name: name, onChange: handleChange, placeholder: placeholder, value: hasOption ? currentValue : null, children: [hideLabel ? null : (_jsxs(Label, { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(Button, { className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex w-full items-center pr-10 text-left text-sm font-semibold disabled:cursor-not-allowed disabled:opacity-60', hideLabel ? '' : 'mt-2', PsInputSizeClassNames[controlSize]), children: [_jsx(SelectValue, { className: 'min-w-0 flex-1 truncate', children: ({ isPlaceholder, selectedText }) => isPlaceholder ? (_jsx("span", { className: 'font-medium text-ink/45', children: placeholder })) : (selectedText) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), helperText ? (_jsx(Text, { className: 'ps-input-helper', slot: 'description', children: helperText })) : null, _jsx(Popover, { className: 'ps-floating-panel ps-scrollbar-hidden max-h-72 min-w-[var(--trigger-width)] overflow-y-auto p-1.5 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(ListBox, { className: 'outline-none', items: options.map((option) => ({ ...option, id: option.value })), children: (option) => _jsx(PsSelectOptionItem, { option: option }) }) })] }));
27
+ return (_jsxs(Select, { "aria-label": hideLabel
28
+ ? PsSuggestedTagService.accessibleLabel(label, isSuggested, suggestedLabel)
29
+ : undefined, className: PallasoftClassNameService.merge('block', className), isDisabled: disabled, isRequired: required, name: name, onChange: handleChange, placeholder: placeholder, value: hasOption ? currentValue : null, children: [hideLabel ? null : (_jsxs(Label, { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required }), _jsx(PsSuggestedTag, { isSuggested: isSuggested, label: suggestedLabel })] })), _jsxs(Button, { className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex w-full items-center pr-10 text-left text-sm font-semibold disabled:cursor-not-allowed disabled:opacity-60', hideLabel ? '' : 'mt-2', PsInputSizeClassNames[controlSize]), children: [_jsx(SelectValue, { className: 'min-w-0 flex-1 truncate', children: ({ isPlaceholder, selectedText }) => isPlaceholder ? (_jsx("span", { className: 'font-medium text-subtle', children: placeholder })) : (selectedText) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), helperText ? (_jsx(Text, { className: 'ps-input-helper', slot: 'description', children: helperText })) : null, _jsx(Popover, { className: 'ps-floating-panel ps-scrollbar-hidden max-h-72 min-w-[var(--trigger-width)] overflow-y-auto p-1.5 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(ListBox, { className: 'outline-none', items: options.map((option) => ({ ...option, id: option.value })), children: (option) => _jsx(PsSelectOptionItem, { option: option }) }) })] }));
26
30
  };
@@ -1,4 +1,4 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
3
3
  import { ListBoxItem } from 'react-aria-components';
4
- export const PsSelectOptionItem = ({ option }) => (_jsx(ListBoxItem, { className: 'ps-floating-option text-ink', id: option.value, textValue: option.label, children: ({ isSelected }) => (_jsxs(_Fragment, { children: [_jsx("span", { className: 'flex h-4 w-4 shrink-0 items-center justify-center text-primary', children: isSelected ? (_jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4', iconKey: PsIconKey.Check })) : null }), _jsxs("span", { className: 'min-w-0 flex-1', children: [_jsx("span", { className: 'block truncate', children: option.label }), option.description ? (_jsx("span", { className: 'mt-0.5 block text-xs font-normal text-ink/55', children: option.description })) : null] })] })) }));
4
+ export const PsSelectOptionItem = ({ option }) => (_jsx(ListBoxItem, { className: 'ps-floating-option text-ink', id: option.value, textValue: option.label, children: ({ isSelected }) => (_jsxs(_Fragment, { children: [_jsx("span", { className: 'flex h-4 w-4 shrink-0 items-center justify-center text-primary', children: isSelected ? (_jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4', iconKey: PsIconKey.Check })) : null }), _jsxs("span", { className: 'min-w-0 flex-1', children: [_jsx("span", { className: 'block truncate', children: option.label }), option.description ? (_jsx("span", { className: 'mt-0.5 block text-xs font-normal text-muted', children: option.description })) : null] })] })) }));
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { PsSelectWithCreateConfig } from '../constants/ps-select-with-create-config';
3
3
  import { PsFormControl } from './ps-form-control';
4
4
  import { PsSelectInput } from './ps-select-input';
5
- export const PsSelectWithCreate = ({ createHref, createOptionLabel, errorText, hideLabel, label, onChange, options, placeholder, required, value, }) => (_jsx(PsFormControl, { errorText: errorText, children: _jsx(PsSelectInput, { hideLabel: hideLabel, label: label, onChange: (next) => {
5
+ export const PsSelectWithCreate = ({ createHref, createOptionLabel, errorText, hideLabel, isSuggested, label, onChange, options, placeholder, required, suggestedLabel, value, }) => (_jsx(PsFormControl, { errorText: errorText, children: _jsx(PsSelectInput, { hideLabel: hideLabel, isSuggested: isSuggested, label: label, onChange: (next) => {
6
6
  if (next !== PsSelectWithCreateConfig.createValue) {
7
7
  onChange(next);
8
8
  return;
@@ -11,4 +11,4 @@ export const PsSelectWithCreate = ({ createHref, createOptionLabel, errorText, h
11
11
  }, options: [
12
12
  ...options,
13
13
  { label: createOptionLabel, value: PsSelectWithCreateConfig.createValue },
14
- ], placeholder: placeholder, required: required, value: value }) }));
14
+ ], placeholder: placeholder, required: required, suggestedLabel: suggestedLabel, value: value }) }));
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
4
+ export const PsSuggestedTag = ({ className, isSuggested = false, label }) => isSuggested && label !== undefined ? (_jsxs("span", { className: PallasoftClassNameService.merge('ml-2 inline-flex shrink-0 items-center gap-1 align-middle text-xs font-medium text-muted', className), children: [_jsx("span", { className: 'sr-only', children: ", " }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'h-3 w-3 text-primary', iconKey: PsIconKey.Spark }), label] })) : null;
@@ -29,7 +29,7 @@ export const PsTagInput = ({ className, errorText, helperText, hideLabel, isDisa
29
29
  return (_jsx(PsFormControl, { className: className, errorText: errorText, helperText: helperText, children: _jsxs("label", { className: 'block', children: [_jsxs("span", { className: hideLabel ? 'sr-only' : 'ps-input-label', children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("span", { className: PallasoftClassNameService.merge('ps-input-control flex flex-wrap items-center gap-1.5 py-1.5', hideLabel ? '' : 'mt-2', isDisabled ? 'opacity-60' : ''), children: [values.map((value) => (_jsx(PsActiveFilterChip, { label: value, onRemove: () => {
30
30
  if (!isDisabled)
31
31
  onChange(PsTagInputService.remove(values, value));
32
- }, removeLabel: removeLabel(value) }, value))), _jsx("input", { "aria-invalid": errorText ? true : undefined, className: 'min-w-24 flex-1 bg-transparent text-sm font-semibold outline-none placeholder:font-medium placeholder:text-ink/45 disabled:cursor-not-allowed', disabled: isDisabled || isFull, name: name, onBlur: () => commit(draft), onChange: (event) => {
32
+ }, removeLabel: removeLabel(value) }, value))), _jsx("input", { "aria-invalid": errorText ? true : undefined, className: 'min-w-24 flex-1 bg-transparent text-sm font-semibold outline-none placeholder:font-medium placeholder:text-subtle disabled:cursor-not-allowed', disabled: isDisabled || isFull, name: name, onBlur: () => commit(draft), onChange: (event) => {
33
33
  const text = event.target.value;
34
34
  if (text.includes(PsTagInputConfig.separator))
35
35
  commit(text);
@@ -4,13 +4,14 @@ import { PsInputSizeClassNames } from '../constants/ps-input-size-class-names';
4
4
  import { PsDateInput } from './ps-date-input';
5
5
  import { PsFieldSkeleton } from './ps-field-skeleton';
6
6
  import { PsRequiredMark } from './ps-required-mark';
7
- export const PsTextInput = ({ className, defaultValue, disabled, helperText, hideLabel, isLoading = false, label, name, onChange, required, controlSize = 'default', type, value, ...props }) => {
7
+ import { PsSuggestedTag } from './ps-suggested-tag';
8
+ export const PsTextInput = ({ className, defaultValue, disabled, helperText, hideLabel, isLoading = false, isSuggested = false, label, name, onChange, required, suggestedLabel, controlSize = 'default', type, value, ...props }) => {
8
9
  if (isLoading)
9
10
  return _jsx(PsFieldSkeleton, { className: className, hideLabel: hideLabel, label: label });
10
11
  if (type === 'date') {
11
12
  return (_jsx(PsDateInput, { className: className, defaultValue: typeof defaultValue === 'string' ? defaultValue : undefined, disabled: disabled, helperText: helperText, hideLabel: hideLabel, label: label, name: name, onChange: (nextValue) => onChange?.({
12
13
  target: { name, value: nextValue },
13
- }), required: required, value: typeof value === 'string' ? value : undefined }));
14
+ }), isSuggested: isSuggested, required: required, suggestedLabel: suggestedLabel, value: typeof value === 'string' ? value : undefined }));
14
15
  }
15
- return (_jsxs("label", { className: 'block', children: [_jsxs("span", { className: hideLabel ? 'sr-only' : 'ps-input-label', children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsx("input", { className: PallasoftClassNameService.merge(hideLabel ? 'ps-input-control' : 'ps-input-control mt-2', PsInputSizeClassNames[controlSize], className), defaultValue: defaultValue, disabled: disabled, name: name, onChange: onChange, required: required, type: type, value: value, ...props }), helperText ? _jsx("span", { className: 'ps-input-helper', children: helperText }) : null] }));
16
+ return (_jsxs("label", { className: 'block', children: [_jsxs("span", { className: hideLabel ? 'sr-only' : 'ps-input-label', children: [label, _jsx(PsRequiredMark, { isRequired: required }), _jsx(PsSuggestedTag, { isSuggested: isSuggested, label: suggestedLabel })] }), _jsx("input", { className: PallasoftClassNameService.merge(hideLabel ? 'ps-input-control' : 'ps-input-control mt-2', PsInputSizeClassNames[controlSize], className), defaultValue: defaultValue, disabled: disabled, name: name, onChange: onChange, required: required, type: type, value: value, ...props }), helperText ? _jsx("span", { className: 'ps-input-helper', children: helperText }) : null] }));
16
17
  };
@@ -15,6 +15,6 @@ export const PsPortableTextEditorConfig = {
15
15
  code: 'rounded bg-ink/10 px-1 font-mono text-[0.9em]',
16
16
  link: 'text-primary underline',
17
17
  orderedList: 'list-decimal pl-6',
18
- placeholder: 'before:pointer-events-none before:float-left before:h-0 before:text-ink/45 before:content-[attr(data-placeholder)]',
18
+ placeholder: 'before:pointer-events-none before:float-left before:h-0 before:text-subtle before:content-[attr(data-placeholder)]',
19
19
  },
20
20
  };
@@ -3,4 +3,4 @@ import { Controller } from 'react-hook-form';
3
3
  import { PsCascaderInput } from '../../components/ps-cascader-input';
4
4
  import { PsFormControl } from '../../components/ps-form-control';
5
5
  import { PsFormFieldService } from '../services/ps-form-field-service';
6
- export const PsFormCascaderField = ({ control, disabled, groups, label, name, placeholder, rules, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => (_jsx(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: _jsx(PsCascaderInput, { disabled: disabled, groups: groups, label: label, onChange: field.onChange, placeholder: placeholder, value: PsFormFieldService.text(field.value) }) })), rules: rules }));
6
+ export const PsFormCascaderField = ({ control, disabled, groups, isSuggested, label, name, placeholder, rules, suggestedLabel, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => (_jsx(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: _jsx(PsCascaderInput, { disabled: disabled, groups: groups, isSuggested: isSuggested, label: label, onChange: field.onChange, placeholder: placeholder, suggestedLabel: suggestedLabel, value: PsFormFieldService.text(field.value) }) })), rules: rules }));
@@ -3,4 +3,4 @@ import { Controller } from 'react-hook-form';
3
3
  import { PsDateInput } from '../../components/ps-date-input';
4
4
  import { PsFormControl } from '../../components/ps-form-control';
5
5
  import { PsFormFieldService } from '../services/ps-form-field-service';
6
- export const PsFormDateField = ({ control, helperText, label, name, rules, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => (_jsx(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: _jsx(PsDateInput, { helperText: helperText, label: label, name: field.name, onChange: field.onChange, required: PsFormFieldService.isRequired(rules), value: PsFormFieldService.text(field.value) }) })), rules: rules }));
6
+ export const PsFormDateField = ({ control, helperText, isSuggested, label, name, rules, suggestedLabel, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => (_jsx(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: _jsx(PsDateInput, { helperText: helperText, isSuggested: isSuggested, label: label, name: field.name, onChange: field.onChange, required: PsFormFieldService.isRequired(rules), suggestedLabel: suggestedLabel, value: PsFormFieldService.text(field.value) }) })), rules: rules }));
@@ -3,7 +3,7 @@ import { Controller } from 'react-hook-form';
3
3
  import { PsAmountInput } from '../../components/ps-amount-input';
4
4
  import { PsFormControl } from '../../components/ps-form-control';
5
5
  import { PsFormFieldService } from '../services/ps-form-field-service';
6
- export const PsFormMoneyField = ({ control, label, name, normalize, placeholder, rules, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => (_jsx(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: _jsx(PsAmountInput, { className: 'text-right tabular-nums', label: label, name: field.name, onBlur: () => {
6
+ export const PsFormMoneyField = ({ control, isSuggested, label, name, normalize, placeholder, rules, suggestedLabel, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => (_jsx(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: _jsx(PsAmountInput, { className: 'text-right tabular-nums', isSuggested: isSuggested, label: label, name: field.name, onBlur: () => {
7
7
  if (normalize)
8
8
  field.onChange(normalize(PsFormFieldService.text(field.value)));
9
- }, onChange: field.onChange, placeholder: placeholder, required: PsFormFieldService.isRequired(rules), value: field.value }) })), rules: rules }));
9
+ }, onChange: field.onChange, placeholder: placeholder, required: PsFormFieldService.isRequired(rules), suggestedLabel: suggestedLabel, value: field.value }) })), rules: rules }));
@@ -3,8 +3,8 @@ import { Controller } from 'react-hook-form';
3
3
  import { PsFormControl } from '../../components/ps-form-control';
4
4
  import { PsSelectInput } from '../../components/ps-select-input';
5
5
  import { PsFormFieldService } from '../services/ps-form-field-service';
6
- export const PsFormSelectField = ({ control, helperText, label, name, onValueChange, options, placeholder, rules, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => (_jsx(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: _jsx(PsSelectInput, { helperText: helperText, label: label, name: field.name, onChange: (value) => {
6
+ export const PsFormSelectField = ({ control, helperText, isSuggested, label, name, onValueChange, options, placeholder, rules, suggestedLabel, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => (_jsx(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: _jsx(PsSelectInput, { helperText: helperText, isSuggested: isSuggested, label: label, name: field.name, onChange: (value) => {
7
7
  field.onChange(value);
8
8
  if (onValueChange)
9
9
  onValueChange(value);
10
- }, options: options, placeholder: placeholder, required: PsFormFieldService.isRequired(rules), value: PsFormFieldService.text(field.value) }) })), rules: rules }));
10
+ }, options: options, placeholder: placeholder, required: PsFormFieldService.isRequired(rules), suggestedLabel: suggestedLabel, value: PsFormFieldService.text(field.value) }) })), rules: rules }));
@@ -9,12 +9,13 @@ import { PsTextInput } from '../../components/ps-text-input';
9
9
  import { PsUrlInput } from '../../components/ps-url-input';
10
10
  import { PsFormTextKind } from '../constants/ps-form-text-kind';
11
11
  import { PsFormFieldService } from '../services/ps-form-field-service';
12
- export const PsFormTextField = ({ asNumber = false, autoComplete, className, control, country = '', disabled, helperText, inputMode, kind = PsFormTextKind.Text, label, maxLength, name, placeholder, rules, type, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => {
12
+ export const PsFormTextField = ({ asNumber = false, autoComplete, className, control, country = '', disabled, helperText, inputMode, isSuggested, kind = PsFormTextKind.Text, label, maxLength, name, placeholder, rules, suggestedLabel, type, }) => (_jsx(Controller, { control: control, name: name, render: ({ field, fieldState }) => {
13
13
  const shared = {
14
14
  autoComplete,
15
15
  className,
16
16
  disabled,
17
17
  helperText,
18
+ isSuggested,
18
19
  label,
19
20
  maxLength,
20
21
  name: field.name,
@@ -22,6 +23,7 @@ export const PsFormTextField = ({ asNumber = false, autoComplete, className, con
22
23
  onChange: (event) => field.onChange(asNumber ? PsFormFieldService.number(event.target.value) : event),
23
24
  placeholder,
24
25
  required: PsFormFieldService.isRequired(rules),
26
+ suggestedLabel,
25
27
  value: PsFormFieldService.text(field.value),
26
28
  };
27
29
  return (_jsxs(PsFormControl, { errorText: PsFormFieldService.error(fieldState.error), children: [kind === PsFormTextKind.Email ? _jsx(PsEmailInput, { ...shared }) : null, kind === PsFormTextKind.Url ? _jsx(PsUrlInput, { ...shared }) : null, kind === PsFormTextKind.Amount ? _jsx(PsAmountInput, { ...shared }) : null, kind === PsFormTextKind.Percent ? _jsx(PsPercentInput, { ...shared }) : null, kind === PsFormTextKind.PostalCode ? (_jsx(PsPostalCodeInput, { ...shared, country: country })) : null, kind === PsFormTextKind.Text ? (_jsx(PsTextInput, { ...shared, inputMode: inputMode, type: type })) : null] }));
package/dist/esm/index.js CHANGED
@@ -38,6 +38,8 @@ export * from './services/ps-postal-code-service';
38
38
  export * from './services/ps-select-option-service';
39
39
  export * from './services/ps-text-format-service';
40
40
  export * from './components/ps-required-mark';
41
+ export * from './components/ps-suggested-tag';
42
+ export * from './services/ps-suggested-tag-service';
41
43
  export * from './components/ps-year-input';
42
44
  export * from './constants/ps-year-input-config';
43
45
  export * from './services/ps-year-input-service';
@@ -0,0 +1,5 @@
1
+ export class PsSuggestedTagService {
2
+ static accessibleLabel(label, isSuggested, suggestedLabel) {
3
+ return isSuggested && suggestedLabel !== undefined ? `${label}, ${suggestedLabel}` : label;
4
+ }
5
+ }
@@ -5,9 +5,11 @@ export interface PsFormCascaderFieldProps<T extends FieldValues> {
5
5
  control: Control<T>;
6
6
  disabled?: boolean;
7
7
  groups: PsCascaderGroup[];
8
+ isSuggested?: boolean;
8
9
  label: string;
9
10
  name: Path<T>;
10
11
  placeholder?: string;
11
12
  rules?: PsFormFieldRules<T>;
13
+ suggestedLabel?: string;
12
14
  }
13
- export declare const PsFormCascaderField: <T extends FieldValues>({ control, disabled, groups, label, name, placeholder, rules, }: PsFormCascaderFieldProps<T>) => import("react").JSX.Element;
15
+ export declare const PsFormCascaderField: <T extends FieldValues>({ control, disabled, groups, isSuggested, label, name, placeholder, rules, suggestedLabel, }: PsFormCascaderFieldProps<T>) => import("react").JSX.Element;
@@ -6,5 +6,5 @@ const react_hook_form_1 = require("react-hook-form");
6
6
  const ps_cascader_input_1 = require("../../components/ps-cascader-input");
7
7
  const ps_form_control_1 = require("../../components/ps-form-control");
8
8
  const ps_form_field_service_1 = require("../services/ps-form-field-service");
9
- const PsFormCascaderField = ({ control, disabled, groups, label, name, placeholder, rules, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => ((0, jsx_runtime_1.jsx)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: (0, jsx_runtime_1.jsx)(ps_cascader_input_1.PsCascaderInput, { disabled: disabled, groups: groups, label: label, onChange: field.onChange, placeholder: placeholder, value: ps_form_field_service_1.PsFormFieldService.text(field.value) }) })), rules: rules }));
9
+ const PsFormCascaderField = ({ control, disabled, groups, isSuggested, label, name, placeholder, rules, suggestedLabel, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => ((0, jsx_runtime_1.jsx)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: (0, jsx_runtime_1.jsx)(ps_cascader_input_1.PsCascaderInput, { disabled: disabled, groups: groups, isSuggested: isSuggested, label: label, onChange: field.onChange, placeholder: placeholder, suggestedLabel: suggestedLabel, value: ps_form_field_service_1.PsFormFieldService.text(field.value) }) })), rules: rules }));
10
10
  exports.PsFormCascaderField = PsFormCascaderField;
@@ -3,8 +3,10 @@ import type { PsFormFieldRules } from '../models/ps-form-field-rules';
3
3
  export interface PsFormDateFieldProps<T extends FieldValues> {
4
4
  control: Control<T>;
5
5
  helperText?: string;
6
+ isSuggested?: boolean;
6
7
  label: string;
7
8
  name: Path<T>;
8
9
  rules?: PsFormFieldRules<T>;
10
+ suggestedLabel?: string;
9
11
  }
10
- export declare const PsFormDateField: <T extends FieldValues>({ control, helperText, label, name, rules, }: PsFormDateFieldProps<T>) => import("react").JSX.Element;
12
+ export declare const PsFormDateField: <T extends FieldValues>({ control, helperText, isSuggested, label, name, rules, suggestedLabel, }: PsFormDateFieldProps<T>) => import("react").JSX.Element;
@@ -6,5 +6,5 @@ const react_hook_form_1 = require("react-hook-form");
6
6
  const ps_date_input_1 = require("../../components/ps-date-input");
7
7
  const ps_form_control_1 = require("../../components/ps-form-control");
8
8
  const ps_form_field_service_1 = require("../services/ps-form-field-service");
9
- const PsFormDateField = ({ control, helperText, label, name, rules, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => ((0, jsx_runtime_1.jsx)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: (0, jsx_runtime_1.jsx)(ps_date_input_1.PsDateInput, { helperText: helperText, label: label, name: field.name, onChange: field.onChange, required: ps_form_field_service_1.PsFormFieldService.isRequired(rules), value: ps_form_field_service_1.PsFormFieldService.text(field.value) }) })), rules: rules }));
9
+ const PsFormDateField = ({ control, helperText, isSuggested, label, name, rules, suggestedLabel, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => ((0, jsx_runtime_1.jsx)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: (0, jsx_runtime_1.jsx)(ps_date_input_1.PsDateInput, { helperText: helperText, isSuggested: isSuggested, label: label, name: field.name, onChange: field.onChange, required: ps_form_field_service_1.PsFormFieldService.isRequired(rules), suggestedLabel: suggestedLabel, value: ps_form_field_service_1.PsFormFieldService.text(field.value) }) })), rules: rules }));
10
10
  exports.PsFormDateField = PsFormDateField;
@@ -2,10 +2,12 @@ import { type Control, type FieldValues, type Path } from 'react-hook-form';
2
2
  import type { PsFormFieldRules } from '../models/ps-form-field-rules';
3
3
  export interface PsFormMoneyFieldProps<T extends FieldValues> {
4
4
  control: Control<T>;
5
+ isSuggested?: boolean;
5
6
  label: string;
6
7
  name: Path<T>;
7
8
  normalize?: (value: string) => string;
8
9
  placeholder?: string;
9
10
  rules?: PsFormFieldRules<T>;
11
+ suggestedLabel?: string;
10
12
  }
11
- export declare const PsFormMoneyField: <T extends FieldValues>({ control, label, name, normalize, placeholder, rules, }: PsFormMoneyFieldProps<T>) => import("react").JSX.Element;
13
+ export declare const PsFormMoneyField: <T extends FieldValues>({ control, isSuggested, label, name, normalize, placeholder, rules, suggestedLabel, }: PsFormMoneyFieldProps<T>) => import("react").JSX.Element;
@@ -6,8 +6,8 @@ const react_hook_form_1 = require("react-hook-form");
6
6
  const ps_amount_input_1 = require("../../components/ps-amount-input");
7
7
  const ps_form_control_1 = require("../../components/ps-form-control");
8
8
  const ps_form_field_service_1 = require("../services/ps-form-field-service");
9
- const PsFormMoneyField = ({ control, label, name, normalize, placeholder, rules, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => ((0, jsx_runtime_1.jsx)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: (0, jsx_runtime_1.jsx)(ps_amount_input_1.PsAmountInput, { className: 'text-right tabular-nums', label: label, name: field.name, onBlur: () => {
9
+ const PsFormMoneyField = ({ control, isSuggested, label, name, normalize, placeholder, rules, suggestedLabel, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => ((0, jsx_runtime_1.jsx)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: (0, jsx_runtime_1.jsx)(ps_amount_input_1.PsAmountInput, { className: 'text-right tabular-nums', isSuggested: isSuggested, label: label, name: field.name, onBlur: () => {
10
10
  if (normalize)
11
11
  field.onChange(normalize(ps_form_field_service_1.PsFormFieldService.text(field.value)));
12
- }, onChange: field.onChange, placeholder: placeholder, required: ps_form_field_service_1.PsFormFieldService.isRequired(rules), value: field.value }) })), rules: rules }));
12
+ }, onChange: field.onChange, placeholder: placeholder, required: ps_form_field_service_1.PsFormFieldService.isRequired(rules), suggestedLabel: suggestedLabel, value: field.value }) })), rules: rules }));
13
13
  exports.PsFormMoneyField = PsFormMoneyField;
@@ -4,11 +4,13 @@ import type { PsFormFieldRules } from '../models/ps-form-field-rules';
4
4
  export interface PsFormSelectFieldProps<T extends FieldValues> {
5
5
  control: Control<T>;
6
6
  helperText?: string;
7
+ isSuggested?: boolean;
7
8
  label: string;
8
9
  name: Path<T>;
9
10
  onValueChange?: (value: string) => void;
10
11
  options: PsSelectOption[];
11
12
  placeholder?: string;
12
13
  rules?: PsFormFieldRules<T>;
14
+ suggestedLabel?: string;
13
15
  }
14
- export declare const PsFormSelectField: <T extends FieldValues>({ control, helperText, label, name, onValueChange, options, placeholder, rules, }: PsFormSelectFieldProps<T>) => import("react").JSX.Element;
16
+ export declare const PsFormSelectField: <T extends FieldValues>({ control, helperText, isSuggested, label, name, onValueChange, options, placeholder, rules, suggestedLabel, }: PsFormSelectFieldProps<T>) => import("react").JSX.Element;
@@ -6,9 +6,9 @@ const react_hook_form_1 = require("react-hook-form");
6
6
  const ps_form_control_1 = require("../../components/ps-form-control");
7
7
  const ps_select_input_1 = require("../../components/ps-select-input");
8
8
  const ps_form_field_service_1 = require("../services/ps-form-field-service");
9
- const PsFormSelectField = ({ control, helperText, label, name, onValueChange, options, placeholder, rules, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => ((0, jsx_runtime_1.jsx)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: (0, jsx_runtime_1.jsx)(ps_select_input_1.PsSelectInput, { helperText: helperText, label: label, name: field.name, onChange: (value) => {
9
+ const PsFormSelectField = ({ control, helperText, isSuggested, label, name, onValueChange, options, placeholder, rules, suggestedLabel, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => ((0, jsx_runtime_1.jsx)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: (0, jsx_runtime_1.jsx)(ps_select_input_1.PsSelectInput, { helperText: helperText, isSuggested: isSuggested, label: label, name: field.name, onChange: (value) => {
10
10
  field.onChange(value);
11
11
  if (onValueChange)
12
12
  onValueChange(value);
13
- }, options: options, placeholder: placeholder, required: ps_form_field_service_1.PsFormFieldService.isRequired(rules), value: ps_form_field_service_1.PsFormFieldService.text(field.value) }) })), rules: rules }));
13
+ }, options: options, placeholder: placeholder, required: ps_form_field_service_1.PsFormFieldService.isRequired(rules), suggestedLabel: suggestedLabel, value: ps_form_field_service_1.PsFormFieldService.text(field.value) }) })), rules: rules }));
14
14
  exports.PsFormSelectField = PsFormSelectField;
@@ -11,12 +11,14 @@ export interface PsFormTextFieldProps<T extends FieldValues> {
11
11
  disabled?: boolean;
12
12
  helperText?: string;
13
13
  inputMode?: HTMLAttributes<HTMLInputElement>['inputMode'];
14
+ isSuggested?: boolean;
14
15
  kind?: PsFormTextKind;
15
16
  label: string;
16
17
  maxLength?: number;
17
18
  name: Path<T>;
18
19
  placeholder?: string;
19
20
  rules?: PsFormFieldRules<T>;
21
+ suggestedLabel?: string;
20
22
  type?: string;
21
23
  }
22
- export declare const PsFormTextField: <T extends FieldValues>({ asNumber, autoComplete, className, control, country, disabled, helperText, inputMode, kind, label, maxLength, name, placeholder, rules, type, }: PsFormTextFieldProps<T>) => import("react").JSX.Element;
24
+ export declare const PsFormTextField: <T extends FieldValues>({ asNumber, autoComplete, className, control, country, disabled, helperText, inputMode, isSuggested, kind, label, maxLength, name, placeholder, rules, suggestedLabel, type, }: PsFormTextFieldProps<T>) => import("react").JSX.Element;
@@ -12,12 +12,13 @@ const ps_text_input_1 = require("../../components/ps-text-input");
12
12
  const ps_url_input_1 = require("../../components/ps-url-input");
13
13
  const ps_form_text_kind_1 = require("../constants/ps-form-text-kind");
14
14
  const ps_form_field_service_1 = require("../services/ps-form-field-service");
15
- const PsFormTextField = ({ asNumber = false, autoComplete, className, control, country = '', disabled, helperText, inputMode, kind = ps_form_text_kind_1.PsFormTextKind.Text, label, maxLength, name, placeholder, rules, type, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => {
15
+ const PsFormTextField = ({ asNumber = false, autoComplete, className, control, country = '', disabled, helperText, inputMode, isSuggested, kind = ps_form_text_kind_1.PsFormTextKind.Text, label, maxLength, name, placeholder, rules, suggestedLabel, type, }) => ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, render: ({ field, fieldState }) => {
16
16
  const shared = {
17
17
  autoComplete,
18
18
  className,
19
19
  disabled,
20
20
  helperText,
21
+ isSuggested,
21
22
  label,
22
23
  maxLength,
23
24
  name: field.name,
@@ -25,6 +26,7 @@ const PsFormTextField = ({ asNumber = false, autoComplete, className, control, c
25
26
  onChange: (event) => field.onChange(asNumber ? ps_form_field_service_1.PsFormFieldService.number(event.target.value) : event),
26
27
  placeholder,
27
28
  required: ps_form_field_service_1.PsFormFieldService.isRequired(rules),
29
+ suggestedLabel,
28
30
  value: ps_form_field_service_1.PsFormFieldService.text(field.value),
29
31
  };
30
32
  return ((0, jsx_runtime_1.jsxs)(ps_form_control_1.PsFormControl, { errorText: ps_form_field_service_1.PsFormFieldService.error(fieldState.error), children: [kind === ps_form_text_kind_1.PsFormTextKind.Email ? (0, jsx_runtime_1.jsx)(ps_email_input_1.PsEmailInput, { ...shared }) : null, kind === ps_form_text_kind_1.PsFormTextKind.Url ? (0, jsx_runtime_1.jsx)(ps_url_input_1.PsUrlInput, { ...shared }) : null, kind === ps_form_text_kind_1.PsFormTextKind.Amount ? (0, jsx_runtime_1.jsx)(ps_amount_input_1.PsAmountInput, { ...shared }) : null, kind === ps_form_text_kind_1.PsFormTextKind.Percent ? (0, jsx_runtime_1.jsx)(ps_percent_input_1.PsPercentInput, { ...shared }) : null, kind === ps_form_text_kind_1.PsFormTextKind.PostalCode ? ((0, jsx_runtime_1.jsx)(ps_postal_code_input_1.PsPostalCodeInput, { ...shared, country: country })) : null, kind === ps_form_text_kind_1.PsFormTextKind.Text ? ((0, jsx_runtime_1.jsx)(ps_text_input_1.PsTextInput, { ...shared, inputMode: inputMode, type: type })) : null] }));
package/dist/index.d.ts CHANGED
@@ -38,6 +38,8 @@ export * from './services/ps-postal-code-service';
38
38
  export * from './services/ps-select-option-service';
39
39
  export * from './services/ps-text-format-service';
40
40
  export * from './components/ps-required-mark';
41
+ export * from './components/ps-suggested-tag';
42
+ export * from './services/ps-suggested-tag-service';
41
43
  export * from './components/ps-year-input';
42
44
  export * from './constants/ps-year-input-config';
43
45
  export * from './services/ps-year-input-service';
package/dist/index.js CHANGED
@@ -54,6 +54,8 @@ __exportStar(require("./services/ps-postal-code-service"), exports);
54
54
  __exportStar(require("./services/ps-select-option-service"), exports);
55
55
  __exportStar(require("./services/ps-text-format-service"), exports);
56
56
  __exportStar(require("./components/ps-required-mark"), exports);
57
+ __exportStar(require("./components/ps-suggested-tag"), exports);
58
+ __exportStar(require("./services/ps-suggested-tag-service"), exports);
57
59
  __exportStar(require("./components/ps-year-input"), exports);
58
60
  __exportStar(require("./constants/ps-year-input-config"), exports);
59
61
  __exportStar(require("./services/ps-year-input-service"), exports);
@@ -0,0 +1,3 @@
1
+ export declare class PsSuggestedTagService {
2
+ static accessibleLabel(label: string, isSuggested: boolean, suggestedLabel: string | undefined): string;
3
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSuggestedTagService = void 0;
4
+ class PsSuggestedTagService {
5
+ static accessibleLabel(label, isSuggested, suggestedLabel) {
6
+ return isSuggested && suggestedLabel !== undefined ? `${label}, ${suggestedLabel}` : label;
7
+ }
8
+ }
9
+ exports.PsSuggestedTagService = PsSuggestedTagService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-input-components",
3
- "version": "3.9.1",
3
+ "version": "3.10.0",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",