uibee 2.11.0 → 2.12.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.
@@ -1,9 +1,16 @@
1
- export type CheckboxProps = Omit<React.ComponentProps<'input'>, 'name'> & {
1
+ export type CheckboxOption = {
2
+ label: string;
3
+ value: string | number;
4
+ };
5
+ export type CheckboxProps = Omit<React.ComponentProps<'input'>, 'name' | 'onChange' | 'value'> & {
2
6
  name: string;
3
7
  label?: string;
4
8
  error?: string;
5
9
  info?: string;
6
10
  description?: string;
7
11
  className?: string;
12
+ options: CheckboxOption[];
13
+ value?: (string | number)[];
14
+ onChange?: (value: (string | number)[]) => void;
8
15
  };
9
16
  export default function Checkbox(props: CheckboxProps): import("react/jsx-runtime").JSX.Element;
@@ -1,18 +1,37 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Check } from 'lucide-react';
3
- import { SelectionWrapper } from './shared';
3
+ import { FieldWrapper, InputLabel } from './shared';
4
4
  export default function Checkbox(props) {
5
- const { name, label, error, info, description, className, ...inputProps } = props;
6
- return (_jsx(SelectionWrapper, { label: label, name: name, required: inputProps.required, info: info, description: description, error: error, className: className, disabled: inputProps.disabled, children: _jsxs("div", { className: 'relative flex items-center', children: [_jsx("input", { ...inputProps, id: name, name: name, type: 'checkbox', className: `
7
- peer appearance-none h-5 w-5 rounded border border-login-500 bg-login-500/50
5
+ const { options, onChange, value, label, description, error, info, name, className, ...rest } = props;
6
+ const selectedValues = Array.isArray(value) ? value : [];
7
+ return (_jsx(FieldWrapper, { label: label, name: name, required: rest.required, info: info, description: description, error: error, className: className, children: _jsx("div", { className: 'flex flex-col gap-2', children: options.map((option) => (_jsx(CheckboxItem, { name: name, value: option.value, label: option.label, checked: selectedValues.includes(option.value), disabled: rest.disabled, onChange: (e) => {
8
+ if (!onChange)
9
+ return;
10
+ const isChecked = e.target.checked;
11
+ let newValues = [...selectedValues];
12
+ if (isChecked) {
13
+ newValues.push(option.value);
14
+ }
15
+ else {
16
+ newValues = newValues.filter((v) => v !== option.value);
17
+ }
18
+ onChange(newValues);
19
+ }, className: 'mb-0' }, option.value))) }) }));
20
+ }
21
+ function CheckboxItem(props) {
22
+ const { name, label, error, ...inputProps } = props;
23
+ const id = inputProps.value ? `${name}-${inputProps.value}` : name;
24
+ return (_jsxs("div", { className: 'flex items-center gap-2', children: [_jsxs("div", { className: 'relative w-5 h-5 shrink-0', children: [_jsx("input", { ...inputProps, id: id, name: name, type: 'checkbox', className: `
25
+ peer appearance-none rounded border border-login-500 bg-login-500/50
8
26
  checked:bg-login checked:border-login
9
27
  focus:outline-none focus:ring-2 focus:ring-login/50
10
28
  disabled:opacity-50 disabled:cursor-not-allowed
11
29
  cursor-pointer transition-all duration-200
30
+ w-5 h-5 absolute inset-0
12
31
  ${error ? 'border-red-500' : ''}
13
32
  ` }), _jsx(Check, { className: `
14
33
  absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
15
34
  w-3.5 h-3.5 pointer-events-none text-white opacity-0
16
35
  peer-checked:opacity-100 transition-opacity duration-200
17
- ` })] }) }));
36
+ ` })] }), label && (_jsx(InputLabel, { label: label, name: name, className: 'select-none cursor-pointer' }))] }));
18
37
  }
