uibee 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/src/components/index.d.ts +5 -3
  2. package/dist/src/components/index.js +5 -3
  3. package/dist/src/components/inputs/checkbox.d.ts +13 -0
  4. package/dist/src/components/inputs/checkbox.js +17 -0
  5. package/dist/src/components/inputs/input.d.ts +11 -9
  6. package/dist/src/components/inputs/input.js +76 -9
  7. package/dist/src/components/inputs/radio.d.ts +14 -0
  8. package/dist/src/components/inputs/radio.js +17 -0
  9. package/dist/src/components/inputs/range.d.ts +17 -0
  10. package/dist/src/components/inputs/range.js +20 -0
  11. package/dist/src/components/inputs/select.d.ts +11 -11
  12. package/dist/src/components/inputs/select.js +54 -50
  13. package/dist/src/components/inputs/shared/dateTimePickerPopup.d.ts +8 -0
  14. package/dist/src/components/inputs/shared/dateTimePickerPopup.js +117 -0
  15. package/dist/src/components/inputs/shared/fieldWrapper.d.ts +12 -0
  16. package/dist/src/components/inputs/shared/fieldWrapper.js +7 -0
  17. package/dist/src/components/inputs/shared/index.d.ts +5 -0
  18. package/dist/src/components/inputs/shared/index.js +5 -0
  19. package/dist/src/components/inputs/shared/inputError.d.ts +6 -0
  20. package/dist/src/components/inputs/shared/inputError.js +6 -0
  21. package/dist/src/components/inputs/shared/inputInfo.d.ts +5 -0
  22. package/dist/src/components/inputs/shared/inputInfo.js +5 -0
  23. package/dist/src/components/inputs/shared/inputLabel.d.ts +9 -0
  24. package/dist/src/components/inputs/shared/inputLabel.js +4 -0
  25. package/dist/src/components/inputs/shared/selectionWrapper.d.ts +13 -0
  26. package/dist/src/components/inputs/shared/selectionWrapper.js +7 -0
  27. package/dist/src/components/inputs/switch.d.ts +10 -7
  28. package/dist/src/components/inputs/switch.js +13 -5
  29. package/dist/src/components/inputs/textarea.d.ts +15 -0
  30. package/dist/src/components/inputs/textarea.js +14 -0
  31. package/dist/src/globals.css +396 -161
  32. package/dist/src/hooks/index.d.ts +1 -0
  33. package/dist/src/hooks/index.js +1 -0
  34. package/dist/src/hooks/useClickOutside.d.ts +1 -0
  35. package/dist/src/hooks/useClickOutside.js +20 -0
  36. package/eslint.config.js +1 -0
  37. package/package.json +3 -2
  38. package/src/components/index.ts +5 -3
  39. package/src/components/inputs/checkbox.tsx +66 -0
  40. package/src/components/inputs/input.tsx +137 -35
  41. package/src/components/inputs/radio.tsx +67 -0
  42. package/src/components/inputs/range.tsx +84 -0
  43. package/src/components/inputs/select.tsx +137 -172
  44. package/src/components/inputs/shared/dateTimePickerPopup.tsx +219 -0
  45. package/src/components/inputs/shared/fieldWrapper.tsx +44 -0
  46. package/src/components/inputs/shared/index.ts +5 -0
  47. package/src/components/inputs/shared/inputError.tsx +21 -0
  48. package/src/components/inputs/shared/inputInfo.tsx +17 -0
  49. package/src/components/inputs/shared/inputLabel.tsx +19 -0
  50. package/src/components/inputs/shared/selectionWrapper.tsx +47 -0
  51. package/src/components/inputs/switch.tsx +48 -25
  52. package/src/components/inputs/textarea.tsx +65 -0
  53. package/src/components/logo/logo.tsx +1 -1
  54. package/src/globals.css +36 -0
  55. package/src/hooks/index.ts +1 -0
  56. package/src/hooks/useClickOutside.ts +27 -0
  57. package/dist/src/components/inputs/erase.d.ts +0 -3
  58. package/dist/src/components/inputs/erase.js +0 -5
  59. package/dist/src/components/inputs/label.d.ts +0 -10
  60. package/dist/src/components/inputs/label.js +0 -13
  61. package/dist/src/components/inputs/markdown.d.ts +0 -15
  62. package/dist/src/components/inputs/markdown.js +0 -32
  63. package/dist/src/components/inputs/tag.d.ts +0 -11
  64. package/dist/src/components/inputs/tag.js +0 -44
  65. package/dist/src/components/inputs/tooltip.d.ts +0 -4
  66. package/dist/src/components/inputs/tooltip.js +0 -4
  67. package/src/components/inputs/erase.tsx +0 -13
  68. package/src/components/inputs/label.tsx +0 -31
  69. package/src/components/inputs/markdown.tsx +0 -129
  70. package/src/components/inputs/tag.tsx +0 -137
  71. package/src/components/inputs/tooltip.tsx +0 -12
