@william-callao/antonella-ui 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +13 -4
  2. package/dist/index.js +228 -214
  3. package/package.json +33 -33
package/dist/index.d.ts CHANGED
@@ -984,14 +984,23 @@ type AppNavigation = {
984
984
  /** Presets = las 5 variantes del motor, reutilizables por nombre. */
985
985
  declare const layoutStates: Record<LayoutStateName, LayoutState>;
986
986
  declare function useAppNavigation(): AppNavigation;
987
+ type AppLayoutDebugSnapshot = {
988
+ route: string;
989
+ anchors: string[];
990
+ anim: Record<string, number>;
991
+ naturals: Record<SectionKey, number>;
992
+ lastMeasured: Record<SectionKey, number>;
993
+ windowH: number;
994
+ };
995
+ declare function useAppLayoutDebug(): {
996
+ snapshot: () => AppLayoutDebugSnapshot;
997
+ };
987
998
  type AppLayoutProps = {
988
999
  initialRoute: AppRoute;
989
1000
  /** Muestra un botón de volver global cuando canGoBack. Default true. */
990
1001
  showBackButton?: boolean;
991
- /** Logs de debug en consola. Default false. */
992
- debug?: boolean;
993
1002
  };
994
- declare function AppLayout({ initialRoute, showBackButton, debug, }: AppLayoutProps): react_jsx_runtime.JSX.Element;
1003
+ declare function AppLayout({ initialRoute, showBackButton, }: AppLayoutProps): react_jsx_runtime.JSX.Element;
995
1004
 
996
1005
  type DivisorPosition = "top" | "bottom";
997
1006
  type DivisorProps = {
@@ -1077,4 +1086,4 @@ declare const AppIcon: {
1077
1086
  readonly Inbox: IconName;
1078
1087
  };
1079
1088
 
1080
- export { AppButton, type AppButtonProps, type AppButtonVariant, AppCheckItem, type AppCheckItemProps, type AppCheckItemStatus, AppDialogMode, type AppFilterChipOption, AppFilterChips, type AppFilterChipsProps, AppFormCard, type AppFormCardProps, AppIcon, type AppInputElement, type AppInputProps, AppLayout, type AppLayoutProps, type AppNavigation, AppResponsiveDialog, type AppResponsiveDialogProps, type AppRoute, AppSelector, type AppSelectorOption, type AppSelectorProps, AppTextArea, type AppTextAreaProps, AppTextHeader, type AppTextHeaderProps, AppTextInput, type AppTextInputProps, AppToggle, type AppToggleProps, Avatar, type AvatarProps, type AvatarSize, type BaseColorKey, BottomSheet, type BottomSheetProps, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Calendar, type CalendarProps, Card, type CardProps, CardStackSheet, type CardStackSheetProps, CardTitle, type CardTitleProps, type CardVariant, CategoryText, type CategoryTextProps, CategoryTextStyle, Chip, type ChipProps, ChipRow, type ChipRowOption, type ChipRowProps, type ChipSize, type ChipVariant, ColorCustomizerDialog, type ColorToken, ColorWheel, ComposingOrb, type Composition, DashboardShell, type DashboardShellProps, Divisor, type DivisorPosition, type DivisorProps, Dock, type DockItem, type DockProps, DonutChart, type DonutChartProps, type DonutSegment, DrawerMenu, DrawerMenuItem, type DrawerMenuItemProps, DrawerMenuItemStyle, type DrawerMenuItemType, type DrawerMenuProps, Dropdown, type DropdownOption, type DropdownProps, type DropdownState, EmptyState, type EmptyStateProps, FloatingActionButton, type FloatingActionButtonPosition, type FloatingActionButtonProps, HeaderBar, type HeaderBarProps, HeaderBarStyle, HeaderCardLayout, type HeaderCardLayoutProps, type HeightSpec, type HostKey, Icon, type IconName, type IconProps, Input, type InputProps, Item, type ItemProps, ItemStyle, KeyboardSafeScreen, type KeyboardSafeScreenProps, type LayerDirection, type LayerRole, LayoutColumn, LayoutRow, type LayoutState, type LayoutStateName, MainLayout, type MainLayoutProps, Modal, type ModalProps, OptionListItem, type OptionListItemProps, OptionListItemVariant, PinKeypad, type PinKeypadProps, ReverseHeaderCardLayout, type ReverseHeaderCardLayoutProps, type Route, type RouteOptions, SearchBar, type SearchBarProps, SearchBarStyle, type SectionBehavior, type SectionKey, type SheetKind, SheetLayout, type SheetLayoutProps, SheetSlot, type SheetSlotProps, type SidebarItem, type SidebarSection, type SidebarType, Skeleton, SkeletonCard, type SkeletonCardProps, SkeletonCircle, type SkeletonCircleProps, type SkeletonProps, type SkeletonShape, SkeletonText, type SkeletonTextProps, type SlotName, SplitColorCard, SplitDarknessCard, SplitTextCard, StateMessage, type StateMessageProps, StateMessageStyle, StateMessageType, TOAST_DEFAULT_DURATION_MS, Text, TextField, type TextFieldProps, type TextProps, type TextVariant, Toast, type ToastOptions, type ToastProps, ToastProvider, ToastStyle, ToastTone, type ToolItem, ToolsCard, type ToolsCardProps, type TransitionSpec, TreeEditor, type TreeEditorMode, type TreeEditorProps, type TreeEditorVariant, type TreeNode, addChild, addSibling, buildInitialCollapsed, countNodes, createNode, directionSign, findNode, hasCode, hostDirection, iconMap, layoutStates, removeNode, resolveComposition, resolveTransition, updateNode, useAppNavigation, useSheetLayout, useToast };
1089
+ export { AppButton, type AppButtonProps, type AppButtonVariant, AppCheckItem, type AppCheckItemProps, type AppCheckItemStatus, AppDialogMode, type AppFilterChipOption, AppFilterChips, type AppFilterChipsProps, AppFormCard, type AppFormCardProps, AppIcon, type AppInputElement, type AppInputProps, AppLayout, type AppLayoutDebugSnapshot, type AppLayoutProps, type AppNavigation, AppResponsiveDialog, type AppResponsiveDialogProps, type AppRoute, AppSelector, type AppSelectorOption, type AppSelectorProps, AppTextArea, type AppTextAreaProps, AppTextHeader, type AppTextHeaderProps, AppTextInput, type AppTextInputProps, AppToggle, type AppToggleProps, Avatar, type AvatarProps, type AvatarSize, type BaseColorKey, BottomSheet, type BottomSheetProps, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Calendar, type CalendarProps, Card, type CardProps, CardStackSheet, type CardStackSheetProps, CardTitle, type CardTitleProps, type CardVariant, CategoryText, type CategoryTextProps, CategoryTextStyle, Chip, type ChipProps, ChipRow, type ChipRowOption, type ChipRowProps, type ChipSize, type ChipVariant, ColorCustomizerDialog, type ColorToken, ColorWheel, ComposingOrb, type Composition, DashboardShell, type DashboardShellProps, Divisor, type DivisorPosition, type DivisorProps, Dock, type DockItem, type DockProps, DonutChart, type DonutChartProps, type DonutSegment, DrawerMenu, DrawerMenuItem, type DrawerMenuItemProps, DrawerMenuItemStyle, type DrawerMenuItemType, type DrawerMenuProps, Dropdown, type DropdownOption, type DropdownProps, type DropdownState, EmptyState, type EmptyStateProps, FloatingActionButton, type FloatingActionButtonPosition, type FloatingActionButtonProps, HeaderBar, type HeaderBarProps, HeaderBarStyle, HeaderCardLayout, type HeaderCardLayoutProps, type HeightSpec, type HostKey, Icon, type IconName, type IconProps, Input, type InputProps, Item, type ItemProps, ItemStyle, KeyboardSafeScreen, type KeyboardSafeScreenProps, type LayerDirection, type LayerRole, LayoutColumn, LayoutRow, type LayoutState, type LayoutStateName, MainLayout, type MainLayoutProps, Modal, type ModalProps, OptionListItem, type OptionListItemProps, OptionListItemVariant, PinKeypad, type PinKeypadProps, ReverseHeaderCardLayout, type ReverseHeaderCardLayoutProps, type Route, type RouteOptions, SearchBar, type SearchBarProps, SearchBarStyle, type SectionBehavior, type SectionKey, type SheetKind, SheetLayout, type SheetLayoutProps, SheetSlot, type SheetSlotProps, type SidebarItem, type SidebarSection, type SidebarType, Skeleton, SkeletonCard, type SkeletonCardProps, SkeletonCircle, type SkeletonCircleProps, type SkeletonProps, type SkeletonShape, SkeletonText, type SkeletonTextProps, type SlotName, SplitColorCard, SplitDarknessCard, SplitTextCard, StateMessage, type StateMessageProps, StateMessageStyle, StateMessageType, TOAST_DEFAULT_DURATION_MS, Text, TextField, type TextFieldProps, type TextProps, type TextVariant, Toast, type ToastOptions, type ToastProps, ToastProvider, ToastStyle, ToastTone, type ToolItem, ToolsCard, type ToolsCardProps, type TransitionSpec, TreeEditor, type TreeEditorMode, type TreeEditorProps, type TreeEditorVariant, type TreeNode, addChild, addSibling, buildInitialCollapsed, countNodes, createNode, directionSign, findNode, hasCode, hostDirection, iconMap, layoutStates, removeNode, resolveComposition, resolveTransition, updateNode, useAppLayoutDebug, useAppNavigation, useSheetLayout, useToast };
package/dist/index.js CHANGED
@@ -123,6 +123,7 @@ __export(index_exports, {
123
123
  resolveComposition: () => resolveComposition,
124
124
  resolveTransition: () => resolveTransition,
125
125
  updateNode: () => updateNode,
126
+ useAppLayoutDebug: () => useAppLayoutDebug,
126
127
  useAppNavigation: () => useAppNavigation,
127
128
  useSheetLayout: () => useSheetLayout,
128
129
  useToast: () => useToast
@@ -1445,6 +1446,7 @@ function BottomSheet({
1445
1446
  const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
1446
1447
  const keyboardHeight = useModalKeyboardHeight();
1447
1448
  const [mounted, setMounted] = (0, import_react5.useState)(visible);
1449
+ const [contentReady, setContentReady] = (0, import_react5.useState)(false);
1448
1450
  const progress = (0, import_react_native_reanimated3.useSharedValue)(0);
1449
1451
  const maxHeightRatio = (0, import_react5.useMemo)(() => {
1450
1452
  let ratio = 0.9;
@@ -1459,6 +1461,13 @@ function BottomSheet({
1459
1461
  (0, import_react5.useEffect)(() => {
1460
1462
  if (visible) setMounted(true);
1461
1463
  }, [visible]);
1464
+ (0, import_react5.useEffect)(() => {
1465
+ if (mounted && visible) {
1466
+ const raf = requestAnimationFrame(() => setContentReady(true));
1467
+ return () => cancelAnimationFrame(raf);
1468
+ }
1469
+ if (!mounted) setContentReady(false);
1470
+ }, [mounted, visible]);
1462
1471
  (0, import_react5.useEffect)(() => {
1463
1472
  if (!mounted) return;
1464
1473
  if (visible) {
@@ -1524,28 +1533,34 @@ function BottomSheet({
1524
1533
  children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_reanimated3.default.View, { style: [styles18.backdrop, backdropStyle] })
1525
1534
  }
1526
1535
  ),
1527
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_reanimated3.default.View, { style: [styles18.panelWrapper, containerAnimatedStyle], pointerEvents: "box-none", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native_reanimated3.default.View, { style: [styles18.panel, panelHeightStyle, panelStyle], children: [
1528
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, { style: styles18.handleBar }),
1529
- title || icon || caption || showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1530
- DialogHeader,
1531
- {
1532
- icon,
1533
- title,
1534
- caption,
1535
- onClose,
1536
- showCloseButton
1537
- }
1538
- ) : null,
1539
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1540
- import_react_native20.ScrollView,
1541
- {
1542
- showsVerticalScrollIndicator: false,
1543
- keyboardShouldPersistTaps: "handled",
1544
- contentContainerStyle: [styles18.content, contentStyle],
1545
- children
1546
- }
1547
- )
1548
- ] }) })
1536
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_reanimated3.default.View, { style: [styles18.panelWrapper, containerAnimatedStyle], pointerEvents: "box-none", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1537
+ import_react_native_reanimated3.default.View,
1538
+ {
1539
+ style: [styles18.panel, panelHeightStyle, panelStyle],
1540
+ children: [
1541
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, { style: styles18.handleBar }),
1542
+ title || icon || caption || showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1543
+ DialogHeader,
1544
+ {
1545
+ icon,
1546
+ title,
1547
+ caption,
1548
+ onClose,
1549
+ showCloseButton
1550
+ }
1551
+ ) : null,
1552
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1553
+ import_react_native20.ScrollView,
1554
+ {
1555
+ showsVerticalScrollIndicator: false,
1556
+ keyboardShouldPersistTaps: "handled",
1557
+ contentContainerStyle: [styles18.content, contentStyle],
1558
+ children: contentReady ? children : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, { style: styles18.deferredPlaceholder })
1559
+ }
1560
+ )
1561
+ ]
1562
+ }
1563
+ ) })
1549
1564
  ] })