@@ -1,9 +1,16 @@
1
- export type RadioProps = Omit<React.ComponentProps<'input'>, 'name'> & {
1
+ export type RadioOption = {
2
+ label: string;
3
+ value: string | number;
4
+ };
5
+ export type RadioProps = Omit<React.ComponentProps<'input'>, 'name' | 'onChange' | 'value'> & {
2
6
  name: string;
3
7
  label?: string;
4
8
  error?: string;
5
9
  info?: string;
6
10
  description?: string;
7
11
  className?: string;
12
+ options: RadioOption[];
13
+ value?: string | number | null;
14
+ onChange?: (value: string | number) => void;
8
15
  };
9
16
  export default function Radio(props: RadioProps): import("react/jsx-runtime").JSX.Element;
@@ -1,19 +1,27 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { SelectionWrapper } from './shared';
2
+ import { FieldWrapper, InputLabel } from './shared';
3
3
  export default function Radio(props) {
4
- const { name, label, error, info, description, className, ...inputProps } = props;
4
+ const { options, onChange, value, label, description, error, info, name, className, ...rest } = props;
5
+ return (_jsx(FieldWrapper, { label: label, name: name, required: rest.required, info: info, description: description, error: error, className: className, children: _jsx("div", { className: 'flex flex-col gap-2', children: options.map((option) => (_jsx(RadioItem, { name: name, value: option.value, label: option.label, checked: value === option.value, disabled: rest.disabled, onChange: () => {
6
+ if (onChange)
7
+ onChange(option.value);
8
+ }, className: 'mb-0' }, option.value))) }) }));
9
+ }
10
+ function RadioItem(props) {
11
+ const { name, label, error, ...inputProps } = props;
5
12
  const { value } = inputProps;
6
13
  const id = `${name}-${value}`;
7
- return (_jsx(SelectionWrapper, { label: label, name: id, required: inputProps.required, info: info, description: description, error: error, className: className, disabled: inputProps.disabled, children: _jsxs("div", { className: 'relative flex items-center', children: [_jsx("input", { ...inputProps, id: id, name: name, type: 'radio', className: `
8
- peer appearance-none h-5 w-5 rounded-full border border-login-500 bg-login-500/50
14
+ return (_jsxs("div", { className: 'flex items-center gap-2', children: [_jsxs("div", { className: 'relative w-5 h-5 shrink-0', children: [_jsx("input", { ...inputProps, id: id, name: name, type: 'radio', className: `
15
+ peer appearance-none rounded-full border border-login-500 bg-login-500/50
9
16
  checked:bg-login checked:border-login
10
17
  focus:outline-none focus:ring-2 focus:ring-login/50
11
18
  disabled:opacity-50 disabled:cursor-not-allowed
12
19
  cursor-pointer transition-all duration-200
20
+ w-5 h-5 absolute inset-0
13
21
  ${error ? 'border-red-500' : ''}
14
22
  ` }), _jsx("div", { className: `
15
23
  absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
16
24
  w-2 h-2 rounded-full bg-white pointer-events-none opacity-0
17
25
  peer-checked:opacity-100 transition-opacity duration-200
18
- ` })] }) }));
26
+ ` })] }), label && (_jsx(InputLabel, { label: label, name: name, className: 'select-none cursor-pointer' }))] }));
19
27
  }
@@ -1,5 +1,4 @@
1
1
  export { default as FieldWrapper } from './fieldWrapper';
2
- export { default as SelectionWrapper } from './selectionWrapper';
3
2
  export { default as InputLabel } from './inputLabel';
4
3
  export { default as InputInfo } from './inputInfo';
5
4
  export { default as InputError } from './inputError';
@@ -1,5 +1,4 @@
1
1
  export { default as FieldWrapper } from './fieldWrapper';
2
- export { default as SelectionWrapper } from './selectionWrapper';
3
2
  export { default as InputLabel } from './inputLabel';
4
3
  export { default as InputInfo } from './inputInfo';
