uibee 2.6.0 → 2.7.1

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 (74) hide show
  1. package/dist/src/components/buttons/button.js +1 -1
  2. package/dist/src/components/index.d.ts +5 -3
  3. package/dist/src/components/index.js +5 -3
  4. package/dist/src/components/inputs/checkbox.d.ts +13 -0
  5. package/dist/src/components/inputs/checkbox.js +17 -0
  6. package/dist/src/components/inputs/input.d.ts +11 -9
  7. package/dist/src/components/inputs/input.js +76 -9
  8. package/dist/src/components/inputs/radio.d.ts +14 -0
  9. package/dist/src/components/inputs/radio.js +17 -0
  10. package/dist/src/components/inputs/range.d.ts +17 -0
  11. package/dist/src/components/inputs/range.js +20 -0
  12. package/dist/src/components/inputs/select.d.ts +11 -11
  13. package/dist/src/components/inputs/select.js +54 -50
  14. package/dist/src/components/inputs/shared/dateTimePickerPopup.d.ts +8 -0
  15. package/dist/src/components/inputs/shared/dateTimePickerPopup.js +117 -0
  16. package/dist/src/components/inputs/shared/fieldWrapper.d.ts +12 -0
  17. package/dist/src/components/inputs/shared/fieldWrapper.js +7 -0
  18. package/dist/src/components/inputs/shared/index.d.ts +5 -0
  19. package/dist/src/components/inputs/shared/index.js +5 -0
  20. package/dist/src/components/inputs/shared/inputError.d.ts +6 -0
  21. package/dist/src/components/inputs/shared/inputError.js +6 -0
  22. package/dist/src/components/inputs/shared/inputInfo.d.ts +5 -0
  23. package/dist/src/components/inputs/shared/inputInfo.js +5 -0
  24. package/dist/src/components/inputs/shared/inputLabel.d.ts +9 -0
  25. package/dist/src/components/inputs/shared/inputLabel.js +4 -0
  26. package/dist/src/components/inputs/shared/selectionWrapper.d.ts +13 -0
  27. package/dist/src/components/inputs/shared/selectionWrapper.js +7 -0
  28. package/dist/src/components/inputs/switch.d.ts +10 -7
  29. package/dist/src/components/inputs/switch.js +13 -5
  30. package/dist/src/components/inputs/textarea.d.ts +15 -0
  31. package/dist/src/components/inputs/textarea.js +14 -0
  32. package/dist/src/components/logo/logo.js +1 -1
  33. package/dist/src/globals.css +386 -161
  34. package/dist/src/hooks/index.d.ts +1 -0
  35. package/dist/src/hooks/index.js +1 -0
  36. package/dist/src/hooks/useClickOutside.d.ts +1 -0
  37. package/dist/src/hooks/useClickOutside.js +20 -0
  38. package/eslint.config.js +1 -0
  39. package/package.json +3 -2
  40. package/src/components/buttons/button.tsx +1 -1
  41. package/src/components/index.ts +5 -3
  42. package/src/components/inputs/checkbox.tsx +66 -0
  43. package/src/components/inputs/input.tsx +137 -35
  44. package/src/components/inputs/radio.tsx +67 -0
  45. package/src/components/inputs/range.tsx +84 -0
  46. package/src/components/inputs/select.tsx +137 -172
  47. package/src/components/inputs/shared/dateTimePickerPopup.tsx +219 -0
  48. package/src/components/inputs/shared/fieldWrapper.tsx +44 -0
  49. package/src/components/inputs/shared/index.ts +5 -0
  50. package/src/components/inputs/shared/inputError.tsx +21 -0
  51. package/src/components/inputs/shared/inputInfo.tsx +17 -0
  52. package/src/components/inputs/shared/inputLabel.tsx +19 -0
  53. package/src/components/inputs/shared/selectionWrapper.tsx +47 -0
  54. package/src/components/inputs/switch.tsx +48 -25
  55. package/src/components/inputs/textarea.tsx +65 -0
  56. package/src/components/logo/logo.tsx +1 -1
  57. package/src/globals.css +36 -0
  58. package/src/hooks/index.ts +1 -0
  59. package/src/hooks/useClickOutside.ts +27 -0
  60. package/dist/src/components/inputs/erase.d.ts +0 -3
  61. package/dist/src/components/inputs/erase.js +0 -5
  62. package/dist/src/components/inputs/label.d.ts +0 -10
  63. package/dist/src/components/inputs/label.js +0 -13
  64. package/dist/src/components/inputs/markdown.d.ts +0 -15
  65. package/dist/src/components/inputs/markdown.js +0 -32
  66. package/dist/src/components/inputs/tag.d.ts +0 -11
  67. package/dist/src/components/inputs/tag.js +0 -44
  68. package/dist/src/components/inputs/tooltip.d.ts +0 -4
  69. package/dist/src/components/inputs/tooltip.js +0 -4
  70. package/src/components/inputs/erase.tsx +0 -13
  71. package/src/components/inputs/label.tsx +0 -31
  72. package/src/components/inputs/markdown.tsx +0 -129
  73. package/src/components/inputs/tag.tsx +0 -137
  74. package/src/components/inputs/tooltip.tsx +0 -12