@@ -0,0 +1,47 @@
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
+ children: ReactNode
13
+ className?: string
14
+ disabled?: boolean
15
+ }
16
+
17
+ export default function SelectionWrapper({
18
+ label,
19
+ name,
20
+ required,
21
+ info,
22
+ error,
23
+ children,
24
+ className,
25
+ disabled,
26
+ }: SelectionWrapperProps) {
27
+ return (
28
+ <div className={`flex flex-col gap-1 ${className || ''}`}>
29
+ <div className='flex items-center justify-between mb-1'>
30
+ <div className='flex items-center gap-2'>
31
+ {children}
32
+ {label && (
33
+ <InputLabel
34
+ label={label}
35
+ name={name}
36
+ required={required}
37
+ disabled={disabled}
38
+ className='select-none cursor-pointer'
39
+ />
40
+ )}
41
+ </div>
42
+ {info && <InputInfo info={info} />}
43
+ </div>
44
+ <InputError error={error} />
45
+ </div>
46
+ )
47
+ }
@@ -1,39 +1,62 @@
1
- 'use client'
1
+ import { type ChangeEvent } from 'react'
2
+ import { SelectionWrapper } from './shared'
2
3
 
3
- import ToolTip from './tooltip'
4
-
5
- type SwitchProps = {
4
+ export type SwitchProps = {
5
+ label?: string
6
6
  name: string
7
- label: string
8
- value?: boolean
9
- setValue: (_: boolean) => void
7
+ checked?: boolean
8
+ onChange?: (e: ChangeEvent<HTMLInputElement>) => void
10
9
  className?: string
11
- tooltip?: string
10
+ disabled?: boolean
11
+ error?: string
12
+ info?: string
13
+ required?: boolean
12
14
  }
13
15
 
14
- export default function Switch({ name, label, value, className, tooltip, setValue }: SwitchProps) {
16
+ export default function Switch({
17
+ label,
18
+ name,
19
+ checked,
20
+ onChange,
21
+ className,
22
+ disabled,
23
+ error,
24
+ info,
25
+ required,
26
+ }: SwitchProps) {
15
27
  return (
16
- <div className={`relative w-full flex items-center px-2.5 pb-2.5 pt-3 border-login-200 rounded-lg border-[0.10rem]
17
- bg-login-800 ${className}`}
28
+ <SelectionWrapper
29
+ label={label}
30
+ name={name}
31
+ required={required}
32
+ info={info}
33
+ error={error}
34
+ className={className}
35
+ disabled={disabled}
18
36
  >
19
- <label className='flex items-center cursor-pointer'>
37
+ <label className='relative inline-flex items-center cursor-pointer'>
20
38
  <input
21
39
  type='checkbox'
40
+ id={name}
22
41
  name={name}
23
- className='sr-only'
24
- checked={value}
25
- onChange={(e) => setValue(e.target.checked)}
42
+ checked={checked}
43
+ onChange={onChange}
44
+ disabled={disabled}
45
+ required={required}
46
+ className='sr-only peer'
26
47
  />
27
- <div className={`w-10 h-6 rounded-full p-1 transition ${value ? 'bg-login-50' : 'bg-login-200'}`}>
28
- <div
29
- className={`w-4 h-4 bg-login-800 rounded-full shadow-md transform transition ${value ? 'translate-x-4' : ''}`}
30
- />
31
- </div>
48
+ <div className={`
49
+ w-11 h-6 bg-login-500/50 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-login/50
50
+ rounded-full peer
51
+ peer-checked:after:translate-x-full peer-checked:after:border-white
52
+ after:content-[''] after:absolute after:top-0.5 after:left-0.5
53
+ after:bg-white after:border-gray-300 after:border after:rounded-full
54
+ after:h-5 after:w-5 after:transition-all
55
+ peer-checked:bg-login
56
+ ${disabled ? 'opacity-50 cursor-not-allowed' : ''}
57
+ ${error ? 'ring-1 ring-red-500' : ''}
58
+ `}></div>
32
59
  </label>
33
- <span className='ml-3 text-sm'>
34
- {label}
35
- </span>
36
- {tooltip && <ToolTip info={tooltip} />}
37
- </div>
60
+ </SelectionWrapper>
38
61
  )
39
62
  }
@@ -0,0 +1,65 @@
1
+ import { type ChangeEvent } from 'react'
2
+ import { FieldWrapper } from './shared'
3
+
4
+ export type TextareaProps = {
5
+ label?: string
6
+ name: string
7
+ placeholder?: string
8
+ value?: string
9
+ onChange?: (e: ChangeEvent<HTMLTextAreaElement>) => void
10
+ error?: string
11
+ className?: string
12
+ disabled?: boolean
13
+ required?: boolean
14
+ rows?: number
15
+ info?: string
16
+ }
17
+
18
+ export default function Textarea({
19
+ label,
20
+ name,
21
+ placeholder,
22
+ value,
23
+ onChange,
24
+ error,
25
+ className,
26
+ disabled,
27
+ required,
28
+ rows = 4,
29
+ info,
30
+ }: TextareaProps) {
31
+ return (
32
+ <FieldWrapper
33
+ label={label}
34
+ name={name}
35
+ required={required}
36
+ info={info}
37
+ error={error}
38
+ className={className}
39
+ >
40
+ <textarea
41
+ id={name}
42
+ name={name}
43
+ placeholder={placeholder}
44
+ value={value}
45
+ onChange={onChange}
46
+ disabled={disabled}
47
+ required={required}
48
+ rows={rows}
49
+ title={label}
50
+ aria-invalid={!!error}
51
+ aria-describedby={error ? `${name}-error` : undefined}
52
+ className={`
53
+ w-full rounded-md bg-login-500/50 border border-login-500
54
+ text-login-text placeholder-login-200
55
+ focus:outline-none focus:border-login focus:ring-1 focus:ring-login
56
+ disabled:opacity-50 disabled:cursor-not-allowed
57
+ p-3
58
+ transition-all duration-200
59
+ resize-y
60
+ ${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : ''}
61
+ `}
62
+ />
63
+ </FieldWrapper>
64
+ )
65
+ }
@@ -35,7 +35,7 @@ export default function Logo({ className }: LogoProps) {
35
35
  <polyline className={letter} style={{strokeMiterlimit: 10}} points='161.983 98.122 176.665 98.122 176.665 83.44' transform='translate(-31.392,-41.894)' />
36
36
  <polyline className={letter} style={{strokeMiterlimit: 10}} points='176.665 58.372 176.665 43.69 161.983 43.69' transform='translate(-31.392,-41.894)' />
37
37
  <path className={corner} d='m 30.02449,40.19351 v 4.12842 H 12.4991 V 13.99038 h 4.92871 v 26.20313 z' />
38
- <path className={corner} d='m 61.53523,29.1564 a 17.15942,17.15942 0 0 1 -1.09473,6.21338 14.35971,14.35971 0 0 1 -3.08593,4.89746 14.091,14.091 0 0 1 -4.78125,3.21191 17.1289,17.1289 0 0 1 -12.38575,0 13.98317,13.98317 0 0 1 -7.88867,-8.10937 18.18161,18.18161 0 0 1 0,-12.42725 14.39119,14.39119 0 0 1 3.09668,-4.90771 14.13157,14.13157 0 0 1 4.792,-3.22315 17.13565,17.13565 0 0 1 12.38575,0 14.02046,14.02046 0 0 1 4.78125,3.22315 14.47032,14.47032 0 0 1 3.08593,4.90771 17.16209,17.16209 0 0 1 1.09472,6.21387 z m -5.03418,0 a 14.62587,14.62587 0 0 0 -0.70508,-4.69727 9.9446,9.9446 0 0 0 -2.02246,-3.53906 8.80545,8.80545 0 0 0 -3.1914,-2.23242 11.719,11.719 0 0 0 -8.4043,0 8.90077,8.90077 0 0 0 -3.20117,2.23242 9.96735,9.96735 0 0 0 -2.043,3.53906 15.81644,15.81644 0 0 0 0,9.415 9.847,9.847 0 0 0 2.043,3.52832 8.85094,8.85094 0 0 0 3.20117,2.21192 11.87213,11.87213 0 0 0 8.4043,0 8.75623,8.75623 0 0 0 3.1914,-2.21192 9.82454,9.82454 0 0 0 2.02249,-3.52828 14.69371,14.69371 0 0 0 0.70505,-4.71777 z' />
38
+ <path className='fill-login transition-all duration-1000' d='m 61.53523,29.1564 a 17.15942,17.15942 0 0 1 -1.09473,6.21338 14.35971,14.35971 0 0 1 -3.08593,4.89746 14.091,14.091 0 0 1 -4.78125,3.21191 17.1289,17.1289 0 0 1 -12.38575,0 13.98317,13.98317 0 0 1 -7.88867,-8.10937 18.18161,18.18161 0 0 1 0,-12.42725 14.39119,14.39119 0 0 1 3.09668,-4.90771 14.13157,14.13157 0 0 1 4.792,-3.22315 17.13565,17.13565 0 0 1 12.38575,0 14.02046,14.02046 0 0 1 4.78125,3.22315 14.47032,14.47032 0 0 1 3.08593,4.90771 17.16209,17.16209 0 0 1 1.09472,6.21387 z m -5.03418,0 a 14.62587,14.62587 0 0 0 -0.70508,-4.69727 9.9446,9.9446 0 0 0 -2.02246,-3.53906 8.80545,8.80545 0 0 0 -3.1914,-2.23242 11.719,11.719 0 0 0 -8.4043,0 8.90077,8.90077 0 0 0 -3.20117,2.23242 9.96735,9.96735 0 0 0 -2.043,3.53906 15.81644,15.81644 0 0 0 0,9.415 9.847,9.847 0 0 0 2.043,3.52832 8.85094,8.85094 0 0 0 3.20117,2.21192 11.87213,11.87213 0 0 0 8.4043,0 8.75623,8.75623 0 0 0 3.1914,-2.21192 9.82454,9.82454 0 0 0 2.02249,-3.52828 14.69371,14.69371 0 0 0 0.70505,-4.71777 z' />
39
39
  <path className={corner} d='m 91.76082,29.38784 v 12.00635 a 17.5354,17.5354 0 0 1 -10.53125,3.26465 18.41512,18.41512 0 0 1 -6.667,-1.148 14.80254,14.80254 0 0 1 -5.08691,-3.20166 14.0148,14.0148 0 0 1 -3.24316,-4.897 16.691,16.691 0 0 1 -1.1377,-6.25586 17.42935,17.42935 0 0 1 1.09473,-6.2876 13.74023,13.74023 0 0 1 8.06738,-8.08838 17.7222,17.7222 0 0 1 6.48828,-1.127 19.10354,19.10354 0 0 1 3.40137,0.28418 16.85244,16.85244 0 0 1 2.917,0.79 13.68442,13.68442 0 0 1 2.48633,1.22168 13.95372,13.95372 0 0 1 2.085,1.60058 l -1.41113,2.25391 a 1.40229,1.40229 0 0 1 -0.86426,0.65283 1.47784,1.47784 0 0 1 -1.13672,-0.25244 q -0.6123,-0.35816 -1.2959,-0.7583 a 11.33129,11.33129 0 0 0 -1.56933,-0.748 11.53387,11.53387 0 0 0 -2.043,-0.56836 14.78335,14.78335 0 0 0 -2.73828,-0.22119 11.32128,11.32128 0 0 0 -4.32813,0.78955 9.26752,9.26752 0 0 0 -3.29687,2.25391 9.99164,9.99164 0 0 0 -2.10645,3.54931 13.90267,13.90267 0 0 0 -0.7373,4.65528 14.11731,14.11731 0 0 0 0.77929,4.855 10.1425,10.1425 0 0 0 2.21192,3.62305 9.43419,9.43419 0 0 0 3.46484,2.26416 13.81975,13.81975 0 0 0 7.87793,0.3789 15.14816,15.14816 0 0 0 2.875,-1.11621 v -6.02383 h -4.2334 a 1.04883,1.04883 0 0 1 -0.75879,-0.26367 0.90553,0.90553 0 0 1 -0.27343,-0.68457 v -2.80127 z' />
40
40
  <path className={corner} d='M 102.546,44.32193 H 97.59581 V 13.99038 h 4.95019 z' />
41
41
  <path className={corner} d='m 134.8575,13.99038 v 30.33155 h -2.50684 a 2.14219,2.14219 0 0 1 -0.96875,-0.2002 2.26108,2.26108 0 0 1 -0.75879,-0.66357 L 113.962,22.05777 q 0.063,0.61083 0.0947,1.21093 0.0322,0.60058 0.0322,1.106 v 19.94723 h -4.3398 V 13.99038 h 2.57031 a 3.89092,3.89092 0 0 1 0.53711,0.03174 1.53328,1.53328 0 0 1 0.41016,0.11572 1.18964,1.18964 0 0 1 0.35839,0.25293 4.01792,4.01792 0 0 1 0.3584,0.4209 l 16.68164,21.42188 q -0.063,-0.65259 -0.0947,-1.28467 -0.0308,-0.63208 -0.0312,-1.17969 V 13.99038 Z' />
package/src/globals.css CHANGED
@@ -184,3 +184,39 @@
184
184
  font-size: 1.2rem;
185
185
  font-weight: 500;
186
186
  }
187
+
188
+ /* Hide default browser icons/buttons for inputs */
189
+ input::-webkit-calendar-picker-indicator {
190
+ display: none !important;
191
+ -webkit-appearance: none !important;
192
+ }
193
+
194
+ input::-webkit-outer-spin-button,
195
+ input::-webkit-inner-spin-button {
196
+ -webkit-appearance: none !important;
197
+ margin: 0 !important;
198
+ }
199
+
200
+ input[type='number'] {
201
+ -moz-appearance: textfield !important;
202
+ appearance: textfield !important;
203
+ }
204
+
205
+ input::-webkit-search-decoration,
206
+ input::-webkit-search-cancel-button,
207
+ input::-webkit-search-results-button,
208
+ input::-webkit-search-results-decoration {
209
+ -webkit-appearance: none !important;
210
+ }
211
+
212
+ input::-webkit-contacts-auto-fill-button,
213
+ input::-webkit-credentials-auto-fill-button {
214
+ visibility: hidden !important;
215
+ display: none !important;
216
+ pointer-events: none !important;
217
+ }
218
+
219
+ input::-ms-reveal,
220
+ input::-ms-clear {
221
+ display: none !important;
222
+ }
@@ -1,2 +1,3 @@
1
1
  export { default as useVisibility } from './useVisibility'
2
2
  export { default as useDarkMode } from './useDarkMode'
3
+ export { default as useClickOutside } from './useClickOutside'
@@ -0,0 +1,27 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ export default function useClickOutside<T extends HTMLElement>(
4
+ handler: (event: MouseEvent | TouchEvent) => void
5
+ ) {
6
+ const ref = useRef<T>(null)
7
+
8
+ useEffect(() => {
9
+ const listener = (event: MouseEvent | TouchEvent) => {
10
+ const el = ref.current
11
+ if (!el || el.contains(event.target as Node)) {
12
+ return
13
+ }
14
+ handler(event)
15
+ }
16
+
17
+ document.addEventListener('mousedown', listener)
18
+ document.addEventListener('touchstart', listener)
19
+
20
+ return () => {
21
+ document.removeEventListener('mousedown', listener)
22
+ document.removeEventListener('touchstart', listener)
23
+ }
24
+ }, [handler])
25
+
26
+ return ref
27
+ }
@@ -1,3 +0,0 @@
1
- export default function EraseButton({ setData }: {
2
- setData: (data: string) => void;
3
- }): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Eraser } from 'lucide-react';
3
- export default function EraseButton({ setData }) {
4
- return (_jsx("button", { type: 'button', onClick: () => setData(''), className: 'absolute right-1 cursor-pointer px-2 py-1 bg-login-800 hover:bg-login-600 rounded-md', children: _jsx(Eraser, { className: 'w-5' }) }));
5
- }
@@ -1,10 +0,0 @@
1
- type labelProps = {
2
- label: string;
3
- value: any;
4
- required?: boolean;
5
- showRequired?: boolean;
6
- className?: string;
7
- color?: string;
8
- };
9
- export default function Label({ label, value, required, showRequired, className, color }: labelProps): import("react/jsx-runtime").JSX.Element;
10
- export {};
@@ -1,13 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- export default function Label({ label, value, required, showRequired, className, color }) {
3
- return (_jsx("label", { className: 'w-[calc(100%-10px)] truncate pointer-events-none absolute text-sm duration-300 transform z-10 ' +
4
- 'peer-focus:px-2 peer-focus:top-2 origin-left px-2 pt-1 peer-focus:scale-75 peer-focus:-translate-y-5 start-2 ' +
5
- `${color ? color : 'bg-login-800'} ` +
6
- `${value ? '-translate-y-5 scale-75 top-2 w-fit '
7
- : '-translate-y-1/2 scale-100 top-1/2 '
8
- + 'peer-focus:w-fit '} ${showRequired ? 'text-red-500/50 ' : ''}
9
- ${!value &&
10
- required ? 'group-[.submitPressed]:text-red-500/50 ' : ''}
11
- ${required ? 'after:content-["_*"] ' : ''}
12
- ${className}`, children: label }));
13
- }
@@ -1,15 +0,0 @@
1
- type MarkdownProps = {
2
- name: string;
3
- label: string;
4
- value: string;
5
- setValue: (_: string | number) => void;
6
- className?: string;
7
- tooltip?: string;
8
- required?: boolean;
9
- rows?: number;
10
- color?: string;
11
- buttonColor?: string;
12
- buttonColorHighlighted?: string;
13
- };
14
- export default function Markdown({ name, label, value, className, tooltip, required, rows, setValue, color, buttonColor, buttonColorHighlighted }: MarkdownProps): import("react/jsx-runtime").JSX.Element;
15
- export {};
@@ -1,32 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useRef, useState } from 'react';
4
- import Label from './label';
5
- import ToolTip from './tooltip';
6
- export default function Markdown({ name, label, value, className, tooltip, required, rows = 6, setValue, color, buttonColor, buttonColorHighlighted }) {
7
- const [hasBlured, setHasBlured] = useState(false);
8
- const textareaRef = useRef(null);
9
- const smallButtonStyle = `px-2 py-1 rounded
10
- ${buttonColorHighlighted ? `hover:${buttonColorHighlighted}` : 'hover:bg-login-500'}
11
- ${' '}${buttonColor ? buttonColor : 'bg-login-600'}`;
12
- function wrapSelection(before, after = before, placeHolder = '') {
13
- const textarea = textareaRef.current;
14
- if (!textarea)
15
- return;
16
- const start = textarea.selectionStart;
17
- const end = textarea.selectionEnd;
18
- const selected = value.slice(start, end) || placeHolder;
19
- const newValue = value.slice(0, start) + before + selected + after + value.slice(end);
20
- setValue(newValue);
21
- requestAnimationFrame(() => {
22
- const pos = start + before.length;
23
- textarea.focus();
24
- textarea.setSelectionRange(pos, pos + selected.length);
25
- });
26
- }
27
- return (_jsxs("div", { className: `w-full ${className ?? ''}`, children: [_jsxs("div", { className: 'relative', children: [_jsx("textarea", { name: name, ref: textareaRef, value: value, onChange: (e) => setValue(e.target.value), onBlur: () => setHasBlured(true), rows: rows, required: required, className: 'block px-2.5 pb-2.5 pt-4 w-full text-sm ' +
28
- 'rounded-lg border-[0.10rem] appearance-none ' +
29
- 'border-login-200 focus:outline-none focus:ring-0' +
30
- ' focus:border-login-50 peer resize-vertical ' +
31
- `${color ? color : 'bg-login-800'}` }), _jsx(Label, { label: label, value: value, color: color, required: required, showRequired: required && !value && hasBlured }), tooltip && _jsx(ToolTip, { info: tooltip })] }), _jsx("div", { className: 'flex items-center justify-between gap-2 mt-2', children: _jsxs("div", { className: 'flex gap-2', children: [_jsx("button", { type: 'button', className: smallButtonStyle, onClick: () => wrapSelection('**', '**', 'bold'), children: "B" }), _jsx("button", { type: 'button', className: smallButtonStyle, onClick: () => wrapSelection('*', '*', 'italic'), children: "I" }), _jsx("button", { type: 'button', className: smallButtonStyle, onClick: () => wrapSelection('\n```\n', '\n```\n', 'code block'), children: "CB" }), _jsx("button", { type: 'button', className: smallButtonStyle, onClick: () => wrapSelection('[', '](url)', 'text'), children: "Link" }), _jsx("button", { type: 'button', className: smallButtonStyle, onClick: () => wrapSelection('\n- ', '', 'list item'), children: "UL" })] }) })] }));
32
- }
@@ -1,11 +0,0 @@
1
- type TagInputProps = {
2
- name: string;
3
- label: string;
4
- value?: string[];
5
- setValue: (_: string[]) => void;
6
- className?: string;
7
- tooltip?: string;
8
- required?: boolean;
9
- };
10
- export default function TagInput({ name, label, value, className, tooltip, required, setValue, }: TagInputProps): import("react/jsx-runtime").JSX.Element;
11
- export {};
@@ -1,44 +0,0 @@
1
- 'use client';
2
- 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
- import { X } from 'lucide-react';
8
- export default function TagInput({ name, label, value = [], className, tooltip, required, setValue, }) {
9
- const original = value;
10
- const [input, setInput] = useState('');
11
- const [hasBlured, setHasBlured] = useState(false);
12
- function addTag(value) {
13
- const trimmed = value.trim();
14
- if (trimmed && !value.includes(trimmed)) {
15
- setValue([...value, trimmed]);
16
- }
17
- }
18
- function removeTag(idx) {
19
- setValue(value.filter((_, i) => i !== idx));
20
- }
21
- function handleKeyDown(e) {
22
- if ((e.key === 'Enter' || e.key === ',' || e.key === 'Tab') &&
23
- input.trim()) {
24
- e.preventDefault();
25
- addTag(input);
26
- setInput('');
27
- }
28
- if (e.key === 'Backspace' && !input && value.length) {
29
- setValue(value.slice(0, -1));
30
- }
31
- }
32
- function handleErase() {
33
- setValue([]);
34
- setInput('');
35
- }
36
- const toRemove = original.filter((tag) => !value.includes(tag));
37
- const toAdd = value.filter((tag) => !original.includes(tag));
38
- return (_jsx("div", { className: `w-full ${className}`, children: _jsxs("div", { className: 'relative flex items-center flex-wrap gap-1 ' +
39
- 'border-[0.10rem] border-login-200 ' +
40
- 'rounded-lg ' +
41
- 'px-2.5 pt-3 pb-2.5 bg-login-800', children: [_jsxs("div", { className: 'flex flex-wrap gap-1 items-center w-full', children: [value.map((tag, idx) => (_jsxs("span", { className: 'bg-login-600 text-sm rounded px-2 ' +
42
- 'py-0.5 flex items-center gap-0.5', children: [tag, _jsx("button", { type: 'button', className: 'ml-1 text-red-700 hover:text-red-800', onClick: () => removeTag(idx), children: _jsx(X, { className: 'h-4 stroke-3' }) })] }, tag + idx))), _jsx("input", { value: input, onChange: (e) => setInput(e.target.value), onKeyDown: handleKeyDown, onBlur: () => setHasBlured(true), className: 'peer flex-1 min-w-[6ch] bg-transparent ' +
43
- 'outline-none text-sm', autoComplete: 'off', required: required && value.length === 0 }), toRemove.map((tag) => (_jsx("input", { type: 'hidden', name: name + '_remove', value: tag }, tag))), toAdd.map((tag) => (_jsx("input", { type: 'hidden', name: name + '_add', value: tag }, tag))), _jsx(Label, { label: label, value: value.length ? value.join(', ') : '', required: required, showRequired: required && value.length === 0 && hasBlured, className: 'pointer-events-none left-2' })] }), value.length > 0 && _jsx(EraseButton, { setData: handleErase }), value.length === 0 && tooltip && _jsx(ToolTip, { info: tooltip })] }) }));
44
- }
@@ -1,4 +0,0 @@
1
- export default function ToolTip({ info, className }: {
2
- info: string;
3
- className?: string;
4
- }): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export default function ToolTip({ info, className }) {
3
- return (_jsxs("div", { className: `absolute z-19 right-0 px-1 flex justify-center ${className}`, children: [_jsx("span", { className: 'peer cursor-pointer rounded-sm px-3 py-1 bg-login-800 hover:bg-login-600', children: "?" }), _jsx("div", { className: 'absolute hidden peer-hover:block p-2 rounded z-20 bg-login-700 border left-12 w-max max-w-3xs', children: info })] }));
4
- }
@@ -1,13 +0,0 @@
1
- import { Eraser } from 'lucide-react'
2
-
3
- export default function EraseButton({ setData }: { setData: (data: string) => void }) {
4
- return (
5
- <button
6
- type='button'
7
- onClick={() => setData('')}
8
- className={'absolute right-1 cursor-pointer px-2 py-1 bg-login-800 hover:bg-login-600 rounded-md'}
9
- >
10
- <Eraser className='w-5' />
11
- </button>
12
- )
13
- }
@@ -1,31 +0,0 @@
1
- type labelProps = {
2
- label: string
3
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
- value: any
5
- required?: boolean
6
- showRequired?: boolean
7
- className?: string
8
- color?: string
9
- }
10
-
11
- export default function Label({ label, value, required, showRequired, className, color }: labelProps) {
12
- return (
13
- <label
14
- className={
15
- 'w-[calc(100%-10px)] truncate pointer-events-none absolute text-sm duration-300 transform z-10 ' +
16
- 'peer-focus:px-2 peer-focus:top-2 origin-left px-2 pt-1 peer-focus:scale-75 peer-focus:-translate-y-5 start-2 ' +
17
- `${color ? color : 'bg-login-800'} ` +
18
- `${value ? '-translate-y-5 scale-75 top-2 w-fit '
19
- : '-translate-y-1/2 scale-100 top-1/2 '
20
- + 'peer-focus:w-fit '
21
- } ${showRequired ? 'text-red-500/50 ' : ''}
22
- ${!value &&
23
- required ? 'group-[.submitPressed]:text-red-500/50 ' : ''}
24
- ${required ? 'after:content-["_*"] ' : ''}
25
- ${className}`
26
- }
27
- >
28
- {label}
29
- </label>
30
- )
31
- }
@@ -1,129 +0,0 @@
1
- 'use client'
2
-
3
- import { useRef, useState } from 'react'
4
- import Label from './label'
5
- import ToolTip from './tooltip'
6
-
7
- type MarkdownProps = {
8
- name: string
9
- label: string
10
- value: string
11
- setValue: (_: string | number) => void
12
- className?: string
13
- tooltip?: string
14
- required?: boolean
15
- rows?: number
16
- color?: string
17
- buttonColor?: string
18
- buttonColorHighlighted?: string
19
- }
20
-
21
- export default function Markdown({
22
- name,
23
- label,
24
- value,
25
- className,
26
- tooltip,
27
- required,
28
- rows = 6,
29
- setValue,
30
- color,
31
- buttonColor,
32
- buttonColorHighlighted
33
- }: MarkdownProps) {
34
- const [hasBlured, setHasBlured] = useState(false)
35
- const textareaRef = useRef<HTMLTextAreaElement | null>(null)
36
- const smallButtonStyle = `px-2 py-1 rounded
37
- ${buttonColorHighlighted ? `hover:${buttonColorHighlighted}` : 'hover:bg-login-500'}
38
- ${' '}${buttonColor ? buttonColor : 'bg-login-600'}`
39
-
40
- function wrapSelection(before: string, after = before, placeHolder = '') {
41
- const textarea = textareaRef.current
42
- if (!textarea) return
43
- const start = textarea.selectionStart
44
- const end = textarea.selectionEnd
45
- const selected = value.slice(start, end) || placeHolder
46
- const newValue =
47
- value.slice(0, start) + before + selected + after + value.slice(end)
48
- setValue(newValue)
49
- requestAnimationFrame(() => {
50
- const pos = start + before.length
51
- textarea.focus()
52
- textarea.setSelectionRange(pos, pos + selected.length)
53
- })
54
- }
55
-
56
- return (
57
- <div className={`w-full ${className ?? ''}`}>
58
- <div className='relative'>
59
- <textarea
60
- name={name}
61
- ref={textareaRef}
62
- value={value}
63
- onChange={(e) => setValue(e.target.value)}
64
- onBlur={() => setHasBlured(true)}
65
- rows={rows}
66
- required={required}
67
- className={
68
- 'block px-2.5 pb-2.5 pt-4 w-full text-sm ' +
69
- 'rounded-lg border-[0.10rem] appearance-none ' +
70
- 'border-login-200 focus:outline-none focus:ring-0' +
71
- ' focus:border-login-50 peer resize-vertical ' +
72
- `${color ? color : 'bg-login-800'}`
73
- }
74
- />
75
-
76
- <Label
77
- label={label}
78
- value={value}
79
- color={color}
80
- required={required}
81
- showRequired={required && !value && hasBlured}
82
- />
83
- {tooltip && <ToolTip info={tooltip} />}
84
- </div>
85
-
86
- <div className='flex items-center justify-between gap-2 mt-2'>
87
- <div className='flex gap-2'>
88
- <button
89
- type='button'
90
- className={smallButtonStyle}
91
- onClick={() => wrapSelection('**', '**', 'bold')}
92
- >
93
- B
94
- </button>
95
- <button
96
- type='button'
97
- className={smallButtonStyle}
98
- onClick={() => wrapSelection('*', '*', 'italic')}
99
- >
100
- I
101
- </button>
102
- <button
103
- type='button'
104
- className={smallButtonStyle}
105
- onClick={() =>
106
- wrapSelection('\n```\n', '\n```\n', 'code block')
107
- }
108
- >
109
- CB
110
- </button>
111
- <button
112
- type='button'
113
- className={smallButtonStyle}
114
- onClick={() => wrapSelection('[', '](url)', 'text')}
115
- >
116
- Link
117
- </button>
118
- <button
119
- type='button'
120
- className={smallButtonStyle}
121
- onClick={() => wrapSelection('\n- ', '', 'list item')}
122
- >
123
- UL
124
- </button>
125
- </div>
126
- </div>
127
- </div>
128
- )
129
- }