panelui-native 0.51.1 → 0.53.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/README.md +2 -1
- package/lib/module/components/candlestick-chart/index.js +1161 -0
- package/lib/module/components/candlestick-chart/index.js.map +1 -0
- package/lib/module/components/combobox/index.js +73 -7
- package/lib/module/components/combobox/index.js.map +1 -1
- package/lib/module/components/context-menu/index.js +529 -0
- package/lib/module/components/context-menu/index.js.map +1 -0
- package/lib/module/components/menu/index.js +18 -10
- package/lib/module/components/menu/index.js.map +1 -1
- package/lib/module/components/popover/index.js +71 -7
- package/lib/module/components/popover/index.js.map +1 -1
- package/lib/module/components/sortable/index.js +159 -23
- package/lib/module/components/sortable/index.js.map +1 -1
- package/lib/module/components/tabs/index.js +56 -15
- package/lib/module/components/tabs/index.js.map +1 -1
- package/lib/module/components/time-picker/index.js +295 -31
- package/lib/module/components/time-picker/index.js.map +1 -1
- package/lib/module/index.js +3 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/components/candlestick-chart/index.d.ts +278 -0
- package/lib/typescript/src/components/candlestick-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/combobox/index.d.ts.map +1 -1
- package/lib/typescript/src/components/context-menu/index.d.ts +270 -0
- package/lib/typescript/src/components/context-menu/index.d.ts.map +1 -0
- package/lib/typescript/src/components/menu/index.d.ts +20 -20
- package/lib/typescript/src/components/menu/index.d.ts.map +1 -1
- package/lib/typescript/src/components/popover/index.d.ts +51 -1
- package/lib/typescript/src/components/popover/index.d.ts.map +1 -1
- package/lib/typescript/src/components/sortable/index.d.ts +13 -3
- package/lib/typescript/src/components/sortable/index.d.ts.map +1 -1
- package/lib/typescript/src/components/tabs/index.d.ts +34 -2
- package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
- package/lib/typescript/src/components/time-picker/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/candlestick-chart/index.tsx +1360 -0
- package/src/components/combobox/index.tsx +84 -6
- package/src/components/context-menu/index.tsx +658 -0
- package/src/components/menu/index.tsx +17 -10
- package/src/components/popover/index.tsx +94 -6
- package/src/components/sortable/index.tsx +208 -22
- package/src/components/tabs/index.tsx +82 -16
- package/src/components/time-picker/index.tsx +330 -35
- package/src/index.ts +27 -0
|
@@ -296,6 +296,13 @@ function eachOption(children: ReactNode, visit: (option: ComboboxItemProps) => v
|
|
|
296
296
|
* A group is rebuilt around whatever survives inside it and dropped when that
|
|
297
297
|
* is nothing — a heading over no options reads as a section that failed to load
|
|
298
298
|
* rather than one the query emptied.
|
|
299
|
+
*
|
|
300
|
+
* Every kept node is given a key on the way out. This walk builds a plain array
|
|
301
|
+
* rather than going through `Children.map`, which is the one that hands out keys
|
|
302
|
+
* of its own, so options written as literal JSX — the ordinary way to write a
|
|
303
|
+
* short, fixed list — arrive here with none. An option's `value` is already
|
|
304
|
+
* unique within a list, and a group is named by its label, so both key
|
|
305
|
+
* themselves; an explicit key on the element still wins.
|
|
299
306
|
*/
|
|
300
307
|
function filterOptions(
|
|
301
308
|
children: ReactNode,
|
|
@@ -303,20 +310,31 @@ function filterOptions(
|
|
|
303
310
|
): ReactNode[] {
|
|
304
311
|
const kept: ReactNode[] = [];
|
|
305
312
|
|
|
306
|
-
Children.forEach(children, (child) => {
|
|
313
|
+
Children.forEach(children, (child, index) => {
|
|
307
314
|
if (!isValidElement(child)) return;
|
|
308
315
|
|
|
309
316
|
if (child.type === ComboboxGroup) {
|
|
310
317
|
const props = child.props as ComboboxGroupProps;
|
|
311
318
|
const inner = filterOptions(props.children, matches);
|
|
312
319
|
if (inner.length) {
|
|
313
|
-
kept.push(
|
|
320
|
+
kept.push(
|
|
321
|
+
cloneElement(
|
|
322
|
+
child as ReactElement<ComboboxGroupProps>,
|
|
323
|
+
{ key: child.key ?? `group:${props.label ?? index}` },
|
|
324
|
+
inner
|
|
325
|
+
)
|
|
326
|
+
);
|
|
314
327
|
}
|
|
315
328
|
return;
|
|
316
329
|
}
|
|
317
330
|
|
|
318
331
|
if (child.type === ComboboxItem && matches(child.props as ComboboxItemProps)) {
|
|
319
|
-
|
|
332
|
+
const props = child.props as ComboboxItemProps;
|
|
333
|
+
kept.push(
|
|
334
|
+
cloneElement(child as ReactElement<ComboboxItemProps>, {
|
|
335
|
+
key: child.key ?? `option:${props.value}`,
|
|
336
|
+
})
|
|
337
|
+
);
|
|
320
338
|
}
|
|
321
339
|
});
|
|
322
340
|
|
|
@@ -549,13 +567,66 @@ function ComboboxRoot<Mode extends ComboboxMode = 'single'>({
|
|
|
549
567
|
* that lifts its content clear of the keyboard moves the field after it was
|
|
550
568
|
* measured, and the list would stay at the old position. Re-measure whenever
|
|
551
569
|
* the keyboard's height changes while the list is open.
|
|
570
|
+
*
|
|
571
|
+
* Except while the list is being dragged. The list dismisses the keyboard on
|
|
572
|
+
* drag, so the first finger movement changes the keyboard's height, which
|
|
573
|
+
* lands a new anchor, which recomputes the panel's `top` *and* its
|
|
574
|
+
* `maxHeight` — the panel resizes and moves under the finger that is
|
|
575
|
+
* scrolling it, which is the stutter. The measurement is only stale once the
|
|
576
|
+
* keyboard has finished leaving, so it is deferred to the end of the drag,
|
|
577
|
+
* which is also the first moment it can be taken correctly.
|
|
552
578
|
*/
|
|
553
|
-
|
|
554
|
-
|
|
579
|
+
const draggingList = useRef(false);
|
|
580
|
+
const anchorStale = useRef(false);
|
|
581
|
+
|
|
582
|
+
const remeasure = useCallback(() => {
|
|
555
583
|
fieldRef.current?.measureInWindow((x, y, width, height) =>
|
|
556
584
|
setAnchor({ x, y, width, height })
|
|
557
585
|
);
|
|
558
|
-
}, [
|
|
586
|
+
}, []);
|
|
587
|
+
|
|
588
|
+
useEffect(() => {
|
|
589
|
+
if (!open || presentation !== 'overlay') return;
|
|
590
|
+
if (draggingList.current) {
|
|
591
|
+
anchorStale.current = true;
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
remeasure();
|
|
595
|
+
}, [open, presentation, keyboardHeight, remeasure]);
|
|
596
|
+
|
|
597
|
+
const settleTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
598
|
+
|
|
599
|
+
const cancelSettle = useCallback(() => {
|
|
600
|
+
if (settleTimer.current === null) return;
|
|
601
|
+
clearTimeout(settleTimer.current);
|
|
602
|
+
settleTimer.current = null;
|
|
603
|
+
}, []);
|
|
604
|
+
|
|
605
|
+
const onListDragStart = useCallback(() => {
|
|
606
|
+
cancelSettle();
|
|
607
|
+
draggingList.current = true;
|
|
608
|
+
}, [cancelSettle]);
|
|
609
|
+
|
|
610
|
+
const onListSettled = useCallback(() => {
|
|
611
|
+
cancelSettle();
|
|
612
|
+
draggingList.current = false;
|
|
613
|
+
if (!anchorStale.current) return;
|
|
614
|
+
anchorStale.current = false;
|
|
615
|
+
remeasure();
|
|
616
|
+
}, [cancelSettle, remeasure]);
|
|
617
|
+
|
|
618
|
+
/*
|
|
619
|
+
* A fling ends the drag and then keeps moving, and momentum begins a frame
|
|
620
|
+
* *after* the drag ends — so the end of the drag cannot tell the two apart by
|
|
621
|
+
* itself. It arms a short timer instead, which momentum starting cancels; a
|
|
622
|
+
* drag that stops dead has no momentum to cancel it and settles on the timer.
|
|
623
|
+
*/
|
|
624
|
+
const onListDragEnd = useCallback(() => {
|
|
625
|
+
cancelSettle();
|
|
626
|
+
settleTimer.current = setTimeout(onListSettled, 80);
|
|
627
|
+
}, [cancelSettle, onListSettled]);
|
|
628
|
+
|
|
629
|
+
useEffect(() => cancelSettle, [cancelSettle]);
|
|
559
630
|
|
|
560
631
|
/*
|
|
561
632
|
* A single-select field shows the chosen option's label when it is not being
|
|
@@ -751,6 +822,13 @@ function ComboboxRoot<Mode extends ComboboxMode = 'single'>({
|
|
|
751
822
|
// option would be swallowed by the keyboard dismissing first.
|
|
752
823
|
keyboardShouldPersistTaps="always"
|
|
753
824
|
keyboardDismissMode="on-drag"
|
|
825
|
+
// Both ends are wired: a slow drag that stops where it started never
|
|
826
|
+
// gets a momentum event, and a fling reports the drag ending long before
|
|
827
|
+
// the list has stopped.
|
|
828
|
+
onScrollBeginDrag={onListDragStart}
|
|
829
|
+
onScrollEndDrag={onListDragEnd}
|
|
830
|
+
onMomentumScrollBegin={cancelSettle}
|
|
831
|
+
onMomentumScrollEnd={onListSettled}
|
|
754
832
|
>
|
|
755
833
|
<View className="gap-1">{body}</View>
|
|
756
834
|
</ScrollView>
|