5
4
  export { default as InputError } from './inputError';
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { SelectionWrapper } from './shared';
2
+ import { FieldWrapper } from './shared';
3
3
  export default function Switch(props) {
4
4
  const { name, label, error, info, description, className, switchOnly, ...inputProps } = props;
5
- return (_jsx(SelectionWrapper, { label: label, name: name, required: inputProps.required, info: info, description: description, error: error, hideError: switchOnly, className: className, disabled: inputProps.disabled, children: _jsxs("label", { className: `relative inline-flex items-center cursor-pointer ${switchOnly ? 'h-fit' : 'h-10.5'}`, children: [_jsx("input", { ...inputProps, type: 'checkbox', id: name, name: name, className: 'sr-only peer' }), _jsx("div", { className: `
5
+ return (_jsx(FieldWrapper, { label: label, name: name, required: inputProps.required, info: info, error: error, description: description, className: className, children: _jsxs("label", { className: `relative inline-flex items-center cursor-pointer ${switchOnly ? 'h-fit' : 'h-10.5'}`, children: [_jsx("input", { ...inputProps, type: 'checkbox', id: name, name: name, className: 'sr-only peer' }), _jsx("div", { className: `
6
6
  w-11 h-6 bg-login-500/50 rounded-full peer
7
7
  peer-checked:after:translate-x-full peer-checked:after:border-white
8
8
  after:content-[''] after:absolute ${switchOnly ? 'after:top-0.5' : 'after:top-2.75'} after:left-0.5
@@ -1028,9 +1028,6 @@
1028
1028
  .-mt-0\.5 {
1029
1029
  margin-top: calc(var(--spacing) * -0.5);
1030
1030
  }
1031
- .-mt-1 {
1032
- margin-top: calc(var(--spacing) * -1);
1033
- }
1034
1031
  .mt-1 {
1035
1032
  margin-top: calc(var(--spacing) * 1);
1036
1033
  }
@@ -1043,6 +1040,9 @@
1043
1040
  .mr-\[0\.3rem\] {
1044
1041
  margin-right: 0.3rem;
1045
1042
  }
1043
+ .mb-0 {
1044
+ margin-bottom: calc(var(--spacing) * 0);
1045
+ }
1046
1046
  .mb-1 {
1047
1047
  margin-bottom: calc(var(--spacing) * 1);
1048
1048
  }
@@ -1061,9 +1061,6 @@
1061
1061
  .ml-1 {
1062
1062
  margin-left: calc(var(--spacing) * 1);
1063
1063
  }
1064
- .ml-7 {
1065
- margin-left: calc(var(--spacing) * 7);
1066
- }
1067
1064
  .page-container {
1068
1065
  display: grid;
1069
1066
  grid-template-columns: 1fr 1rem minmax(0, 72rem) 1rem 1fr;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uibee",
3
- "version": "2.11.0",
3
+ "version": "2.12.1",
4
4
  "description": "Shared components, functions and hooks for reuse across Login projects",
5
5
  "homepage": "https://github.com/Login-Linjeforening-for-IT/uibee#readme",
6
6
  "bugs": {
@@ -1,41 +1,93 @@
1
1
  import { Check } from 'lucide-react'
2
- import { SelectionWrapper } from './shared'
2
+ import { FieldWrapper, InputLabel } from './shared'
3
3
 
4
- export type CheckboxProps = Omit<React.ComponentProps<'input'>, 'name'> & {
4
+ export type CheckboxOption = {
5
+ label: string
6
+ value: string | number
7
+ }
8
+
9
+ type CheckboxItemProps = Omit<React.ComponentProps<'input'>, 'name'> & {
10
+ name: string
11
+ label?: string
12
+ error?: string
13
+ info?: string
14
+ description?: string
15
+ className?: string
16
+ }
17
+
18
+ export type CheckboxProps = Omit<React.ComponentProps<'input'>, 'name' | 'onChange' | 'value'> & {
5
19
  name: string
6
20
  label?: string
7
21
  error?: string
8
22
  info?: string
9
23
  description?: string
10
24
  className?: string
25
+ options: CheckboxOption[]
26
+ value?: (string | number)[]
27
+ onChange?: (value: (string | number)[]) => void
11
28
  }
12
29
 
13
30
  export default function Checkbox(props: CheckboxProps) {
14
- const { name, label, error, info, description, className, ...inputProps } = props
31
+ const { options, onChange, value, label, description, error, info, name, className, ...rest } = props
32
+ const selectedValues = Array.isArray(value) ? value : []
15
33
 
16
34
  return (
17
- <SelectionWrapper
35
+ <FieldWrapper
18
36
  label={label}
19
37
  name={name}
20
- required={inputProps.required}
38
+ required={rest.required}
21
39
  info={info}
22
40
  description={description}
23
41
  error={error}
24
42
  className={className}
25
- disabled={inputProps.disabled}
26
43
  >
27
- <div className='relative flex items-center'>
44
+ <div className='flex flex-col gap-2'>
45
+ {options.map((option) => (
46
+ <CheckboxItem
47
+ key={option.value}
48
+ name={name}
49
+ value={option.value}
50
+ label={option.label}
51
+ checked={selectedValues.includes(option.value)}
52
+ disabled={rest.disabled}
53
+ onChange={(e) => {
54
+ if (!onChange) return
55
+ const isChecked = e.target.checked
56
+ let newValues = [...selectedValues]
57
+ if (isChecked) {
58
+ newValues.push(option.value)
59
+ } else {
60
+ newValues = newValues.filter((v) => v !== option.value)
61
+ }
62
+ onChange(newValues)
63
+ }}
64
+ className='mb-0'
65
+ />
66
+ ))}
67
+ </div>
68
+ </FieldWrapper>
69
+ )
70
+ }
71
+
72
+ function CheckboxItem(props: CheckboxItemProps) {
73
+ const { name, label, error, ...inputProps } = props
74
+ const id = inputProps.value ? `${name}-${inputProps.value}` : name
75
+
76
+ return (
77
+ <div className='flex items-center gap-2'>
78
+ <div className='relative w-5 h-5 shrink-0'>
28
79
  <input
29
80
  {...inputProps}
30
- id={name}
81
+ id={id}
31
82
  name={name}
32
83
  type='checkbox'
33
84
  className={`
34
- peer appearance-none h-5 w-5 rounded border border-login-500 bg-login-500/50
85
+ peer appearance-none rounded border border-login-500 bg-login-500/50
35
86
  checked:bg-login checked:border-login
36
87
  focus:outline-none focus:ring-2 focus:ring-login/50
37
88
  disabled:opacity-50 disabled:cursor-not-allowed
38
89
  cursor-pointer transition-all duration-200
90
+ w-5 h-5 absolute inset-0
39
91
  ${error ? 'border-red-500' : ''}
40
92
  `}
41
93
  />
@@ -47,6 +99,13 @@ export default function Checkbox(props: CheckboxProps) {
47
99
  `}
48
100
  />
49
101
  </div>
50
- </SelectionWrapper>
102
+ {label && (
103
+ <InputLabel
104
+ label={label}
105
+ name={name}
106
+ className='select-none cursor-pointer'
107
+ />
108
+ )}
109
+ </div>
51
110
  )
52
111
  }
@@ -1,6 +1,11 @@
1
- import { SelectionWrapper } from './shared'
1
+ import { FieldWrapper, InputLabel } from './shared'
2
2
 
3
- export type RadioProps = Omit<React.ComponentProps<'input'>, 'name'> & {
3
+ export type RadioOption = {
4
+ label: string
5
+ value: string | number
6
+ }
7
+
8
+ type RadioItemProps = Omit<React.ComponentProps<'input'>, 'name'> & {
4
9
  name: string
5
10
  label?: string
6
11
  error?: string
@@ -9,34 +14,71 @@ export type RadioProps = Omit<React.ComponentProps<'input'>, 'name'> & {
9
14
  className?: string
10
15
  }
11
16
 
17
+ export type RadioProps = Omit<React.ComponentProps<'input'>, 'name' | 'onChange' | 'value'> & {
18
+ name: string
19
+ label?: string
20
+ error?: string
21
+ info?: string
22
+ description?: string
23
+ className?: string
24
+ options: RadioOption[]
25
+ value?: string | number | null
26
+ onChange?: (value: string | number) => void
27
+ }
28
+
12
29
  export default function Radio(props: RadioProps) {
13
- const { name, label, error, info, description, className, ...inputProps } = props
14
- const { value } = inputProps
15
- const id = `${name}-${value}`
30
+ const { options, onChange, value, label, description, error, info, name, className, ...rest } = props
16
31
 
17
32
  return (
18
- <SelectionWrapper
33
+ <FieldWrapper
19
34
  label={label}
20
- name={id}
21
- required={inputProps.required}
35
+ name={name}
36
+ required={rest.required}
22
37
  info={info}
23
38
  description={description}
24
39
  error={error}
25
40
  className={className}
26
- disabled={inputProps.disabled}
27
41
  >
28
- <div className='relative flex items-center'>
42
+ <div className='flex flex-col gap-2'>
43
+ {options.map((option) => (
44
+ <RadioItem
45
+ key={option.value}
46
+ name={name}
47
+ value={option.value}
48
+ label={option.label}
49
+ checked={value === option.value}
50
+ disabled={rest.disabled}
51
+ onChange={() => {
52
+ if (onChange) onChange(option.value)
53
+ }}
54
+ className='mb-0'
55
+ />
56
+ ))}
57
+ </div>
58
+ </FieldWrapper>
59
+ )
60
+ }
61
+
62
+ function RadioItem(props: RadioItemProps) {
63
+ const { name, label, error, ...inputProps } = props
64
+ const { value } = inputProps
65
+ const id = `${name}-${value}`
66
+
67
+ return (
68
+ <div className='flex items-center gap-2'>
69
+ <div className='relative w-5 h-5 shrink-0'>
29
70
  <input
30
71
  {...inputProps}
31
72
  id={id}
32
73
  name={name}
33
74
  type='radio'
34
75
  className={`
35
- peer appearance-none h-5 w-5 rounded-full border border-login-500 bg-login-500/50
76
+ peer appearance-none rounded-full border border-login-500 bg-login-500/50
36
77
  checked:bg-login checked:border-login
37
78
  focus:outline-none focus:ring-2 focus:ring-login/50
38
79
  disabled:opacity-50 disabled:cursor-not-allowed
39
80
  cursor-pointer transition-all duration-200
81
+ w-5 h-5 absolute inset-0
40
82
  ${error ? 'border-red-500' : ''}
41
83
  `}
42
84
  />
@@ -44,8 +86,15 @@ export default function Radio(props: RadioProps) {
44
86
  absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
45
87
  w-2 h-2 rounded-full bg-white pointer-events-none opacity-0
46
88
  peer-checked:opacity-100 transition-opacity duration-200
47
- `}></div>
89
+ `}/>
48
90
  </div>
49
- </SelectionWrapper>
91
+ {label && (
92
+ <InputLabel
93
+ label={label}
94
+ name={name}
95
+ className='select-none cursor-pointer'
96
+ />
97
+ )}
98
+ </div>
50
99
  )
51
100
  }
@@ -1,5 +1,4 @@
1
1
  export { default as FieldWrapper } from './fieldWrapper'
2
- export { default as SelectionWrapper } from './selectionWrapper'
3
2
  export { default as InputLabel } from './inputLabel'
4
3
  export { default as InputInfo } from './inputInfo'
5
4
  export { default as InputError } from './inputError'
@@ -1,4 +1,4 @@
1
- import { SelectionWrapper } from './shared'
1
+ import { FieldWrapper } from './shared'
2
2
 
3
3
  export type SwitchProps = Omit<React.ComponentProps<'input'>, 'name'> & {
4
4
  name: string
@@ -14,16 +14,14 @@ export default function Switch(props: SwitchProps) {
14
14
  const { name, label, error, info, description, className, switchOnly, ...inputProps } = props
15
15
 
16
16
  return (
17
- <SelectionWrapper
17
+ <FieldWrapper
18
18
  label={label}
19
19
  name={name}
20
20
  required={inputProps.required}
21
21
  info={info}
22
- description={description}
23
22
  error={error}
24
- hideError={switchOnly}
23
+ description={description}
25
24
  className={className}
26
- disabled={inputProps.disabled}
27
25
  >
28
26
  <label className={`relative inline-flex items-center cursor-pointer ${switchOnly ? 'h-fit' : 'h-10.5'}`}>
29
27
  <input
@@ -41,8 +39,8 @@ export default function Switch(props: SwitchProps) {
41
39
  after:h-5 after:w-5 after:transition-all peer-checked:bg-login
42
40
  ${inputProps.disabled ? 'opacity-50 cursor-not-allowed' : ''}
43
41
  ${error ? 'ring-1 ring-red-500' : ''}
44
- `}></div>
42
+ `} />
45
43
  </label>
46
- </SelectionWrapper>
44
+ </FieldWrapper>
47
45
  )
48
46
  }
@@ -1,15 +0,0 @@
1
- import { ReactNode } from 'react';
2
- interface SelectionWrapperProps {
3
- label?: string;
4
- name: string;
5
- required?: boolean;
6
- info?: string;
7
- error?: string;
8
- description?: string;
9
- children: ReactNode;
10
- className?: string;
11
- disabled?: boolean;
12
- hideError?: boolean;
13
- }
14
- export default function SelectionWrapper({ label, name, required, info, error, description, children, className, disabled, hideError, }: SelectionWrapperProps): import("react/jsx-runtime").JSX.Element;
15
- export {};
@@ -1,7 +0,0 @@
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 SelectionWrapper({ label, name, required, info, error, description, children, className, disabled, hideError, }) {
6
- return (_jsxs("div", { className: `flex flex-col gap-1 ${className || ''}`, children: [_jsxs("div", { className: 'flex items-start justify-between mb-1', children: [_jsxs("div", { className: 'flex items-center gap-2', children: [children, label && (_jsx(InputLabel, { label: label, name: name, required: required, disabled: disabled, className: 'select-none cursor-pointer' }))] }), info && _jsx(InputInfo, { info: info })] }), description && (_jsx("p", { className: 'text-xs text-login-200 ml-7 -mt-1 mb-1', children: description })), !hideError && _jsx(InputError, { error: error })] }));
7
- }
@@ -1,56 +0,0 @@
1
- import { ReactNode } from 'react'
2
- import InputLabel from './inputLabel'
3
- import InputInfo from './inputInfo'
4
- import InputError from './inputError'
5
-
6
- interface SelectionWrapperProps {
7
- label?: string
8
- name: string
9
- required?: boolean
10
- info?: string
11
- error?: string
12
- description?: string
13
- children: ReactNode
14
- className?: string
15
- disabled?: boolean
16
- hideError?: boolean
17
- }
18
-
19
- export default function SelectionWrapper({
20
- label,
21
- name,
22
- required,
23
- info,
24
- error,
25
- description,
26
- children,
27
- className,
28
- disabled,
29
- hideError,
30
- }: SelectionWrapperProps) {
31
- return (
32
- <div className={`flex flex-col gap-1 ${className || ''}`}>
33
- <div className='flex items-start justify-between mb-1'>
34
- <div className='flex items-center gap-2'>
35
- {children}
36
- {label && (
37
- <InputLabel
38
- label={label}
39
- name={name}
40
- required={required}
41
- disabled={disabled}
42
- className='select-none cursor-pointer'
43
- />
44
- )}
45
- </div>
46
- {info && <InputInfo info={info} />}
47
- </div>
48
- {description && (
49
- <p className='text-xs text-login-200 ml-7 -mt-1 mb-1'>
50
- {description}
51
- </p>
52
- )}
53
- {!hideError && <InputError error={error} />}
54
- </div>
55
- )
56
- }