@@ -9,7 +9,7 @@ export default function Button({ text, className, icon, path, color, type, onCli
9
9
  ${bg} cursor-pointer px-4 rounded-md min-h-8 h-8 flex
10
10
  justify-evenly items-center gap-2 select-none
11
11
  focus:outline-none border-0 outline w-fit ${className}
12
- `, children: [_jsx("h1", { className: 'font-bold', children: icon || '' }), _jsx("h1", { children: text })] }));
12
+ `, children: [_jsx("h1", { className: 'font-bold', children: icon || '' }), _jsx("h1", { className: 'w-fit', children: text })] }));
13
13
  }
14
14
  if (disabled) {
15
15
  return (_jsxs("div", { className: `
@@ -1,8 +1,10 @@
1
1
  export { default as Input } from './inputs/input';
2
- export { default as SwitchInput } from './inputs/switch';
3
- export { default as TagInput } from './inputs/tag';
4
- export { default as Textarea } from './inputs/markdown';
2
+ export { default as Textarea } from './inputs/textarea';
3
+ export { default as Checkbox } from './inputs/checkbox';
5
4
  export { default as Select } from './inputs/select';
5
+ export { default as Switch } from './inputs/switch';
6
+ export { default as Radio } from './inputs/radio';
7
+ export { default as Range } from './inputs/range';
6
8
  export { default as Logo } from './logo/logo';
7
9
  export { default as LogoSmall } from './logo/logoSmall';
8
10
  export { default as ThemeToggle } from './toggle/theme';
@@ -1,9 +1,11 @@
1
1
  // Input components
2
2
  export { default as Input } from './inputs/input';
3
- export { default as SwitchInput } from './inputs/switch';
4
- export { default as TagInput } from './inputs/tag';
5
- export { default as Textarea } from './inputs/markdown';
3
+ export { default as Textarea } from './inputs/textarea';
4
+ export { default as Checkbox } from './inputs/checkbox';
6
5
  export { default as Select } from './inputs/select';
6
+ export { default as Switch } from './inputs/switch';
7
+ export { default as Radio } from './inputs/radio';
8
+ export { default as Range } from './inputs/range';
7
9
  // Logos
8
10
  export { default as Logo } from './logo/logo';
9
11
  export { default as LogoSmall } from './logo/logoSmall';
@@ -0,0 +1,13 @@
1
+ import { type ChangeEvent } from 'react';
2
+ export type CheckboxProps = {
3
+ label?: string;
4
+ name: string;
5
+ checked?: boolean;
6
+ onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
7
+ className?: string;
8
+ disabled?: boolean;
9
+ error?: string;
10
+ info?: string;
11
+ required?: boolean;
12
+ };
13
+ export default function Checkbox({ label, name, checked, onChange, className, disabled, error, info, required, }: CheckboxProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Check } from 'lucide-react';
3
+ import { SelectionWrapper } from './shared';
4
+ export default function Checkbox({ label, name, checked, onChange, className, disabled, error, info, required, }) {
5
+ return (_jsx(SelectionWrapper, { label: label, name: name, required: required, info: info, error: error, className: className, disabled: disabled, children: _jsxs("div", { className: 'relative flex items-center', children: [_jsx("input", { id: name, name: name, type: 'checkbox', checked: checked, onChange: onChange, disabled: disabled, required: required, className: `
6
+ peer appearance-none h-5 w-5 rounded border border-login-500 bg-login-500/50
7
+ checked:bg-login checked:border-login
8
+ focus:outline-none focus:ring-2 focus:ring-login/50
9
+ disabled:opacity-50 disabled:cursor-not-allowed
10
+ cursor-pointer transition-all duration-200
11
+ ${error ? 'border-red-500' : ''}
12
+ ` }), _jsx(Check, { className: `
13
+ absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
14
+ w-3.5 h-3.5 pointer-events-none text-white opacity-0
15
+ peer-checked:opacity-100 transition-opacity duration-200
16
+ ` })] }) }));
17
+ }
@@ -1,14 +1,16 @@
1
- import { HTMLInputTypeAttribute } from 'react';
2
- type InputProps = {
1
+ import { type ChangeEvent, type JSX } from 'react';
2
+ export type InputProps = {
3
+ label?: string;
3
4
  name: string;
4
- type: HTMLInputTypeAttribute;
5
- label: string;
5
+ type?: React.HTMLInputTypeAttribute;
6
+ placeholder?: string;
6
7
  value?: string | number;
7
- setValue: (value: string | number) => void;
8
+ onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
9
+ error?: string;
8
10
  className?: string;
9
- tooltip?: string;
11
+ disabled?: boolean;
10
12
  required?: boolean;
11
- color?: string;
13
+ icon?: JSX.Element;
14
+ info?: string;
12
15
  };
13
- export default function Input({ name, type, label, className, tooltip, required, value, setValue, color }: InputProps): import("react/jsx-runtime").JSX.Element;
14
- export {};
16
+ export default function Input({ label, name, type, placeholder, value, onChange, error, className, disabled, required, icon, info, }: InputProps): import("react/jsx-runtime").JSX.Element;
@@ -1,11 +1,78 @@
1
- 'use client';
2
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState } from 'react';
4
- import ToolTip from './tooltip';
5
- import Label from './label';
6
- import EraseButton from './erase';
7
- export default function Input({ name, type, label, className, tooltip, required, value, setValue, color }) {
8
- const [hasBlured, setHasBlured] = useState(false);
9
- return (_jsx("div", { className: `w-full ${className}`, children: _jsxs("div", { className: 'relative flex items-center', children: [_jsx("input", { name: name, type: type, className: 'block bg-login-800 px-2.5 pb-2.5 pt-4 w-full text-sm rounded-lg border-[0.10rem] appearance-none ' +
10
- 'border-login-200 focus:outline-none focus:ring-0 focus:border-login-50 peer', value: value || '', onChange: (e) => setValue(e.target.value), onFocus: (e) => e.target.showPicker(), onBlur: () => setHasBlured(true), placeholder: '', required: required }), _jsx(Label, { label: label, value: value, required: required, color: color, showRequired: required && !value && hasBlured }), value && _jsx(EraseButton, { setData: setValue }), !value && tooltip && _jsx(ToolTip, { info: tooltip })] }) }));
2
+ import { useRef, useState } from 'react';
3
+ import { Calendar, Clock } from 'lucide-react';
4
+ import { FieldWrapper } from './shared';
5
+ import DateTimePickerPopup from './shared/dateTimePickerPopup';
6
+ import useClickOutside from '../../hooks/useClickOutside';
7
+ export default function Input({ label, name, type = 'text', placeholder, value, onChange, error, className, disabled, required, icon, info, }) {
8
+ const localRef = useRef(null);
9
+ const [isOpen, setIsOpen] = useState(false);
10
+ const containerRef = useClickOutside(() => setIsOpen(false));
11
+ const isDateType = ['date', 'datetime-local', 'time'].includes(type);
12
+ const handleIconClick = () => {
13
+ if (isDateType && !disabled) {
14
+ setIsOpen(!isOpen);
15
+ }
16
+ else if (localRef.current && !disabled) {
17
+ localRef.current.focus();
18
+ }
19
+ };
20
+ const handleDateChange = (date) => {
21
+ if (!onChange)
22
+ return;
23
+ const pad = (n) => n.toString().padStart(2, '0');
24
+ const yyyy = date.getFullYear();
25
+ const MM = pad(date.getMonth() + 1);
26
+ const dd = pad(date.getDate());
27
+ const hh = pad(date.getHours());
28
+ const mm = pad(date.getMinutes());
29
+ let newValue = '';
30
+ if (type === 'date')
31
+ newValue = `${dd}/${MM}/${yyyy}`;
32
+ else if (type === 'time')
33
+ newValue = `${hh}:${mm}`;
34
+ else if (type === 'datetime-local')
35
+ newValue = `${dd}/${MM}/${yyyy} ${hh}:${mm}`;
36
+ const event = {
37
+ target: {
38
+ name,
39
+ value: newValue,
40
+ type,
41
+ },
42
+ };
43
+ onChange(event);
44
+ };
45
+ let displayIcon = icon;
46
+ if (!displayIcon && isDateType) {
47
+ if (type === 'time') {
48
+ displayIcon = _jsx(Clock, { className: 'w-4 h-4' });
49
+ }
50
+ else {
51
+ displayIcon = _jsx(Calendar, { className: 'w-4 h-4' });
52
+ }
53
+ }
54
+ const getDateValue = () => {
55
+ if (!value)
56
+ return null;
57
+ if (type === 'time') {
58
+ const date = new Date(`2000-01-01T${value}`);
59
+ return isNaN(date.getTime()) ? null : date;
60
+ }
61
+ const date = new Date(value);
62
+ return isNaN(date.getTime()) ? null : date;
63
+ };
64
+ return (_jsx(FieldWrapper, { label: label, name: name, required: required, info: info, error: error, className: className, children: _jsxs("div", { className: 'relative flex items-center', ref: containerRef, children: [displayIcon && (_jsx("div", { className: `
65
+ absolute left-3 text-login-200
66
+ ${isDateType && !disabled ? 'cursor-pointer hover:text-login-text' : 'pointer-events-none'}
67
+ `, onClick: handleIconClick, children: displayIcon })), _jsx("input", { ref: localRef, id: name, name: name, type: isDateType ? 'text' : type, placeholder: placeholder, value: value, onChange: onChange, disabled: disabled, required: required, readOnly: isDateType, onClick: () => isDateType && !disabled && setIsOpen(true), title: label, "aria-invalid": !!error, "aria-describedby": error ? `${name}-error` : undefined, className: `
68
+ w-full rounded-md bg-login-500/50 border border-login-500
69
+ text-login-text placeholder-login-200
70
+ focus:outline-none focus:border-login focus:ring-1 focus:ring-login
71
+ disabled:opacity-50 disabled:cursor-not-allowed
72
+ py-2 ${displayIcon ? 'pl-10 pr-3' : 'px-3'}
73
+ transition-all duration-200
74
+ input-reset
75
+ ${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : ''}
76
+ ${isDateType && !disabled ? 'cursor-pointer' : ''}
77
+ ` }), isOpen && isDateType && !disabled && (_jsx(DateTimePickerPopup, { value: getDateValue(), onChange: handleDateChange, type: type, onClose: () => setIsOpen(false) }))] }) }));
11
78
  }
@@ -0,0 +1,14 @@
1
+ import { type ChangeEvent } from 'react';
2
+ export type RadioProps = {
3
+ label?: string;
4
+ name: string;
5
+ value: string | number;
6
+ checked?: boolean;
7
+ onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
8
+ className?: string;
9
+ disabled?: boolean;
10
+ error?: string;
11
+ info?: string;
12
+ required?: boolean;
13
+ };
14
+ export default function Radio({ label, name, value, checked, onChange, className, disabled, error, info, required, }: RadioProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { SelectionWrapper } from './shared';
3
+ export default function Radio({ label, name, value, checked, onChange, className, disabled, error, info, required, }) {
4
+ const id = `${name}-${value}`;
5
+ return (_jsx(SelectionWrapper, { label: label, name: id, required: required, info: info, error: error, className: className, disabled: disabled, children: _jsxs("div", { className: 'relative flex items-center', children: [_jsx("input", { id: id, name: name, type: 'radio', value: value, checked: checked, onChange: onChange, disabled: disabled, required: required, className: `
6
+ peer appearance-none h-5 w-5 rounded-full border border-login-500 bg-login-500/50
7
+ checked:bg-login checked:border-login
8
+ focus:outline-none focus:ring-2 focus:ring-login/50
9
+ disabled:opacity-50 disabled:cursor-not-allowed
10
+ cursor-pointer transition-all duration-200
11
+ ${error ? 'border-red-500' : ''}
12
+ ` }), _jsx("div", { className: `
13
+ absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
14
+ w-2 h-2 rounded-full bg-white pointer-events-none opacity-0
15
+ peer-checked:opacity-100 transition-opacity duration-200
16
+ ` })] }) }));
17
+ }
@@ -0,0 +1,17 @@
1
+ import { type ChangeEvent } from 'react';
2
+ export type RangeProps = {
3
+ label?: string;
4
+ name: string;
5
+ min?: number;
6
+ max?: number;
7
+ step?: number;
8
+ value?: number;
9
+ onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
10
+ error?: string;
11
+ className?: string;
12
+ disabled?: boolean;
13
+ required?: boolean;
14
+ info?: string;
15
+ showValue?: boolean;
16
+ };
17
+ export default function Range({ label, name, min, max, step, value, onChange, error, className, disabled, required, info, showValue, }: RangeProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { FieldWrapper } from './shared';
3
+ export default function Range({ label, name, min = 0, max = 100, step = 1, value = 0, onChange, error, className, disabled, required, info, showValue = true, }) {
4
+ return (_jsx(FieldWrapper, { label: label, name: name, required: required, info: info, error: error, className: className, children: _jsxs("div", { className: 'flex items-center gap-4', children: [_jsx("input", { id: name, name: name, type: 'range', min: min, max: max, step: step, value: value, onChange: onChange, disabled: disabled, required: required, title: label, "aria-invalid": !!error, "aria-describedby": error ? `${name}-error` : undefined, className: `
5
+ flex-1 h-2 bg-login-500 rounded-lg appearance-none cursor-pointer
6
+ accent-login
7
+ [&::-webkit-slider-thumb]:appearance-none
8
+ [&::-webkit-slider-thumb]:w-4
9
+ [&::-webkit-slider-thumb]:h-4
10
+ [&::-webkit-slider-thumb]:rounded-full
11
+ [&::-webkit-slider-thumb]:bg-login
12
+ [&::-moz-range-thumb]:w-4
13
+ [&::-moz-range-thumb]:h-4
14
+ [&::-moz-range-thumb]:rounded-full
15
+ [&::-moz-range-thumb]:bg-login
16
+ [&::-moz-range-thumb]:border-none
17
+ disabled:opacity-50 disabled:cursor-not-allowed
18
+ ${error ? 'accent-red-500' : ''}
19
+ ` }), showValue && (_jsx("span", { className: 'text-login-text text-sm font-medium min-w-10 text-right', children: value }))] }) }));
20
+ }
@@ -1,19 +1,19 @@
1
- type Option = {
1
+ export type Option = {
2
2
  value: string | number;
3
3
  label: string;
4
- image?: string;
5
4
  };
6
- type SelectProps = {
5
+ export type SelectProps = {
6
+ label?: string;
7
7
  name: string;
8
- label: string;
9
- value: string | number;
10
- setValue: (_: string | number) => void;
8
+ value?: string | number | null;
9
+ onChange?: (value: string | number | null) => void;
11
10
  options: Option[];
11
+ error?: string;
12
12
  className?: string;
13
- tooltip?: string;
13
+ disabled?: boolean;
14
14
  required?: boolean;
15
- children?: React.ReactNode;
16
- color?: string;
15
+ placeholder?: string;
16
+ info?: string;
17
+ clearable?: boolean;
17
18
  };
18
- export default function Select({ name, label, value, options, className, tooltip, required, children, setValue, color }: SelectProps): import("react/jsx-runtime").JSX.Element;
19
- export {};
19
+ export default function Select({ label, name, value, onChange, options, error, className, disabled, required, placeholder, info, clearable, }: SelectProps): import("react/jsx-runtime").JSX.Element;
@@ -1,53 +1,57 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useRef, useState } from 'react';
4
- import ToolTip from './tooltip';
5
- import Label from './label';
6
- import EraseButton from './erase';
7
- export default function Select({ name, label, value, options, className, tooltip, required, children, setValue, color }) {
8
- const [hasBlured, setHasBlured] = useState(false);
9
- const selectRef = useRef(null);
10
- const selectedOption = options.find((o) => o.value === value);
11
- function handleChoose(value) {
12
- setValue(value);
13
- setHasBlured(true);
14
- if (selectRef.current) {
15
- selectRef.current.value = String(value);
16
- selectRef.current.blur();
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useEffect } from 'react';
4
+ import { useClickOutside } from '../../hooks';
5
+ import { ChevronDown, X } from 'lucide-react';
6
+ import { FieldWrapper } from './shared';
7
+ export default function Select({ label, name, value, onChange, options, error, className, disabled, required, placeholder = 'Select an option', info, clearable = true, }) {
8
+ const [isOpen, setIsOpen] = useState(false);
9
+ const [selectedOption, setSelectedOption] = useState(options.find(opt => opt.value === value));
10
+ useEffect(() => {
11
+ setSelectedOption(options.find(opt => opt.value === value));
12
+ }, [value, options]);
13
+ const containerRef = useClickOutside(() => setIsOpen(false));
14
+ const handleSelect = (option) => {
15
+ if (disabled)
16
+ return;
17
+ setSelectedOption(option);
18
+ setIsOpen(false);
19
+ if (onChange) {
20
+ onChange(option.value);
17
21
  }
18
- }
19
- return (_jsxs("div", { className: `w-full ${className}`, children: [_jsxs("div", { className: 'relative flex items-center', children: [_jsxs("select", { ref: selectRef, name: name, className: 'peer cursor-pointer block px-2.5 pb-2.5 pt-4 ' +
20
- 'w-full text-sm rounded-lg border-[0.10rem] ' +
21
- 'appearance-none border-login-200 focus:ring-0 ' +
22
- 'focus:outline-none focus:border-login-50 ' +
23
- `${color ? color : 'bg-login-800'}`, value: value, onChange: (e) => {
24
- setValue(e.target.value);
25
- setHasBlured(true);
26
- }, onBlur: () => setHasBlured(true), onMouseDown: (e) => {
27
- e.preventDefault();
28
- selectRef.current?.focus();
29
- }, required: required, children: [_jsx("option", { value: '', hidden: true }), options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value)))] }), _jsx(Label, { label: label, value: value, required: required, color: color, showRequired: required && !value && hasBlured }), value && (_jsx(EraseButton, { setData: (v) => {
30
- setValue(v);
31
- setHasBlured(true);
32
- } })), !value && tooltip && _jsx(ToolTip, { info: tooltip }), _jsx(SelectContent, { options: options, value: value, selectedOption: selectedOption, handleChoose: handleChoose, color: color })] }), children] }));
33
- }
34
- function SelectContent({ options, value, selectedOption, handleChoose, color }) {
35
- return (_jsx("div", { className: 'hidden peer-focus:block absolute left-0 ' +
36
- 'right-0 top-full mt-1 z-50', children: _jsx("div", { className: `${color ? color : 'bg-login-800'}` + ' border-[0.10rem] border-login-200 ' +
37
- 'rounded-lg shadow-lg p-0 max-h-72 overflow-hidden', children: _jsxs("div", { className: 'max-h-72 overflow-auto', children: [_jsx(SelectedOption, { value: value, selectedOption: selectedOption }), _jsx("div", { className: 'p-2', children: options
38
- .filter((o) => o.value !== value)
39
- .map((opt) => (_jsx("button", { type: 'button', className: 'cursor-pointer w-full flex ' +
40
- 'items-center gap-3 px-2 py-2 ' +
41
- 'text-sm hover:bg-surface ' +
42
- 'rounded hover:bg-login-600', onMouseDown: (e) => {
43
- e.preventDefault();
44
- handleChoose(opt.value);
45
- }, children: _jsx("span", { className: 'text-left', children: opt.label }) }, opt.value))) })] }) }) }));
46
- }
47
- function SelectedOption({ value, selectedOption }) {
48
- if (!value) {
49
- return _jsx(_Fragment, {});
50
- }
51
- return (_jsx("div", { className: 'sticky top-0 bg-surface px-2 py-2 z-10 border-b ' +
52
- 'border-login-200 bg-login-600', children: _jsx("div", { className: 'flex items-center gap-3', children: _jsx("span", { className: 'font-medium text-left', children: selectedOption?.label }) }) }));
22
+ };
23
+ const handleClear = (e) => {
24
+ e.stopPropagation();
25
+ if (disabled)
26
+ return;
27
+ setSelectedOption(undefined);
28
+ if (onChange) {
29
+ onChange(null);
30
+ }
31
+ };
32
+ return (_jsxs(FieldWrapper, { label: label, name: name, required: required, info: info, error: error, className: className, children: [_jsxs("div", { className: 'relative', ref: containerRef, children: [_jsxs("button", { type: 'button', onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, "aria-haspopup": 'listbox', "aria-expanded": isOpen, "aria-labelledby": label ? undefined : name, className: `
33
+ w-full rounded-md bg-login-500/50 border border-login-500
34
+ text-login-text text-left
35
+ focus:outline-none focus:border-login focus:ring-1 focus:ring-login
36
+ disabled:opacity-50 disabled:cursor-not-allowed
37
+ py-2 pl-3 pr-10
38
+ transition-all duration-200
39
+ flex items-center justify-between
40
+ ${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : ''}
41
+ ${!selectedOption ? 'text-login-200' : ''}
42
+ `, title: label, children: [_jsx("span", { className: 'truncate', children: selectedOption ? selectedOption.label : placeholder }), _jsxs("div", { className: 'absolute inset-y-0 right-0 flex items-center px-2 gap-1', children: [clearable && selectedOption && !disabled && (_jsx("div", { role: 'button', onClick: handleClear, className: `
43
+ p-1 hover:bg-login-500 rounded-full text-login-200
44
+ hover:text-red-400 transition-colors cursor-pointer
45
+ `, title: 'Clear selection', children: _jsx(X, { className: 'w-3 h-3' }) })), _jsx("div", { className: `
46
+ text-login-200 pointer-events-none
47
+ transition-transform duration-200
48
+ ${isOpen ? 'rotate-180' : ''}
49
+ `, children: _jsx(ChevronDown, { className: 'w-4 h-4' }) })] })] }), isOpen && (_jsx("div", { className: `
50
+ absolute z-50 w-full mt-1 bg-login-600 border border-login-500
51
+ rounded-md shadow-lg max-h-60 overflow-auto noscroll
52
+ `, children: options.length > 0 ? (_jsx("ul", { className: 'py-1', role: 'listbox', children: options.map((option) => (_jsx("li", { role: 'option', "aria-selected": selectedOption?.value === option.value, children: _jsx("button", { type: 'button', onClick: () => handleSelect(option), className: `
53
+ w-full text-left px-3 py-2 text-sm
54
+ hover:bg-login-500 transition-colors duration-150
55
+ ${selectedOption?.value === option.value ? 'bg-login-500 text-login' : 'text-login-text'}
56
+ `, children: option.label }) }, option.value))) })) : (_jsx("div", { className: 'px-3 py-2 text-sm text-login-200', children: "No options available" })) }))] }), _jsx("input", { type: 'hidden', name: name, value: selectedOption?.value || '', required: required })] }));
53
57
  }
@@ -0,0 +1,8 @@
1
+ type DateTimePickerPopupProps = {
2
+ value: Date | null;
3
+ onChange: (date: Date) => void;
4
+ type: 'date' | 'time' | 'datetime-local';
5
+ onClose?: () => void;
6
+ };
7
+ export default function DateTimePickerPopup({ value, onChange, type, onClose, }: DateTimePickerPopupProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,117 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ import { ChevronLeft, ChevronRight } from 'lucide-react';
4
+ const DAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
5
+ const MONTHS = [
6
+ 'January', 'February', 'March', 'April', 'May', 'June',
7
+ 'July', 'August', 'September', 'October', 'November', 'December'
8
+ ];
9
+ export default function DateTimePickerPopup({ value, onChange, type, onClose, }) {
10
+ const [currentDate, setCurrentDate] = useState(new Date());
11
+ const [timeInput, setTimeInput] = useState({
12
+ hours: value ? value.getHours().toString() : '0',
13
+ minutes: value ? value.getMinutes().toString() : '0',
14
+ });
15
+ useEffect(() => {
16
+ if (value) {
17
+ setCurrentDate(value);
18
+ setTimeInput(prev => ({
19
+ hours: prev.hours === '' && value.getHours() === 0 ? '' : value.getHours().toString(),
20
+ minutes: prev.minutes === '' && value.getMinutes() === 0 ? '' : value.getMinutes().toString(),
21
+ }));
22
+ }
23
+ }, [value]);
24
+ const handleDateSelect = (day) => {
25
+ const newDate = new Date(currentDate);
26
+ newDate.setDate(day);
27
+ if (value) {
28
+ newDate.setHours(value.getHours());
29
+ newDate.setMinutes(value.getMinutes());
30
+ }
31
+ else {
32
+ newDate.setHours(0, 0, 0, 0);
33
+ }
34
+ onChange(newDate);
35
+ if (type === 'date' && onClose) {
36
+ onClose();
37
+ }
38
+ };
39
+ const handleTimeChange = (timeUnit, val) => {
40
+ const newDate = value ? new Date(value) : new Date();
41
+ if (!value) {
42
+ newDate.setHours(0, 0, 0, 0);
43
+ }
44
+ if (timeUnit === 'hours') {
45
+ if (val < 0 || val > 23)
46
+ return;
47
+ newDate.setHours(val);
48
+ }
49
+ if (timeUnit === 'minutes') {
50
+ if (val < 0 || val > 59)
51
+ return;
52
+ newDate.setMinutes(val);
53
+ }
54
+ onChange(newDate);
55
+ };
56
+ const onTimeInputChange = (unit, val) => {
57
+ if (val === '') {
58
+ setTimeInput(prev => ({ ...prev, [unit]: '' }));
59
+ handleTimeChange(unit, 0);
60
+ return;
61
+ }
62
+ if (!/^\d+$/.test(val))
63
+ return;
64
+ const num = parseInt(val);
65
+ if (unit === 'hours' && num > 23)
66
+ return;
67
+ if (unit === 'minutes' && num > 59)
68
+ return;
69
+ setTimeInput(prev => ({ ...prev, [unit]: val }));
70
+ handleTimeChange(unit, num);
71
+ };
72
+ const onTimeInputBlur = (unit) => {
73
+ if (timeInput[unit] === '') {
74
+ const num = unit === 'hours' ? (value?.getHours() ?? 0) : (value?.getMinutes() ?? 0);
75
+ setTimeInput(prev => ({ ...prev, [unit]: num.toString() }));
76
+ }
77
+ };
78
+ const getDaysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
79
+ const getFirstDayOfMonth = (year, month) => new Date(year, month, 1).getDay();
80
+ const renderCalendar = () => {
81
+ const year = currentDate.getFullYear();
82
+ const month = currentDate.getMonth();
83
+ const daysInMonth = getDaysInMonth(year, month);
84
+ const firstDay = getFirstDayOfMonth(year, month);
85
+ const days = [];
86
+ for (let i = 0; i < firstDay; i++) {
87
+ days.push(_jsx("div", { className: 'w-8 h-8' }, `empty-${i}`));
88
+ }
89
+ for (let i = 1; i <= daysInMonth; i++) {
90
+ const isSelected = value &&
91
+ value.getDate() === i &&
92
+ value.getMonth() === month &&
93
+ value.getFullYear() === year;
94
+ const isToday = new Date().getDate() === i &&
95
+ new Date().getMonth() === month &&
96
+ new Date().getFullYear() === year;
97
+ days.push(_jsx("button", { type: 'button', onClick: () => handleDateSelect(i), className: `
98
+ w-8 h-8 flex items-center justify-center rounded-full text-sm
99
+ hover:bg-login-500 transition-colors
100
+ ${isSelected ? 'bg-login! text-white! hover:bg-login!' : ''}
101
+ ${!isSelected && isToday ? 'text-login! font-bold' : ''}
102
+ ${!isSelected && !isToday ? 'text-login-text!' : ''}
103
+ `, children: i }, i));
104
+ }
105
+ return (_jsxs("div", { className: 'p-2', children: [_jsxs("div", { className: 'flex items-center justify-between mb-2', children: [_jsx("button", { type: 'button', onClick: () => setCurrentDate(new Date(year, month - 1)), className: 'p-1 hover:bg-login-500 rounded-full text-login-text', children: _jsx(ChevronLeft, { className: 'w-4 h-4' }) }), _jsxs("span", { className: 'font-medium text-login-text', children: [MONTHS[month], " ", year] }), _jsx("button", { type: 'button', onClick: () => setCurrentDate(new Date(year, month + 1)), className: 'p-1 hover:bg-login-500 rounded-full text-login-text', children: _jsx(ChevronRight, { className: 'w-4 h-4' }) })] }), _jsx("div", { className: 'grid grid-cols-7 gap-1 mb-1', children: DAYS.map(d => (_jsx("div", { className: 'w-8 text-center text-xs text-login-200 font-medium', children: d }, d))) }), _jsx("div", { className: 'grid grid-cols-7 gap-1', children: days })] }));
106
+ };
107
+ const renderTimePicker = () => {
108
+ return (_jsxs("div", { className: 'p-2 border-t border-login-500 flex justify-center gap-2', children: [_jsxs("div", { className: 'flex flex-col items-center', children: [_jsx("label", { className: 'text-xs text-login-200 mb-1', children: "Hour" }), _jsx("input", { type: 'text', inputMode: 'numeric', value: timeInput.hours, onChange: (e) => onTimeInputChange('hours', e.target.value), onBlur: () => onTimeInputBlur('hours'), className: `
109
+ w-16 p-1 bg-login-500 rounded text-center text-login-text
110
+ border border-login-500 focus:border-login outline-none
111
+ ` })] }), _jsx("div", { className: 'flex items-end pb-2 text-login-text', children: ":" }), _jsxs("div", { className: 'flex flex-col items-center', children: [_jsx("label", { className: 'text-xs text-login-200 mb-1', children: "Minute" }), _jsx("input", { type: 'text', inputMode: 'numeric', value: timeInput.minutes, onChange: (e) => onTimeInputChange('minutes', e.target.value), onBlur: () => onTimeInputBlur('minutes'), className: `
112
+ w-16 p-1 bg-login-500 rounded text-center text-login-text
113
+ border border-login-500 focus:border-login outline-none
114
+ ` })] })] }));
115
+ };
116
+ return (_jsxs("div", { className: 'absolute top-full left-0 z-50 mt-1 bg-login-600 border border-login-500 rounded-md shadow-lg p-1 min-w-70', children: [type !== 'time' && renderCalendar(), (type === 'time' || type === 'datetime-local') && renderTimePicker()] }));
117
+ }
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from 'react';
2
+ interface FieldWrapperProps {
3
+ label?: string;
4
+ name: string;
5
+ required?: boolean;
6
+ info?: string;
7
+ error?: string;
8
+ children: ReactNode;
9
+ className?: string;
10
+ }
11
+ export default function FieldWrapper({ label, name, required, info, error, children, className, }: FieldWrapperProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import InputLabel from './inputLabel';
3
+ import InputInfo from './inputInfo';
4
+ import InputError from './inputError';
5
+ export default function FieldWrapper({ label, name, required, info, error, children, className, }) {
6
+ return (_jsxs("div", { className: `flex flex-col gap-1 w-full relative ${className || ''}`, children: [(label || info) && (_jsxs("div", { className: 'flex items-center justify-between mb-1', children: [label && (_jsx(InputLabel, { label: label, name: name, required: required, className: 'ml-1' })), info && _jsx(InputInfo, { info: info })] })), children, _jsx(InputError, { error: error, id: `${name}-error` })] }));
7
+ }
@@ -0,0 +1,5 @@
1
+ export { default as FieldWrapper } from './fieldWrapper';
2
+ export { default as SelectionWrapper } from './selectionWrapper';
3
+ export { default as InputLabel } from './inputLabel';
4
+ export { default as InputInfo } from './inputInfo';
5
+ export { default as InputError } from './inputError';
@@ -0,0 +1,5 @@
1
+ export { default as FieldWrapper } from './fieldWrapper';
2
+ export { default as SelectionWrapper } from './selectionWrapper';
3
+ export { default as InputLabel } from './inputLabel';
4
+ export { default as InputInfo } from './inputInfo';
5
+ export { default as InputError } from './inputError';
@@ -0,0 +1,6 @@
1
+ interface InputErrorProps {
2
+ error?: string;
3
+ id?: string;
4
+ }
5
+ export default function InputError({ error, id }: InputErrorProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export default function InputError({ error, id }) {
3
+ if (!error)
4
+ return _jsx("div", { className: 'h-4' });
5
+ return (_jsx("div", { className: 'h-4', children: _jsx("span", { id: id, className: 'text-xs text-red-500 ml-1 truncate block', role: 'alert', title: error, children: error }) }));
6
+ }
@@ -0,0 +1,5 @@
1
+ interface InputInfoProps {
2
+ info: string;
3
+ }
4
+ export default function InputInfo({ info }: InputInfoProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { CircleHelp } from 'lucide-react';
3
+ export default function InputInfo({ info }) {
4
+ return (_jsx("div", { className: 'text-login-200 hover:text-login-text transition-colors', "aria-label": info, title: info, children: _jsx(CircleHelp, { className: 'w-4 h-4' }) }));
5
+ }
@@ -0,0 +1,9 @@
1
+ interface InputLabelProps {
2
+ label: string;
3
+ name: string;
4
+ required?: boolean;
5
+ disabled?: boolean;
6
+ className?: string;
7
+ }
8
+ export default function InputLabel({ label, name, required, disabled, className }: InputLabelProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};