1550
1565
  }
1551
1566
  );
@@ -1581,6 +1596,9 @@ var styles18 = import_react_native20.StyleSheet.create({
1581
1596
  content: {
1582
1597
  paddingTop: import_antonella_theme19.space.space2,
1583
1598
  paddingBottom: Math.max(import_antonella_theme19.space.space3, 24)
1599
+ },
1600
+ deferredPlaceholder: {
1601
+ minHeight: import_antonella_theme19.space.space16
1584
1602
  }
1585
1603
  });
1586
1604
 
@@ -1609,6 +1627,7 @@ function CardStackSheet({
1609
1627
  const insets = (0, import_react_native_safe_area_context2.useSafeAreaInsets)();
1610
1628
  const keyboardHeight = useModalKeyboardHeight();
1611
1629
  const [mounted, setMounted] = (0, import_react6.useState)(visible);
1630
+ const [contentReady, setContentReady] = (0, import_react6.useState)(false);
1612
1631
  const progress = (0, import_react_native_reanimated4.useSharedValue)(0);
1613
1632
  const maxHeightRatio = (0, import_react6.useMemo)(() => {
1614
1633
  let ratio = 0.9;
@@ -1623,6 +1642,13 @@ function CardStackSheet({
1623
1642
  (0, import_react6.useEffect)(() => {
1624
1643
  if (visible) setMounted(true);
1625
1644
  }, [visible]);
1645
+ (0, import_react6.useEffect)(() => {
1646
+ if (mounted && visible) {
1647
+ const raf = requestAnimationFrame(() => setContentReady(true));
1648
+ return () => cancelAnimationFrame(raf);
1649
+ }
1650
+ if (!mounted) setContentReady(false);
1651
+ }, [mounted, visible]);
1626
1652
  (0, import_react6.useEffect)(() => {
1627
1653
  if (!mounted) return;
1628
1654
  if (visible) {
@@ -1703,7 +1729,7 @@ function CardStackSheet({
1703
1729
  contentStyle,
1704
1730
  areaColor ? { backgroundColor: areaColor } : void 0
1705
1731
  ],
1706
- children
1732
+ children: contentReady ? children : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native21.View, { style: styles19.deferredPlaceholder })
1707
1733
  }
1708
1734
  ) })
1709
1735
  }
@@ -1732,6 +1758,9 @@ var styles19 = import_react_native21.StyleSheet.create({
1732
1758
  content: {
1733
1759
  gap: import_antonella_theme20.space.space3,
1734
1760
  paddingBottom: Math.max(import_antonella_theme20.space.space3, 24)
1761
+ },
1762
+ deferredPlaceholder: {
1763
+ minHeight: import_antonella_theme20.space.space16
1735
1764
  }
1736
1765
  });
1737
1766
 
@@ -5569,14 +5598,6 @@ function markBranchCollapsed(nodes, acc) {
5569
5598
  markBranchCollapsed(n.children, acc);
5570
5599
  }
5571
5600
  }
5572
- function findSiblingGroup(nodes, id) {
5573
- if (nodes.some((n) => n.id === id)) return nodes;
5574
- for (const n of nodes) {
5575
- const found = findSiblingGroup(n.children, id);
5576
- if (found) return found;
5577
- }
5578
- return null;
5579
- }
5580
5601
  function hasCode(nodes, code, excludeId) {
5581
5602
  for (const n of nodes) {
5582
5603
  if (n.code === code && n.id !== excludeId) return true;
@@ -5641,6 +5662,7 @@ var NodeGutter = import_react24.default.memo(function NodeGutter2({
5641
5662
  return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_jsx_runtime51.Fragment, { children: columns });
5642
5663
  });
5643
5664
  function renderForest(ctx, nodes, depth, parentName) {
5665
+ const collapsed = ctx.getCollapsed();
5644
5666
  return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_jsx_runtime51.Fragment, { children: nodes.map((node, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
5645
5667
  TreeNodeItem,
5646
5668
  {
@@ -5648,20 +5670,34 @@ function renderForest(ctx, nodes, depth, parentName) {
5648
5670
  depth,
5649
5671
  isLast: i === nodes.length - 1,
5650
5672
  parentName,
5673
+ isCollapsed: !!collapsed[node.id],
5674
+ branchVersion: ctx.getVersion(node.id),
5651
5675
  ctx
5652
5676
  },
5653
5677
  node.id
5654
5678
  )) });
5655
5679
  }
5680
+ function markDirtyPath(id, parentMap, acc) {
5681
+ let curr = id;
5682
+ while (curr) {
5683
+ acc.add(curr);
5684
+ curr = parentMap.get(curr);
5685
+ }
5686
+ }
5687
+ function markSubtreeDirty(node, acc) {
5688
+ acc.add(node.id);
5689
+ for (const child of node.children) markSubtreeDirty(child, acc);
5690
+ }
5656
5691
  var TreeNodeItem = import_react24.default.memo(function TreeNodeItem2({
5657
5692
  node,
5658
5693
  depth,
5659
5694
  isLast,
5660
5695
  parentName,
5696
+ isCollapsed,
5697
+ branchVersion,
5661
5698
  ctx
5662
5699
  }) {
5663
5700
  const hasChildren = node.children.length > 0;
5664
- const isCollapsed = !!ctx.collapsed[node.id];
5665
5701
  const isActive = hasChildren && !isCollapsed;
5666
5702
  const terminalElbow = isLast;
5667
5703
  const contentOpacity = (0, import_react24.useRef)(new import_react_native49.Animated.Value(0)).current;
@@ -5774,6 +5810,53 @@ function TreeEditor({ value, onChange, mode = "view", variant = "default", colla
5774
5810
  [needsImplicitInit, value]
5775
5811
  );
5776
5812
  const collapsed = implicitInit ?? source;
5813
+ const parentMap = (0, import_react24.useMemo)(() => {
5814
+ const map = /* @__PURE__ */ new Map();
5815
+ const walk = (list, parent) => {
5816
+ for (const n of list) {
5817
+ if (parent) map.set(n.id, parent);
5818
+ walk(n.children, n.id);
5819
+ }
5820
+ };
5821
+ walk(value);
5822
+ return map;
5823
+ }, [value]);
5824
+ const collapsedRef = (0, import_react24.useRef)(collapsed);
5825
+ collapsedRef.current = collapsed;
5826
+ const valueRef = (0, import_react24.useRef)(value);
5827
+ valueRef.current = value;
5828
+ const onCollapsedChangeRef = (0, import_react24.useRef)(onCollapsedChange);
5829
+ onCollapsedChangeRef.current = onCollapsedChange;
5830
+ const onRequestEditRef = (0, import_react24.useRef)(onRequestEdit);
5831
+ onRequestEditRef.current = onRequestEdit;
5832
+ const controlledRef = (0, import_react24.useRef)(collapsedProp !== void 0);
5833
+ const versionRef = (0, import_react24.useRef)(/* @__PURE__ */ new Map());
5834
+ const renderSeqRef = (0, import_react24.useRef)(0);
5835
+ const prevCollapsedRef = (0, import_react24.useRef)(collapsed);
5836
+ const parentMapRef = (0, import_react24.useRef)(parentMap);
5837
+ parentMapRef.current = parentMap;
5838
+ {
5839
+ const versions = versionRef.current;
5840
+ const dirty = /* @__PURE__ */ new Set();
5841
+ const prev = prevCollapsedRef.current;
5842
+ const markChange = (id) => {
5843
+ markDirtyPath(id, parentMapRef.current, dirty);
5844
+ const node = findNode(value, id);
5845
+ if (node) markSubtreeDirty(node, dirty);
5846
+ };
5847
+ for (const id of Object.keys(collapsed)) {
5848
+ if (prev[id] !== collapsed[id]) markChange(id);
5849
+ }
5850
+ for (const id of Object.keys(prev)) {
5851
+ if (prev[id] === true && !(id in collapsed)) markChange(id);
5852
+ }
5853
+ prevCollapsedRef.current = collapsed;
5854
+ if (dirty.size > 0) {
5855
+ renderSeqRef.current += 1;
5856
+ const seq = renderSeqRef.current;
5857
+ for (const id of dirty) versions.set(id, seq);
5858
+ }
5859
+ }
5777
5860
  (0, import_react24.useEffect)(() => {
5778
5861
  if (implicitInit == null) return;
5779
5862
  if (collapsedProp != null) {
@@ -5784,52 +5867,41 @@ function TreeEditor({ value, onChange, mode = "view", variant = "default", colla
5784
5867
  }, [implicitInit]);
5785
5868
  const vt = VARIANT_TOKENS[variant];
5786
5869
  const isEdit = mode === "edit";
5787
- const toggleCollapse = (0, import_react24.useCallback)(
5788
- (id) => {
5789
- const collapsing = !collapsed[id];
5790
- let next;
5791
- if (collapsing) {
5792
- next = { ...collapsed, [id]: true };
5793
- const node = findNode(value, id);
5794
- if (node) markBranchCollapsed(node.children, next);
5795
- } else {
5796
- next = { ...collapsed, [id]: false };
5797
- const siblings = findSiblingGroup(value, id);
5798
- const rootId = value.length > 0 ? value[0].id : null;
5799
- if (siblings) {
5800
- for (const s of siblings) {
5801
- if (s.id !== id && s.id !== rootId && s.children.length > 0) {
5802
- next[s.id] = true;
5803
- markBranchCollapsed(s.children, next);
5804
- }
5805
- }
5806
- }
5807
- }
5808
- if (collapsedProp != null) {
5809
- onCollapsedChange?.(next);
5810
- } else {
5811
- setInternalCollapsed(next);
5812
- }
5813
- },
5814
- [collapsed, collapsedProp, value, onCollapsedChange]
5815
- );
5816
- const onOpenActions = (0, import_react24.useCallback)(
5817
- (nodeId) => {
5818
- const node = findNode(value, nodeId);
5819
- if (node) onRequestEdit?.(node);
5820
- },
5821
- [value, onRequestEdit]
5822
- );
5870
+ const getCollapsed = (0, import_react24.useCallback)(() => collapsedRef.current, []);
5871
+ const getVersion = (0, import_react24.useCallback)((id) => versionRef.current.get(id) ?? 0, []);
5872
+ const toggleCollapse = (0, import_react24.useCallback)((id) => {
5873
+ const collapseMap = collapsedRef.current;
5874
+ const tree = valueRef.current;
5875
+ const collapsing = !collapseMap[id];
5876
+ let next;
5877
+ if (collapsing) {
5878
+ next = { ...collapseMap, [id]: true };
5879
+ const node = findNode(tree, id);
5880
+ if (node) markBranchCollapsed(node.children, next);
5881
+ } else {
5882
+ next = { ...collapseMap, [id]: false };
5883
+ }
5884
+ if (controlledRef.current) {
5885
+ onCollapsedChangeRef.current?.(next);
5886
+ } else {
5887
+ setInternalCollapsed(next);
5888
+ }
5889
+ }, []);
5890
+ const onOpenActions = (0, import_react24.useCallback)((nodeId) => {
5891
+ const node = findNode(valueRef.current, nodeId);
5892
+ if (node) onRequestEditRef.current?.(node);
5893
+ }, []);
5823
5894
  const ctx = (0, import_react24.useMemo)(
5824
5895
  () => ({
5825
5896
  isEdit,
5826
- collapsed,
5827
5897
  onToggle: toggleCollapse,
5828
5898
  onOpenActions,
5829
5899
  renderNode,
5830
- vt
5900
+ vt,
5901
+ getCollapsed,
5902
+ getVersion
5831
5903
  }),
5832
- [isEdit, collapsed, toggleCollapse, onOpenActions, renderNode, vt]
5904
+ [isEdit, toggleCollapse, onOpenActions, renderNode, vt, getCollapsed, getVersion]
5833
5905
  );
5834
5906
  return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
5835
5907
  import_react_native49.View,
@@ -7246,7 +7318,6 @@ var styles56 = import_react_native61.StyleSheet.create({
7246
7318
  var import_react32 = require("react");
7247
7319
  var import_react_native63 = require("react-native");
7248
7320
  var import_react_native64 = require("react-native");
7249
- var import_react_native_reanimated14 = __toESM(require("react-native-reanimated"));
7250
7321
 
7251
7322
  // src/layout/Divisor.tsx
7252
7323
  var import_react_native62 = require("react-native");
@@ -7346,8 +7417,6 @@ var DEFAULT_COLORS = {
7346
7417
  mid: DEFAULT_BG2,
7347
7418
  bottom: DARK_BG
7348
7419
  };
7349
- var COLLAPSE_DISTANCE = 80;
7350
- var TRANSITION = 320;
7351
7420
  var AppNavigationContext = (0, import_react32.createContext)(null);
7352
7421
  function useAppNavigation() {
7353
7422
  const ctx = (0, import_react32.useContext)(AppNavigationContext);
@@ -7356,10 +7425,17 @@ function useAppNavigation() {
7356
7425
  }
7357
7426
  return ctx;
7358
7427
  }
7428
+ var AppLayoutDebugContext = (0, import_react32.createContext)(null);
7429
+ function useAppLayoutDebug() {
7430
+ const ctx = (0, import_react32.useContext)(AppLayoutDebugContext);
7431
+ if (!ctx) {
7432
+ throw new Error("useAppLayoutDebug debe usarse dentro de <AppLayout>");
7433
+ }
7434
+ return ctx;
7435
+ }
7359
7436
  function AppLayout({
7360
7437
  initialRoute,
7361
- showBackButton = true,
7362
- debug = false
7438
+ showBackButton = true
7363
7439
  }) {
7364
7440
  const { height: H } = (0, import_react_native64.useWindowDimensions)();
7365
7441
  const [stack, setStack] = (0, import_react32.useState)([initialRoute]);
@@ -7410,47 +7486,19 @@ function AppLayout({
7410
7486
  const bottomVisible = !!state.sections.bottom?.visible;
7411
7487
  const showTopDivisor = topVisible && (midVisible || bottomVisible);
7412
7488
  const showBottomDivisor = bottomVisible && (topVisible || midVisible);
7413
- const topNatural = (0, import_react_native_reanimated14.useSharedValue)(H / 3);
7414
- const midNatural = (0, import_react_native_reanimated14.useSharedValue)(H / 3);
7415
- const bottomNatural = (0, import_react_native_reanimated14.useSharedValue)(H / 3);
7416
- const naturals = {
7417
- top: topNatural,
7418
- mid: midNatural,
7419
- bottom: bottomNatural
7420
- };
7421
- const animating = (0, import_react_native_reanimated14.useSharedValue)(0);
7422
- const scrollY = (0, import_react_native_reanimated14.useSharedValue)(0);
7489
+ const [layoutHeights, setLayoutHeights] = (0, import_react32.useState)({
7490
+ top: H / 3,
7491
+ mid: H / 3,
7492
+ bottom: H / 3
7493
+ });
7423
7494
  const scrollRef = (0, import_react32.useRef)(null);
7424
7495
  const innerScrollRef = (0, import_react32.useRef)(null);
7425
- const settleTimerRef = (0, import_react32.useRef)(null);
7426
- const progress = (0, import_react_native_reanimated14.useSharedValue)(1);
7427
- const fromH = {
7428
- top: (0, import_react_native_reanimated14.useSharedValue)(H / 3),
7429
- mid: (0, import_react_native_reanimated14.useSharedValue)(H / 3),
7430
- bottom: (0, import_react_native_reanimated14.useSharedValue)(H / 3)
7431
- };
7432
- const toH = {
7433
- top: (0, import_react_native_reanimated14.useSharedValue)(H / 3),
7434
- mid: (0, import_react_native_reanimated14.useSharedValue)(H / 3),
7435
- bottom: (0, import_react_native_reanimated14.useSharedValue)(H / 3)
7436
- };
7437
- const topDisplay = (0, import_react_native_reanimated14.useDerivedValue)(
7438
- () => (0, import_react_native_reanimated14.interpolate)(progress.value, [0, 1], [fromH.top.value, toH.top.value])
7439
- );
7440
- const midDisplay = (0, import_react_native_reanimated14.useDerivedValue)(
7441
- () => (0, import_react_native_reanimated14.interpolate)(progress.value, [0, 1], [fromH.mid.value, toH.mid.value])
7442
- );
7443
- const bottomDisplay = (0, import_react_native_reanimated14.useDerivedValue)(
7444
- () => (0, import_react_native_reanimated14.interpolate)(progress.value, [0, 1], [fromH.bottom.value, toH.bottom.value])
7445
- );
7446
- const display = {
7447
- top: topDisplay,
7448
- mid: midDisplay,
7449
- bottom: bottomDisplay
7450
- };
7451
- const onScroll = (0, import_react_native_reanimated14.useAnimatedScrollHandler)((event) => {
7452
- scrollY.value = event.contentOffset.y;
7496
+ const naturalsRef = (0, import_react32.useRef)({
7497
+ top: H / 3,
7498
+ mid: H / 3,
7499
+ bottom: H / 3
7453
7500
  });
7501
+ const lastMeasured = (0, import_react32.useRef)({ top: 0, mid: 0, bottom: 0 });
7454
7502
  const computeTargets = (st) => {
7455
7503
  const base = { top: 0, mid: 0, bottom: 0 };
7456
7504
  for (const k of SECTION_KEYS) {
@@ -7460,103 +7508,68 @@ function AppLayout({
7460
7508
  continue;
7461
7509
  }
7462
7510
  const h = b.height ?? "content";
7463
- if (h === "content") base[k] = naturals[k].value;
7511
+ if (h === "content") base[k] = naturalsRef.current[k];
7464
7512
  else if (h === "third") base[k] = H / 3;
7465
7513
  else if (h === "fill") base[k] = H;
7466
- else if (h === "fillRest") base[k] = b.restsOn ? H - naturals[b.restsOn].value : 0;
7514
+ else if (h === "fillRest") base[k] = b.restsOn ? H - naturalsRef.current[b.restsOn] : 0;
7467
7515
  else base[k] = h;
7468
7516
  }
7469
7517
  return base;
7470
7518
  };
7519
+ const applyTargets = (0, import_react32.useCallback)((next) => {
7520
+ setLayoutHeights(
7521
+ (prev) => SECTION_KEYS.every((k) => prev[k] === next[k]) ? prev : next
7522
+ );
7523
+ }, []);
7471
7524
  const makeOnMeasure = (k) => (e) => {
7472
7525
  const h = e.nativeEvent.layout.height;
7473
- naturals[k].value = h;
7474
- const b = state.sections[k];
7475
- if (b?.height === "content") {
7476
- fromH[k].value = display[k].value;
7477
- toH[k].value = h;
7478
- }
7479
- for (const j of SECTION_KEYS) {
7480
- const bj = state.sections[j];
7481
- if (bj?.visible && bj.height === "fillRest" && bj.restsOn === k) {
7482
- fromH[j].value = display[j].value;
7483
- toH[j].value = H - h;
7484
- }
7485
- }
7526
+ const prev = lastMeasured.current[k];
7527
+ const collapsed = prev > 0 && h < Math.min(prev * 0.5, 100);
7528
+ if (collapsed) return;
7529
+ naturalsRef.current[k] = h;
7530
+ lastMeasured.current[k] = h;
7531
+ applyTargets(computeTargets(state));
7486
7532
  };
7487
7533
  (0, import_react32.useLayoutEffect)(() => {
7488
- if (settleTimerRef.current) clearTimeout(settleTimerRef.current);
7489
- animating.value = 1;
7534
+ const targets = computeTargets(state);
7490
7535
  if (!state.pageScroll) {
7491
7536
  scrollRef.current?.scrollTo({ y: 0, animated: false });
7492
7537
  innerScrollRef.current?.scrollTo({ y: 0, animated: false });
7493
- scrollY.value = 0;
7494
- }
7495
- const targets = computeTargets(state);
7496
- for (const k of SECTION_KEYS) {
7497
- fromH[k].value = display[k].value;
7498
- toH[k].value = targets[k];
7499
- }
7500
- progress.value = 0;
7501
- progress.value = (0, import_react_native_reanimated14.withTiming)(
7502
- 1,
7503
- { duration: TRANSITION, easing: import_react_native_reanimated14.Easing.inOut(import_react_native_reanimated14.Easing.cubic) },
7504
- () => {
7505
- animating.value = 0;
7506
- }
7507
- );
7508
- settleTimerRef.current = setTimeout(() => {
7509
- scrollRef.current?.scrollTo({ y: 0, animated: false });
7510
- scrollY.value = 0;
7511
- setPrevRoute(currentRoute);
7512
- }, TRANSITION);
7513
- if (debug) {
7514
- console.log("[APP] transition ->", currentRoute.name, targets);
7515
7538
  }
7539
+ applyTargets(targets);
7540
+ setPrevRoute(currentRoute);
7516
7541
  }, [currentRoute.name]);
7517
- const topStyle = (0, import_react_native_reanimated14.useAnimatedStyle)(() => ({ height: topDisplay.value }));
7518
- const midStyle = (0, import_react_native_reanimated14.useAnimatedStyle)(() => ({ height: midDisplay.value }));
7519
- const bottomStyle = (0, import_react_native_reanimated14.useAnimatedStyle)(() => ({ height: bottomDisplay.value }));
7520
- const stylesFor = {
7521
- top: topStyle,
7522
- mid: midStyle,
7523
- bottom: bottomStyle
7524
- };
7525
- const topFade = (0, import_react_native_reanimated14.useAnimatedStyle)(
7526
- () => {
7527
- const scrollFade = state.sections.top?.fadeOnScroll ? (0, import_react_native_reanimated14.interpolate)(scrollY.value, [0, COLLAPSE_DISTANCE], [1, 0], import_react_native_reanimated14.Extrapolation.CLAMP) : 1;
7528
- return { opacity: scrollFade };
7529
- },
7530
- [state]
7531
- );
7532
- const midFade = (0, import_react_native_reanimated14.useAnimatedStyle)(
7533
- () => {
7534
- const scrollFade = state.sections.mid?.fadeOnScroll ? (0, import_react_native_reanimated14.interpolate)(scrollY.value, [0, COLLAPSE_DISTANCE], [1, 0], import_react_native_reanimated14.Extrapolation.CLAMP) : 1;
7535
- const full = naturals.mid.value || 1;
7536
- const collapseFade = (0, import_react_native_reanimated14.interpolate)(midDisplay.value, [0, full], [0, 1], import_react_native_reanimated14.Extrapolation.CLAMP);
7537
- return { opacity: Math.min(scrollFade, collapseFade) };
7538
- },
7539
- [state]
7540
- );
7541
- const bottomFade = (0, import_react_native_reanimated14.useAnimatedStyle)(
7542
+ const snapshot = (0, import_react32.useCallback)(
7542
7543
  () => {
7543
- const scrollFade = state.sections.bottom?.fadeOnScroll ? (0, import_react_native_reanimated14.interpolate)(scrollY.value, [0, COLLAPSE_DISTANCE], [1, 0], import_react_native_reanimated14.Extrapolation.CLAMP) : 1;
7544
- return { opacity: scrollFade };
7544
+ const midNatural = naturalsRef.current.mid || 1;
7545
+ return {
7546
+ route: currentRoute.name,
7547
+ anchors: stack.map((r) => r.name),
7548
+ anim: {
7549
+ scrollY: 0,
7550
+ animating: 0,
7551
+ top: Math.round(layoutHeights.top),
7552
+ mid: Math.round(layoutHeights.mid),
7553
+ bottom: Math.round(layoutHeights.bottom),
7554
+ topFade: 1,
7555
+ midFade: Math.min(layoutHeights.mid / midNatural, 1),
7556
+ bottomFade: 1
7557
+ },
7558
+ naturals: { ...naturalsRef.current },
7559
+ lastMeasured: { ...lastMeasured.current },
7560
+ windowH: H
7561
+ };
7545
7562
  },
7546
- [state]
7563
+ [currentRoute.name, stack, H, layoutHeights]
7547
7564
  );
7548
- const fadeFor = {
7549
- top: topFade,
7550
- mid: midFade,
7551
- bottom: bottomFade
7552
- };
7553
7565
  const renderSection = (k) => {
7554
7566
  const cur = state.sections[k];
7555
7567
  const prevB = prevLayoutState?.sections[k];
7556
7568
  const prevVisible = !!prevB?.visible;
7557
7569
  const visible = !!cur?.visible || prevVisible;
7570
+ const height = layoutHeights[k];
7558
7571
  if (!visible) {
7559
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native_reanimated14.default.View, { style: [styles58.colBlock, stylesFor[k]], children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native63.View, { style: styles58.measureCopy, onLayout: makeOnMeasure(k), children: cur?.slot ? slots[cur.slot] : null }) }, k);
7572
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native63.View, { style: [styles58.colBlock, { height }], children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native63.View, { style: styles58.measureCopy, onLayout: makeOnMeasure(k), children: cur?.slot ? slots[cur.slot] : null }) }, k);
7560
7573
  }
7561
7574
  const usePrevContent = !cur?.visible && prevVisible;
7562
7575
  const slot = usePrevContent ? prevB?.slot : cur?.slot;
@@ -7564,39 +7577,36 @@ function AppLayout({
7564
7577
  const bg = cur?.backgroundColor ?? prevB?.backgroundColor ?? DEFAULT_COLORS[k];
7565
7578
  const isDynamic = (cur?.height ?? prevB?.height) === "content";
7566
7579
  const scroll = cur?.scroll ?? prevB?.scroll ?? false;
7567
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
7568
- import_react_native_reanimated14.default.View,
7569
- {
7570
- style: [styles58.colBlock, { backgroundColor: bg, overflow: "hidden" }, stylesFor[k]],
7571
- children: [
7572
- isDynamic && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native63.View, { style: styles58.measureCopy, onLayout: makeOnMeasure(k), children: content }),
7573
- scroll ? /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
7574
- import_react_native_reanimated14.default.ScrollView,
7575
- {
7576
- ref: innerScrollRef,
7577
- style: styles58.innerScroll,
7578
- showsVerticalScrollIndicator: false,
7579
- scrollEventThrottle: 16,
7580
- onScroll,
7581
- children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native_reanimated14.default.View, { style: fadeFor[k], children: content })
7582
- }
7583
- ) : /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native_reanimated14.default.View, { style: styles58.sectionContent, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native_reanimated14.default.View, { style: fadeFor[k], children: content }) })
7584
- ]
7585
- },
7586
- k
7587
- );
7580
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(import_react_native63.View, { style: [styles58.colBlock, { backgroundColor: bg, height }], children: [
7581
+ isDynamic && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
7582
+ import_react_native63.View,
7583
+ {
7584
+ pointerEvents: "none",
7585
+ style: styles58.measureOuter,
7586
+ onLayout: makeOnMeasure(k),
7587
+ children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native63.View, { style: styles58.measureCopy, children: content })
7588
+ }
7589
+ ),
7590
+ scroll ? /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
7591
+ import_react_native63.ScrollView,
7592
+ {
7593
+ ref: innerScrollRef,
7594
+ style: styles58.innerScroll,
7595
+ showsVerticalScrollIndicator: false,
7596
+ children: content
7597
+ }
7598
+ ) : /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native63.View, { style: styles58.sectionContent, children: content })
7599
+ ] }, k);
7588
7600
  };
7589
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(AppNavigationContext.Provider, { value: navigationValue, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(import_react_native63.View, { style: [styles58.root, { backgroundColor: pageBg }], children: [
7601
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(AppLayoutDebugContext.Provider, { value: { snapshot }, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(AppNavigationContext.Provider, { value: navigationValue, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(import_react_native63.View, { style: [styles58.root, { backgroundColor: pageBg }], children: [
7590
7602
  /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
7591
- import_react_native_reanimated14.default.ScrollView,
7603
+ import_react_native63.ScrollView,
7592
7604
  {
7593
7605
  ref: scrollRef,
7594
7606
  style: styles58.pageScroll,
7595
7607
  contentContainerStyle: [styles58.pageContent, { backgroundColor: pageBg }],
7596
7608
  scrollEnabled: !!state.pageScroll,
7597
7609
  showsVerticalScrollIndicator: false,
7598
- scrollEventThrottle: 16,
7599
- onScroll,
7600
7610
  children: [
7601
7611
  renderSection("top"),
7602
7612
  showTopDivisor && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(Divisor, { position: "top", handle: currentRoute.state === "top" }),
@@ -7607,7 +7617,7 @@ function AppLayout({
7607
7617
  }
7608
7618
  ),
7609
7619
  showBackButton && canGoBack && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native63.View, { style: styles58.backBar, pointerEvents: "box-none", children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(Button, { variant: "secondary", size: "sm", label: "\u2190 Volver", onPress: back }) })
7610
- ] }) });
7620
+ ] }) }) });
7611
7621
  }
7612
7622
  var styles58 = import_react_native63.StyleSheet.create({
7613
7623
  root: {
@@ -7623,7 +7633,7 @@ var styles58 = import_react_native63.StyleSheet.create({
7623
7633
  width: "100%",
7624
7634
  position: "relative"
7625
7635
  },
7626
- measureCopy: {
7636
+ measureOuter: {
7627
7637
  position: "absolute",
7628
7638
  top: 0,
7629
7639
  left: 0,
@@ -7631,6 +7641,9 @@ var styles58 = import_react_native63.StyleSheet.create({
7631
7641
  opacity: 0,
7632
7642
  zIndex: -1
7633
7643
  },
7644
+ measureCopy: {
7645
+ width: "100%"
7646
+ },
7634
7647
  sectionContent: {
7635
7648
  flex: 1
7636
7649
  },
@@ -7771,6 +7784,7 @@ var import_antonella_theme59 = require("@william-callao/antonella-theme");
7771
7784
  resolveComposition,
7772
7785
  resolveTransition,
7773
7786
  updateNode,
7787
+ useAppLayoutDebug,
7774
7788
  useAppNavigation,
7775
7789
  useSheetLayout,
7776
7790
  useToast
package/package.json CHANGED
@@ -1,33 +1,33 @@
1
- {
2
- "name": "@william-callao/antonella-ui",
3
- "version": "1.0.1",
4
- "description": "Componentes UI de Antonella.",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "react-native": "dist/index.js",
8
- "sideEffects": false,
9
- "publishConfig": {
10
- "access": "public"
11
- },
12
- "files": [
13
- "dist"
14
- ],
15
- "dependencies": {
16
- "@william-callao/antonella-theme": "^1.0.0",
17
- "@shopify/react-native-skia": "2.2.12",
18
- "expo-linear-gradient": "^57.0.1",
19
- "lucide-react-native": "^0.517.0",
20
- "react-native-svg": "^15.12.1"
21
- },
22
- "peerDependencies": {
23
- "react": ">=19.0.0",
24
- "react-native": ">=0.81.0",
25
- "react-native-keyboard-controller": "1.18.5",
26
- "react-native-reanimated": ">=4.0.0",
27
- "react-native-safe-area-context": "^5.6.0"
28
- },
29
- "scripts": {
30
- "build": "tsup",
31
- "typecheck": "tsc --noEmit"
32
- }
33
- }
1
+ {
2
+ "name": "@william-callao/antonella-ui",
3
+ "version": "1.0.2",
4
+ "description": "Componentes UI de Antonella.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "react-native": "dist/index.js",
8
+ "sideEffects": false,
9
+ "scripts": {
10
+ "build": "tsup",
11
+ "typecheck": "tsc --noEmit"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "dependencies": {
20
+ "@william-callao/antonella-theme": "^1.0.0",
21
+ "@shopify/react-native-skia": "2.2.12",
22
+ "expo-linear-gradient": "^57.0.1",
23
+ "lucide-react-native": "^0.517.0",
24
+ "react-native-svg": "^15.12.1"
25
+ },
26
+ "peerDependencies": {
27
+ "react": ">=19.0.0",
28
+ "react-native": ">=0.81.0",
29
+ "react-native-keyboard-controller": ">=1.18.5",
30
+ "react-native-reanimated": ">=4.0.0",
31
+ "react-native-safe-area-context": "^5.6.0"
32
+ }
33
+ }