react-ui89 0.60.0 → 0.62.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.
- package/dist/esm/Ui89Provider.d.ts +4 -0
- package/dist/esm/components/Ui89DateTimePicker.d.ts +0 -1
- package/dist/esm/components/Ui89DateTimePicker.stories.d.ts +3 -0
- package/dist/esm/components/Ui89InputNumber.d.ts +1 -0
- package/dist/esm/components/Ui89InputText.d.ts +1 -0
- package/dist/esm/components/Ui89InputText.stories.d.ts +1 -0
- package/dist/esm/components/Ui89InputTextNumber.d.ts +1 -0
- package/dist/esm/components/Ui89ModalDialog.stories.d.ts +1 -0
- package/dist/esm/components/Ui89Popover.d.ts +6 -2
- package/dist/esm/index.css +4 -5
- package/dist/esm/index.js +649 -526
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -2
package/dist/esm/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import React__default, { createContext, useState, useContext, useEffect, useRef,
|
|
3
|
-
import DatePicker from 'react-datepicker';
|
|
4
|
-
import Timeout from 'smart-timeout';
|
|
5
|
-
import { useFloating, size, autoUpdate, useClick, useDismiss, useRole, useInteractions, FloatingPortal, FloatingFocusManager } from '@floating-ui/react';
|
|
2
|
+
import React__default, { createContext, useState, useContext, useEffect, useRef, useImperativeHandle, useMemo, useCallback } from 'react';
|
|
6
3
|
import { createPortal } from 'react-dom';
|
|
4
|
+
import { useFloating, size, autoUpdate, useClick, useDismiss, useRole, useInteractions, FloatingPortal, FloatingFocusManager } from '@floating-ui/react';
|
|
5
|
+
import Timeout from 'smart-timeout';
|
|
7
6
|
import { toast, ToastContainer } from 'react-toastify';
|
|
8
7
|
|
|
9
8
|
var Ui89Theme;
|
|
@@ -24,15 +23,16 @@ var Ui89Look;
|
|
|
24
23
|
const Ui89Context = createContext({
|
|
25
24
|
currentZIndex: 1,
|
|
26
25
|
nextZIndex: () => 1,
|
|
26
|
+
createPortal: createPortal,
|
|
27
27
|
});
|
|
28
|
-
const Ui89Provider = ({ routerPush, children, }) => {
|
|
28
|
+
const Ui89Provider = ({ routerPush, children, createPortal: createPortal$1 = createPortal, }) => {
|
|
29
29
|
const [zIndex, setZIndex] = useState(1);
|
|
30
30
|
function nextZIndex() {
|
|
31
31
|
const next = zIndex + 1;
|
|
32
32
|
setZIndex(next);
|
|
33
33
|
return next;
|
|
34
34
|
}
|
|
35
|
-
return (React__default.createElement(Ui89Context.Provider, { value: { routerPush, currentZIndex: zIndex, nextZIndex } }, children));
|
|
35
|
+
return (React__default.createElement(Ui89Context.Provider, { value: { routerPush, currentZIndex: zIndex, nextZIndex, createPortal: createPortal$1 } }, children));
|
|
36
36
|
};
|
|
37
37
|
const useUi89 = () => {
|
|
38
38
|
return useContext(Ui89Context);
|
|
@@ -207,33 +207,123 @@ function Ui89CardHorizontalConnection({ children, overflow, }) {
|
|
|
207
207
|
return (React__default.createElement("div", { className: `ui89-card__horizontal-connection ${overflow ? "ui89-card__horizontal-connection--overflow" : ""}` }, children));
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
if (props.onChange) {
|
|
213
|
-
props.onChange(value);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return (React__default.createElement("span", { className: "ui89-date-time-picker" },
|
|
217
|
-
React__default.createElement(DatePicker, { className: ["ui89-input-box"].join(" "), calendarClassName: "ui89-typo-normal", showTimeSelect: true, dateFormat: props.dateFormat ?? "yyyy/MM/dd HH:mm:ss", timeFormat: "HH:mm", selected: props.value, onChange: datepickerOnChange, popperPlacement: "bottom-start" })));
|
|
210
|
+
function Ui89Scene({ look = Ui89Look.main, children }) {
|
|
211
|
+
return (React__default.createElement("div", { className: `ui89-scene ui-89-look-${look} ui89-typo-normal ui89-scrollbar` }, children));
|
|
218
212
|
}
|
|
219
213
|
|
|
220
|
-
|
|
221
|
-
const
|
|
214
|
+
function useZIndexer(open) {
|
|
215
|
+
const overrides = useUi89();
|
|
216
|
+
const [value, setValue] = useState(overrides.currentZIndex);
|
|
222
217
|
useEffect(() => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
218
|
+
if (open) {
|
|
219
|
+
setValue(overrides.nextZIndex());
|
|
220
|
+
}
|
|
221
|
+
}, [open]);
|
|
222
|
+
return {
|
|
223
|
+
value,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
var Ui89PopoverPropsPlacement;
|
|
228
|
+
(function (Ui89PopoverPropsPlacement) {
|
|
229
|
+
Ui89PopoverPropsPlacement["top"] = "top";
|
|
230
|
+
Ui89PopoverPropsPlacement["topStart"] = "topStart";
|
|
231
|
+
Ui89PopoverPropsPlacement["topEnd"] = "topEnd";
|
|
232
|
+
Ui89PopoverPropsPlacement["right"] = "right";
|
|
233
|
+
Ui89PopoverPropsPlacement["rightStart"] = "rightStart";
|
|
234
|
+
Ui89PopoverPropsPlacement["rightEnd"] = "rightEnd";
|
|
235
|
+
Ui89PopoverPropsPlacement["bottom"] = "bottom";
|
|
236
|
+
Ui89PopoverPropsPlacement["bottomStart"] = "bottomStart";
|
|
237
|
+
Ui89PopoverPropsPlacement["bottomEnd"] = "bottomEnd";
|
|
238
|
+
Ui89PopoverPropsPlacement["left"] = "left";
|
|
239
|
+
Ui89PopoverPropsPlacement["leftStart"] = "leftStart";
|
|
240
|
+
Ui89PopoverPropsPlacement["leftEnd"] = "leftEnd";
|
|
241
|
+
})(Ui89PopoverPropsPlacement || (Ui89PopoverPropsPlacement = {}));
|
|
242
|
+
function toFloatingUiPlacement(placement) {
|
|
243
|
+
switch (placement) {
|
|
244
|
+
case Ui89PopoverPropsPlacement.top:
|
|
245
|
+
return "top";
|
|
246
|
+
case Ui89PopoverPropsPlacement.topStart:
|
|
247
|
+
return "top-start";
|
|
248
|
+
case Ui89PopoverPropsPlacement.topEnd:
|
|
249
|
+
return "top-end";
|
|
250
|
+
case Ui89PopoverPropsPlacement.right:
|
|
251
|
+
return "right";
|
|
252
|
+
case Ui89PopoverPropsPlacement.rightStart:
|
|
253
|
+
return "right-start";
|
|
254
|
+
case Ui89PopoverPropsPlacement.rightEnd:
|
|
255
|
+
return "right-end";
|
|
256
|
+
case Ui89PopoverPropsPlacement.bottom:
|
|
257
|
+
return "bottom";
|
|
258
|
+
case Ui89PopoverPropsPlacement.bottomStart:
|
|
259
|
+
return "bottom-start";
|
|
260
|
+
case Ui89PopoverPropsPlacement.bottomEnd:
|
|
261
|
+
return "bottom-end";
|
|
262
|
+
case Ui89PopoverPropsPlacement.left:
|
|
263
|
+
return "left";
|
|
264
|
+
case Ui89PopoverPropsPlacement.leftStart:
|
|
265
|
+
return "left-start";
|
|
266
|
+
case Ui89PopoverPropsPlacement.leftEnd:
|
|
267
|
+
return "left-end";
|
|
268
|
+
default:
|
|
269
|
+
throw new Error(`Unknown placement: ${placement}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function Ui89Popover(props) {
|
|
273
|
+
const zIndexer = useZIndexer(props.open);
|
|
274
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
275
|
+
open: props.open,
|
|
276
|
+
onOpenChange: props.onOpenChange,
|
|
277
|
+
middleware: [
|
|
278
|
+
size({
|
|
279
|
+
apply({ availableWidth, availableHeight, elements }) {
|
|
280
|
+
let width = elements.reference.getBoundingClientRect().width;
|
|
281
|
+
if (props.popoverOverflowMaxWidth !== undefined) {
|
|
282
|
+
if (props.popoverOverflowMaxWidth > width) {
|
|
283
|
+
width = props.popoverOverflowMaxWidth;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const style = {
|
|
287
|
+
maxWidth: `${width}px`,
|
|
288
|
+
maxHeight: `${Math.max(0, availableHeight)}px`,
|
|
289
|
+
};
|
|
290
|
+
if (props.popoverOverflowForce) {
|
|
291
|
+
style.width = `${availableWidth}px`;
|
|
292
|
+
}
|
|
293
|
+
// Change styles, e.g.
|
|
294
|
+
Object.assign(elements.floating.style, style);
|
|
295
|
+
},
|
|
296
|
+
}),
|
|
297
|
+
],
|
|
298
|
+
whileElementsMounted: autoUpdate,
|
|
299
|
+
placement: toFloatingUiPlacement(props.placement ?? Ui89PopoverPropsPlacement.bottomStart),
|
|
300
|
+
strategy: "fixed",
|
|
301
|
+
});
|
|
302
|
+
const click = useClick(context, {
|
|
303
|
+
keyboardHandlers: false,
|
|
304
|
+
});
|
|
305
|
+
const dismiss = useDismiss(context);
|
|
306
|
+
const role = useRole(context);
|
|
307
|
+
const { getReferenceProps, getFloatingProps } = useInteractions([
|
|
308
|
+
click,
|
|
309
|
+
dismiss,
|
|
310
|
+
role,
|
|
311
|
+
]);
|
|
312
|
+
return (React__default.createElement(React__default.Fragment, null,
|
|
313
|
+
props.renderContainer({
|
|
314
|
+
setRef: refs.setReference,
|
|
315
|
+
props: getReferenceProps(),
|
|
316
|
+
}),
|
|
317
|
+
props.open && (React__default.createElement(FloatingPortal, null,
|
|
318
|
+
React__default.createElement(FloatingFocusManager, { context: context, modal: false, initialFocus: -1 },
|
|
319
|
+
React__default.createElement(Ui89Scene, null,
|
|
320
|
+
React__default.createElement("div", { ref: refs.setFloating, style: {
|
|
321
|
+
...floatingStyles,
|
|
322
|
+
zIndex: zIndexer.value,
|
|
323
|
+
display: "flex",
|
|
324
|
+
flexDirection: "column",
|
|
325
|
+
} }, props.renderPopover())))))));
|
|
326
|
+
}
|
|
237
327
|
|
|
238
328
|
function dateFormat(date, format) {
|
|
239
329
|
const placeholders = {
|
|
@@ -254,83 +344,458 @@ function dateFormat(date, format) {
|
|
|
254
344
|
return formattedDate;
|
|
255
345
|
}
|
|
256
346
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
return
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const style = {
|
|
284
|
-
paddingTop: `calc(var(--ui89-safe-space) * ${props.gapTop ?? props.gapVertical ?? gap})`,
|
|
285
|
-
paddingRight: `calc(var(--ui89-safe-space) * ${props.gapRight ?? props.gapHorizontal ?? gap})`,
|
|
286
|
-
paddingBottom: `calc(var(--ui89-safe-space) * ${props.gapBottom ?? props.gapVertical ?? gap})`,
|
|
287
|
-
paddingLeft: `calc(var(--ui89-safe-space) * ${props.gapLeft ?? props.gapHorizontal ?? gap})`,
|
|
347
|
+
let uniqueId = 0;
|
|
348
|
+
function throttledTimeout() {
|
|
349
|
+
const id = String(uniqueId++);
|
|
350
|
+
let callback;
|
|
351
|
+
return {
|
|
352
|
+
call(delay, f) {
|
|
353
|
+
callback = f;
|
|
354
|
+
if (Timeout.pending(id)) {
|
|
355
|
+
Timeout.restart(id);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
Timeout.set(id, () => callback(), delay);
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
/**
|
|
362
|
+
* If there is a call that has been scheduled, remove it from the queue.
|
|
363
|
+
*/
|
|
364
|
+
abort() {
|
|
365
|
+
Timeout.clear(id, true);
|
|
366
|
+
},
|
|
367
|
+
/**
|
|
368
|
+
* Lets you know whether a call is pending.
|
|
369
|
+
*/
|
|
370
|
+
isPending() {
|
|
371
|
+
return Timeout.pending(id);
|
|
372
|
+
},
|
|
288
373
|
};
|
|
289
|
-
return React__default.createElement("div", { style: style }, props.children);
|
|
290
374
|
}
|
|
291
375
|
|
|
292
|
-
function
|
|
293
|
-
const
|
|
294
|
-
|
|
376
|
+
function useUpdatedRef(value) {
|
|
377
|
+
const valueRef = useRef(value);
|
|
378
|
+
useEffect(() => {
|
|
379
|
+
valueRef.current = value;
|
|
380
|
+
}, [value]);
|
|
381
|
+
return valueRef;
|
|
295
382
|
}
|
|
296
383
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
384
|
+
const LAST_VALUE_CHANGED = Symbol("LAST_VALUE_CHANGED");
|
|
385
|
+
const OVERRIDEN_VALUE_UNDEFINED = Symbol("OVERRIDEN_VALUE_UNDEFINED");
|
|
386
|
+
function useDelayedOnChange(props) {
|
|
387
|
+
const valueRef = useUpdatedRef(props.value);
|
|
388
|
+
const onChangeRef = useUpdatedRef(props.onChange);
|
|
389
|
+
const [intermediateValue, setIntermediateValue] = useState(props.defaultValue || props.value);
|
|
390
|
+
useEffect(() => {
|
|
391
|
+
stateRef.current.setValue(props.value);
|
|
392
|
+
}, [props.value]);
|
|
393
|
+
function callOnChange() {
|
|
394
|
+
let newVal = stateRef.current.value;
|
|
395
|
+
if (props.filter !== undefined) {
|
|
396
|
+
newVal = props.filter(newVal);
|
|
301
397
|
}
|
|
398
|
+
if (newVal !== valueRef.current) {
|
|
399
|
+
onChangeRef.current?.call(null, newVal);
|
|
400
|
+
}
|
|
401
|
+
return newVal;
|
|
302
402
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
useEffect(() => {
|
|
310
|
-
const observer = new ResizeObserver((entries) => {
|
|
311
|
-
for (let entry of entries) {
|
|
312
|
-
setSize({
|
|
313
|
-
width: entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width,
|
|
314
|
-
height: entry.borderBoxSize?.[0]?.blockSize ?? entry.contentRect.height,
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
if (ref.current) {
|
|
319
|
-
observer.observe(ref.current);
|
|
403
|
+
class StateUnknown {
|
|
404
|
+
state = "unknown";
|
|
405
|
+
value;
|
|
406
|
+
throttledTimeout;
|
|
407
|
+
constructor() {
|
|
408
|
+
this.throttledTimeout = throttledTimeout();
|
|
320
409
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
410
|
+
setValue(newVal) {
|
|
411
|
+
setIntermediateValue(newVal);
|
|
412
|
+
}
|
|
413
|
+
onChange(newVal) {
|
|
414
|
+
setIntermediateValue(newVal);
|
|
415
|
+
stateRef.current.throttledTimeout.call(300, callOnChange);
|
|
416
|
+
}
|
|
417
|
+
onFocus() {
|
|
418
|
+
let newState = new StateFocus();
|
|
419
|
+
newState.value = stateRef.current.value;
|
|
420
|
+
newState.lastValue = newState.value;
|
|
421
|
+
setState(newState);
|
|
422
|
+
}
|
|
423
|
+
onBlur() { }
|
|
424
|
+
onConfirm() {
|
|
425
|
+
callOnChange();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
class StateFocus {
|
|
429
|
+
state = "focus";
|
|
430
|
+
value;
|
|
431
|
+
lastValue;
|
|
432
|
+
/**
|
|
433
|
+
* If we receive a new value, we keep track of it here. We set this to
|
|
434
|
+
* OVERRIDEN_VALUE_UNDEFINED if the value is meant to be discarded.
|
|
435
|
+
*/
|
|
436
|
+
overridenValue;
|
|
437
|
+
throttledTimeout;
|
|
438
|
+
constructor() {
|
|
439
|
+
this.overridenValue = OVERRIDEN_VALUE_UNDEFINED;
|
|
440
|
+
this.throttledTimeout = throttledTimeout();
|
|
441
|
+
}
|
|
442
|
+
setValue(newVal) {
|
|
443
|
+
if (stateRef.current.value === stateRef.current.lastValue) {
|
|
444
|
+
// No changes.
|
|
445
|
+
setIntermediateValue(newVal);
|
|
446
|
+
// Making sure we keep updating.
|
|
447
|
+
stateRef.current.lastValue = newVal;
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
// There have been changes. Let's not bother the user.
|
|
451
|
+
stateRef.current.overridenValue = newVal;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
onChange(newVal) {
|
|
455
|
+
// Discard last setValue call
|
|
456
|
+
stateRef.current.overridenValue = OVERRIDEN_VALUE_UNDEFINED;
|
|
457
|
+
stateRef.current.lastValue = LAST_VALUE_CHANGED;
|
|
458
|
+
setIntermediateValue(newVal);
|
|
459
|
+
stateRef.current.throttledTimeout.call(300, callOnChange);
|
|
460
|
+
}
|
|
461
|
+
onFocus() { }
|
|
462
|
+
onBlur() {
|
|
463
|
+
// We need to make sure that we emit immediately. Do not want to leave
|
|
464
|
+
// user waiting.
|
|
465
|
+
// We can cancel this one.
|
|
466
|
+
stateRef.current.throttledTimeout.abort();
|
|
467
|
+
if (stateRef.current.overridenValue !== OVERRIDEN_VALUE_UNDEFINED) {
|
|
468
|
+
stateRef.current.value = stateRef.current.overridenValue;
|
|
469
|
+
}
|
|
470
|
+
let newVal = callOnChange();
|
|
471
|
+
setIntermediateValue(newVal);
|
|
472
|
+
let newState = new StateUnknown();
|
|
473
|
+
newState.value = newVal;
|
|
474
|
+
setState(newState);
|
|
475
|
+
}
|
|
476
|
+
onConfirm() {
|
|
477
|
+
callOnChange();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const [state, setState] = useState(() => {
|
|
481
|
+
let newState = new StateUnknown();
|
|
482
|
+
newState.value = intermediateValue;
|
|
483
|
+
return newState;
|
|
484
|
+
});
|
|
485
|
+
const stateRef = useUpdatedRef(state);
|
|
486
|
+
stateRef.current.value = intermediateValue;
|
|
487
|
+
return state;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const Ui89InputText = React__default.forwardRef(function Ui89InputText({ value, placeholder, autoTrim = true, disabled, textAlign, onChange, onTyping, onFocus, onBlur, }, ref) {
|
|
491
|
+
const inputRef = useRef(null);
|
|
492
|
+
const delayedState = useDelayedOnChange({
|
|
493
|
+
defaultValue: "",
|
|
494
|
+
value,
|
|
495
|
+
onChange,
|
|
496
|
+
filter(value) {
|
|
497
|
+
if (autoTrim) {
|
|
498
|
+
if (typeof value === "string") {
|
|
499
|
+
value = value.replace(/\s+/g, " ").trim();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return value;
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
useImperativeHandle(ref, () => ({
|
|
506
|
+
focus: () => {
|
|
507
|
+
inputRef.current?.focus();
|
|
508
|
+
},
|
|
509
|
+
}));
|
|
510
|
+
return (React__default.createElement("div", null,
|
|
511
|
+
React__default.createElement("input", { ref: inputRef, className: [
|
|
512
|
+
"ui89-input-box",
|
|
513
|
+
disabled ? "ui89-input-box--disabled" : "",
|
|
514
|
+
].join(" "), style: { textAlign }, type: "text", disabled: disabled, value: delayedState.value, onChange: (e) => delayedState.onChange(e.target.value), onBlur: delayedState.onBlur, onFocus: delayedState.onFocus, onKeyDown: (e) => {
|
|
515
|
+
if (e.key === "Enter") {
|
|
516
|
+
delayedState.onConfirm();
|
|
517
|
+
}
|
|
518
|
+
}, placeholder: placeholder })));
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
function stringRemoveAllWhitespace(str) {
|
|
522
|
+
return str.replace(/\s+/g, "");
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function isTextNumber(text) {
|
|
526
|
+
return /^\d+(\.\d+)?$/.test(text);
|
|
527
|
+
}
|
|
528
|
+
function displayText(value) {
|
|
529
|
+
if (value === undefined) {
|
|
530
|
+
// No idea how to display this.
|
|
531
|
+
return "";
|
|
532
|
+
}
|
|
533
|
+
else if (isNaN(value)) {
|
|
534
|
+
// No idea what to display.
|
|
535
|
+
return "";
|
|
536
|
+
}
|
|
537
|
+
return value.toString();
|
|
538
|
+
}
|
|
539
|
+
function dotsMakeMoreSense(value) {
|
|
540
|
+
return value.replaceAll(",", ".");
|
|
541
|
+
}
|
|
542
|
+
function Ui89InputTextNumber(props) {
|
|
543
|
+
const wrappedValue = useMemo(() => {
|
|
544
|
+
return displayText(props.value);
|
|
545
|
+
}, [props.value]);
|
|
546
|
+
function implOnChange(value) {
|
|
547
|
+
if (props.onChange === undefined) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
if (value === "") {
|
|
551
|
+
// Use empty value.
|
|
552
|
+
props.onChange(props.emptyValue);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
value = stringRemoveAllWhitespace(value);
|
|
556
|
+
value = dotsMakeMoreSense(value);
|
|
557
|
+
if (!isTextNumber(value)) {
|
|
558
|
+
// We end here.
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const numberValue = Number(value);
|
|
562
|
+
if (props.min !== undefined) {
|
|
563
|
+
if (numberValue <= props.min) {
|
|
564
|
+
value = String(props.min);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (props.max !== undefined) {
|
|
568
|
+
if (numberValue >= props.max) {
|
|
569
|
+
value = String(props.max);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
props.onChange(value);
|
|
573
|
+
}
|
|
574
|
+
return (React__default.createElement(Ui89InputText, { value: wrappedValue, onChange: implOnChange, disabled: props.disabled, textAlign: props.textAlign }));
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function Ui89DateTimePicker(props) {
|
|
578
|
+
const [open, setOpen] = useState(false);
|
|
579
|
+
const [inputValue, setInputValue] = useState("");
|
|
580
|
+
const [viewDate, setViewDate] = useState(new Date());
|
|
581
|
+
const dateFormat$1 = props.dateFormat ?? "YYYY/MM/DD HH:mm:ss";
|
|
582
|
+
useEffect(() => {
|
|
583
|
+
if (props.value) {
|
|
584
|
+
setInputValue(dateFormat(props.value, dateFormat$1));
|
|
585
|
+
setViewDate(props.value);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
setInputValue("");
|
|
589
|
+
}
|
|
590
|
+
}, [props.value, dateFormat$1]);
|
|
591
|
+
function handleInputChange(val) {
|
|
592
|
+
setInputValue(val);
|
|
593
|
+
const date = new Date(val);
|
|
594
|
+
if (!isNaN(date.getTime())) {
|
|
595
|
+
if (props.onChange)
|
|
596
|
+
props.onChange(date);
|
|
597
|
+
setViewDate(date);
|
|
598
|
+
}
|
|
599
|
+
else if (val.trim() === "") {
|
|
600
|
+
if (props.onChange)
|
|
601
|
+
props.onChange(null);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function adjustMonth(offset) {
|
|
605
|
+
const newDate = new Date(viewDate);
|
|
606
|
+
newDate.setMonth(newDate.getMonth() + offset);
|
|
607
|
+
setViewDate(newDate);
|
|
608
|
+
}
|
|
609
|
+
function handleDayClick(day) {
|
|
610
|
+
const newDate = new Date(day);
|
|
611
|
+
if (props.value) {
|
|
612
|
+
newDate.setHours(props.value.getHours());
|
|
613
|
+
newDate.setMinutes(props.value.getMinutes());
|
|
614
|
+
newDate.setSeconds(props.value.getSeconds());
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
newDate.setHours(12, 0, 0, 0);
|
|
618
|
+
}
|
|
619
|
+
if (props.onChange)
|
|
620
|
+
props.onChange(newDate);
|
|
621
|
+
}
|
|
622
|
+
function handleTimeChange(type, val) {
|
|
623
|
+
if (!props.value)
|
|
624
|
+
return;
|
|
625
|
+
const num = parseInt(val, 10);
|
|
626
|
+
if (isNaN(num))
|
|
627
|
+
return;
|
|
628
|
+
const newDate = new Date(props.value);
|
|
629
|
+
if (type === "h")
|
|
630
|
+
newDate.setHours(Math.min(23, Math.max(0, num)));
|
|
631
|
+
if (type === "m")
|
|
632
|
+
newDate.setMinutes(Math.min(59, Math.max(0, num)));
|
|
633
|
+
if (type === "s")
|
|
634
|
+
newDate.setSeconds(Math.min(59, Math.max(0, num)));
|
|
635
|
+
if (props.onChange)
|
|
636
|
+
props.onChange(newDate);
|
|
637
|
+
}
|
|
638
|
+
function renderCalendar() {
|
|
639
|
+
const year = viewDate.getFullYear();
|
|
640
|
+
const month = viewDate.getMonth();
|
|
641
|
+
const firstDay = new Date(year, month, 1);
|
|
642
|
+
const startDay = firstDay.getDay();
|
|
643
|
+
const startDate = new Date(year, month, 1 - startDay);
|
|
644
|
+
const days = [];
|
|
645
|
+
const current = new Date(startDate);
|
|
646
|
+
for (let i = 0; i < 42; i++) {
|
|
647
|
+
days.push(new Date(current));
|
|
648
|
+
current.setDate(current.getDate() + 1);
|
|
649
|
+
}
|
|
650
|
+
return (React__default.createElement("div", { style: { width: "300px", padding: "10px" } },
|
|
651
|
+
React__default.createElement("div", { style: {
|
|
652
|
+
display: "flex",
|
|
653
|
+
justifyContent: "space-between",
|
|
654
|
+
alignItems: "center",
|
|
655
|
+
marginBottom: "10px",
|
|
656
|
+
} },
|
|
657
|
+
React__default.createElement(Ui89Button, { size: Ui89ButtonPropsSize.square, onClick: () => adjustMonth(-1) }, "<"),
|
|
658
|
+
React__default.createElement("div", { className: "ui89-typo-normal" }, dateFormat(viewDate, "MM/YYYY")),
|
|
659
|
+
React__default.createElement(Ui89Button, { size: Ui89ButtonPropsSize.square, onClick: () => adjustMonth(1) }, ">")),
|
|
660
|
+
React__default.createElement("div", { style: {
|
|
661
|
+
display: "grid",
|
|
662
|
+
gridTemplateColumns: "repeat(7, 1fr)",
|
|
663
|
+
gap: "2px",
|
|
664
|
+
} },
|
|
665
|
+
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((d) => (React__default.createElement("div", { key: d, className: "ui89-typo-small-bold", style: { textAlign: "center", padding: "5px" } }, d))),
|
|
666
|
+
days.map((d, i) => {
|
|
667
|
+
const isSelected = props.value &&
|
|
668
|
+
d.getDate() === props.value.getDate() &&
|
|
669
|
+
d.getMonth() === props.value.getMonth() &&
|
|
670
|
+
d.getFullYear() === props.value.getFullYear();
|
|
671
|
+
const isCurrentMonth = d.getMonth() === month;
|
|
672
|
+
return (React__default.createElement("div", { key: i, className: "ui89-typo-normal", onClick: () => handleDayClick(d), style: {
|
|
673
|
+
textAlign: "center",
|
|
674
|
+
padding: "5px",
|
|
675
|
+
cursor: "pointer",
|
|
676
|
+
backgroundColor: isSelected
|
|
677
|
+
? "var(--ui89-theme-primary-bg-color)"
|
|
678
|
+
: "transparent",
|
|
679
|
+
opacity: isCurrentMonth ? 1 : 0.3,
|
|
680
|
+
} }, d.getDate()));
|
|
681
|
+
})),
|
|
682
|
+
props.value && (React__default.createElement("div", { style: {
|
|
683
|
+
display: "flex",
|
|
684
|
+
gap: "5px",
|
|
685
|
+
marginTop: "10px",
|
|
686
|
+
justifyContent: "center",
|
|
687
|
+
alignItems: "center",
|
|
688
|
+
} },
|
|
689
|
+
React__default.createElement("div", { style: { width: "35px" } },
|
|
690
|
+
React__default.createElement(Ui89InputTextNumber, { value: props.value.getHours(), onChange: (val) => handleTimeChange("h", val), min: 0, max: 23, textAlign: "right" })),
|
|
691
|
+
":",
|
|
692
|
+
React__default.createElement("div", { style: { width: "35px" } },
|
|
693
|
+
React__default.createElement(Ui89InputTextNumber, { value: props.value.getMinutes(), onChange: (val) => handleTimeChange("m", val), min: 0, max: 59, textAlign: "right" })),
|
|
694
|
+
":",
|
|
695
|
+
React__default.createElement("div", { style: { width: "35px" } },
|
|
696
|
+
React__default.createElement(Ui89InputTextNumber, { value: props.value.getSeconds(), onChange: (val) => handleTimeChange("s", val), min: 0, max: 59, textAlign: "right" }))))));
|
|
697
|
+
}
|
|
698
|
+
return (React__default.createElement(Ui89Popover, { open: open, onOpenChange: setOpen, popoverOverflowMaxWidth: 360, renderContainer: ({ setRef, props: popoverProps }) => (React__default.createElement("div", { className: "ui89-date-time-picker", ref: setRef, ...popoverProps },
|
|
699
|
+
React__default.createElement(Ui89InputText, { value: inputValue, onChange: handleInputChange, placeholder: dateFormat$1 }))), renderPopover: () => (React__default.createElement("div", { style: { maxWidth: "360px" } },
|
|
700
|
+
React__default.createElement(HoverShadow, null,
|
|
701
|
+
React__default.createElement(Ui89Card, null, renderCalendar())))) }));
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const TimeAnimation = ({ children }) => {
|
|
705
|
+
const [currentTime, setCurrentTime] = useState(new Date());
|
|
706
|
+
useEffect(() => {
|
|
707
|
+
const tick = () => {
|
|
708
|
+
const now = new Date();
|
|
709
|
+
setCurrentTime(now);
|
|
710
|
+
// Calculate time until the next exact second
|
|
711
|
+
const msUntilNextSecond = 1000 - now.getMilliseconds();
|
|
712
|
+
setTimeout(tick, msUntilNextSecond);
|
|
713
|
+
};
|
|
714
|
+
// Start the first tick
|
|
715
|
+
const msUntilNextSecond = 1000 - currentTime.getMilliseconds();
|
|
716
|
+
const timeoutId = setTimeout(tick, msUntilNextSecond);
|
|
717
|
+
return () => clearTimeout(timeoutId);
|
|
718
|
+
}, []);
|
|
719
|
+
return React__default.createElement(React__default.Fragment, null, children({ now: currentTime }));
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
function Ui89DigitalClock({ format = "HH:mm:ss", }) {
|
|
723
|
+
function render({ now }) {
|
|
724
|
+
return dateFormat(now, format);
|
|
725
|
+
}
|
|
726
|
+
return (React__default.createElement("span", { className: "ui89-typo-special" },
|
|
727
|
+
React__default.createElement(TimeAnimation, null, render)));
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function Ui89HighlightText({ theme, block, children, }) {
|
|
731
|
+
return (React__default.createElement("span", { className: `ui89-highlight-text ui89-chosen-theme-${theme} ${block ? "ui89-highlight-text--block" : null}` }, children));
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
var Ui89HrPropsLook;
|
|
735
|
+
(function (Ui89HrPropsLook) {
|
|
736
|
+
Ui89HrPropsLook["straight"] = "straight";
|
|
737
|
+
Ui89HrPropsLook["dotted"] = "dotted";
|
|
738
|
+
Ui89HrPropsLook["dashed"] = "dashed";
|
|
739
|
+
Ui89HrPropsLook["double"] = "double";
|
|
740
|
+
})(Ui89HrPropsLook || (Ui89HrPropsLook = {}));
|
|
741
|
+
function Ui89Hr({ look = "straight", theme }) {
|
|
742
|
+
return (React__default.createElement("div", { className: `ui-89-hr ${`ui-89-hr--${look}`} ${theme !== undefined ? "ui-89-hr--use-theme" : ""} ${theme !== undefined ? `ui89-chosen-theme-${theme}` : ""}` },
|
|
743
|
+
React__default.createElement("div", { className: "ui-89-hr__double" })));
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function Ui89SpacePadding(props) {
|
|
747
|
+
const gap = props.gap ?? 1;
|
|
748
|
+
const style = {
|
|
749
|
+
paddingTop: `calc(var(--ui89-safe-space) * ${props.gapTop ?? props.gapVertical ?? gap})`,
|
|
750
|
+
paddingRight: `calc(var(--ui89-safe-space) * ${props.gapRight ?? props.gapHorizontal ?? gap})`,
|
|
751
|
+
paddingBottom: `calc(var(--ui89-safe-space) * ${props.gapBottom ?? props.gapVertical ?? gap})`,
|
|
752
|
+
paddingLeft: `calc(var(--ui89-safe-space) * ${props.gapLeft ?? props.gapHorizontal ?? gap})`,
|
|
753
|
+
};
|
|
754
|
+
return React__default.createElement("div", { style: style }, props.children);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function Ui89Indent(props) {
|
|
758
|
+
const gap = props.gap ?? 1;
|
|
759
|
+
return (React__default.createElement(Ui89SpacePadding, { gap: 0, gapLeft: gap }, props.children));
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function Ui89InputCheckBox(props) {
|
|
763
|
+
function toggle() {
|
|
764
|
+
if (props.onChange) {
|
|
765
|
+
props.onChange(!props.value);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return (React__default.createElement("span", { className: "ui89-input-check-box", onClick: toggle, role: "checkbox", "aria-checked": props.value ? "true" : "false" },
|
|
769
|
+
React__default.createElement("span", { className: "ui89-input-check-box__x" }, props.value ? React__default.createElement(React__default.Fragment, null, "X") : React__default.createElement(React__default.Fragment, null, "\u00A0"))));
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
const useResizeObserver = (ref) => {
|
|
773
|
+
const [size, setSize] = useState({ width: 0, height: 0 });
|
|
774
|
+
useEffect(() => {
|
|
775
|
+
const observer = new ResizeObserver((entries) => {
|
|
776
|
+
for (let entry of entries) {
|
|
777
|
+
setSize({
|
|
778
|
+
width: entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width,
|
|
779
|
+
height: entry.borderBoxSize?.[0]?.blockSize ?? entry.contentRect.height,
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
if (ref.current) {
|
|
784
|
+
observer.observe(ref.current);
|
|
785
|
+
}
|
|
786
|
+
return () => {
|
|
787
|
+
observer.disconnect();
|
|
788
|
+
};
|
|
789
|
+
}, [ref.current]);
|
|
790
|
+
return {
|
|
791
|
+
size,
|
|
792
|
+
};
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
const useScrollYPosition = (ref) => {
|
|
796
|
+
const [scrollY, setScrollY] = useState(0);
|
|
797
|
+
const ticking = useRef(false);
|
|
798
|
+
const observer = useRef(null);
|
|
334
799
|
useEffect(() => {
|
|
335
800
|
const element = ref.current;
|
|
336
801
|
if (!element)
|
|
@@ -468,384 +933,97 @@ function Ui89InputCheckList(props) {
|
|
|
468
933
|
? props.getValueKey(value)
|
|
469
934
|
: String(value);
|
|
470
935
|
}
|
|
471
|
-
const valueSet = useMemo(() => {
|
|
472
|
-
const set = new Set();
|
|
473
|
-
for (const value of props.value) {
|
|
474
|
-
set.add(getValueKey(value));
|
|
475
|
-
}
|
|
476
|
-
return set;
|
|
477
|
-
}, [props.value]);
|
|
478
|
-
const renderRow = (props2) => {
|
|
479
|
-
const key = getValueKey(props2.row);
|
|
480
|
-
const value = valueSet.has(key);
|
|
481
|
-
const label = props.renderOption !== undefined
|
|
482
|
-
? props.renderOption({ option: props2.row, index: props2.index })
|
|
483
|
-
: String(props2.row);
|
|
484
|
-
function onChange(checked) {
|
|
485
|
-
if (checked) {
|
|
486
|
-
if (props.onSelect !== undefined) {
|
|
487
|
-
props.onSelect(props2.row);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
else {
|
|
491
|
-
if (props.onDeselect !== undefined) {
|
|
492
|
-
props.onDeselect(props2.row);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
if (props.onChange !== undefined) {
|
|
496
|
-
if (checked) {
|
|
497
|
-
props.onChange([...props.value, props2.row]);
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
props.onChange(props.value.filter((item) => getValueKey(item) !== key));
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
function toggle() {
|
|
505
|
-
onChange(!value);
|
|
506
|
-
}
|
|
507
|
-
return (React__default.createElement("div", { style: {
|
|
508
|
-
display: "flex",
|
|
509
|
-
alignItems: "center",
|
|
510
|
-
gap: "var(--ui89-safe-space)",
|
|
511
|
-
height: "100%",
|
|
512
|
-
} },
|
|
513
|
-
React__default.createElement(Ui89InputCheckBox, { value: value, onChange: onChange }),
|
|
514
|
-
React__default.createElement("div", { className: "ui89-text-ellipsis", style: { minWidth: 0, cursor: "pointer" }, onClick: toggle }, label)));
|
|
515
|
-
};
|
|
516
|
-
return (React__default.createElement("div", { style: {
|
|
517
|
-
display: "flex",
|
|
518
|
-
flexDirection: "column",
|
|
519
|
-
maxHeight: props.maxHeight,
|
|
520
|
-
} },
|
|
521
|
-
React__default.createElement(Ui89VirtualList, { rows: props.options, renderRow: renderRow, getRowKey: props.getValueKey, rowHeight: props.optionHeight ?? 40, maxHeight: "100%" })));
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
function Ui89InputCheckText(props) {
|
|
525
|
-
function toggle() {
|
|
526
|
-
if (props.onChange) {
|
|
527
|
-
props.onChange(!props.value);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
return (React__default.createElement("span", { className: "ui89-input-check-text", onClick: toggle }, props.value ? "[X]" : "[ ]"));
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
function Ui89InputFileUpload(props) {
|
|
534
|
-
const inputRef = useRef(null);
|
|
535
|
-
function implOnChange(e) {
|
|
536
|
-
if (!props.onChange) {
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
if (e.target.files === null) {
|
|
540
|
-
props.onChange(null);
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
|
-
if (e.target.files.length === 0) {
|
|
544
|
-
props.onChange(null);
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
props.onChange(e.target.files[0]);
|
|
548
|
-
// Reset the file input's value to allow selecting the same file again.
|
|
549
|
-
e.target.value = "";
|
|
550
|
-
}
|
|
551
|
-
function onClick() {
|
|
552
|
-
if (inputRef.current === null) {
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
inputRef.current.click();
|
|
556
|
-
}
|
|
557
|
-
return (React__default.createElement("div", null,
|
|
558
|
-
React__default.createElement("input", { ref: inputRef, className: "ui89-typo-special", type: "file", onChange: implOnChange, accept: props.accept, hidden: true }),
|
|
559
|
-
props.value ? (React__default.createElement("div", { className: "ui89-input-file-upload" },
|
|
560
|
-
React__default.createElement(Ui89Button, { onClick: onClick }, "Change"),
|
|
561
|
-
React__default.createElement("span", { className: `ui89-input-file-upload__info ui89-text-single-line ui89-text-single-line--ellipsis-left`, title: props.value.name }, props.value.name))) : (React__default.createElement(Ui89Button, { onClick: onClick }, "Upload"))));
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
let uniqueId = 0;
|
|
565
|
-
function throttledTimeout() {
|
|
566
|
-
const id = String(uniqueId++);
|
|
567
|
-
let callback;
|
|
568
|
-
return {
|
|
569
|
-
call(delay, f) {
|
|
570
|
-
callback = f;
|
|
571
|
-
if (Timeout.pending(id)) {
|
|
572
|
-
Timeout.restart(id);
|
|
573
|
-
}
|
|
574
|
-
else {
|
|
575
|
-
Timeout.set(id, () => callback(), delay);
|
|
576
|
-
}
|
|
577
|
-
},
|
|
578
|
-
/**
|
|
579
|
-
* If there is a call that has been scheduled, remove it from the queue.
|
|
580
|
-
*/
|
|
581
|
-
abort() {
|
|
582
|
-
Timeout.clear(id, true);
|
|
583
|
-
},
|
|
584
|
-
/**
|
|
585
|
-
* Lets you know whether a call is pending.
|
|
586
|
-
*/
|
|
587
|
-
isPending() {
|
|
588
|
-
return Timeout.pending(id);
|
|
589
|
-
},
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
function useUpdatedRef(value) {
|
|
594
|
-
const valueRef = useRef(value);
|
|
595
|
-
useEffect(() => {
|
|
596
|
-
valueRef.current = value;
|
|
597
|
-
}, [value]);
|
|
598
|
-
return valueRef;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
const LAST_VALUE_CHANGED = Symbol("LAST_VALUE_CHANGED");
|
|
602
|
-
const OVERRIDEN_VALUE_UNDEFINED = Symbol("OVERRIDEN_VALUE_UNDEFINED");
|
|
603
|
-
function useDelayedOnChange(props) {
|
|
604
|
-
const valueRef = useUpdatedRef(props.value);
|
|
605
|
-
const onChangeRef = useUpdatedRef(props.onChange);
|
|
606
|
-
const [intermediateValue, setIntermediateValue] = useState(props.defaultValue || props.value);
|
|
607
|
-
useEffect(() => {
|
|
608
|
-
stateRef.current.setValue(props.value);
|
|
609
|
-
}, [props.value]);
|
|
610
|
-
function callOnChange() {
|
|
611
|
-
let newVal = stateRef.current.value;
|
|
612
|
-
if (props.filter !== undefined) {
|
|
613
|
-
newVal = props.filter(newVal);
|
|
614
|
-
}
|
|
615
|
-
if (newVal !== valueRef.current) {
|
|
616
|
-
onChangeRef.current?.call(null, newVal);
|
|
617
|
-
}
|
|
618
|
-
return newVal;
|
|
619
|
-
}
|
|
620
|
-
class StateUnknown {
|
|
621
|
-
state = "unknown";
|
|
622
|
-
value;
|
|
623
|
-
throttledTimeout;
|
|
624
|
-
constructor() {
|
|
625
|
-
this.throttledTimeout = throttledTimeout();
|
|
626
|
-
}
|
|
627
|
-
setValue(newVal) {
|
|
628
|
-
setIntermediateValue(newVal);
|
|
629
|
-
}
|
|
630
|
-
onChange(newVal) {
|
|
631
|
-
setIntermediateValue(newVal);
|
|
632
|
-
stateRef.current.throttledTimeout.call(300, callOnChange);
|
|
633
|
-
}
|
|
634
|
-
onFocus() {
|
|
635
|
-
let newState = new StateFocus();
|
|
636
|
-
newState.value = stateRef.current.value;
|
|
637
|
-
newState.lastValue = newState.value;
|
|
638
|
-
setState(newState);
|
|
639
|
-
}
|
|
640
|
-
onBlur() { }
|
|
641
|
-
onConfirm() {
|
|
642
|
-
callOnChange();
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
class StateFocus {
|
|
646
|
-
state = "focus";
|
|
647
|
-
value;
|
|
648
|
-
lastValue;
|
|
649
|
-
/**
|
|
650
|
-
* If we receive a new value, we keep track of it here. We set this to
|
|
651
|
-
* OVERRIDEN_VALUE_UNDEFINED if the value is meant to be discarded.
|
|
652
|
-
*/
|
|
653
|
-
overridenValue;
|
|
654
|
-
throttledTimeout;
|
|
655
|
-
constructor() {
|
|
656
|
-
this.overridenValue = OVERRIDEN_VALUE_UNDEFINED;
|
|
657
|
-
this.throttledTimeout = throttledTimeout();
|
|
658
|
-
}
|
|
659
|
-
setValue(newVal) {
|
|
660
|
-
if (stateRef.current.value === stateRef.current.lastValue) {
|
|
661
|
-
// No changes.
|
|
662
|
-
setIntermediateValue(newVal);
|
|
663
|
-
// Making sure we keep updating.
|
|
664
|
-
stateRef.current.lastValue = newVal;
|
|
665
|
-
}
|
|
666
|
-
else {
|
|
667
|
-
// There have been changes. Let's not bother the user.
|
|
668
|
-
stateRef.current.overridenValue = newVal;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
onChange(newVal) {
|
|
672
|
-
// Discard last setValue call
|
|
673
|
-
stateRef.current.overridenValue = OVERRIDEN_VALUE_UNDEFINED;
|
|
674
|
-
stateRef.current.lastValue = LAST_VALUE_CHANGED;
|
|
675
|
-
setIntermediateValue(newVal);
|
|
676
|
-
stateRef.current.throttledTimeout.call(300, callOnChange);
|
|
677
|
-
}
|
|
678
|
-
onFocus() { }
|
|
679
|
-
onBlur() {
|
|
680
|
-
// We need to make sure that we emit immediately. Do not want to leave
|
|
681
|
-
// user waiting.
|
|
682
|
-
// We can cancel this one.
|
|
683
|
-
stateRef.current.throttledTimeout.abort();
|
|
684
|
-
if (stateRef.current.overridenValue !== OVERRIDEN_VALUE_UNDEFINED) {
|
|
685
|
-
stateRef.current.value = stateRef.current.overridenValue;
|
|
686
|
-
}
|
|
687
|
-
let newVal = callOnChange();
|
|
688
|
-
setIntermediateValue(newVal);
|
|
689
|
-
let newState = new StateUnknown();
|
|
690
|
-
newState.value = newVal;
|
|
691
|
-
setState(newState);
|
|
692
|
-
}
|
|
693
|
-
onConfirm() {
|
|
694
|
-
callOnChange();
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
const [state, setState] = useState(() => {
|
|
698
|
-
let newState = new StateUnknown();
|
|
699
|
-
newState.value = intermediateValue;
|
|
700
|
-
return newState;
|
|
701
|
-
});
|
|
702
|
-
const stateRef = useUpdatedRef(state);
|
|
703
|
-
stateRef.current.value = intermediateValue;
|
|
704
|
-
return state;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
const Ui89InputText = React__default.forwardRef(function Ui89InputText({ value, placeholder, autoTrim = true, disabled, onChange, onTyping, onFocus, onBlur, }, ref) {
|
|
708
|
-
const inputRef = useRef(null);
|
|
709
|
-
const delayedState = useDelayedOnChange({
|
|
710
|
-
defaultValue: "",
|
|
711
|
-
value,
|
|
712
|
-
onChange,
|
|
713
|
-
filter(value) {
|
|
714
|
-
if (autoTrim) {
|
|
715
|
-
if (typeof value === "string") {
|
|
716
|
-
value = value.replace(/\s+/g, " ").trim();
|
|
936
|
+
const valueSet = useMemo(() => {
|
|
937
|
+
const set = new Set();
|
|
938
|
+
for (const value of props.value) {
|
|
939
|
+
set.add(getValueKey(value));
|
|
940
|
+
}
|
|
941
|
+
return set;
|
|
942
|
+
}, [props.value]);
|
|
943
|
+
const renderRow = (props2) => {
|
|
944
|
+
const key = getValueKey(props2.row);
|
|
945
|
+
const value = valueSet.has(key);
|
|
946
|
+
const label = props.renderOption !== undefined
|
|
947
|
+
? props.renderOption({ option: props2.row, index: props2.index })
|
|
948
|
+
: String(props2.row);
|
|
949
|
+
function onChange(checked) {
|
|
950
|
+
if (checked) {
|
|
951
|
+
if (props.onSelect !== undefined) {
|
|
952
|
+
props.onSelect(props2.row);
|
|
717
953
|
}
|
|
718
954
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
useImperativeHandle(ref, () => ({
|
|
723
|
-
focus: () => {
|
|
724
|
-
inputRef.current?.focus();
|
|
725
|
-
},
|
|
726
|
-
}));
|
|
727
|
-
return (React__default.createElement("div", null,
|
|
728
|
-
React__default.createElement("input", { ref: inputRef, className: [
|
|
729
|
-
"ui89-input-box",
|
|
730
|
-
disabled ? "ui89-input-box--disabled" : "",
|
|
731
|
-
].join(" "), type: "text", disabled: disabled, value: delayedState.value, onChange: (e) => delayedState.onChange(e.target.value), onBlur: delayedState.onBlur, onFocus: delayedState.onFocus, onKeyDown: (e) => {
|
|
732
|
-
if (e.key === "Enter") {
|
|
733
|
-
delayedState.onConfirm();
|
|
955
|
+
else {
|
|
956
|
+
if (props.onDeselect !== undefined) {
|
|
957
|
+
props.onDeselect(props2.row);
|
|
734
958
|
}
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
const [value, setValue] = useState(overrides.currentZIndex);
|
|
745
|
-
useEffect(() => {
|
|
746
|
-
if (open) {
|
|
747
|
-
setValue(overrides.nextZIndex());
|
|
959
|
+
}
|
|
960
|
+
if (props.onChange !== undefined) {
|
|
961
|
+
if (checked) {
|
|
962
|
+
props.onChange([...props.value, props2.row]);
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
props.onChange(props.value.filter((item) => getValueKey(item) !== key));
|
|
966
|
+
}
|
|
967
|
+
}
|
|
748
968
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
969
|
+
function toggle() {
|
|
970
|
+
onChange(!value);
|
|
971
|
+
}
|
|
972
|
+
return (React__default.createElement("div", { style: {
|
|
973
|
+
display: "flex",
|
|
974
|
+
alignItems: "center",
|
|
975
|
+
gap: "var(--ui89-safe-space)",
|
|
976
|
+
height: "100%",
|
|
977
|
+
} },
|
|
978
|
+
React__default.createElement(Ui89InputCheckBox, { value: value, onChange: onChange }),
|
|
979
|
+
React__default.createElement("div", { className: "ui89-text-ellipsis", style: { minWidth: 0, cursor: "pointer" }, onClick: toggle }, label)));
|
|
752
980
|
};
|
|
981
|
+
return (React__default.createElement("div", { style: {
|
|
982
|
+
display: "flex",
|
|
983
|
+
flexDirection: "column",
|
|
984
|
+
maxHeight: props.maxHeight,
|
|
985
|
+
} },
|
|
986
|
+
React__default.createElement(Ui89VirtualList, { rows: props.options, renderRow: renderRow, getRowKey: props.getValueKey, rowHeight: props.optionHeight ?? 40, maxHeight: "100%" })));
|
|
753
987
|
}
|
|
754
988
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
Ui89PopoverPropsPlacement["right"] = "right";
|
|
761
|
-
Ui89PopoverPropsPlacement["rightStart"] = "rightStart";
|
|
762
|
-
Ui89PopoverPropsPlacement["rightEnd"] = "rightEnd";
|
|
763
|
-
Ui89PopoverPropsPlacement["bottom"] = "bottom";
|
|
764
|
-
Ui89PopoverPropsPlacement["bottomStart"] = "bottomStart";
|
|
765
|
-
Ui89PopoverPropsPlacement["bottomEnd"] = "bottomEnd";
|
|
766
|
-
Ui89PopoverPropsPlacement["left"] = "left";
|
|
767
|
-
Ui89PopoverPropsPlacement["leftStart"] = "leftStart";
|
|
768
|
-
Ui89PopoverPropsPlacement["leftEnd"] = "leftEnd";
|
|
769
|
-
})(Ui89PopoverPropsPlacement || (Ui89PopoverPropsPlacement = {}));
|
|
770
|
-
function toFloatingUiPlacement(placement) {
|
|
771
|
-
switch (placement) {
|
|
772
|
-
case Ui89PopoverPropsPlacement.top:
|
|
773
|
-
return "top";
|
|
774
|
-
case Ui89PopoverPropsPlacement.topStart:
|
|
775
|
-
return "top-start";
|
|
776
|
-
case Ui89PopoverPropsPlacement.topEnd:
|
|
777
|
-
return "top-end";
|
|
778
|
-
case Ui89PopoverPropsPlacement.right:
|
|
779
|
-
return "right";
|
|
780
|
-
case Ui89PopoverPropsPlacement.rightStart:
|
|
781
|
-
return "right-start";
|
|
782
|
-
case Ui89PopoverPropsPlacement.rightEnd:
|
|
783
|
-
return "right-end";
|
|
784
|
-
case Ui89PopoverPropsPlacement.bottom:
|
|
785
|
-
return "bottom";
|
|
786
|
-
case Ui89PopoverPropsPlacement.bottomStart:
|
|
787
|
-
return "bottom-start";
|
|
788
|
-
case Ui89PopoverPropsPlacement.bottomEnd:
|
|
789
|
-
return "bottom-end";
|
|
790
|
-
case Ui89PopoverPropsPlacement.left:
|
|
791
|
-
return "left";
|
|
792
|
-
case Ui89PopoverPropsPlacement.leftStart:
|
|
793
|
-
return "left-start";
|
|
794
|
-
case Ui89PopoverPropsPlacement.leftEnd:
|
|
795
|
-
return "left-end";
|
|
796
|
-
default:
|
|
797
|
-
throw new Error(`Unknown placement: ${placement}`);
|
|
989
|
+
function Ui89InputCheckText(props) {
|
|
990
|
+
function toggle() {
|
|
991
|
+
if (props.onChange) {
|
|
992
|
+
props.onChange(!props.value);
|
|
993
|
+
}
|
|
798
994
|
}
|
|
995
|
+
return (React__default.createElement("span", { className: "ui89-input-check-text", onClick: toggle }, props.value ? "[X]" : "[ ]"));
|
|
799
996
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
const { getReferenceProps, getFloatingProps } = useInteractions([
|
|
831
|
-
click,
|
|
832
|
-
dismiss,
|
|
833
|
-
role,
|
|
834
|
-
]);
|
|
835
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
836
|
-
props.renderContainer({
|
|
837
|
-
setRef: refs.setReference,
|
|
838
|
-
props: getReferenceProps(),
|
|
839
|
-
}),
|
|
840
|
-
props.open && (React__default.createElement(FloatingPortal, null,
|
|
841
|
-
React__default.createElement(FloatingFocusManager, { context: context, modal: false, initialFocus: -1 },
|
|
842
|
-
React__default.createElement(Ui89Scene, null,
|
|
843
|
-
React__default.createElement("div", { ref: refs.setFloating, style: {
|
|
844
|
-
...floatingStyles,
|
|
845
|
-
zIndex: zIndexer.value,
|
|
846
|
-
display: "flex",
|
|
847
|
-
flexDirection: "column",
|
|
848
|
-
} }, props.renderPopover())))))));
|
|
997
|
+
|
|
998
|
+
function Ui89InputFileUpload(props) {
|
|
999
|
+
const inputRef = useRef(null);
|
|
1000
|
+
function implOnChange(e) {
|
|
1001
|
+
if (!props.onChange) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
if (e.target.files === null) {
|
|
1005
|
+
props.onChange(null);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
if (e.target.files.length === 0) {
|
|
1009
|
+
props.onChange(null);
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
props.onChange(e.target.files[0]);
|
|
1013
|
+
// Reset the file input's value to allow selecting the same file again.
|
|
1014
|
+
e.target.value = "";
|
|
1015
|
+
}
|
|
1016
|
+
function onClick() {
|
|
1017
|
+
if (inputRef.current === null) {
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
inputRef.current.click();
|
|
1021
|
+
}
|
|
1022
|
+
return (React__default.createElement("div", null,
|
|
1023
|
+
React__default.createElement("input", { ref: inputRef, className: "ui89-typo-special", type: "file", onChange: implOnChange, accept: props.accept, hidden: true }),
|
|
1024
|
+
props.value ? (React__default.createElement("div", { className: "ui89-input-file-upload" },
|
|
1025
|
+
React__default.createElement(Ui89Button, { onClick: onClick }, "Change"),
|
|
1026
|
+
React__default.createElement("span", { className: `ui89-input-file-upload__info ui89-text-single-line ui89-text-single-line--ellipsis-left`, title: props.value.name }, props.value.name))) : (React__default.createElement(Ui89Button, { onClick: onClick }, "Upload"))));
|
|
849
1027
|
}
|
|
850
1028
|
|
|
851
1029
|
/**
|
|
@@ -919,7 +1097,7 @@ function Ui89InputSelect(props) {
|
|
|
919
1097
|
searchInput.current?.focus();
|
|
920
1098
|
}
|
|
921
1099
|
return (React__default.createElement("div", { className: "ui89-input-select" },
|
|
922
|
-
React__default.createElement(Ui89Popover, { open: isOpen, onOpenChange: setIsOpen, popoverOverflowMaxWidth: props.menuOverflowMaxWidth, renderContainer: (props2) => (React__default.createElement("div", { ref: props2.setRef, className: [
|
|
1100
|
+
React__default.createElement(Ui89Popover, { open: isOpen, onOpenChange: setIsOpen, popoverOverflowForce: true, popoverOverflowMaxWidth: props.menuOverflowMaxWidth, renderContainer: (props2) => (React__default.createElement("div", { ref: props2.setRef, className: [
|
|
923
1101
|
"ui89-input-box",
|
|
924
1102
|
"ui89-input-box--unselectable",
|
|
925
1103
|
"ui89-input-box--clickable",
|
|
@@ -935,62 +1113,6 @@ function Ui89InputSelect(props) {
|
|
|
935
1113
|
].join(" ") }, "<empty>")))) })));
|
|
936
1114
|
}
|
|
937
1115
|
|
|
938
|
-
function stringRemoveAllWhitespace(str) {
|
|
939
|
-
return str.replace(/\s+/g, "");
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
function isTextNumber(text) {
|
|
943
|
-
return /^\d+(\.\d+)?$/.test(text);
|
|
944
|
-
}
|
|
945
|
-
function displayText(value) {
|
|
946
|
-
if (value === undefined) {
|
|
947
|
-
// No idea how to display this.
|
|
948
|
-
return "";
|
|
949
|
-
}
|
|
950
|
-
else if (isNaN(value)) {
|
|
951
|
-
// No idea what to display.
|
|
952
|
-
return "";
|
|
953
|
-
}
|
|
954
|
-
return value.toString();
|
|
955
|
-
}
|
|
956
|
-
function dotsMakeMoreSense(value) {
|
|
957
|
-
return value.replaceAll(",", ".");
|
|
958
|
-
}
|
|
959
|
-
function Ui89InputTextNumber(props) {
|
|
960
|
-
const wrappedValue = useMemo(() => {
|
|
961
|
-
return displayText(props.value);
|
|
962
|
-
}, [props.value]);
|
|
963
|
-
function implOnChange(value) {
|
|
964
|
-
if (props.onChange === undefined) {
|
|
965
|
-
return;
|
|
966
|
-
}
|
|
967
|
-
if (value === "") {
|
|
968
|
-
// Use empty value.
|
|
969
|
-
props.onChange(props.emptyValue);
|
|
970
|
-
return;
|
|
971
|
-
}
|
|
972
|
-
value = stringRemoveAllWhitespace(value);
|
|
973
|
-
value = dotsMakeMoreSense(value);
|
|
974
|
-
if (!isTextNumber(value)) {
|
|
975
|
-
// We end here.
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
const numberValue = Number(value);
|
|
979
|
-
if (props.min !== undefined) {
|
|
980
|
-
if (numberValue <= props.min) {
|
|
981
|
-
value = String(props.min);
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
if (props.max !== undefined) {
|
|
985
|
-
if (numberValue >= props.max) {
|
|
986
|
-
value = String(props.max);
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
props.onChange(value);
|
|
990
|
-
}
|
|
991
|
-
return (React__default.createElement(Ui89InputText, { value: wrappedValue, onChange: implOnChange, disabled: props.disabled }));
|
|
992
|
-
}
|
|
993
|
-
|
|
994
1116
|
function Ui89InputNumber(props) {
|
|
995
1117
|
const wrappedValue = useMemo(() => {
|
|
996
1118
|
if (props.value !== undefined && props.value !== null) {
|
|
@@ -1017,7 +1139,7 @@ function Ui89InputNumber(props) {
|
|
|
1017
1139
|
}
|
|
1018
1140
|
}
|
|
1019
1141
|
}
|
|
1020
|
-
return (React__default.createElement(Ui89InputTextNumber, { emptyValue: props.emptyValue, value: wrappedValue, onChange: wrappedOnChange, min: props.min, max: props.max, disabled: props.disabled, precision: props.precision }));
|
|
1142
|
+
return (React__default.createElement(Ui89InputTextNumber, { emptyValue: props.emptyValue, value: wrappedValue, onChange: wrappedOnChange, min: props.min, max: props.max, disabled: props.disabled, precision: props.precision, textAlign: props.textAlign }));
|
|
1021
1143
|
}
|
|
1022
1144
|
|
|
1023
1145
|
function Ui89InputPassword({ value, placeholder, disabled, onChange, }) {
|
|
@@ -1088,6 +1210,7 @@ function ScrollContainer({ children, }) {
|
|
|
1088
1210
|
const portalRoot = typeof document !== "undefined" ? document.body : null;
|
|
1089
1211
|
function Ui89ModalDialog({ open, size = "medium", children, topCenter, onRequestClose, }) {
|
|
1090
1212
|
const zIndexer = useZIndexer(open);
|
|
1213
|
+
const { createPortal } = useUi89();
|
|
1091
1214
|
const dialogClass = useMemo(() => {
|
|
1092
1215
|
return ["ui89-modal-dialog", open ? "ui89-modal-dialog--open" : ""].join(" ");
|
|
1093
1216
|
}, [size, open]);
|