uibee 2.2.6 → 2.2.8
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.
- package/dist/globals.css +31 -0
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/components/index.js +1 -0
- package/dist/src/components/inputs/select.d.ts +19 -0
- package/dist/src/components/inputs/select.js +53 -0
- package/dist/src/utils/auth/token.js +1 -1
- package/package.json +1 -1
- package/src/components/index.ts +1 -0
- package/src/components/inputs/select.tsx +204 -0
- package/src/utils/auth/token.ts +1 -1
package/dist/globals.css
CHANGED
|
@@ -254,6 +254,9 @@
|
|
|
254
254
|
.relative {
|
|
255
255
|
position: relative;
|
|
256
256
|
}
|
|
257
|
+
.sticky {
|
|
258
|
+
position: sticky;
|
|
259
|
+
}
|
|
257
260
|
.start-2 {
|
|
258
261
|
inset-inline-start: calc(var(--spacing) * 2);
|
|
259
262
|
}
|
|
@@ -278,6 +281,9 @@
|
|
|
278
281
|
.top-16 {
|
|
279
282
|
top: calc(var(--spacing) * 16);
|
|
280
283
|
}
|
|
284
|
+
.top-full {
|
|
285
|
+
top: 100%;
|
|
286
|
+
}
|
|
281
287
|
.right-0 {
|
|
282
288
|
right: calc(var(--spacing) * 0);
|
|
283
289
|
}
|
|
@@ -323,6 +329,9 @@
|
|
|
323
329
|
.-mt-0\.5 {
|
|
324
330
|
margin-top: calc(var(--spacing) * -0.5);
|
|
325
331
|
}
|
|
332
|
+
.mt-1 {
|
|
333
|
+
margin-top: calc(var(--spacing) * 1);
|
|
334
|
+
}
|
|
326
335
|
.mt-2 {
|
|
327
336
|
margin-top: calc(var(--spacing) * 2);
|
|
328
337
|
}
|
|
@@ -395,6 +404,9 @@
|
|
|
395
404
|
.max-h-0 {
|
|
396
405
|
max-height: calc(var(--spacing) * 0);
|
|
397
406
|
}
|
|
407
|
+
.max-h-72 {
|
|
408
|
+
max-height: calc(var(--spacing) * 72);
|
|
409
|
+
}
|
|
398
410
|
.max-h-\[calc\(100vh-4rem\)\] {
|
|
399
411
|
max-height: calc(100vh - 4rem);
|
|
400
412
|
}
|
|
@@ -598,6 +610,9 @@
|
|
|
598
610
|
text-overflow: ellipsis;
|
|
599
611
|
white-space: nowrap;
|
|
600
612
|
}
|
|
613
|
+
.overflow-auto {
|
|
614
|
+
overflow: auto;
|
|
615
|
+
}
|
|
601
616
|
.overflow-hidden {
|
|
602
617
|
overflow: hidden;
|
|
603
618
|
}
|
|
@@ -633,6 +648,10 @@
|
|
|
633
648
|
border-style: var(--tw-border-style);
|
|
634
649
|
border-width: 0.10rem;
|
|
635
650
|
}
|
|
651
|
+
.border-b {
|
|
652
|
+
border-bottom-style: var(--tw-border-style);
|
|
653
|
+
border-bottom-width: 1px;
|
|
654
|
+
}
|
|
636
655
|
.border-none {
|
|
637
656
|
--tw-border-style: none;
|
|
638
657
|
border-style: none;
|
|
@@ -715,6 +734,9 @@
|
|
|
715
734
|
.object-contain {
|
|
716
735
|
object-fit: contain;
|
|
717
736
|
}
|
|
737
|
+
.p-0 {
|
|
738
|
+
padding: calc(var(--spacing) * 0);
|
|
739
|
+
}
|
|
718
740
|
.p-1 {
|
|
719
741
|
padding: calc(var(--spacing) * 1);
|
|
720
742
|
}
|
|
@@ -920,6 +942,10 @@
|
|
|
920
942
|
--tw-shadow: 0 0.1rem 0.5rem var(--tw-shadow-color, rgba(3,3,3,0.5));
|
|
921
943
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
922
944
|
}
|
|
945
|
+
.shadow-lg {
|
|
946
|
+
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
947
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
948
|
+
}
|
|
923
949
|
.shadow-md {
|
|
924
950
|
--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
925
951
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -1093,6 +1119,11 @@
|
|
|
1093
1119
|
top: calc(var(--spacing) * 2);
|
|
1094
1120
|
}
|
|
1095
1121
|
}
|
|
1122
|
+
.peer-focus\:block {
|
|
1123
|
+
&:is(:where(.peer):focus ~ *) {
|
|
1124
|
+
display: block;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1096
1127
|
.peer-focus\:w-fit {
|
|
1097
1128
|
&:is(:where(.peer):focus ~ *) {
|
|
1098
1129
|
width: fit-content;
|
|
@@ -2,6 +2,7 @@ export { default as Input } from './inputs/input';
|
|
|
2
2
|
export { default as SwitchInput } from './inputs/switch';
|
|
3
3
|
export { default as TagInput } from './inputs/tag';
|
|
4
4
|
export { default as Textarea } from './inputs/markdown';
|
|
5
|
+
export { default as Select } from './inputs/select';
|
|
5
6
|
export { default as Logo } from './logo/logo';
|
|
6
7
|
export { default as LogoSmall } from './logo/logoSmall';
|
|
7
8
|
export { default as ThemeToggle } from './toggle/theme';
|
|
@@ -3,6 +3,7 @@ export { default as Input } from './inputs/input';
|
|
|
3
3
|
export { default as SwitchInput } from './inputs/switch';
|
|
4
4
|
export { default as TagInput } from './inputs/tag';
|
|
5
5
|
export { default as Textarea } from './inputs/markdown';
|
|
6
|
+
export { default as Select } from './inputs/select';
|
|
6
7
|
// Logos
|
|
7
8
|
export { default as Logo } from './logo/logo';
|
|
8
9
|
export { default as LogoSmall } from './logo/logoSmall';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type Option = {
|
|
2
|
+
value: string | number;
|
|
3
|
+
label: string;
|
|
4
|
+
image?: string;
|
|
5
|
+
};
|
|
6
|
+
type SelectProps = {
|
|
7
|
+
name: string;
|
|
8
|
+
label: string;
|
|
9
|
+
value: string | number;
|
|
10
|
+
setValue: (_: string | number) => void;
|
|
11
|
+
options: Option[];
|
|
12
|
+
className?: string;
|
|
13
|
+
tooltip?: string;
|
|
14
|
+
required?: boolean;
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
color?: string;
|
|
17
|
+
};
|
|
18
|
+
export default function Select({ name, label, value, options, className, tooltip, required, children, setValue, color }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
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();
|
|
17
|
+
}
|
|
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 }) }) }));
|
|
53
|
+
}
|
|
@@ -12,7 +12,7 @@ export default async function AuthToken({ req, frontendURL, redirectPath }) {
|
|
|
12
12
|
const accessToken = url.searchParams.get('access_token');
|
|
13
13
|
const userID = url.searchParams.get('id');
|
|
14
14
|
const username = url.searchParams.get('name');
|
|
15
|
-
const userNickname = url.searchParams.get('
|
|
15
|
+
const userNickname = url.searchParams.get('username');
|
|
16
16
|
const userEmail = url.searchParams.get('email');
|
|
17
17
|
const userGroups = url.searchParams.get('groups');
|
|
18
18
|
const response = NextResponse.redirect(new URL(redirectPath || '/', frontendURL));
|
package/package.json
CHANGED
package/src/components/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { default as Input } from './inputs/input'
|
|
|
3
3
|
export { default as SwitchInput } from './inputs/switch'
|
|
4
4
|
export { default as TagInput } from './inputs/tag'
|
|
5
5
|
export { default as Textarea } from './inputs/markdown'
|
|
6
|
+
export { default as Select } from './inputs/select'
|
|
6
7
|
|
|
7
8
|
// Logos
|
|
8
9
|
export { default as Logo } from './logo/logo'
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useRef, useState } from 'react'
|
|
4
|
+
import ToolTip from './tooltip'
|
|
5
|
+
import Label from './label'
|
|
6
|
+
import EraseButton from './erase'
|
|
7
|
+
|
|
8
|
+
type Option = {
|
|
9
|
+
value: string | number;
|
|
10
|
+
label: string;
|
|
11
|
+
image?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
type SelectProps = {
|
|
16
|
+
name: string
|
|
17
|
+
label: string
|
|
18
|
+
value: string | number
|
|
19
|
+
setValue: (_: string | number) => void
|
|
20
|
+
options: Option[]
|
|
21
|
+
className?: string
|
|
22
|
+
tooltip?: string
|
|
23
|
+
required?: boolean
|
|
24
|
+
children?: React.ReactNode
|
|
25
|
+
color?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type SelectedOptionProps = {
|
|
29
|
+
value: string | number
|
|
30
|
+
selectedOption: Option | undefined
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default function Select({
|
|
34
|
+
name,
|
|
35
|
+
label,
|
|
36
|
+
value,
|
|
37
|
+
options,
|
|
38
|
+
className,
|
|
39
|
+
tooltip,
|
|
40
|
+
required,
|
|
41
|
+
children,
|
|
42
|
+
setValue,
|
|
43
|
+
color
|
|
44
|
+
}: SelectProps) {
|
|
45
|
+
const [hasBlured, setHasBlured] = useState(false)
|
|
46
|
+
const selectRef = useRef<HTMLSelectElement | null>(null)
|
|
47
|
+
const selectedOption = options.find((o) => o.value === value)
|
|
48
|
+
|
|
49
|
+
function handleChoose(value: string | number) {
|
|
50
|
+
setValue(value)
|
|
51
|
+
setHasBlured(true)
|
|
52
|
+
if (selectRef.current) {
|
|
53
|
+
selectRef.current.value = String(value)
|
|
54
|
+
selectRef.current.blur()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div className={`w-full ${className}`}>
|
|
60
|
+
<div className='relative flex items-center'>
|
|
61
|
+
<select
|
|
62
|
+
ref={selectRef}
|
|
63
|
+
name={name}
|
|
64
|
+
className={
|
|
65
|
+
'peer cursor-pointer block px-2.5 pb-2.5 pt-4 ' +
|
|
66
|
+
'w-full text-sm rounded-lg border-[0.10rem] ' +
|
|
67
|
+
'appearance-none border-login-200 focus:ring-0 ' +
|
|
68
|
+
'focus:outline-none focus:border-login-50 ' +
|
|
69
|
+
`${color ? color : 'bg-login-800'}`
|
|
70
|
+
}
|
|
71
|
+
value={value}
|
|
72
|
+
onChange={(e) => {
|
|
73
|
+
setValue(e.target.value)
|
|
74
|
+
setHasBlured(true)
|
|
75
|
+
}}
|
|
76
|
+
onBlur={() => setHasBlured(true)}
|
|
77
|
+
onMouseDown={(e) => {
|
|
78
|
+
e.preventDefault()
|
|
79
|
+
selectRef.current?.focus()
|
|
80
|
+
}}
|
|
81
|
+
required={required}
|
|
82
|
+
>
|
|
83
|
+
<option value='' hidden />
|
|
84
|
+
{options.map((option) => (
|
|
85
|
+
<option key={option.value} value={option.value}>
|
|
86
|
+
{option.label}
|
|
87
|
+
</option>
|
|
88
|
+
))}
|
|
89
|
+
</select>
|
|
90
|
+
|
|
91
|
+
<Label
|
|
92
|
+
label={label}
|
|
93
|
+
value={value}
|
|
94
|
+
required={required}
|
|
95
|
+
color={color}
|
|
96
|
+
showRequired={required && !value && hasBlured}
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
{value && (
|
|
100
|
+
<EraseButton
|
|
101
|
+
setData={(v: string) => {
|
|
102
|
+
setValue(v)
|
|
103
|
+
setHasBlured(true)
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
)}
|
|
107
|
+
{!value && tooltip && <ToolTip info={tooltip} />}
|
|
108
|
+
|
|
109
|
+
<SelectContent
|
|
110
|
+
options={options}
|
|
111
|
+
value={value}
|
|
112
|
+
selectedOption={selectedOption}
|
|
113
|
+
handleChoose={handleChoose}
|
|
114
|
+
color={color}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
{children}
|
|
118
|
+
</div>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function SelectContent({
|
|
123
|
+
options,
|
|
124
|
+
value,
|
|
125
|
+
selectedOption,
|
|
126
|
+
handleChoose,
|
|
127
|
+
color
|
|
128
|
+
}: {
|
|
129
|
+
options: Option[]
|
|
130
|
+
value: string | number
|
|
131
|
+
selectedOption: Option | undefined
|
|
132
|
+
handleChoose: (value: string | number) => void
|
|
133
|
+
color?: string
|
|
134
|
+
}) {
|
|
135
|
+
return (
|
|
136
|
+
<div
|
|
137
|
+
className={
|
|
138
|
+
'hidden peer-focus:block absolute left-0 ' +
|
|
139
|
+
'right-0 top-full mt-1 z-50'
|
|
140
|
+
}
|
|
141
|
+
>
|
|
142
|
+
<div
|
|
143
|
+
className={
|
|
144
|
+
`${color ? color : 'bg-login-800'}` + ' border-[0.10rem] border-login-200 ' +
|
|
145
|
+
'rounded-lg shadow-lg p-0 max-h-72 overflow-hidden'
|
|
146
|
+
}
|
|
147
|
+
>
|
|
148
|
+
<div className='max-h-72 overflow-auto'>
|
|
149
|
+
<SelectedOption
|
|
150
|
+
value={value}
|
|
151
|
+
selectedOption={selectedOption}
|
|
152
|
+
/>
|
|
153
|
+
<div className='p-2'>
|
|
154
|
+
{options
|
|
155
|
+
.filter((o) => o.value !== value)
|
|
156
|
+
.map((opt) => (
|
|
157
|
+
<button
|
|
158
|
+
key={opt.value}
|
|
159
|
+
type='button'
|
|
160
|
+
className={
|
|
161
|
+
'cursor-pointer w-full flex ' +
|
|
162
|
+
'items-center gap-3 px-2 py-2 ' +
|
|
163
|
+
'text-sm hover:bg-surface ' +
|
|
164
|
+
'rounded hover:bg-login-600'
|
|
165
|
+
}
|
|
166
|
+
onMouseDown={(e) => {
|
|
167
|
+
e.preventDefault()
|
|
168
|
+
handleChoose(opt.value)
|
|
169
|
+
}}
|
|
170
|
+
>
|
|
171
|
+
<span className='text-left'>
|
|
172
|
+
{opt.label}
|
|
173
|
+
</span>
|
|
174
|
+
</button>
|
|
175
|
+
))}
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function SelectedOption({ value, selectedOption }: SelectedOptionProps) {
|
|
184
|
+
if (!value) {
|
|
185
|
+
return <></>
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<div
|
|
190
|
+
className={
|
|
191
|
+
'sticky top-0 bg-surface px-2 py-2 z-10 border-b ' +
|
|
192
|
+
'border-login-200 bg-login-600'
|
|
193
|
+
}
|
|
194
|
+
>
|
|
195
|
+
<div className='flex items-center gap-3'>
|
|
196
|
+
<span className='font-medium text-left'>
|
|
197
|
+
{selectedOption?.label}
|
|
198
|
+
</span>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
|
package/src/utils/auth/token.ts
CHANGED
|
@@ -16,7 +16,7 @@ export default async function AuthToken({ req, frontendURL, redirectPath }: Auth
|
|
|
16
16
|
const accessToken = url.searchParams.get('access_token')!
|
|
17
17
|
const userID = url.searchParams.get('id')!
|
|
18
18
|
const username = url.searchParams.get('name')!
|
|
19
|
-
const userNickname = url.searchParams.get('
|
|
19
|
+
const userNickname = url.searchParams.get('username')!
|
|
20
20
|
const userEmail = url.searchParams.get('email')!
|
|
21
21
|
const userGroups = url.searchParams.get('groups')!
|
|
22
22
|
|