@pallasoft/ps-input-components 3.7.1 → 3.7.3

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.
@@ -20,21 +20,11 @@ const PsCascaderInput = ({ className, disabled, groups, helperText, hideLabel, i
20
20
  const [activeGroupKey, setActiveGroupKey] = (0, react_1.useState)(null);
21
21
  const selected = (0, react_1.useMemo)(() => ps_cascader_service_1.PsCascaderService.findSelected(groups, value), [groups, value]);
22
22
  const matches = (0, react_1.useMemo)(() => ps_cascader_service_1.PsCascaderService.search(groups, query), [groups, query]);
23
- const activeGroup = (0, react_1.useMemo)(() => {
24
- const preferred = preferredGroupKey !== undefined && groups.some((group) => group.key === preferredGroupKey)
25
- ? preferredGroupKey
26
- : null;
27
- const key = activeGroupKey
28
- ? activeGroupKey
29
- : preferred !== null
30
- ? preferred
31
- : selected
32
- ? selected.group.key
33
- : groups.length > 0
34
- ? groups[0].key
35
- : null;
36
- return groups.find((group) => group.key === key) ?? null;
37
- }, [activeGroupKey, groups, preferredGroupKey, selected]);
23
+ const activeGroup = (0, react_1.useMemo)(() => ps_cascader_service_1.PsCascaderService.openGroup(groups, [
24
+ activeGroupKey,
25
+ preferredGroupKey === undefined ? null : preferredGroupKey,
26
+ selected ? selected.group.key : null,
27
+ ]), [activeGroupKey, groups, preferredGroupKey, selected]);
38
28
  const open = (nextOpen) => {
39
29
  setIsOpen(nextOpen);
40
30
  if (!nextOpen)
@@ -51,10 +41,19 @@ const PsCascaderInput = ({ className, disabled, groups, helperText, hideLabel, i
51
41
  : option.value === value
52
42
  ? 'bg-primary/10 text-ink'
53
43
  : 'text-ink/80 hover:bg-mist/60 hover:text-ink'), disabled: option.isDisabled, onClick: () => select(option.value, close), role: 'option', type: 'button', children: [(0, jsx_runtime_1.jsx)("span", { className: 'flex h-5 w-4 shrink-0 items-center justify-center text-primary', children: option.value === value ? ((0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4', iconKey: ps_icons_1.PsIconKey.Check })) : null }), (0, jsx_runtime_1.jsxs)("span", { className: 'min-w-0 flex-1', children: [(0, jsx_runtime_1.jsx)("span", { className: 'block break-words', children: option.label }), groupLabel ? ((0, jsx_runtime_1.jsx)("span", { className: 'mt-0.5 block break-words text-xs font-normal text-ink/50', children: groupLabel })) : null, option.description ? ((0, jsx_runtime_1.jsx)("span", { className: 'mt-0.5 block break-words text-xs font-normal text-ink/55', children: option.description })) : null] })] }, option.value));
54
- return ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('block', className), children: [hideLabel ? null : ((0, jsx_runtime_1.jsxs)("span", { className: 'ps-input-label block', children: [label, (0, jsx_runtime_1.jsx)(ps_required_mark_1.PsRequiredMark, { isRequired: required })] })), (0, jsx_runtime_1.jsxs)(react_aria_components_1.DialogTrigger, { isOpen: isOpen, onOpenChange: open, children: [(0, jsx_runtime_1.jsxs)(react_aria_components_1.Button, { "aria-label": hideLabel ? label : undefined, className: ps_design_system_1.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', isSuggested ? 'border-dashed border-primary/60 bg-primary/5' : ''), isDisabled: disabled, children: [(0, jsx_runtime_1.jsx)("span", { className: 'min-w-0 flex-1 truncate', children: selected ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: 'truncate', children: selected.option.label }), (0, jsx_runtime_1.jsx)("span", { className: 'ml-2 text-xs font-medium text-ink/45', children: selected.group.label })] })) : ((0, jsx_runtime_1.jsx)("span", { className: 'font-medium text-ink/45', children: placeholder })) }), (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2 text-primary', iconKey: ps_icons_1.PsIconKey.Chevron })] }), (0, jsx_runtime_1.jsx)(react_aria_components_1.Popover, { className: 'ps-floating-panel w-[min(calc(100vw-2rem),32rem)] min-w-[var(--trigger-width)] outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: (0, jsx_runtime_1.jsx)(react_aria_components_1.Dialog, { "aria-label": label, className: 'flex flex-col outline-none', children: ({ close }) => ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: groups.length === 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-col gap-1 px-4 py-8 text-center', children: [(0, jsx_runtime_1.jsx)("p", { className: 'text-sm font-semibold text-ink', children: ps_cascader_config_1.PsCascaderConfig.emptyLabel }), (0, jsx_runtime_1.jsx)("p", { className: 'text-xs text-ink/55', children: ps_cascader_config_1.PsCascaderConfig.emptyDescription })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: 'border-b border-line p-2', children: (0, jsx_runtime_1.jsx)("input", { "aria-label": searchPlaceholder, autoFocus: true, className: 'ps-input-control ps-control-compact ps-focus-ring w-full text-sm', onChange: (event) => setQuery(event.target.value), placeholder: searchPlaceholder, type: 'search', value: query }) }), query.trim() === '' ? ((0, jsx_runtime_1.jsxs)("div", { className: 'grid grid-cols-1 sm:grid-cols-[minmax(0,11rem)_minmax(0,1fr)]', children: [(0, jsx_runtime_1.jsx)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5 sm:border-r sm:border-line', activeGroupKey && groups.length > 1 ? 'hidden sm:block' : ''), children: groups.map((group) => ((0, jsx_runtime_1.jsxs)("button", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center gap-2 rounded-ps-control px-3 py-2.5 text-left text-sm font-semibold transition-colors', activeGroup?.key === group.key
55
- ? 'bg-mist text-ink'
56
- : 'text-ink/70 hover:bg-mist/60 hover:text-ink'), onClick: () => setActiveGroupKey(group.key), type: 'button', children: [(0, jsx_runtime_1.jsx)("span", { className: 'min-w-0 flex-1 truncate', children: group.label }), (0, jsx_runtime_1.jsx)("span", { className: 'text-xs font-medium text-ink/45', children: group.options.length }), (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 shrink-0 -rotate-90 text-ink/35', iconKey: ps_icons_1.PsIconKey.Chevron })] }, group.key))) }), (0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5', activeGroupKey && groups.length > 1 ? '' : 'hidden sm:block'), role: 'listbox', children: [groups.length > 1 ? ((0, jsx_runtime_1.jsxs)("button", { className: 'ps-focus-ring mb-1 flex w-full items-center gap-2 rounded-ps-control px-3 py-2 text-left text-xs font-semibold text-ink/60 hover:text-ink sm:hidden', onClick: () => setActiveGroupKey(null), type: 'button', children: [(0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 rotate-90', iconKey: ps_icons_1.PsIconKey.Chevron }), "All groups"] })) : null, activeGroup
44
+ return ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('block', className), children: [hideLabel ? null : ((0, jsx_runtime_1.jsxs)("span", { className: 'ps-input-label block', children: [label, (0, jsx_runtime_1.jsx)(ps_required_mark_1.PsRequiredMark, { isRequired: required })] })), (0, jsx_runtime_1.jsxs)(react_aria_components_1.DialogTrigger, { isOpen: isOpen, onOpenChange: open, children: [(0, jsx_runtime_1.jsxs)(react_aria_components_1.Button, { "aria-label": hideLabel ? label : undefined, className: ps_design_system_1.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', isSuggested ? 'border-dashed border-primary/60 bg-primary/5' : ''), isDisabled: disabled, children: [(0, jsx_runtime_1.jsx)("span", { className: 'min-w-0 flex-1 truncate', children: selected ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: 'truncate', children: selected.option.label }), ps_cascader_service_1.PsCascaderService.groupLabelFor(selected) === null ? null : ((0, jsx_runtime_1.jsx)("span", { className: 'ml-2 text-xs font-medium text-ink/45', children: selected.group.label }))] })) : ((0, jsx_runtime_1.jsx)("span", { className: 'font-medium text-ink/45', children: placeholder })) }), (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2 text-primary', iconKey: ps_icons_1.PsIconKey.Chevron })] }), (0, jsx_runtime_1.jsx)(react_aria_components_1.Popover, { className: 'ps-floating-panel w-[min(calc(100vw-2rem),32rem)] min-w-[var(--trigger-width)] outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: (0, jsx_runtime_1.jsx)(react_aria_components_1.Dialog, { "aria-label": label, className: 'flex flex-col outline-none', children: ({ close }) => ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: groups.length === 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-col gap-1 px-4 py-8 text-center', children: [(0, jsx_runtime_1.jsx)("p", { className: 'text-sm font-semibold text-ink', children: ps_cascader_config_1.PsCascaderConfig.emptyLabel }), (0, jsx_runtime_1.jsx)("p", { className: 'text-xs text-ink/55', children: ps_cascader_config_1.PsCascaderConfig.emptyDescription })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: 'border-b border-line p-2', children: (0, jsx_runtime_1.jsx)("input", { "aria-label": searchPlaceholder, autoFocus: true, className: 'ps-input-control ps-control-compact ps-focus-ring w-full text-sm', onChange: (event) => setQuery(event.target.value), placeholder: searchPlaceholder, type: 'search', value: query }) }), query.trim() === '' ? ((0, jsx_runtime_1.jsxs)("div", { className: 'grid grid-cols-1 sm:grid-cols-[minmax(0,11rem)_minmax(0,1fr)]', children: [(0, jsx_runtime_1.jsx)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5 sm:border-r sm:border-line', activeGroupKey && groups.length > 1 ? 'hidden sm:block' : ''), children: groups.map((group) => {
45
+ const direct = ps_cascader_service_1.PsCascaderService.directOption(group);
46
+ if (direct !== null)
47
+ return ((0, jsx_runtime_1.jsxs)("button", { "aria-selected": direct.value === value, className: ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center gap-2 rounded-ps-control px-3 py-2.5 text-left text-sm font-semibold transition-colors', direct.isDisabled
48
+ ? 'cursor-not-allowed text-ink/40'
49
+ : direct.value === value
50
+ ? 'bg-primary/10 text-ink'
51
+ : 'text-ink/70 hover:bg-mist/60 hover:text-ink'), disabled: direct.isDisabled, onClick: () => select(direct.value, close), role: 'option', type: 'button', children: [(0, jsx_runtime_1.jsx)("span", { className: 'min-w-0 flex-1 truncate', children: direct.label }), direct.value === value ? ((0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 shrink-0 text-primary', iconKey: ps_icons_1.PsIconKey.Check })) : null] }, group.key));
52
+ return ((0, jsx_runtime_1.jsxs)("button", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center gap-2 rounded-ps-control px-3 py-2.5 text-left text-sm font-semibold transition-colors', activeGroup?.key === group.key
53
+ ? 'bg-mist text-ink'
54
+ : 'text-ink/70 hover:bg-mist/60 hover:text-ink'), onClick: () => setActiveGroupKey(group.key), type: 'button', children: [(0, jsx_runtime_1.jsx)("span", { className: 'min-w-0 flex-1 truncate', children: group.label }), (0, jsx_runtime_1.jsx)("span", { className: 'text-xs font-medium text-ink/45', children: group.options.length }), (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 shrink-0 -rotate-90 text-ink/35', iconKey: ps_icons_1.PsIconKey.Chevron })] }, group.key));
55
+ }) }), (0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5', activeGroupKey && groups.length > 1 ? '' : 'hidden sm:block'), role: 'listbox', children: [groups.length > 1 ? ((0, jsx_runtime_1.jsxs)("button", { className: 'ps-focus-ring mb-1 flex w-full items-center gap-2 rounded-ps-control px-3 py-2 text-left text-xs font-semibold text-ink/60 hover:text-ink sm:hidden', onClick: () => setActiveGroupKey(null), type: 'button', children: [(0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 rotate-90', iconKey: ps_icons_1.PsIconKey.Chevron }), "All groups"] })) : null, activeGroup
57
56
  ? activeGroup.options.map((option) => renderOption(option, null, close))
58
- : null] })] })) : ((0, jsx_runtime_1.jsx)("div", { className: 'ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? ((0, jsx_runtime_1.jsx)("p", { className: 'px-3 py-6 text-center text-sm text-ink/55', children: ps_cascader_config_1.PsCascaderConfig.noMatchesLabel })) : (matches.map((match) => renderOption(match.option, match.group.label, close))) }))] })) })) }) })] }), helperText ? (0, jsx_runtime_1.jsx)("span", { className: 'ps-input-helper mt-2 block', children: helperText }) : null] }));
57
+ : null] })] })) : ((0, jsx_runtime_1.jsx)("div", { className: 'ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? ((0, jsx_runtime_1.jsx)("p", { className: 'px-3 py-6 text-center text-sm text-ink/55', children: ps_cascader_config_1.PsCascaderConfig.noMatchesLabel })) : (matches.map((match) => renderOption(match.option, ps_cascader_service_1.PsCascaderService.groupLabelFor(match), close))) }))] })) })) }) })] }), helperText ? (0, jsx_runtime_1.jsx)("span", { className: 'ps-input-helper mt-2 block', children: helperText }) : null] }));
59
58
  };
60
59
  exports.PsCascaderInput = PsCascaderInput;
@@ -37,7 +37,7 @@ const PsPhoneInput = ({ className, defaultCountry = ps_phone_input_config_1.PsPh
37
37
  emit(national, code);
38
38
  document.getElementById(inputId)?.focus();
39
39
  };
40
- return ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('block', className), children: [(0, jsx_runtime_1.jsxs)("label", { className: hideLabel ? 'sr-only' : 'ps-input-label', htmlFor: inputId, children: [label, (0, jsx_runtime_1.jsx)(ps_required_mark_1.PsRequiredMark, { isRequired: required })] }), (0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-input-control flex items-stretch overflow-hidden p-0 focus-within:border-primary has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-primary', hideLabel ? '' : 'mt-2', isInvalid ? 'border-danger bg-danger/5' : '', disabled ? 'opacity-60' : ''), children: [(0, jsx_runtime_1.jsxs)(react_aria_components_1.DialogTrigger, { isOpen: isOpen, onOpenChange: setIsOpen, children: [(0, jsx_runtime_1.jsxs)(react_aria_components_1.Button, { "aria-label": ps_phone_input_config_1.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, (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'block h-3.5 w-3.5 text-ink/45', iconKey: ps_icons_1.PsIconKey.Chevron })] }), (0, jsx_runtime_1.jsx)(react_aria_components_1.Popover, { className: 'ps-floating-panel w-72 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: (0, jsx_runtime_1.jsxs)(react_aria_components_1.Dialog, { "aria-label": ps_phone_input_config_1.PsPhoneInputConfig.countryLabel, className: 'flex flex-col outline-none', children: [(0, jsx_runtime_1.jsx)("div", { className: 'border-b border-line p-2', children: (0, jsx_runtime_1.jsx)("input", { "aria-label": ps_phone_input_config_1.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: ps_phone_input_config_1.PsPhoneInputConfig.searchPlaceholder, type: 'search', value: query }) }), (0, jsx_runtime_1.jsx)("ul", { className: 'ps-scrollbar-hidden max-h-64 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? ((0, jsx_runtime_1.jsx)("li", { className: 'px-3 py-2.5 text-sm text-ink/50', children: ps_phone_input_config_1.PsPhoneInputConfig.emptyMessage })) : (matches.map((option) => ((0, jsx_runtime_1.jsx)("li", { role: 'none', children: (0, jsx_runtime_1.jsxs)("button", { "aria-selected": option.code === country, className: ps_design_system_1.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
40
+ return ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('block', className), children: [(0, jsx_runtime_1.jsxs)("label", { className: hideLabel ? 'sr-only' : 'ps-input-label', htmlFor: inputId, children: [label, (0, jsx_runtime_1.jsx)(ps_required_mark_1.PsRequiredMark, { isRequired: required })] }), (0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.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: [(0, jsx_runtime_1.jsxs)(react_aria_components_1.DialogTrigger, { isOpen: isOpen, onOpenChange: setIsOpen, children: [(0, jsx_runtime_1.jsxs)(react_aria_components_1.Button, { "aria-label": ps_phone_input_config_1.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, (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'block h-3.5 w-3.5 text-ink/45', iconKey: ps_icons_1.PsIconKey.Chevron })] }), (0, jsx_runtime_1.jsx)(react_aria_components_1.Popover, { className: 'ps-floating-panel w-72 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: (0, jsx_runtime_1.jsxs)(react_aria_components_1.Dialog, { "aria-label": ps_phone_input_config_1.PsPhoneInputConfig.countryLabel, className: 'flex flex-col outline-none', children: [(0, jsx_runtime_1.jsx)("div", { className: 'border-b border-line p-2', children: (0, jsx_runtime_1.jsx)("input", { "aria-label": ps_phone_input_config_1.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: ps_phone_input_config_1.PsPhoneInputConfig.searchPlaceholder, type: 'search', value: query }) }), (0, jsx_runtime_1.jsx)("ul", { className: 'ps-scrollbar-hidden max-h-64 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? ((0, jsx_runtime_1.jsx)("li", { className: 'px-3 py-2.5 text-sm text-ink/50', children: ps_phone_input_config_1.PsPhoneInputConfig.emptyMessage })) : (matches.map((option) => ((0, jsx_runtime_1.jsx)("li", { role: 'none', children: (0, jsx_runtime_1.jsxs)("button", { "aria-selected": option.code === country, className: ps_design_system_1.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
41
41
  ? 'bg-primary/10 text-ink'
42
42
  : 'text-ink/80 hover:bg-mist/60 hover:text-ink'), onClick: () => choose(option.code), role: 'option', type: 'button', children: [(0, jsx_runtime_1.jsx)("span", { className: 'min-w-0 truncate', children: ps_phone_input_service_1.PsPhoneInputService.highlight(option.label, query).map((part, index) => part.isMatch ? ((0, jsx_runtime_1.jsx)("strong", { className: 'font-semibold text-ink', children: part.text }, index)) : ((0, jsx_runtime_1.jsx)("span", { children: part.text }, index))) }), (0, jsx_runtime_1.jsxs)("span", { className: 'shrink-0 text-xs text-ink/50', children: ["+", option.callingCode] })] }) }, option.code)))) })] }) })] }), (0, jsx_runtime_1.jsxs)("span", { "aria-hidden": 'true', className: 'flex items-center pl-3 text-sm text-ink/45', children: [ps_phone_input_config_1.PsPhoneInputConfig.plus, ps_phone_input_service_1.PsPhoneInputService.callingCode(country)] }), (0, jsx_runtime_1.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: () => {
43
43
  setIsTouched(true);
@@ -17,21 +17,11 @@ export const PsCascaderInput = ({ className, disabled, groups, helperText, hideL
17
17
  const [activeGroupKey, setActiveGroupKey] = useState(null);
18
18
  const selected = useMemo(() => PsCascaderService.findSelected(groups, value), [groups, value]);
19
19
  const matches = useMemo(() => PsCascaderService.search(groups, query), [groups, query]);
20
- const activeGroup = useMemo(() => {
21
- const preferred = preferredGroupKey !== undefined && groups.some((group) => group.key === preferredGroupKey)
22
- ? preferredGroupKey
23
- : null;
24
- const key = activeGroupKey
25
- ? activeGroupKey
26
- : preferred !== null
27
- ? preferred
28
- : selected
29
- ? selected.group.key
30
- : groups.length > 0
31
- ? groups[0].key
32
- : null;
33
- return groups.find((group) => group.key === key) ?? null;
34
- }, [activeGroupKey, groups, preferredGroupKey, selected]);
20
+ const activeGroup = useMemo(() => PsCascaderService.openGroup(groups, [
21
+ activeGroupKey,
22
+ preferredGroupKey === undefined ? null : preferredGroupKey,
23
+ selected ? selected.group.key : null,
24
+ ]), [activeGroupKey, groups, preferredGroupKey, selected]);
35
25
  const open = (nextOpen) => {
36
26
  setIsOpen(nextOpen);
37
27
  if (!nextOpen)
@@ -48,9 +38,18 @@ export const PsCascaderInput = ({ className, disabled, groups, helperText, hideL
48
38
  : option.value === value
49
39
  ? 'bg-primary/10 text-ink'
50
40
  : 'text-ink/80 hover:bg-mist/60 hover:text-ink'), disabled: option.isDisabled, onClick: () => select(option.value, close), role: 'option', type: 'button', children: [_jsx("span", { className: 'flex h-5 w-4 shrink-0 items-center justify-center text-primary', children: option.value === value ? (_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 break-words', children: option.label }), groupLabel ? (_jsx("span", { className: 'mt-0.5 block break-words text-xs font-normal text-ink/50', children: groupLabel })) : null, option.description ? (_jsx("span", { className: 'mt-0.5 block break-words text-xs font-normal text-ink/55', children: option.description })) : null] })] }, option.value));
51
- return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [hideLabel ? null : (_jsxs("span", { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(DialogTrigger, { isOpen: isOpen, onOpenChange: open, children: [_jsxs(Button, { "aria-label": hideLabel ? label : undefined, 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', isSuggested ? 'border-dashed border-primary/60 bg-primary/5' : ''), isDisabled: disabled, children: [_jsx("span", { className: 'min-w-0 flex-1 truncate', children: selected ? (_jsxs(_Fragment, { children: [_jsx("span", { className: 'truncate', children: selected.option.label }), _jsx("span", { className: 'ml-2 text-xs font-medium text-ink/45', children: selected.group.label })] })) : (_jsx("span", { className: 'font-medium text-ink/45', children: placeholder })) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), _jsx(Popover, { className: 'ps-floating-panel w-[min(calc(100vw-2rem),32rem)] min-w-[var(--trigger-width)] outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(Dialog, { "aria-label": label, className: 'flex flex-col outline-none', children: ({ close }) => (_jsx(_Fragment, { children: groups.length === 0 ? (_jsxs("div", { className: 'flex flex-col gap-1 px-4 py-8 text-center', children: [_jsx("p", { className: 'text-sm font-semibold text-ink', children: PsCascaderConfig.emptyLabel }), _jsx("p", { className: 'text-xs text-ink/55', children: PsCascaderConfig.emptyDescription })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: 'border-b border-line p-2', children: _jsx("input", { "aria-label": searchPlaceholder, autoFocus: true, className: 'ps-input-control ps-control-compact ps-focus-ring w-full text-sm', onChange: (event) => setQuery(event.target.value), placeholder: searchPlaceholder, type: 'search', value: query }) }), query.trim() === '' ? (_jsxs("div", { className: 'grid grid-cols-1 sm:grid-cols-[minmax(0,11rem)_minmax(0,1fr)]', children: [_jsx("div", { className: PallasoftClassNameService.merge('ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5 sm:border-r sm:border-line', activeGroupKey && groups.length > 1 ? 'hidden sm:block' : ''), children: groups.map((group) => (_jsxs("button", { className: PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center gap-2 rounded-ps-control px-3 py-2.5 text-left text-sm font-semibold transition-colors', activeGroup?.key === group.key
52
- ? 'bg-mist text-ink'
53
- : 'text-ink/70 hover:bg-mist/60 hover:text-ink'), onClick: () => setActiveGroupKey(group.key), type: 'button', children: [_jsx("span", { className: 'min-w-0 flex-1 truncate', children: group.label }), _jsx("span", { className: 'text-xs font-medium text-ink/45', children: group.options.length }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 shrink-0 -rotate-90 text-ink/35', iconKey: PsIconKey.Chevron })] }, group.key))) }), _jsxs("div", { className: PallasoftClassNameService.merge('ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5', activeGroupKey && groups.length > 1 ? '' : 'hidden sm:block'), role: 'listbox', children: [groups.length > 1 ? (_jsxs("button", { className: 'ps-focus-ring mb-1 flex w-full items-center gap-2 rounded-ps-control px-3 py-2 text-left text-xs font-semibold text-ink/60 hover:text-ink sm:hidden', onClick: () => setActiveGroupKey(null), type: 'button', children: [_jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 rotate-90', iconKey: PsIconKey.Chevron }), "All groups"] })) : null, activeGroup
41
+ return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [hideLabel ? null : (_jsxs("span", { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(DialogTrigger, { isOpen: isOpen, onOpenChange: open, children: [_jsxs(Button, { "aria-label": hideLabel ? label : undefined, 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', isSuggested ? 'border-dashed border-primary/60 bg-primary/5' : ''), isDisabled: disabled, children: [_jsx("span", { className: 'min-w-0 flex-1 truncate', children: selected ? (_jsxs(_Fragment, { children: [_jsx("span", { className: 'truncate', children: selected.option.label }), PsCascaderService.groupLabelFor(selected) === null ? null : (_jsx("span", { className: 'ml-2 text-xs font-medium text-ink/45', children: selected.group.label }))] })) : (_jsx("span", { className: 'font-medium text-ink/45', children: placeholder })) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), _jsx(Popover, { className: 'ps-floating-panel w-[min(calc(100vw-2rem),32rem)] min-w-[var(--trigger-width)] outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(Dialog, { "aria-label": label, className: 'flex flex-col outline-none', children: ({ close }) => (_jsx(_Fragment, { children: groups.length === 0 ? (_jsxs("div", { className: 'flex flex-col gap-1 px-4 py-8 text-center', children: [_jsx("p", { className: 'text-sm font-semibold text-ink', children: PsCascaderConfig.emptyLabel }), _jsx("p", { className: 'text-xs text-ink/55', children: PsCascaderConfig.emptyDescription })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: 'border-b border-line p-2', children: _jsx("input", { "aria-label": searchPlaceholder, autoFocus: true, className: 'ps-input-control ps-control-compact ps-focus-ring w-full text-sm', onChange: (event) => setQuery(event.target.value), placeholder: searchPlaceholder, type: 'search', value: query }) }), query.trim() === '' ? (_jsxs("div", { className: 'grid grid-cols-1 sm:grid-cols-[minmax(0,11rem)_minmax(0,1fr)]', children: [_jsx("div", { className: PallasoftClassNameService.merge('ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5 sm:border-r sm:border-line', activeGroupKey && groups.length > 1 ? 'hidden sm:block' : ''), children: groups.map((group) => {
42
+ const direct = PsCascaderService.directOption(group);
43
+ if (direct !== null)
44
+ return (_jsxs("button", { "aria-selected": direct.value === value, className: PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center gap-2 rounded-ps-control px-3 py-2.5 text-left text-sm font-semibold transition-colors', direct.isDisabled
45
+ ? 'cursor-not-allowed text-ink/40'
46
+ : direct.value === value
47
+ ? 'bg-primary/10 text-ink'
48
+ : 'text-ink/70 hover:bg-mist/60 hover:text-ink'), disabled: direct.isDisabled, onClick: () => select(direct.value, close), role: 'option', type: 'button', children: [_jsx("span", { className: 'min-w-0 flex-1 truncate', children: direct.label }), direct.value === value ? (_jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 shrink-0 text-primary', iconKey: PsIconKey.Check })) : null] }, group.key));
49
+ return (_jsxs("button", { className: PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center gap-2 rounded-ps-control px-3 py-2.5 text-left text-sm font-semibold transition-colors', activeGroup?.key === group.key
50
+ ? 'bg-mist text-ink'
51
+ : 'text-ink/70 hover:bg-mist/60 hover:text-ink'), onClick: () => setActiveGroupKey(group.key), type: 'button', children: [_jsx("span", { className: 'min-w-0 flex-1 truncate', children: group.label }), _jsx("span", { className: 'text-xs font-medium text-ink/45', children: group.options.length }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 shrink-0 -rotate-90 text-ink/35', iconKey: PsIconKey.Chevron })] }, group.key));
52
+ }) }), _jsxs("div", { className: PallasoftClassNameService.merge('ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5', activeGroupKey && groups.length > 1 ? '' : 'hidden sm:block'), role: 'listbox', children: [groups.length > 1 ? (_jsxs("button", { className: 'ps-focus-ring mb-1 flex w-full items-center gap-2 rounded-ps-control px-3 py-2 text-left text-xs font-semibold text-ink/60 hover:text-ink sm:hidden', onClick: () => setActiveGroupKey(null), type: 'button', children: [_jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-4 w-4 rotate-90', iconKey: PsIconKey.Chevron }), "All groups"] })) : null, activeGroup
54
53
  ? activeGroup.options.map((option) => renderOption(option, null, close))
55
- : null] })] })) : (_jsx("div", { className: 'ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? (_jsx("p", { className: 'px-3 py-6 text-center text-sm text-ink/55', children: PsCascaderConfig.noMatchesLabel })) : (matches.map((match) => renderOption(match.option, match.group.label, close))) }))] })) })) }) })] }), helperText ? _jsx("span", { className: 'ps-input-helper mt-2 block', children: helperText }) : null] }));
54
+ : null] })] })) : (_jsx("div", { className: 'ps-scrollbar-hidden max-h-72 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? (_jsx("p", { className: 'px-3 py-6 text-center text-sm text-ink/55', children: PsCascaderConfig.noMatchesLabel })) : (matches.map((match) => renderOption(match.option, PsCascaderService.groupLabelFor(match), close))) }))] })) })) }) })] }), helperText ? _jsx("span", { className: 'ps-input-helper mt-2 block', children: helperText }) : null] }));
56
55
  };
@@ -34,7 +34,7 @@ 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 has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-primary', 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-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
38
38
  ? 'bg-primary/10 text-ink'
39
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: () => {
40
40
  setIsTouched(true);
@@ -1,4 +1,23 @@
1
1
  export class PsCascaderService {
2
+ static groupLabelFor(match) {
3
+ if (PsCascaderService.directOption(match.group) !== null)
4
+ return null;
5
+ return match.group.label.trim().toLowerCase() === match.option.label.trim().toLowerCase()
6
+ ? null
7
+ : match.group.label;
8
+ }
9
+ static directOption(group) {
10
+ return group.options.length === 1 ? group.options[0] : null;
11
+ }
12
+ static openGroup(groups, wantedKeys) {
13
+ const lists = groups.filter((group) => PsCascaderService.directOption(group) === null);
14
+ for (const key of wantedKeys) {
15
+ const wanted = lists.find((group) => group.key === key);
16
+ if (wanted !== undefined)
17
+ return wanted;
18
+ }
19
+ return lists.length > 0 ? lists[0] : null;
20
+ }
2
21
  static findSelected(groups, value) {
3
22
  if (value === '')
4
23
  return null;
@@ -4,6 +4,9 @@ export interface PsCascaderMatch {
4
4
  option: PsCascaderOption;
5
5
  }
6
6
  export declare class PsCascaderService {
7
+ static groupLabelFor(match: PsCascaderMatch): string | null;
8
+ static directOption(group: PsCascaderGroup): PsCascaderOption | null;
9
+ static openGroup(groups: PsCascaderGroup[], wantedKeys: (string | null)[]): PsCascaderGroup | null;
7
10
  static findSelected(groups: PsCascaderGroup[], value: string): PsCascaderMatch | null;
8
11
  static search(groups: PsCascaderGroup[], query: string): PsCascaderMatch[];
9
12
  }
@@ -2,6 +2,25 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsCascaderService = void 0;
4
4
  class PsCascaderService {
5
+ static groupLabelFor(match) {
6
+ if (PsCascaderService.directOption(match.group) !== null)
7
+ return null;
8
+ return match.group.label.trim().toLowerCase() === match.option.label.trim().toLowerCase()
9
+ ? null
10
+ : match.group.label;
11
+ }
12
+ static directOption(group) {
13
+ return group.options.length === 1 ? group.options[0] : null;
14
+ }
15
+ static openGroup(groups, wantedKeys) {
16
+ const lists = groups.filter((group) => PsCascaderService.directOption(group) === null);
17
+ for (const key of wantedKeys) {
18
+ const wanted = lists.find((group) => group.key === key);
19
+ if (wanted !== undefined)
20
+ return wanted;
21
+ }
22
+ return lists.length > 0 ? lists[0] : null;
23
+ }
5
24
  static findSelected(groups, value) {
6
25
  if (value === '')
7
26
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-input-components",
3
- "version": "3.7.1",
3
+ "version": "3.7.3",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",