panelui-native 0.78.0 → 0.79.1

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 (64) hide show
  1. package/lib/module/components/accordion/index.js +13 -1
  2. package/lib/module/components/accordion/index.js.map +1 -1
  3. package/lib/module/components/map/index.js +63 -39
  4. package/lib/module/components/map/index.js.map +1 -1
  5. package/lib/module/components/map/map-children.js +54 -0
  6. package/lib/module/components/map/map-children.js.map +1 -0
  7. package/lib/module/components/map/maplibre.js +31 -3
  8. package/lib/module/components/map/maplibre.js.map +1 -1
  9. package/lib/module/components/markdown-editor/index.js +288 -34
  10. package/lib/module/components/markdown-editor/index.js.map +1 -1
  11. package/lib/module/components/markdown-editor/markdown-transforms.js +272 -9
  12. package/lib/module/components/markdown-editor/markdown-transforms.js.map +1 -1
  13. package/lib/module/components/marquee/index.js +119 -46
  14. package/lib/module/components/marquee/index.js.map +1 -1
  15. package/lib/module/components/panelside/index.js +162 -34
  16. package/lib/module/components/panelside/index.js.map +1 -1
  17. package/lib/module/components/progress-button/index.js +279 -52
  18. package/lib/module/components/progress-button/index.js.map +1 -1
  19. package/lib/module/components/progress-button/progress-button-hold.js +40 -6
  20. package/lib/module/components/progress-button/progress-button-hold.js.map +1 -1
  21. package/lib/module/components/theme-selector/index.js +239 -0
  22. package/lib/module/components/theme-selector/index.js.map +1 -0
  23. package/lib/module/components/theme-selector/theme-preview.js +320 -0
  24. package/lib/module/components/theme-selector/theme-preview.js.map +1 -0
  25. package/lib/module/index.js +1 -0
  26. package/lib/module/index.js.map +1 -1
  27. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
  28. package/lib/typescript/src/components/map/index.d.ts +8 -4
  29. package/lib/typescript/src/components/map/index.d.ts.map +1 -1
  30. package/lib/typescript/src/components/map/map-children.d.ts +41 -0
  31. package/lib/typescript/src/components/map/map-children.d.ts.map +1 -0
  32. package/lib/typescript/src/components/map/maplibre.d.ts +8 -4
  33. package/lib/typescript/src/components/map/maplibre.d.ts.map +1 -1
  34. package/lib/typescript/src/components/markdown-editor/index.d.ts +64 -5
  35. package/lib/typescript/src/components/markdown-editor/index.d.ts.map +1 -1
  36. package/lib/typescript/src/components/markdown-editor/markdown-transforms.d.ts +33 -5
  37. package/lib/typescript/src/components/markdown-editor/markdown-transforms.d.ts.map +1 -1
  38. package/lib/typescript/src/components/marquee/index.d.ts.map +1 -1
  39. package/lib/typescript/src/components/panelside/index.d.ts +79 -4
  40. package/lib/typescript/src/components/panelside/index.d.ts.map +1 -1
  41. package/lib/typescript/src/components/progress-button/index.d.ts +29 -13
  42. package/lib/typescript/src/components/progress-button/index.d.ts.map +1 -1
  43. package/lib/typescript/src/components/progress-button/progress-button-hold.d.ts +26 -6
  44. package/lib/typescript/src/components/progress-button/progress-button-hold.d.ts.map +1 -1
  45. package/lib/typescript/src/components/theme-selector/index.d.ts +107 -0
  46. package/lib/typescript/src/components/theme-selector/index.d.ts.map +1 -0
  47. package/lib/typescript/src/components/theme-selector/theme-preview.d.ts +32 -0
  48. package/lib/typescript/src/components/theme-selector/theme-preview.d.ts.map +1 -0
  49. package/lib/typescript/src/index.d.ts +4 -3
  50. package/lib/typescript/src/index.d.ts.map +1 -1
  51. package/package.json +1 -1
  52. package/src/components/accordion/index.tsx +13 -0
  53. package/src/components/map/index.tsx +63 -36
  54. package/src/components/map/map-children.ts +66 -0
  55. package/src/components/map/maplibre.ts +32 -4
  56. package/src/components/markdown-editor/index.tsx +413 -35
  57. package/src/components/markdown-editor/markdown-transforms.ts +274 -10
  58. package/src/components/marquee/index.tsx +128 -55
  59. package/src/components/panelside/index.tsx +179 -40
  60. package/src/components/progress-button/index.tsx +264 -45
  61. package/src/components/progress-button/progress-button-hold.ts +37 -6
  62. package/src/components/theme-selector/index.tsx +281 -0
  63. package/src/components/theme-selector/theme-preview.tsx +205 -0
  64. package/src/index.ts +15 -0
