uibee 2.16.35 → 2.16.37
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/src/components/inputs/input.js +5 -3
- package/dist/src/components/inputs/shared/colorPickerPopup.d.ts +2 -1
- package/dist/src/components/inputs/shared/colorPickerPopup.js +8 -2
- package/dist/src/components/inputs/shared/dateTimePickerPopup.d.ts +2 -1
- package/dist/src/components/inputs/shared/dateTimePickerPopup.js +8 -2
- package/dist/src/components/table/header.js +8 -2
- package/dist/src/globals.css +8 -3
- package/package.json +2 -2
- package/src/components/inputs/input.tsx +6 -3
- package/src/components/inputs/shared/colorPickerPopup.tsx +12 -2
- package/src/components/inputs/shared/dateTimePickerPopup.tsx +12 -1
- package/src/components/table/header.tsx +10 -2
- package/src/globals.css +10 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRef, useState } from 'react';
|
|
2
|
+
import { useRef, useState, useId } from 'react';
|
|
3
3
|
import { Calendar, Clock } from 'lucide-react';
|
|
4
4
|
import { FieldWrapper } from './shared';
|
|
5
5
|
import DateTimePickerPopup from './shared/dateTimePickerPopup';
|
|
@@ -10,6 +10,8 @@ export default function Input(props) {
|
|
|
10
10
|
const { type = 'text', value } = inputProps;
|
|
11
11
|
const localRef = useRef(null);
|
|
12
12
|
const [isOpen, setIsOpen] = useState(false);
|
|
13
|
+
const id = useId();
|
|
14
|
+
const anchorName = `--input-${id.replace(/:/g, '')}`;
|
|
13
15
|
const containerRef = useClickOutside(() => setIsOpen(false));
|
|
14
16
|
const isDateType = ['date', 'datetime-local', 'time'].includes(type);
|
|
15
17
|
const isColorType = type === 'color';
|
|
@@ -108,7 +110,7 @@ export default function Input(props) {
|
|
|
108
110
|
return (_jsx(FieldWrapper, { label: label, name: name, required: inputProps.required, info: info, error: error, description: description, textSize: textSize, className: className, children: _jsxs("div", { className: 'relative flex items-center', ref: containerRef, children: [displayIcon && (_jsx("div", { className: `
|
|
109
111
|
absolute left-3 text-login-200
|
|
110
112
|
${isClickableType && !inputProps.disabled ? 'cursor-pointer hover:text-login-text' : 'pointer-events-none'}
|
|
111
|
-
`, onClick: handleIconClick, children: displayIcon })), _jsx("input", { ...inputProps, ref: localRef, id: name, name: isClickableType ? undefined : name, type: isClickableType ? 'text' : type, value: isDateType ? getDateDisplayValue() : value, readOnly: isClickableType, onClick: () => isClickableType && !inputProps.disabled && setIsOpen(true),
|
|
113
|
+
`, onClick: handleIconClick, children: displayIcon })), _jsx("input", { ...inputProps, ref: localRef, id: name, name: isClickableType ? undefined : name, type: isClickableType ? 'text' : type, value: isDateType ? getDateDisplayValue() : value, readOnly: isClickableType, onClick: () => isClickableType && !inputProps.disabled && setIsOpen(true), "aria-describedby": error ? `${name}-error` : undefined, style: { anchorName }, className: `
|
|
112
114
|
w-full rounded-md bg-login-500/50 border border-login-500
|
|
113
115
|
text-login-text placeholder-login-200
|
|
114
116
|
focus:outline-none focus:border-login focus:ring-1 focus:ring-login
|
|
@@ -118,5 +120,5 @@ export default function Input(props) {
|
|
|
118
120
|
input-reset
|
|
119
121
|
${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : ''}
|
|
120
122
|
${isClickableType && !inputProps.disabled ? 'cursor-pointer' : ''}
|
|
121
|
-
` }), isClickableType && (_jsx("input", { type: 'hidden', name: name, value: value })), isOpen && isDateType && !inputProps.disabled && (_jsx(DateTimePickerPopup, { value: getDateValue(), onChange: handleDateChange, type: type, onClose: () => setIsOpen(false) })), isOpen && isColorType && !inputProps.disabled && (_jsx(ColorPickerPopup, { value: value || '', onChange: handleColorChange, onClose: () => setIsOpen(false) }))] }) }));
|
|
123
|
+
` }), isClickableType && (_jsx("input", { type: 'hidden', name: name, value: value })), isOpen && isDateType && !inputProps.disabled && (_jsx(DateTimePickerPopup, { value: getDateValue(), onChange: handleDateChange, type: type, onClose: () => setIsOpen(false), anchorName: anchorName })), isOpen && isColorType && !inputProps.disabled && (_jsx(ColorPickerPopup, { value: value || '', onChange: handleColorChange, onClose: () => setIsOpen(false), anchorName: anchorName }))] }) }));
|
|
122
124
|
}
|
|
@@ -3,5 +3,6 @@ export type ColorPickerPopupProps = {
|
|
|
3
3
|
value: string;
|
|
4
4
|
onChange: (color: string) => void;
|
|
5
5
|
onClose: () => void;
|
|
6
|
+
anchorName?: string;
|
|
6
7
|
};
|
|
7
|
-
export default function ColorPickerPopup({ value, onChange, onClose }: ColorPickerPopupProps): JSX.Element;
|
|
8
|
+
export default function ColorPickerPopup({ value, onChange, onClose, anchorName }: ColorPickerPopupProps): JSX.Element;
|
|
@@ -142,7 +142,7 @@ function HuePicker({ hue, onChange }) {
|
|
|
142
142
|
top-1/2 pointer-events-none
|
|
143
143
|
`, style: { left: `${(hue / 360) * 100}%` } }) }));
|
|
144
144
|
}
|
|
145
|
-
export default function ColorPickerPopup({ value, onChange, onClose }) {
|
|
145
|
+
export default function ColorPickerPopup({ value, onChange, onClose, anchorName }) {
|
|
146
146
|
const [hsv, setHsv] = useState(() => hexToHsv(value || '#000000'));
|
|
147
147
|
const [hexInput, setHexInput] = useState(value || '#000000');
|
|
148
148
|
useEffect(() => {
|
|
@@ -168,7 +168,13 @@ export default function ColorPickerPopup({ value, onChange, onClose }) {
|
|
|
168
168
|
onChange(val);
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
return (_jsxs("div", { className: '
|
|
171
|
+
return (_jsxs("div", { className: 'fixed z-50 bg-login-600 border border-login-500 rounded-md shadow-lg p-3 w-64 select-none anchor-popup', style: {
|
|
172
|
+
positionAnchor: anchorName,
|
|
173
|
+
positionArea: 'bottom span-right',
|
|
174
|
+
insetArea: 'bottom span-right',
|
|
175
|
+
positionTryFallbacks: 'flip-block',
|
|
176
|
+
margin: '0.25rem 0',
|
|
177
|
+
}, children: [_jsx(SaturationPicker, { hsv: hsv, onChange: handleSaturationChange }), _jsx(HuePicker, { hue: hsv.h, onChange: handleHueChange }), _jsxs("div", { className: 'flex items-center gap-2 mb-3', children: [_jsx("div", { className: 'text-xs text-login-200 font-mono', children: "HEX" }), _jsx("input", { type: 'text', value: hexInput, onChange: manualHexChange, className: `
|
|
172
178
|
flex-1 min-w-0 bg-login-500 border border-login-500 rounded
|
|
173
179
|
px-2 py-1 text-sm text-login-text focus:outline-none
|
|
174
180
|
focus:border-login focus:ring-1 focus:ring-login
|
|
@@ -3,6 +3,7 @@ type DateTimePickerPopupProps = {
|
|
|
3
3
|
onChange: (date: Date) => void;
|
|
4
4
|
type: 'date' | 'time' | 'datetime-local';
|
|
5
5
|
onClose?: () => void;
|
|
6
|
+
anchorName?: string;
|
|
6
7
|
};
|
|
7
|
-
export default function DateTimePickerPopup({ value, onChange, type, onClose, }: DateTimePickerPopupProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default function DateTimePickerPopup({ value, onChange, type, onClose, anchorName, }: DateTimePickerPopupProps): import("react/jsx-runtime").JSX.Element;
|
|
8
9
|
export {};
|
|
@@ -6,7 +6,7 @@ const MONTHS = [
|
|
|
6
6
|
'January', 'February', 'March', 'April', 'May', 'June',
|
|
7
7
|
'July', 'August', 'September', 'October', 'November', 'December'
|
|
8
8
|
];
|
|
9
|
-
export default function DateTimePickerPopup({ value, onChange, type, onClose, }) {
|
|
9
|
+
export default function DateTimePickerPopup({ value, onChange, type, onClose, anchorName, }) {
|
|
10
10
|
const [currentDate, setCurrentDate] = useState(new Date());
|
|
11
11
|
const [timeInput, setTimeInput] = useState({
|
|
12
12
|
hours: value ? value.getHours().toString() : '0',
|
|
@@ -118,5 +118,11 @@ export default function DateTimePickerPopup({ value, onChange, type, onClose, })
|
|
|
118
118
|
border border-login-500 focus:border-login outline-none
|
|
119
119
|
` })] })] }));
|
|
120
120
|
}
|
|
121
|
-
return (_jsxs("div", { className: '
|
|
121
|
+
return (_jsxs("div", { className: 'fixed z-50 bg-login-600 border border-login-500 rounded-md shadow-lg p-1 min-w-70 anchor-popup', style: {
|
|
122
|
+
positionAnchor: anchorName,
|
|
123
|
+
positionArea: 'bottom span-right',
|
|
124
|
+
insetArea: 'bottom span-right',
|
|
125
|
+
positionTryFallbacks: 'flip-block',
|
|
126
|
+
margin: '0.25rem 0',
|
|
127
|
+
}, children: [type !== 'time' && renderCalendar(), (type === 'time' || type === 'datetime-local') && renderTimePicker()] }));
|
|
122
128
|
}
|
|
@@ -2,13 +2,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { ChevronDown, ChevronUp } from 'lucide-react';
|
|
3
3
|
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
4
4
|
import { useEffect, useState } from 'react';
|
|
5
|
+
function parseOrder(value) {
|
|
6
|
+
return value === 'asc' || value === 'desc' ? value : undefined;
|
|
7
|
+
}
|
|
5
8
|
export default function Header({ columns, hideMenu, variant = 'default' }) {
|
|
6
|
-
const [column, setColumn] = useState(columns[0]?.key || '');
|
|
7
|
-
const [order, setOrder] = useState('asc');
|
|
8
9
|
const router = useRouter();
|
|
9
10
|
const pathname = usePathname();
|
|
10
11
|
const searchParams = useSearchParams();
|
|
12
|
+
const [column, setColumn] = useState(searchParams.get('column') ?? '');
|
|
13
|
+
const [order, setOrder] = useState(parseOrder(searchParams.get('order')));
|
|
11
14
|
useEffect(() => {
|
|
15
|
+
if (!column || !order) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
12
18
|
const params = new URLSearchParams(searchParams.toString());
|
|
13
19
|
if (searchParams.get('order') !== order ||
|
|
14
20
|
searchParams.get('column') !== column) {
|
package/dist/src/globals.css
CHANGED
|
@@ -333,6 +333,14 @@
|
|
|
333
333
|
.end {
|
|
334
334
|
inset-inline-end: var(--spacing);
|
|
335
335
|
}
|
|
336
|
+
.anchor-popup {
|
|
337
|
+
top: 100%;
|
|
338
|
+
left: 0;
|
|
339
|
+
@supports (position-anchor: --foo) {
|
|
340
|
+
top: auto;
|
|
341
|
+
left: auto;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
336
344
|
.-top-3 {
|
|
337
345
|
top: calc(var(--spacing) * -3);
|
|
338
346
|
}
|
|
@@ -360,9 +368,6 @@
|
|
|
360
368
|
.top-16 {
|
|
361
369
|
top: calc(var(--spacing) * 16);
|
|
362
370
|
}
|
|
363
|
-
.top-full {
|
|
364
|
-
top: 100%;
|
|
365
|
-
}
|
|
366
371
|
.right-0 {
|
|
367
372
|
right: calc(var(--spacing) * 0);
|
|
368
373
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uibee",
|
|
3
|
-
"version": "2.16.
|
|
3
|
+
"version": "2.16.37",
|
|
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": {
|
|
@@ -57,4 +57,4 @@
|
|
|
57
57
|
"remark-gfm": "^4.0.1",
|
|
58
58
|
"utilbee": "^1.4.5"
|
|
59
59
|
}
|
|
60
|
-
}
|
|
60
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ChangeEvent, type JSX, useRef, useState } from 'react'
|
|
1
|
+
import { type ChangeEvent, type JSX, useRef, useState, useId } from 'react'
|
|
2
2
|
import { Calendar, Clock } from 'lucide-react'
|
|
3
3
|
import { FieldWrapper } from './shared'
|
|
4
4
|
import DateTimePickerPopup from './shared/dateTimePickerPopup'
|
|
@@ -21,6 +21,8 @@ export default function Input(props: InputProps) {
|
|
|
21
21
|
const { type = 'text', value } = inputProps
|
|
22
22
|
const localRef = useRef<HTMLInputElement>(null)
|
|
23
23
|
const [isOpen, setIsOpen] = useState(false)
|
|
24
|
+
const id = useId()
|
|
25
|
+
const anchorName = `--input-${id.replace(/:/g, '')}`
|
|
24
26
|
|
|
25
27
|
const containerRef = useClickOutside<HTMLDivElement>(() => setIsOpen(false))
|
|
26
28
|
|
|
@@ -157,9 +159,8 @@ export default function Input(props: InputProps) {
|
|
|
157
159
|
value={isDateType ? getDateDisplayValue() : value}
|
|
158
160
|
readOnly={isClickableType}
|
|
159
161
|
onClick={() => isClickableType && !inputProps.disabled && setIsOpen(true)}
|
|
160
|
-
title={label}
|
|
161
|
-
aria-invalid={!!error}
|
|
162
162
|
aria-describedby={error ? `${name}-error` : undefined}
|
|
163
|
+
style={{ anchorName } as any}
|
|
163
164
|
className={`
|
|
164
165
|
w-full rounded-md bg-login-500/50 border border-login-500
|
|
165
166
|
text-login-text placeholder-login-200
|
|
@@ -181,6 +182,7 @@ export default function Input(props: InputProps) {
|
|
|
181
182
|
onChange={handleDateChange}
|
|
182
183
|
type={type as 'date' | 'time' | 'datetime-local'}
|
|
183
184
|
onClose={() => setIsOpen(false)}
|
|
185
|
+
anchorName={anchorName}
|
|
184
186
|
/>
|
|
185
187
|
)}
|
|
186
188
|
{isOpen && isColorType && !inputProps.disabled && (
|
|
@@ -188,6 +190,7 @@ export default function Input(props: InputProps) {
|
|
|
188
190
|
value={value as string || ''}
|
|
189
191
|
onChange={handleColorChange}
|
|
190
192
|
onClose={() => setIsOpen(false)}
|
|
193
|
+
anchorName={anchorName}
|
|
191
194
|
/>
|
|
192
195
|
)}
|
|
193
196
|
</div>
|
|
@@ -4,6 +4,7 @@ export type ColorPickerPopupProps = {
|
|
|
4
4
|
value: string
|
|
5
5
|
onChange: (color: string) => void
|
|
6
6
|
onClose: () => void
|
|
7
|
+
anchorName?: string
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
function hexToHsv(hex: string): { h: number; s: number; v: number } {
|
|
@@ -159,7 +160,7 @@ function HuePicker({ hue, onChange }: { hue: number, onChange: (h: number) => vo
|
|
|
159
160
|
)
|
|
160
161
|
}
|
|
161
162
|
|
|
162
|
-
export default function ColorPickerPopup({ value, onChange, onClose }: ColorPickerPopupProps): JSX.Element {
|
|
163
|
+
export default function ColorPickerPopup({ value, onChange, onClose, anchorName }: ColorPickerPopupProps): JSX.Element {
|
|
163
164
|
const [hsv, setHsv] = useState(() => hexToHsv(value || '#000000'))
|
|
164
165
|
const [hexInput, setHexInput] = useState(value || '#000000')
|
|
165
166
|
|
|
@@ -191,7 +192,16 @@ export default function ColorPickerPopup({ value, onChange, onClose }: ColorPick
|
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
return (
|
|
194
|
-
<div
|
|
195
|
+
<div
|
|
196
|
+
className='fixed z-50 bg-login-600 border border-login-500 rounded-md shadow-lg p-3 w-64 select-none anchor-popup'
|
|
197
|
+
style={{
|
|
198
|
+
positionAnchor: anchorName,
|
|
199
|
+
positionArea: 'bottom span-right',
|
|
200
|
+
insetArea: 'bottom span-right',
|
|
201
|
+
positionTryFallbacks: 'flip-block',
|
|
202
|
+
margin: '0.25rem 0',
|
|
203
|
+
} as React.CSSProperties}
|
|
204
|
+
>
|
|
195
205
|
<SaturationPicker hsv={hsv} onChange={handleSaturationChange} />
|
|
196
206
|
<HuePicker hue={hsv.h} onChange={handleHueChange} />
|
|
197
207
|
|
|
@@ -6,6 +6,7 @@ type DateTimePickerPopupProps = {
|
|
|
6
6
|
onChange: (date: Date) => void
|
|
7
7
|
type: 'date' | 'time' | 'datetime-local'
|
|
8
8
|
onClose?: () => void
|
|
9
|
+
anchorName?: string
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
const DAYS = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']
|
|
@@ -19,6 +20,7 @@ export default function DateTimePickerPopup({
|
|
|
19
20
|
onChange,
|
|
20
21
|
type,
|
|
21
22
|
onClose,
|
|
23
|
+
anchorName,
|
|
22
24
|
}: DateTimePickerPopupProps) {
|
|
23
25
|
const [currentDate, setCurrentDate] = useState(new Date())
|
|
24
26
|
const [timeInput, setTimeInput] = useState({
|
|
@@ -218,7 +220,16 @@ export default function DateTimePickerPopup({
|
|
|
218
220
|
}
|
|
219
221
|
|
|
220
222
|
return (
|
|
221
|
-
<div
|
|
223
|
+
<div
|
|
224
|
+
className='fixed z-50 bg-login-600 border border-login-500 rounded-md shadow-lg p-1 min-w-70 anchor-popup'
|
|
225
|
+
style={{
|
|
226
|
+
positionAnchor: anchorName,
|
|
227
|
+
positionArea: 'bottom span-right',
|
|
228
|
+
insetArea: 'bottom span-right',
|
|
229
|
+
positionTryFallbacks: 'flip-block',
|
|
230
|
+
margin: '0.25rem 0',
|
|
231
|
+
} as React.CSSProperties}
|
|
232
|
+
>
|
|
222
233
|
{type !== 'time' && renderCalendar()}
|
|
223
234
|
{(type === 'time' || type === 'datetime-local') && renderTimePicker()}
|
|
224
235
|
</div>
|
|
@@ -9,14 +9,22 @@ type HeaderProps = {
|
|
|
9
9
|
variant?: 'default' | 'minimal'
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function parseOrder(value: string | null) {
|
|
13
|
+
return value === 'asc' || value === 'desc' ? value : undefined
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
export default function Header({ columns, hideMenu, variant = 'default' }: HeaderProps) {
|
|
13
|
-
const [column, setColumn] = useState(columns[0]?.key || '')
|
|
14
|
-
const [order, setOrder] = useState<'asc' | 'desc'>('asc')
|
|
15
17
|
const router = useRouter()
|
|
16
18
|
const pathname = usePathname()
|
|
17
19
|
const searchParams = useSearchParams()
|
|
20
|
+
const [column, setColumn] = useState(searchParams.get('column') ?? '')
|
|
21
|
+
const [order, setOrder] = useState<'asc' | 'desc' | undefined>(parseOrder(searchParams.get('order')))
|
|
18
22
|
|
|
19
23
|
useEffect(() => {
|
|
24
|
+
if (!column || !order) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
const params = new URLSearchParams(searchParams.toString())
|
|
21
29
|
if (
|
|
22
30
|
searchParams.get('order') !== order ||
|
package/src/globals.css
CHANGED
|
@@ -205,6 +205,16 @@
|
|
|
205
205
|
font-weight: 500;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
@utility anchor-popup {
|
|
209
|
+
top: 100%;
|
|
210
|
+
left: 0;
|
|
211
|
+
|
|
212
|
+
@supports (position-anchor: --foo) {
|
|
213
|
+
top: auto;
|
|
214
|
+
left: auto;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
208
218
|
/* Hide default browser icons/buttons for inputs */
|
|
209
219
|
input::-webkit-calendar-picker-indicator {
|
|
210
220
|
display: none !important;
|