@@ -119,7 +119,7 @@ import { LinearGradient } from 'expo-linear-gradient';
119
119
  import { EllipsisIcon, IconColorProvider, MenuIcon, SearchIcon } from '../../icons';
120
120
  import { Button } from '../button';
121
121
  import { AnimatedPressable } from '../../primitives/animated-pressable';
122
- import { Text, textChildren } from '../../primitives/text';
122
+ import { Text, textChildren, type TextProps } from '../../primitives/text';
123
123
  import { useBackHandler } from '../../hooks/use-back-handler';
124
124
  import { useDirectionSign } from '../../hooks/use-direction';
125
125
  import { cn } from '../../utils/cn';
@@ -888,17 +888,47 @@ function PanelsideGroupLabel({ className, children, ...props }: PanelsideGroupLa
888
888
  );
889
889
  }
890
890
 
891
+ /**
892
+ * What a row's parts read off the row, rather than being handed it.
893
+ *
894
+ * A label goes medium and un-muted when the row is the current destination,
895
+ * and an icon takes the matching tint. Passing that to every part would mean
896
+ * `<Panelside.ItemLabel active={active}>` at every call site, with an `active`
897
+ * that has to be kept in step with the row's own.
898
+ */
899
+ interface PanelsideItemContextValue {
900
+ active: boolean;
901
+ disabled: boolean;
902
+ size: PanelsideItemSize;
903
+ /** The colour an icon in this row should take, resolved once by the row. */
904
+ tint: string | undefined;
905
+ }
906
+
907
+ const PanelsideItemContext = createContext<PanelsideItemContextValue | null>(null);
908
+
909
+ function usePanelsideItem(part: string): PanelsideItemContextValue {
910
+ const value = useContext(PanelsideItemContext);
911
+ if (!value) throw new Error(`${part} must be used inside a <Panelside.Item>.`);
912
+ return value;
913
+ }
914
+
891
915
  export interface PanelsideItemProps extends Omit<PressableProps, 'children'> {
892
916
  className?: string;
893
- /** Leading element — an icon, an avatar, a coloured dot. */
917
+ /**
918
+ * Leading element — an icon, an avatar, a coloured dot. The shorthand for
919
+ * `Panelside.ItemIcon`.
920
+ */
894
921
  icon?: ReactNode;
895
- /** The row's text. Truncated to one line, since chat titles run long. */
922
+ /**
923
+ * The row's text, truncated to one line since chat titles run long. The
924
+ * shorthand for `Panelside.ItemLabel`.
925
+ */
896
926
  label?: string;
897
927
  /** Marks the row as the current destination. */
898
928
  active?: boolean;
899
929
  /**
900
930
  * Trailing count or status. A number or string renders as a pill; anything
901
- * else renders as given.
931
+ * else renders as given. The shorthand for `Panelside.ItemBadge`.
902
932
  */
903
933
  badge?: ReactNode;
904
934
  disabled?: boolean;
@@ -908,10 +938,37 @@ export interface PanelsideItemProps extends Omit<PressableProps, 'children'> {
908
938
  * worth more than two extra rows.
909
939
  */
910
940
  size?: PanelsideItemSize;
911
- /** Trailing content — usually a `Panelside.Action`. */
941
+ /**
942
+ * The row's contents, written out: `Panelside.ItemIcon`,
943
+ * `Panelside.ItemLabel`, `Panelside.ItemBadge` and `Panelside.Action`, in
944
+ * whatever order the row wants them. Anything else you draw works too.
945
+ *
946
+ * Children and the shorthand props compose — a row can take its label from
947
+ * `label` and still write a trailing `Panelside.Action` as a child.
948
+ */
912
949
  children?: ReactNode;
913
950
  }
914
951
 
952
+ /**
953
+ * One destination, or one conversation.
954
+ *
955
+ * There are two ways to fill it, and they are the same row. The shorthand —
956
+ * `icon`, `label`, `badge` — covers the row every navigation panel has, and is
957
+ * what most call sites should use. The parts cover everything else: two lines
958
+ * of text, a label that is not a string, a badge before the label rather than
959
+ * after it, a trailing control that is not an overflow menu.
960
+ *
961
+ * ```tsx
962
+ * <Panelside.Item icon={<InboxIcon />} label="Inbox" badge={12} />
963
+ *
964
+ * <Panelside.Item active>
965
+ * <Panelside.ItemIcon><Avatar size="xs" src={author.avatar} /></Panelside.ItemIcon>
966
+ * <Panelside.ItemLabel>{thread.title}</Panelside.ItemLabel>
967
+ * <Panelside.ItemBadge>{thread.unread}</Panelside.ItemBadge>
968
+ * <Panelside.Action onPress={rename} />
969
+ * </Panelside.Item>
970
+ * ```
971
+ */
915
972
  function PanelsideItem({
916
973
  className,
917
974
  icon,
@@ -934,46 +991,122 @@ function PanelsideItem({
934
991
  ? restTint
935
992
  : undefined;
936
993
 
994
+ const context = useMemo<PanelsideItemContextValue>(
995
+ () => ({ active, disabled, size, tint }),
996
+ [active, disabled, size, tint]
997
+ );
998
+
999
+ /*
1000
+ * The row needs something flexible in the middle or its trailing content
1001
+ * floats next to the icon instead of sitting at the end. A label supplies
1002
+ * that, and a written-out `Panelside.ItemLabel` supplies it too — so the
1003
+ * spacer is only for the row that has neither, which is a row of nothing but
1004
+ * an icon and a badge.
1005
+ */
1006
+ const filled = label !== undefined || children !== undefined;
1007
+
937
1008
  return (
938
- <AnimatedPressable
939
- className={itemVariants({ active, disabled, size, className })}
940
- disabled={disabled}
941
- accessibilityRole="button"
942
- accessibilityState={{ selected: active, disabled }}
943
- accessibilityLabel={label}
944
- pressScale={0.985}
1009
+ <PanelsideItemContext.Provider value={context}>
1010
+ <AnimatedPressable
1011
+ className={itemVariants({ active, disabled, size, className })}
1012
+ disabled={disabled}
1013
+ accessibilityRole="button"
1014
+ accessibilityState={{ selected: active, disabled }}
1015
+ accessibilityLabel={label}
1016
+ pressScale={0.985}
1017
+ {...props}
1018
+ >
1019
+ {icon ? <PanelsideItemIcon>{icon}</PanelsideItemIcon> : null}
1020
+
1021
+ {label !== undefined ? <PanelsideItemLabel>{label}</PanelsideItemLabel> : null}
1022
+
1023
+ {filled ? null : <View className="flex-1" />}
1024
+
1025
+ {badge !== undefined && badge !== null ? (
1026
+ <PanelsideItemBadge>{badge}</PanelsideItemBadge>
1027
+ ) : null}
1028
+
1029
+ {children}
1030
+ </AnimatedPressable>
1031
+ </PanelsideItemContext.Provider>
1032
+ );
1033
+ }
1034
+
1035
+ export interface PanelsideItemIconProps extends ViewProps {
1036
+ className?: string;
1037
+ children?: ReactNode;
1038
+ }
1039
+
1040
+ /**
1041
+ * The leading slot on a row.
1042
+ *
1043
+ * Whatever is inside it inherits the row's own tint rather than each call site
1044
+ * passing a colour that stops being right the moment the row goes active.
1045
+ */
1046
+ function PanelsideItemIcon({ className, children, ...props }: PanelsideItemIconProps) {
1047
+ const { tint } = usePanelsideItem('Panelside.ItemIcon');
1048
+
1049
+ // No wrapper unless one was asked for: an icon is already the right size,
1050
+ // and a `View` around it is a layout node between the row and its glyph.
1051
+ if (className === undefined && Object.keys(props).length === 0) {
1052
+ return <IconColorProvider color={tint}>{children}</IconColorProvider>;
1053
+ }
1054
+
1055
+ return (
1056
+ <View className={className} {...props}>
1057
+ <IconColorProvider color={tint}>{children}</IconColorProvider>
1058
+ </View>
1059
+ );
1060
+ }
1061
+
1062
+ export interface PanelsideItemLabelProps extends TextProps {
1063
+ className?: string;
1064
+ children?: ReactNode;
1065
+ }
1066
+
1067
+ /**
1068
+ * The row's text. It takes the flexible middle, so a long title truncates
1069
+ * rather than pushing the badge and the action off the end of the panel.
1070
+ */
1071
+ function PanelsideItemLabel({ className, children, ...props }: PanelsideItemLabelProps) {
1072
+ const { active } = usePanelsideItem('Panelside.ItemLabel');
1073
+
1074
+ return (
1075
+ <Text
1076
+ size="base"
1077
+ weight={active ? 'medium' : 'normal'}
1078
+ muted={!active}
1079
+ numberOfLines={1}
1080
+ className={cn('flex-1', className)}
945
1081
  {...props}
946
1082
  >
947
- {/* Icons inherit the row's state rather than each caller passing a
948
- colour that stops being right the moment the row goes active. */}
949
- {icon ? <IconColorProvider color={tint}>{icon}</IconColorProvider> : null}
950
-
951
- {label ? (
952
- <Text
953
- size="base"
954
- weight={active ? 'medium' : 'normal'}
955
- muted={!active}
956
- numberOfLines={1}
957
- className="flex-1"
958
- >
959
- {label}
960
- </Text>
961
- ) : (
962
- <View className="flex-1" />
963
- )}
1083
+ {children}
1084
+ </Text>
1085
+ );
1086
+ }
964
1087
 
965
- {typeof badge === 'string' || typeof badge === 'number' ? (
966
- <View className="rounded-full bg-secondary px-2 py-0.5">
967
- <Text size="xs" muted>
968
- {badge}
969
- </Text>
970
- </View>
971
- ) : (
972
- badge
973
- )}
1088
+ export interface PanelsideItemBadgeProps extends ViewProps {
1089
+ className?: string;
1090
+ children?: ReactNode;
1091
+ }
974
1092
 
975
- {children}
976
- </AnimatedPressable>
1093
+ /**
1094
+ * The trailing count or status on a row. Text becomes a pill; anything else is
1095
+ * drawn as given, so a dot or a chip needs no opting out of the pill.
1096
+ */
1097
+ function PanelsideItemBadge({ className, children, ...props }: PanelsideItemBadgeProps) {
1098
+ usePanelsideItem('Panelside.ItemBadge');
1099
+
1100
+ if (typeof children !== 'string' && typeof children !== 'number') {
1101
+ return <>{children}</>;
1102
+ }
1103
+
1104
+ return (
1105
+ <View className={cn('rounded-full bg-secondary px-2 py-0.5', className)} {...props}>
1106
+ <Text size="xs" muted>
1107
+ {children}
1108
+ </Text>
1109
+ </View>
977
1110
  );
978
1111
  }
979
1112
 
@@ -1456,6 +1589,9 @@ PanelsideContent.displayName = 'Panelside.Content';
1456
1589
  PanelsideGroup.displayName = 'Panelside.Group';
1457
1590
  PanelsideGroupLabel.displayName = 'Panelside.GroupLabel';
1458
1591
  PanelsideItem.displayName = 'Panelside.Item';
1592
+ PanelsideItemIcon.displayName = 'Panelside.ItemIcon';
1593
+ PanelsideItemLabel.displayName = 'Panelside.ItemLabel';
1594
+ PanelsideItemBadge.displayName = 'Panelside.ItemBadge';
1459
1595
  PanelsideAction.displayName = 'Panelside.Action';
1460
1596
  PanelsideFooter.displayName = 'Panelside.Footer';
1461
1597
  PanelsideCta.displayName = 'Panelside.Cta';
@@ -1470,6 +1606,9 @@ export const Panelside = Object.assign(PanelsideRoot, {
1470
1606
  Group: PanelsideGroup,
1471
1607
  GroupLabel: PanelsideGroupLabel,
1472
1608
  Item: PanelsideItem,
1609
+ ItemIcon: PanelsideItemIcon,
1610
+ ItemLabel: PanelsideItemLabel,
1611
+ ItemBadge: PanelsideItemBadge,
1473
1612
  Action: PanelsideAction,
1474
1613
  Footer: PanelsideFooter,
1475
1614
  Cta: PanelsideCta,