@agimon-ai/po-native-components 0.0.0-alpha.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.
Files changed (122) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +71 -0
  3. package/dist/components/Badge.d.mts +17 -0
  4. package/dist/components/Badge.d.mts.map +1 -0
  5. package/dist/components/Badge.mjs +106 -0
  6. package/dist/components/Badge.mjs.map +1 -0
  7. package/dist/components/Button.d.mts +20 -0
  8. package/dist/components/Button.d.mts.map +1 -0
  9. package/dist/components/Button.mjs +278 -0
  10. package/dist/components/Button.mjs.map +1 -0
  11. package/dist/components/CodeBlock.d.mts +10 -0
  12. package/dist/components/CodeBlock.d.mts.map +1 -0
  13. package/dist/components/CodeBlock.mjs +88 -0
  14. package/dist/components/CodeBlock.mjs.map +1 -0
  15. package/dist/components/Dialog.d.mts +52 -0
  16. package/dist/components/Dialog.d.mts.map +1 -0
  17. package/dist/components/Dialog.mjs +257 -0
  18. package/dist/components/Dialog.mjs.map +1 -0
  19. package/dist/components/Dot.d.mts +17 -0
  20. package/dist/components/Dot.d.mts.map +1 -0
  21. package/dist/components/Dot.mjs +94 -0
  22. package/dist/components/Dot.mjs.map +1 -0
  23. package/dist/components/DropdownMenu.d.mts +63 -0
  24. package/dist/components/DropdownMenu.d.mts.map +1 -0
  25. package/dist/components/DropdownMenu.mjs +256 -0
  26. package/dist/components/DropdownMenu.mjs.map +1 -0
  27. package/dist/components/EmptyState.d.mts +14 -0
  28. package/dist/components/EmptyState.d.mts.map +1 -0
  29. package/dist/components/EmptyState.mjs +64 -0
  30. package/dist/components/EmptyState.mjs.map +1 -0
  31. package/dist/components/Input.d.mts +19 -0
  32. package/dist/components/Input.d.mts.map +1 -0
  33. package/dist/components/Input.mjs +123 -0
  34. package/dist/components/Input.mjs.map +1 -0
  35. package/dist/components/Label.d.mts +13 -0
  36. package/dist/components/Label.d.mts.map +1 -0
  37. package/dist/components/Label.mjs +36 -0
  38. package/dist/components/Label.mjs.map +1 -0
  39. package/dist/components/List.d.mts +48 -0
  40. package/dist/components/List.d.mts.map +1 -0
  41. package/dist/components/List.mjs +156 -0
  42. package/dist/components/List.mjs.map +1 -0
  43. package/dist/components/Markdown.d.mts +15 -0
  44. package/dist/components/Markdown.d.mts.map +1 -0
  45. package/dist/components/Markdown.mjs +219 -0
  46. package/dist/components/Markdown.mjs.map +1 -0
  47. package/dist/components/MessageItem.d.mts +87 -0
  48. package/dist/components/MessageItem.d.mts.map +1 -0
  49. package/dist/components/MessageItem.mjs +361 -0
  50. package/dist/components/MessageItem.mjs.map +1 -0
  51. package/dist/components/Panel.d.mts +15 -0
  52. package/dist/components/Panel.d.mts.map +1 -0
  53. package/dist/components/Panel.mjs +77 -0
  54. package/dist/components/Panel.mjs.map +1 -0
  55. package/dist/components/PoNativeProvider.d.mts +15 -0
  56. package/dist/components/PoNativeProvider.d.mts.map +1 -0
  57. package/dist/components/PoNativeProvider.mjs +22 -0
  58. package/dist/components/PoNativeProvider.mjs.map +1 -0
  59. package/dist/components/SectionLabel.d.mts +6 -0
  60. package/dist/components/SectionLabel.d.mts.map +1 -0
  61. package/dist/components/SectionLabel.mjs +40 -0
  62. package/dist/components/SectionLabel.mjs.map +1 -0
  63. package/dist/components/SegmentedControl.d.mts +26 -0
  64. package/dist/components/SegmentedControl.d.mts.map +1 -0
  65. package/dist/components/SegmentedControl.mjs +56 -0
  66. package/dist/components/SegmentedControl.mjs.map +1 -0
  67. package/dist/components/Sheet.d.mts +39 -0
  68. package/dist/components/Sheet.d.mts.map +1 -0
  69. package/dist/components/Sheet.mjs +166 -0
  70. package/dist/components/Sheet.mjs.map +1 -0
  71. package/dist/components/SheetFrame.mjs +84 -0
  72. package/dist/components/SheetFrame.mjs.map +1 -0
  73. package/dist/components/Spinner.d.mts +19 -0
  74. package/dist/components/Spinner.d.mts.map +1 -0
  75. package/dist/components/Spinner.mjs +34 -0
  76. package/dist/components/Spinner.mjs.map +1 -0
  77. package/dist/components/StatusBadge.d.mts +23 -0
  78. package/dist/components/StatusBadge.d.mts.map +1 -0
  79. package/dist/components/StatusBadge.mjs +116 -0
  80. package/dist/components/StatusBadge.mjs.map +1 -0
  81. package/dist/components/Tabs.d.mts +44 -0
  82. package/dist/components/Tabs.d.mts.map +1 -0
  83. package/dist/components/Tabs.mjs +197 -0
  84. package/dist/components/Tabs.mjs.map +1 -0
  85. package/dist/components/Textarea.d.mts +10 -0
  86. package/dist/components/Textarea.d.mts.map +1 -0
  87. package/dist/components/Textarea.mjs +29 -0
  88. package/dist/components/Textarea.mjs.map +1 -0
  89. package/dist/icons/IconColorContext.d.mts +10 -0
  90. package/dist/icons/IconColorContext.d.mts.map +1 -0
  91. package/dist/icons/IconColorContext.mjs +13 -0
  92. package/dist/icons/IconColorContext.mjs.map +1 -0
  93. package/dist/icons/iconGlyphs.d.mts +120 -0
  94. package/dist/icons/iconGlyphs.d.mts.map +1 -0
  95. package/dist/icons/iconGlyphs.mjs +121 -0
  96. package/dist/icons/iconGlyphs.mjs.map +1 -0
  97. package/dist/icons/icons.d.mts +122 -0
  98. package/dist/icons/icons.d.mts.map +1 -0
  99. package/dist/icons/icons.mjs +79 -0
  100. package/dist/icons/icons.mjs.map +1 -0
  101. package/dist/index.d.mts +27 -0
  102. package/dist/index.mjs +27 -0
  103. package/dist/lib/fonts.d.mts +13 -0
  104. package/dist/lib/fonts.d.mts.map +1 -0
  105. package/dist/lib/fonts.mjs +22 -0
  106. package/dist/lib/fonts.mjs.map +1 -0
  107. package/dist/lib/haptics.d.mts +7 -0
  108. package/dist/lib/haptics.d.mts.map +1 -0
  109. package/dist/lib/haptics.mjs +25 -0
  110. package/dist/lib/haptics.mjs.map +1 -0
  111. package/dist/lib/insideSheet.mjs +16 -0
  112. package/dist/lib/insideSheet.mjs.map +1 -0
  113. package/dist/lib/markdown.mjs +271 -0
  114. package/dist/lib/markdown.mjs.map +1 -0
  115. package/dist/lib/tone.mjs +50 -0
  116. package/dist/lib/tone.mjs.map +1 -0
  117. package/dist/lib/useControllable.mjs +22 -0
  118. package/dist/lib/useControllable.mjs.map +1 -0
  119. package/dist/lib/wrapText.mjs +20 -0
  120. package/dist/lib/wrapText.mjs.map +1 -0
  121. package/llms.txt +8 -0
  122. package/package.json +104 -0
@@ -0,0 +1,88 @@
1
+ import { fontOf } from "../lib/fonts.mjs";
2
+ import { Button } from "./Button.mjs";
3
+ import { CheckIcon, CopyIcon } from "../icons/icons.mjs";
4
+ import { View } from "react-native-unistyles/components/native/View";
5
+ import { StyleSheet } from "react-native-unistyles";
6
+ import { Text } from "react-native-unistyles/components/native/Text";
7
+ import { useEffect, useState } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { ScrollView } from "react-native-unistyles/components/native/ScrollView";
10
+ import { setStringAsync } from "expo-clipboard";
11
+
12
+ //#region src/components/CodeBlock.tsx
13
+ /** How long the control stays acknowledged before returning to its icon. */
14
+ const FEEDBACK_MS = 1500;
15
+ const LABELS = {
16
+ idle: "copy",
17
+ copied: "copied",
18
+ failed: "copying failed"
19
+ };
20
+ function CodeBlock({ text, language }) {
21
+ const [state, setState] = useState("idle");
22
+ useEffect(() => {
23
+ if (state === "idle") return void 0;
24
+ const timer = setTimeout(() => setState("idle"), FEEDBACK_MS);
25
+ return () => clearTimeout(timer);
26
+ }, [state]);
27
+ const label = LABELS[state];
28
+ return /* @__PURE__ */ jsxs(View, {
29
+ style: styles.block,
30
+ accessibilityLabel: language === void 0 ? void 0 : `${language} code`,
31
+ children: [/* @__PURE__ */ jsx(ScrollView, {
32
+ horizontal: true,
33
+ showsHorizontalScrollIndicator: false,
34
+ contentContainerStyle: styles.scroll,
35
+ children: /* @__PURE__ */ jsx(Text, {
36
+ selectable: true,
37
+ style: styles.code,
38
+ children: text
39
+ })
40
+ }), /* @__PURE__ */ jsx(Button, {
41
+ variant: "ghost",
42
+ size: "icon",
43
+ accessibilityLabel: label,
44
+ onPress: () => {
45
+ setStringAsync(text).then((saved) => setState(saved ? "copied" : "failed"), () => setState("failed"));
46
+ },
47
+ style: styles.copy,
48
+ children: state === "copied" ? /* @__PURE__ */ jsx(CheckIcon, {
49
+ size: 12,
50
+ color: "green"
51
+ }) : /* @__PURE__ */ jsx(CopyIcon, {
52
+ size: 12,
53
+ color: "faint"
54
+ })
55
+ })]
56
+ });
57
+ }
58
+ const styles = StyleSheet.create((theme) => ({
59
+ block: {
60
+ borderRadius: theme.borderRadius.DEFAULT,
61
+ borderWidth: 1,
62
+ borderColor: theme.colors.border,
63
+ backgroundColor: theme.colors.deep,
64
+ uni__dependencies: [0]
65
+ },
66
+ scroll: {
67
+ padding: theme.spacing(2.5),
68
+ paddingRight: theme.spacing(9),
69
+ uni__dependencies: [0]
70
+ },
71
+ code: {
72
+ color: theme.colors.text,
73
+ fontFamily: fontOf(theme.fontFamily.mono),
74
+ fontSize: theme.fontSize.sm,
75
+ lineHeight: theme.lineHeightRelaxed.sm,
76
+ uni__dependencies: [0]
77
+ },
78
+ copy: {
79
+ position: "absolute",
80
+ top: theme.spacing(1.5),
81
+ right: theme.spacing(1.5),
82
+ uni__dependencies: [0]
83
+ }
84
+ }));
85
+
86
+ //#endregion
87
+ export { CodeBlock };
88
+ //# sourceMappingURL=CodeBlock.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeBlock.mjs","names":["setStringAsync","useEffect","useState","StyleSheet","CheckIcon","CopyIcon","fontOf","Button","FEEDBACK_MS","CopyState","LABELS","Readonly","Record","idle","copied","failed","CodeBlockProps","text","language","CodeBlock","state","setState","undefined","timer","setTimeout","clearTimeout","label","styles","block","scroll","code","then","saved","copy","create","theme","borderRadius","DEFAULT","borderWidth","borderColor","colors","border","backgroundColor","deep","uni__dependencies","padding","spacing","paddingRight","color","fontFamily","mono","fontSize","sm","lineHeight","lineHeightRelaxed","position","top","right"],"sources":["../../src/components/CodeBlock.tsx"],"sourcesContent":["import { setStringAsync } from 'expo-clipboard';\nimport { useEffect, useState } from 'react';\nimport { ScrollView, Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport { CheckIcon, CopyIcon } from '../icons/icons';\nimport { fontOf } from '../lib/fonts';\nimport { Button } from './Button';\n\n/*\n * A fenced code block: the source in selectable mono type that scrolls\n * sideways rather than wrapping, and a copy button that says when it worked.\n *\n * ponytail: no syntax colouring and no mermaid diagrams yet; a mermaid fence\n * shows its source, which is still the whole content.\n */\n\n/** How long the control stays acknowledged before returning to its icon. */\nconst FEEDBACK_MS = 1500;\n\ntype CopyState = 'idle' | 'copied' | 'failed';\n\nconst LABELS: Readonly<Record<CopyState, string>> = {\n idle: 'copy',\n copied: 'copied',\n failed: 'copying failed',\n};\n\nexport interface CodeBlockProps {\n /** The block's source, without the fence lines. */\n text: string;\n /** The fence's language word, such as `ts`; the web reads it from a `language-*` class. */\n language?: string;\n}\n\nexport function CodeBlock({ text, language }: CodeBlockProps) {\n const [state, setState] = useState<CopyState>('idle');\n\n useEffect(() => {\n if (state === 'idle') return undefined;\n const timer = setTimeout(() => setState('idle'), FEEDBACK_MS);\n return () => clearTimeout(timer);\n }, [state]);\n\n const label = LABELS[state];\n return (\n <View style={styles.block} accessibilityLabel={language === undefined ? undefined : `${language} code`}>\n <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.scroll}>\n <Text selectable style={styles.code}>\n {text}\n </Text>\n </ScrollView>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n accessibilityLabel={label}\n onPress={() => {\n setStringAsync(text).then(\n (saved) => setState(saved ? 'copied' : 'failed'),\n () => setState('failed'),\n );\n }}\n style={styles.copy}\n >\n {state === 'copied' ? <CheckIcon size={12} color=\"green\" /> : <CopyIcon size={12} color=\"faint\" />}\n </Button>\n </View>\n );\n}\n\nconst styles = StyleSheet.create((theme) => ({\n block: {\n borderRadius: theme.borderRadius.DEFAULT,\n borderWidth: 1,\n borderColor: theme.colors.border,\n backgroundColor: theme.colors.deep,\n },\n // The right padding keeps the first line clear of the copy button.\n scroll: { padding: theme.spacing(2.5), paddingRight: theme.spacing(9) },\n code: {\n color: theme.colors.text,\n fontFamily: fontOf(theme.fontFamily.mono),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeightRelaxed.sm,\n },\n copy: { position: 'absolute', top: theme.spacing(1.5), right: theme.spacing(1.5) },\n}));\n"],"mappings":";;;;;;;;;;;;;AAkBA,MAAMQ,cAAc;AAIpB,MAAME,SAA8C;CAClDG,MAAM;CACNC,QAAQ;CACRC,QAAQ;AACV;AASA,SAAgBI,UAAU,EAAEF,MAAMC,YAA4B;CAC5D,MAAM,CAACE,OAAOC,YAAYnB,SAAoB,MAAM;CAEpDD,gBAAgB;EACd,IAAImB,UAAU,QAAQ,OAAOE;EAC7B,MAAMC,QAAQC,iBAAiBH,SAAS,MAAM,GAAGb,WAAW;EAC5D,aAAaiB,aAAaF,KAAK;CACjC,GAAG,CAACH,KAAK,CAAC;CAEV,MAAMM,QAAQhB,OAAOU;CACrB,OACE,qBAAC,MAAD;EAAM,OAAOO,OAAOC;EAAO,oBAAoBV,aAAaI,SAAYA,SAAY,GAAGJ,SAAQ;YAA/F,CACE,oBAAC,YAAD;GAAY;GAAW,gCAAgC;GAAO,uBAAuBS,OAAOE;aAC1F,oBAAC,MAAD;IAAM;IAAW,OAAOF,OAAOG;cAC5Bb;GACG;EACI,IACZ,oBAAC,QAAD;GACE,SAAQ;GACR,MAAK;GACL,oBAAoBS;GACpB,eAAe;IACb1B,eAAeiB,IAAI,CAAC,CAACc,MAClBC,UAAUX,SAASW,QAAQ,WAAW,QAAQ,SACzCX,SAAS,QAAQ,CACzB;GACF;GACA,OAAOM,OAAOM;aAEbb,UAAU,WAAW,oBAAC,WAAD;IAAW,MAAM;IAAI,OAAM;GAAO,KAAM,oBAAC,UAAD;IAAU,MAAM;IAAI,OAAM;GAAO;EACzF,EACJ;;AAEV;AAEA,MAAMO,SAASxB,WAAW+B,QAAQC,WAAW;CAC3CP,OAAO;EACLQ,cAAcD,MAAMC,aAAaC;EACjCC,aAAa;EACbC,aAAaJ,MAAMK,OAAOC;EAC1BC,iBAAiBP,MAAMK,OAAOG;EAAIC,mBAAA,CAAA,CAAA;CACpC;CAEAf,QAAQ;EAAEgB,SAASV,MAAMW,QAAQ,GAAG;EAAGC,cAAcZ,MAAMW,QAAQ,CAAC;EAACF,mBAAA,CAAA,CAAA;CAAC;CACtEd,MAAM;EACJkB,OAAOb,MAAMK,OAAOvB;EACpBgC,YAAY3C,OAAO6B,MAAMc,WAAWC,IAAI;EACxCC,UAAUhB,MAAMgB,SAASC;EACzBC,YAAYlB,MAAMmB,kBAAkBF;EAAER,mBAAA,CAAA,CAAA;CACxC;CACAX,MAAM;EAAEsB,UAAU;EAAYC,KAAKrB,MAAMW,QAAQ,GAAG;EAAGW,OAAOtB,MAAMW,QAAQ,GAAG;EAACF,mBAAA,CAAA,CAAA;CAAC;AACnF,EAAE"}
@@ -0,0 +1,52 @@
1
+ import { ButtonProps } from "./Button.mjs";
2
+ import { StyleProp, TextProps, ViewProps, ViewStyle } from "react-native";
3
+ import { ReactNode } from "react";
4
+ //#region src/components/Dialog.d.ts
5
+ export type DialogWidth = 'sm' | 'md' | 'lg';
6
+ export interface DialogProps {
7
+ /** Controlled mode; pair with onOpenChange. Omit it and the dialog keeps its own state. */
8
+ open?: boolean;
9
+ defaultOpen?: boolean;
10
+ onOpenChange?: (open: boolean) => void;
11
+ children?: ReactNode;
12
+ }
13
+ export declare function Dialog({ open, defaultOpen, onOpenChange, children }: DialogProps): import("react").JSX.Element;
14
+ /** A Button that opens the enclosing dialog. */
15
+ export declare function DialogTrigger({ onPress, ...props }: ButtonProps): import("react").JSX.Element;
16
+ /** A Button that closes the enclosing dialog. */
17
+ export declare function DialogClose({ onPress, ...props }: ButtonProps): import("react").JSX.Element;
18
+ export interface DialogContentProps {
19
+ /** Width preset; `style` may still override. */
20
+ width?: DialogWidth;
21
+ /** Applied to the card, after the preset. */
22
+ style?: StyleProp<ViewStyle>;
23
+ /** What the backdrop announces as its close action. */
24
+ closeLabel?: string;
25
+ children?: ReactNode;
26
+ }
27
+ export declare function DialogContent({ width, style, closeLabel, children }: DialogContentProps): import("react").JSX.Element;
28
+ export interface DialogPartProps extends Omit<ViewProps, 'children' | 'style'> {
29
+ children?: ReactNode;
30
+ style?: StyleProp<ViewStyle>;
31
+ }
32
+ export interface DialogHeaderProps extends DialogPartProps {
33
+ /**
34
+ * Show the close control at the right of the strip. Off by default, as on
35
+ * the web: Android back and a backdrop tap already close every dialog.
36
+ */
37
+ dismissible?: boolean;
38
+ /** What the close control announces. */
39
+ closeLabel?: string;
40
+ }
41
+ export declare function DialogHeader({ dismissible, closeLabel, style, children, ...props }: DialogHeaderProps): import("react").JSX.Element;
42
+ export declare function DialogTitle({ style, ...props }: TextProps): import("react").JSX.Element;
43
+ export declare function DialogDescription({ style, ...props }: TextProps): import("react").JSX.Element;
44
+ export declare function DialogBody({ style, children, ...props }: DialogPartProps): import("react").JSX.Element;
45
+ export type DialogFooterVariant = 'plain' | 'bar';
46
+ export interface DialogFooterProps extends DialogPartProps {
47
+ /** `plain`: buttons alone, inside the body's padding. `bar`: the recessed full-width strip with a hint at the left. */
48
+ variant?: DialogFooterVariant;
49
+ }
50
+ export declare function DialogFooter({ variant, style, children, ...props }: DialogFooterProps): import("react").JSX.Element;
51
+ //#endregion
52
+ //# sourceMappingURL=Dialog.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dialog.d.mts","names":[],"sources":["../../src/components/Dialog.tsx"],"mappings":";;;;YAoCY;iBASK;;EAEf;EACA;EACA,gBAAgB;EAChB,WAAW;;wBAGG,SAAS,MAAM,aAAqB,cAAc,YAAY,8BAAW,IAAA;;wBAMzE,gBAAgB,YAAY,SAAS,8BAAW,IAAA;;wBAchD,cAAc,YAAY,SAAS,8BAAW,IAAA;iBAa7C;;EAEf,QAAQ;;EAER,QAAQ,UAAU;;EAElB;EACA,WAAW;;wBAGG,gBAAgB,OAAc,OAAO,YAAsB,YAAY,qCAAkB,IAAA;iBA6CxF,wBAAwB,KAAK;EAC5C,WAAW;EACX,QAAQ,UAAU;;iBAGH,0BAA0B;;;;;EAKzC;;EAEA;;wBAGc,eACd,aACA,YACA,OACA,aACG,SACF,oCAAiB,IAAA;wBAcJ,cAAc,UAAU,SAAS,4BAAS,IAAA;wBAI1C,oBAAoB,UAAU,SAAS,4BAAS,IAAA;wBAIhD,aAAa,OAAO,aAAa,SAAS,kCAAe,IAAA;YAQ7D;iBAEK,0BAA0B;;EAEzC,UAAU;;wBAGI,eAAe,SAAmB,OAAO,aAAa,SAAS,oCAAiB,IAAA"}
@@ -0,0 +1,257 @@
1
+ import { fontOf } from "../lib/fonts.mjs";
2
+ import { wrapText } from "../lib/wrapText.mjs";
3
+ import { Button } from "./Button.mjs";
4
+ import { CloseIcon } from "../icons/icons.mjs";
5
+ import { useControllable } from "../lib/useControllable.mjs";
6
+ import { View } from "react-native-unistyles/components/native/View";
7
+ import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
8
+ import { StyleSheet, useUnistyles } from "react-native-unistyles";
9
+ import { Easing, Modal, Platform } from "react-native";
10
+ import { Text } from "react-native-unistyles/components/native/Text";
11
+ import { createContext, useContext, useEffect, useRef } from "react";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ import { Pressable } from "react-native-unistyles/components/native/Pressable";
14
+ import { Animated } from "react-native-unistyles/components/native/Animated";
15
+
16
+ //#region src/components/Dialog.tsx
17
+ /** `bg-doom-deep/70`. */
18
+ const BACKDROP_ALPHA_PERCENT = 70;
19
+ /** `animate-doom-pop` starts the card slightly small and grows it into place. */
20
+ const POP_FROM_SCALE = .96;
21
+ /** `max-w-[calc(100vw-24px)]`: 12pt clear of each screen edge. */
22
+ const SCREEN_MARGIN = 12;
23
+ const DialogContext = createContext({
24
+ open: false,
25
+ setOpen: () => void 0
26
+ });
27
+ function Dialog({ open, defaultOpen = false, onOpenChange, children }) {
28
+ const [current, setOpen] = useControllable(open, defaultOpen, onOpenChange);
29
+ return /* @__PURE__ */ jsx(DialogContext.Provider, {
30
+ value: {
31
+ open: current,
32
+ setOpen
33
+ },
34
+ children
35
+ });
36
+ }
37
+ /** A Button that opens the enclosing dialog. */
38
+ function DialogTrigger({ onPress, ...props }) {
39
+ const { setOpen } = useContext(DialogContext);
40
+ return /* @__PURE__ */ jsx(Button, {
41
+ onPress: (event) => {
42
+ onPress?.(event);
43
+ setOpen(true);
44
+ },
45
+ ...props
46
+ });
47
+ }
48
+ /** A Button that closes the enclosing dialog. */
49
+ function DialogClose({ onPress, ...props }) {
50
+ const { setOpen } = useContext(DialogContext);
51
+ return /* @__PURE__ */ jsx(Button, {
52
+ onPress: (event) => {
53
+ onPress?.(event);
54
+ setOpen(false);
55
+ },
56
+ ...props
57
+ });
58
+ }
59
+ function DialogContent({ width = "md", style, closeLabel = "close", children }) {
60
+ const { open, setOpen } = useContext(DialogContext);
61
+ const { theme } = useUnistyles();
62
+ const progress = useRef(new Animated.Value(0)).current;
63
+ const [x1, y1, x2, y2] = theme.motion.easing;
64
+ useEffect(() => {
65
+ if (!open) return;
66
+ progress.setValue(0);
67
+ Animated.timing(progress, {
68
+ toValue: 1,
69
+ duration: theme.motion.pop,
70
+ easing: Easing.bezier(x1, y1, x2, y2),
71
+ useNativeDriver: Platform.OS !== "web"
72
+ }).start();
73
+ }, [
74
+ open,
75
+ progress,
76
+ theme.motion.pop,
77
+ x1,
78
+ y1,
79
+ x2,
80
+ y2
81
+ ]);
82
+ const _styles = styles;
83
+ {
84
+ const styles = _styles.useVariants({ width });
85
+ return /* @__PURE__ */ jsx(Modal, {
86
+ visible: open,
87
+ transparent: true,
88
+ animationType: "fade",
89
+ statusBarTranslucent: true,
90
+ onRequestClose: () => setOpen(false),
91
+ children: /* @__PURE__ */ jsxs(View, {
92
+ style: styles.root,
93
+ children: [/* @__PURE__ */ jsx(Pressable, {
94
+ accessibilityRole: "button",
95
+ accessibilityLabel: closeLabel,
96
+ onPress: () => setOpen(false),
97
+ style: [styles.backdrop, { backgroundColor: withAlpha(theme.colors.deep, BACKDROP_ALPHA_PERCENT) }]
98
+ }), /* @__PURE__ */ jsx(Animated.View, {
99
+ accessibilityViewIsModal: true,
100
+ style: [
101
+ styles.card,
102
+ style,
103
+ {
104
+ opacity: progress,
105
+ transform: [{ scale: progress.interpolate({
106
+ inputRange: [0, 1],
107
+ outputRange: [POP_FROM_SCALE, 1]
108
+ }) }]
109
+ }
110
+ ],
111
+ children
112
+ })]
113
+ })
114
+ });
115
+ }
116
+ }
117
+ function DialogHeader({ dismissible = false, closeLabel = "close", style, children, ...props }) {
118
+ const { setOpen } = useContext(DialogContext);
119
+ return /* @__PURE__ */ jsxs(View, {
120
+ style: [styles.header, style],
121
+ ...props,
122
+ children: [children, dismissible ? /* @__PURE__ */ jsx(Button, {
123
+ variant: "ghost",
124
+ size: "icon",
125
+ accessibilityLabel: closeLabel,
126
+ onPress: () => setOpen(false),
127
+ children: /* @__PURE__ */ jsx(CloseIcon, {
128
+ size: 12,
129
+ color: "faint"
130
+ })
131
+ }) : null]
132
+ });
133
+ }
134
+ function DialogTitle({ style, ...props }) {
135
+ return /* @__PURE__ */ jsx(Text, {
136
+ accessibilityRole: "header",
137
+ style: [styles.title, style],
138
+ ...props
139
+ });
140
+ }
141
+ function DialogDescription({ style, ...props }) {
142
+ return /* @__PURE__ */ jsx(Text, {
143
+ style: [styles.description, style],
144
+ ...props
145
+ });
146
+ }
147
+ function DialogBody({ style, children, ...props }) {
148
+ return /* @__PURE__ */ jsx(View, {
149
+ style: [styles.body, style],
150
+ ...props,
151
+ children: wrapText(children, styles.description)
152
+ });
153
+ }
154
+ function DialogFooter({ variant = "plain", style, children, ...props }) {
155
+ const _styles2 = styles;
156
+ {
157
+ const styles = _styles2.useVariants({ footer: variant });
158
+ return /* @__PURE__ */ jsx(View, {
159
+ style: [styles.footer, style],
160
+ ...props,
161
+ children: wrapText(children, styles.hint)
162
+ });
163
+ }
164
+ }
165
+ const styles = StyleSheet.create((theme) => ({
166
+ root: {
167
+ flex: 1,
168
+ alignItems: "center",
169
+ justifyContent: "center",
170
+ padding: SCREEN_MARGIN
171
+ },
172
+ backdrop: {
173
+ position: "absolute",
174
+ top: 0,
175
+ right: 0,
176
+ bottom: 0,
177
+ left: 0
178
+ },
179
+ card: {
180
+ width: "100%",
181
+ maxHeight: "100%",
182
+ overflow: "hidden",
183
+ borderRadius: theme.borderRadius.lg,
184
+ borderWidth: 1,
185
+ borderColor: theme.colors.border,
186
+ backgroundColor: theme.colors.panel,
187
+ variants: { width: {
188
+ sm: { maxWidth: 360 },
189
+ md: { maxWidth: 480 },
190
+ lg: { maxWidth: 620 }
191
+ } },
192
+ uni__dependencies: [0, 4]
193
+ },
194
+ header: {
195
+ flexDirection: "row",
196
+ alignItems: "center",
197
+ justifyContent: "space-between",
198
+ gap: theme.spacing(3),
199
+ minWidth: 0,
200
+ borderBottomWidth: 1,
201
+ borderBottomColor: theme.colors.border,
202
+ padding: theme.spacing(3),
203
+ uni__dependencies: [0]
204
+ },
205
+ title: {
206
+ flexShrink: 1,
207
+ color: theme.colors.hi,
208
+ fontFamily: fontOf(theme.fontFamily.sans),
209
+ fontSize: theme.fontSize.xl,
210
+ lineHeight: theme.lineHeight.xl,
211
+ letterSpacing: theme.letterSpacing.xl,
212
+ fontWeight: theme.fontWeight.semibold,
213
+ uni__dependencies: [0]
214
+ },
215
+ description: {
216
+ color: theme.colors.dim,
217
+ fontFamily: fontOf(theme.fontFamily.sans),
218
+ fontSize: theme.fontSize.sm,
219
+ lineHeight: theme.lineHeightRelaxed.sm,
220
+ uni__dependencies: [0]
221
+ },
222
+ body: {
223
+ gap: theme.spacing(3),
224
+ padding: theme.spacing(3),
225
+ uni__dependencies: [0]
226
+ },
227
+ footer: {
228
+ flexDirection: "row",
229
+ alignItems: "center",
230
+ gap: theme.spacing(2),
231
+ variants: { footer: {
232
+ plain: { justifyContent: "flex-end" },
233
+ bar: {
234
+ flexWrap: "wrap",
235
+ justifyContent: "space-between",
236
+ minHeight: 34,
237
+ borderTopWidth: 1,
238
+ borderTopColor: theme.colors["border-soft"],
239
+ backgroundColor: theme.colors.deep,
240
+ paddingHorizontal: theme.spacing(3),
241
+ paddingVertical: theme.spacing(1.5)
242
+ }
243
+ } },
244
+ uni__dependencies: [0, 4]
245
+ },
246
+ hint: {
247
+ color: theme.colors.faint,
248
+ fontFamily: fontOf(theme.fontFamily.sans),
249
+ fontSize: theme.fontSize["2xs"],
250
+ lineHeight: theme.lineHeight["2xs"],
251
+ uni__dependencies: [0]
252
+ }
253
+ }));
254
+
255
+ //#endregion
256
+ export { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger };
257
+ //# sourceMappingURL=Dialog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dialog.mjs","names":["withAlpha","createContext","ReactNode","useContext","useEffect","useRef","Easing","Modal","Platform","StyleProp","TextProps","ViewProps","ViewStyle","StyleSheet","useUnistyles","CloseIcon","fontOf","useControllable","wrapText","Button","ButtonProps","BACKDROP_ALPHA_PERCENT","POP_FROM_SCALE","SCREEN_MARGIN","DialogWidth","DialogState","open","setOpen","DialogContext","undefined","DialogProps","defaultOpen","onOpenChange","children","Dialog","current","DialogTrigger","onPress","props","event","DialogClose","DialogContentProps","width","style","closeLabel","DialogContent","theme","progress","Animated","Value","x1","y1","x2","y2","motion","easing","setValue","timing","toValue","duration","pop","bezier","useNativeDriver","OS","start","_styles","styles","useVariants","root","backdrop","backgroundColor","colors","deep","card","opacity","transform","scale","interpolate","inputRange","outputRange","DialogPartProps","Omit","DialogHeaderProps","dismissible","DialogHeader","header","DialogTitle","title","DialogDescription","description","DialogBody","body","DialogFooterVariant","DialogFooterProps","variant","DialogFooter","_styles2","footer","hint","create","flex","alignItems","justifyContent","padding","position","top","right","bottom","left","maxHeight","overflow","borderRadius","lg","borderWidth","borderColor","border","panel","variants","sm","maxWidth","md","uni__dependencies","flexDirection","gap","spacing","minWidth","borderBottomWidth","borderBottomColor","flexShrink","color","hi","fontFamily","sans","fontSize","xl","lineHeight","letterSpacing","fontWeight","semibold","dim","lineHeightRelaxed","plain","bar","flexWrap","minHeight","borderTopWidth","borderTopColor","paddingHorizontal","paddingVertical","faint"],"sources":["../../src/components/Dialog.tsx"],"sourcesContent":["import { withAlpha } from '@agimon-ai/po-web-components/nativeTheme';\nimport { createContext, type ReactNode, useContext, useEffect, useRef } from 'react';\nimport {\n Animated,\n Easing,\n Modal,\n Platform,\n Pressable,\n type StyleProp,\n Text,\n type TextProps,\n View,\n type ViewProps,\n type ViewStyle,\n} from 'react-native';\nimport { StyleSheet, useUnistyles } from 'react-native-unistyles';\n\nimport { CloseIcon } from '../icons/icons';\nimport { fontOf } from '../lib/fonts';\nimport { useControllable } from '../lib/useControllable';\nimport { wrapText } from '../lib/wrapText';\nimport { Button, type ButtonProps } from './Button';\n\n/*\n * The web Dialog as a centred card in an RN Modal: the native shape for a\n * question that blocks, such as a destructive confirmation. Android back and\n * a backdrop tap close it, as Escape and an outside click do on the web.\n */\n\n/** `bg-doom-deep/70`. */\nconst BACKDROP_ALPHA_PERCENT = 70;\n/** `animate-doom-pop` starts the card slightly small and grows it into place. */\nconst POP_FROM_SCALE = 0.96;\n/** `max-w-[calc(100vw-24px)]`: 12pt clear of each screen edge. */\nconst SCREEN_MARGIN = 12;\n\nexport type DialogWidth = 'sm' | 'md' | 'lg';\n\ninterface DialogState {\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nconst DialogContext = createContext<DialogState>({ open: false, setOpen: () => undefined });\n\nexport interface DialogProps {\n /** Controlled mode; pair with onOpenChange. Omit it and the dialog keeps its own state. */\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: ReactNode;\n}\n\nexport function Dialog({ open, defaultOpen = false, onOpenChange, children }: DialogProps) {\n const [current, setOpen] = useControllable(open, defaultOpen, onOpenChange);\n return <DialogContext.Provider value={{ open: current, setOpen }}>{children}</DialogContext.Provider>;\n}\n\n/** A Button that opens the enclosing dialog. */\nexport function DialogTrigger({ onPress, ...props }: ButtonProps) {\n const { setOpen } = useContext(DialogContext);\n return (\n <Button\n onPress={(event) => {\n onPress?.(event);\n setOpen(true);\n }}\n {...props}\n />\n );\n}\n\n/** A Button that closes the enclosing dialog. */\nexport function DialogClose({ onPress, ...props }: ButtonProps) {\n const { setOpen } = useContext(DialogContext);\n return (\n <Button\n onPress={(event) => {\n onPress?.(event);\n setOpen(false);\n }}\n {...props}\n />\n );\n}\n\nexport interface DialogContentProps {\n /** Width preset; `style` may still override. */\n width?: DialogWidth;\n /** Applied to the card, after the preset. */\n style?: StyleProp<ViewStyle>;\n /** What the backdrop announces as its close action. */\n closeLabel?: string;\n children?: ReactNode;\n}\n\nexport function DialogContent({ width = 'md', style, closeLabel = 'close', children }: DialogContentProps) {\n const { open, setOpen } = useContext(DialogContext);\n const { theme } = useUnistyles();\n const progress = useRef(new Animated.Value(0)).current;\n const [x1, y1, x2, y2] = theme.motion.easing;\n useEffect(() => {\n if (!open) return;\n progress.setValue(0);\n Animated.timing(progress, {\n toValue: 1,\n duration: theme.motion.pop,\n easing: Easing.bezier(x1, y1, x2, y2),\n useNativeDriver: Platform.OS !== 'web',\n }).start();\n }, [open, progress, theme.motion.pop, x1, y1, x2, y2]);\n styles.useVariants({ width });\n return (\n <Modal visible={open} transparent animationType=\"fade\" statusBarTranslucent onRequestClose={() => setOpen(false)}>\n <View style={styles.root}>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={closeLabel}\n onPress={() => setOpen(false)}\n // Alpha mixes are computed in render from useUnistyles(), not in StyleSheet.create: on web Unistyles hands\n // the stylesheet CSS variables, which withAlpha cannot read.\n style={[styles.backdrop, { backgroundColor: withAlpha(theme.colors.deep, BACKDROP_ALPHA_PERCENT) }]}\n />\n <Animated.View\n accessibilityViewIsModal\n style={[\n styles.card,\n style,\n {\n opacity: progress,\n transform: [{ scale: progress.interpolate({ inputRange: [0, 1], outputRange: [POP_FROM_SCALE, 1] }) }],\n },\n ]}\n >\n {children}\n </Animated.View>\n </View>\n </Modal>\n );\n}\n\nexport interface DialogPartProps extends Omit<ViewProps, 'children' | 'style'> {\n children?: ReactNode;\n style?: StyleProp<ViewStyle>;\n}\n\nexport interface DialogHeaderProps extends DialogPartProps {\n /**\n * Show the close control at the right of the strip. Off by default, as on\n * the web: Android back and a backdrop tap already close every dialog.\n */\n dismissible?: boolean;\n /** What the close control announces. */\n closeLabel?: string;\n}\n\nexport function DialogHeader({\n dismissible = false,\n closeLabel = 'close',\n style,\n children,\n ...props\n}: DialogHeaderProps) {\n const { setOpen } = useContext(DialogContext);\n return (\n <View style={[styles.header, style]} {...props}>\n {children}\n {dismissible ? (\n <Button variant=\"ghost\" size=\"icon\" accessibilityLabel={closeLabel} onPress={() => setOpen(false)}>\n <CloseIcon size={12} color=\"faint\" />\n </Button>\n ) : null}\n </View>\n );\n}\n\nexport function DialogTitle({ style, ...props }: TextProps) {\n return <Text accessibilityRole=\"header\" style={[styles.title, style]} {...props} />;\n}\n\nexport function DialogDescription({ style, ...props }: TextProps) {\n return <Text style={[styles.description, style]} {...props} />;\n}\n\nexport function DialogBody({ style, children, ...props }: DialogPartProps) {\n return (\n <View style={[styles.body, style]} {...props}>\n {wrapText(children, styles.description)}\n </View>\n );\n}\n\nexport type DialogFooterVariant = 'plain' | 'bar';\n\nexport interface DialogFooterProps extends DialogPartProps {\n /** `plain`: buttons alone, inside the body's padding. `bar`: the recessed full-width strip with a hint at the left. */\n variant?: DialogFooterVariant;\n}\n\nexport function DialogFooter({ variant = 'plain', style, children, ...props }: DialogFooterProps) {\n styles.useVariants({ footer: variant });\n return (\n <View style={[styles.footer, style]} {...props}>\n {wrapText(children, styles.hint)}\n </View>\n );\n}\n\nconst styles = StyleSheet.create((theme) => ({\n root: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: SCREEN_MARGIN },\n backdrop: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0 },\n card: {\n width: '100%',\n maxHeight: '100%',\n overflow: 'hidden',\n borderRadius: theme.borderRadius.lg,\n borderWidth: 1,\n borderColor: theme.colors.border,\n backgroundColor: theme.colors.panel,\n variants: {\n width: {\n sm: { maxWidth: 360 },\n md: { maxWidth: 480 },\n lg: { maxWidth: 620 },\n },\n },\n },\n header: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: theme.spacing(3),\n minWidth: 0,\n borderBottomWidth: 1,\n borderBottomColor: theme.colors.border,\n padding: theme.spacing(3),\n },\n title: {\n flexShrink: 1,\n color: theme.colors.hi,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.xl,\n lineHeight: theme.lineHeight.xl,\n letterSpacing: theme.letterSpacing.xl,\n fontWeight: theme.fontWeight.semibold,\n },\n description: {\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeightRelaxed.sm,\n },\n body: { gap: theme.spacing(3), padding: theme.spacing(3) },\n footer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: theme.spacing(2),\n variants: {\n footer: {\n plain: { justifyContent: 'flex-end' },\n bar: {\n flexWrap: 'wrap',\n justifyContent: 'space-between',\n minHeight: 34,\n borderTopWidth: 1,\n borderTopColor: theme.colors['border-soft'],\n backgroundColor: theme.colors.deep,\n paddingHorizontal: theme.spacing(3),\n paddingVertical: theme.spacing(1.5),\n },\n },\n },\n },\n hint: {\n color: theme.colors.faint,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize['2xs'],\n lineHeight: theme.lineHeight['2xs'],\n },\n}));\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { DotTone } from "@agimon-ai/po-web-components/nativeTheme";
2
+ import { StyleProp, ViewStyle } from "react-native";
3
+ //#region src/components/Dot.d.ts
4
+ type DotTone$1 = DotTone;
5
+ export type DotSize = 'xs' | 'sm' | 'md' | 'lg';
6
+ export interface DotProps {
7
+ tone?: DotTone$1;
8
+ size?: DotSize;
9
+ /** Something is live: the dot breathes. */
10
+ pulse?: boolean;
11
+ style?: StyleProp<ViewStyle>;
12
+ }
13
+ /** The status dot: a colour and, while something is live, a pulse. Hidden from screen readers. */
14
+ export declare function Dot({ tone, size, pulse, style }: DotProps): import("react").JSX.Element;
15
+ //#endregion
16
+ export { DotTone$1 as DotTone };
17
+ //# sourceMappingURL=Dot.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dot.d.mts","names":["DotTone","Tone"],"sources":["../../src/components/Dot.tsx"],"mappings":";;;KAKYA,YAAUC;YACV;iBAQK;EACf,OAAOD;EACP,OAAO;;EAEP;EACA,QAAQ,UAAU;;;wBAIJ,MAAM,MAAkB,MAAa,OAAe,SAAS,2BAAQ,IAAA"}
@@ -0,0 +1,94 @@
1
+ import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
2
+ import { StyleSheet, useUnistyles } from "react-native-unistyles";
3
+ import { useEffect, useRef } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { Animated } from "react-native-unistyles/components/native/Animated";
6
+
7
+ //#region src/components/Dot.tsx
8
+ /** `bg-doom-faint/40`: a thing that exists but is not live. */
9
+ const MUTED_ALPHA_PERCENT = 40;
10
+ /** Tailwind's `animate-pulse`: a 2s cycle down to half opacity and back. */
11
+ const PULSE_HALF_CYCLE_MS = 1e3;
12
+ const PULSE_LOW_OPACITY = .5;
13
+ /** The status dot: a colour and, while something is live, a pulse. Hidden from screen readers. */
14
+ function Dot({ tone = "neutral", size = "sm", pulse = false, style }) {
15
+ const { theme } = useUnistyles();
16
+ const _styles = styles;
17
+ {
18
+ const styles = _styles.useVariants({
19
+ tone,
20
+ size
21
+ });
22
+ const opacity = useRef(new Animated.Value(1)).current;
23
+ useEffect(() => {
24
+ if (!pulse) {
25
+ opacity.setValue(1);
26
+ return;
27
+ }
28
+ const loop = Animated.loop(Animated.sequence([Animated.timing(opacity, {
29
+ toValue: PULSE_LOW_OPACITY,
30
+ duration: PULSE_HALF_CYCLE_MS,
31
+ useNativeDriver: true
32
+ }), Animated.timing(opacity, {
33
+ toValue: 1,
34
+ duration: PULSE_HALF_CYCLE_MS,
35
+ useNativeDriver: true
36
+ })]));
37
+ loop.start();
38
+ return () => loop.stop();
39
+ }, [pulse, opacity]);
40
+ return /* @__PURE__ */ jsx(Animated.View, {
41
+ accessible: false,
42
+ importantForAccessibility: "no-hide-descendants",
43
+ accessibilityElementsHidden: true,
44
+ style: [
45
+ styles.dot,
46
+ tone === "muted" && { backgroundColor: withAlpha(theme.colors.faint, MUTED_ALPHA_PERCENT) },
47
+ { opacity },
48
+ style
49
+ ]
50
+ });
51
+ }
52
+ }
53
+ const styles = StyleSheet.create((theme) => ({ dot: {
54
+ flexShrink: 0,
55
+ borderRadius: theme.borderRadius.full,
56
+ variants: {
57
+ tone: {
58
+ neutral: { backgroundColor: theme.colors.faint },
59
+ muted: {},
60
+ blue: { backgroundColor: theme.colors.blue },
61
+ green: { backgroundColor: theme.colors.green },
62
+ yellow: { backgroundColor: theme.colors.yellow },
63
+ red: { backgroundColor: theme.colors.red },
64
+ magenta: { backgroundColor: theme.colors.magenta },
65
+ violet: { backgroundColor: theme.colors.violet },
66
+ cyan: { backgroundColor: theme.colors.cyan },
67
+ orange: { backgroundColor: theme.colors.orange },
68
+ teal: { backgroundColor: theme.colors.teal }
69
+ },
70
+ size: {
71
+ xs: {
72
+ width: theme.spacing(1),
73
+ height: theme.spacing(1)
74
+ },
75
+ sm: {
76
+ width: theme.spacing(1.5),
77
+ height: theme.spacing(1.5)
78
+ },
79
+ md: {
80
+ width: theme.spacing(2),
81
+ height: theme.spacing(2)
82
+ },
83
+ lg: {
84
+ width: theme.spacing(2.5),
85
+ height: theme.spacing(2.5)
86
+ }
87
+ }
88
+ },
89
+ uni__dependencies: [0, 4]
90
+ } }));
91
+
92
+ //#endregion
93
+ export { Dot };
94
+ //# sourceMappingURL=Dot.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dot.mjs","names":["DotTone","Tone","withAlpha","useEffect","useRef","StyleProp","ViewStyle","StyleSheet","useUnistyles","DotSize","MUTED_ALPHA_PERCENT","PULSE_HALF_CYCLE_MS","PULSE_LOW_OPACITY","DotProps","tone","size","pulse","style","Dot","theme","_styles","styles","useVariants","opacity","Animated","Value","current","setValue","undefined","loop","sequence","timing","toValue","duration","useNativeDriver","start","stop","dot","backgroundColor","colors","faint","create","flexShrink","borderRadius","full","variants","neutral","muted","blue","green","yellow","red","magenta","violet","cyan","orange","teal","xs","width","spacing","height","sm","md","lg","uni__dependencies"],"sources":["../../src/components/Dot.tsx"],"sourcesContent":["import { type DotTone as Tone, withAlpha } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useEffect, useRef } from 'react';\nimport { Animated, type StyleProp, type ViewStyle } from 'react-native';\nimport { StyleSheet, useUnistyles } from 'react-native-unistyles';\n\nexport type DotTone = Tone;\nexport type DotSize = 'xs' | 'sm' | 'md' | 'lg';\n\n/** `bg-doom-faint/40`: a thing that exists but is not live. */\nconst MUTED_ALPHA_PERCENT = 40;\n/** Tailwind's `animate-pulse`: a 2s cycle down to half opacity and back. */\nconst PULSE_HALF_CYCLE_MS = 1000;\nconst PULSE_LOW_OPACITY = 0.5;\n\nexport interface DotProps {\n tone?: DotTone;\n size?: DotSize;\n /** Something is live: the dot breathes. */\n pulse?: boolean;\n style?: StyleProp<ViewStyle>;\n}\n\n/** The status dot: a colour and, while something is live, a pulse. Hidden from screen readers. */\nexport function Dot({ tone = 'neutral', size = 'sm', pulse = false, style }: DotProps) {\n const { theme } = useUnistyles();\n styles.useVariants({ tone, size });\n const opacity = useRef(new Animated.Value(1)).current;\n useEffect(() => {\n if (!pulse) {\n opacity.setValue(1);\n return undefined;\n }\n const loop = Animated.loop(\n Animated.sequence([\n Animated.timing(opacity, { toValue: PULSE_LOW_OPACITY, duration: PULSE_HALF_CYCLE_MS, useNativeDriver: true }),\n Animated.timing(opacity, { toValue: 1, duration: PULSE_HALF_CYCLE_MS, useNativeDriver: true }),\n ]),\n );\n loop.start();\n return () => loop.stop();\n }, [pulse, opacity]);\n return (\n <Animated.View\n accessible={false}\n importantForAccessibility=\"no-hide-descendants\"\n accessibilityElementsHidden\n style={[\n styles.dot,\n // Alpha mixes are computed in render from useUnistyles(), not in StyleSheet.create: on web Unistyles hands\n // the stylesheet CSS variables, which withAlpha cannot read.\n tone === 'muted' && { backgroundColor: withAlpha(theme.colors.faint, MUTED_ALPHA_PERCENT) },\n { opacity },\n style,\n ]}\n />\n );\n}\n\nconst styles = StyleSheet.create((theme) => ({\n dot: {\n flexShrink: 0,\n borderRadius: theme.borderRadius.full,\n variants: {\n tone: {\n neutral: { backgroundColor: theme.colors.faint },\n muted: {},\n blue: { backgroundColor: theme.colors.blue },\n green: { backgroundColor: theme.colors.green },\n yellow: { backgroundColor: theme.colors.yellow },\n red: { backgroundColor: theme.colors.red },\n magenta: { backgroundColor: theme.colors.magenta },\n violet: { backgroundColor: theme.colors.violet },\n cyan: { backgroundColor: theme.colors.cyan },\n orange: { backgroundColor: theme.colors.orange },\n teal: { backgroundColor: theme.colors.teal },\n },\n size: {\n xs: { width: theme.spacing(1), height: theme.spacing(1) },\n sm: { width: theme.spacing(1.5), height: theme.spacing(1.5) },\n md: { width: theme.spacing(2), height: theme.spacing(2) },\n lg: { width: theme.spacing(2.5), height: theme.spacing(2.5) },\n },\n },\n },\n}));\n"],"mappings":";;;;;;;;AASA,MAAMU,sBAAsB;;AAE5B,MAAMC,sBAAsB;AAC5B,MAAMC,oBAAoB;;AAW1B,SAAgBM,IAAI,EAAEJ,OAAO,WAAWC,OAAO,MAAMC,QAAQ,OAAOC,SAAmB;CACrF,MAAM,EAAEE,UAAUX,aAAa;CAAE,MAAAY,UAAAC;CAAA;EAAA,MAAAA,SAAAD,QAAAE,YACd;GAAER;GAAMC;EAAK,CAAC;EACjC,MAAMQ,UAAUnB,OAAO,IAAIoB,SAASC,MAAM,CAAC,CAAC,CAAC,CAACC;EAC9CvB,gBAAgB;GACd,IAAI,CAACa,OAAO;IACVO,QAAQI,SAAS,CAAC;IAClB;GACF;GACA,MAAME,OAAOL,SAASK,KACpBL,SAASM,SAAS,CAChBN,SAASO,OAAOR,SAAS;IAAES,SAASpB;IAAmBqB,UAAUtB;IAAqBuB,iBAAiB;GAAK,CAAC,GAC7GV,SAASO,OAAOR,SAAS;IAAES,SAAS;IAAGC,UAAUtB;IAAqBuB,iBAAiB;GAAK,CAAC,CAAC,CAC/F,CACH;GACAL,KAAKM,MAAM;GACX,aAAaN,KAAKO,KAAK;EACzB,GAAG,CAACpB,OAAOO,OAAO,CAAC;EACnB,OACE,oBAAC,SAAS,MAAV;GACE,YAAY;GACZ,2BAA0B;GAC1B;GACA,OAAO;IACLF,OAAOgB;IAGPvB,SAAS,WAAW,EAAEwB,iBAAiBpC,UAAUiB,MAAMoB,OAAOC,OAAO9B,mBAAmB,EAAE;IAC1F,EAAEa,QAAQ;IACVN;GAAK;EACL;CAEJ;AACJ;AAEA,MAAMI,SAASd,WAAWkC,QAAQtB,WAAW,EAC3CkB,KAAK;CACHK,YAAY;CACZC,cAAcxB,MAAMwB,aAAaC;CACjCC,UAAU;EACR/B,MAAM;GACJgC,SAAS,EAAER,iBAAiBnB,MAAMoB,OAAOC,MAAM;GAC/CO,OAAO,CAAC;GACRC,MAAM,EAAEV,iBAAiBnB,MAAMoB,OAAOS,KAAK;GAC3CC,OAAO,EAAEX,iBAAiBnB,MAAMoB,OAAOU,MAAM;GAC7CC,QAAQ,EAAEZ,iBAAiBnB,MAAMoB,OAAOW,OAAO;GAC/CC,KAAK,EAAEb,iBAAiBnB,MAAMoB,OAAOY,IAAI;GACzCC,SAAS,EAAEd,iBAAiBnB,MAAMoB,OAAOa,QAAQ;GACjDC,QAAQ,EAAEf,iBAAiBnB,MAAMoB,OAAOc,OAAO;GAC/CC,MAAM,EAAEhB,iBAAiBnB,MAAMoB,OAAOe,KAAK;GAC3CC,QAAQ,EAAEjB,iBAAiBnB,MAAMoB,OAAOgB,OAAO;GAC/CC,MAAM,EAAElB,iBAAiBnB,MAAMoB,OAAOiB,KAAK;EAC7C;EACAzC,MAAM;GACJ0C,IAAI;IAAEC,OAAOvC,MAAMwC,QAAQ,CAAC;IAAGC,QAAQzC,MAAMwC,QAAQ,CAAC;GAAE;GACxDE,IAAI;IAAEH,OAAOvC,MAAMwC,QAAQ,GAAG;IAAGC,QAAQzC,MAAMwC,QAAQ,GAAG;GAAE;GAC5DG,IAAI;IAAEJ,OAAOvC,MAAMwC,QAAQ,CAAC;IAAGC,QAAQzC,MAAMwC,QAAQ,CAAC;GAAE;GACxDI,IAAI;IAAEL,OAAOvC,MAAMwC,QAAQ,GAAG;IAAGC,QAAQzC,MAAMwC,QAAQ,GAAG;GAAE;EAC9D;CACF;CAACK,mBAAA,CAAA,GAAA,CAAA;AACH,EACF,EAAE"}
@@ -0,0 +1,63 @@
1
+ import { ButtonProps } from "./Button.mjs";
2
+ import { StyleProp, TextProps, ViewProps, ViewStyle } from "react-native";
3
+ import { ReactNode } from "react";
4
+ //#region src/components/DropdownMenu.d.ts
5
+ export interface DropdownMenuProps {
6
+ /** Controlled mode; pair with onOpenChange. Omit it and the menu keeps its own state. */
7
+ open?: boolean;
8
+ defaultOpen?: boolean;
9
+ onOpenChange?: (open: boolean) => void;
10
+ children?: ReactNode;
11
+ }
12
+ export declare function DropdownMenu({ open, defaultOpen, onOpenChange, children }: DropdownMenuProps): import("react").JSX.Element;
13
+ /** A Button that opens the menu; announces that it opens a menu. */
14
+ export declare function DropdownMenuTrigger({ onPress, accessibilityState, ...props }: ButtonProps): import("react").JSX.Element;
15
+ export interface DropdownMenuContentProps {
16
+ children?: ReactNode;
17
+ }
18
+ /** The action list, in a bottom sheet. */
19
+ export declare function DropdownMenuContent({ children }: DropdownMenuContentProps): import("react").JSX.Element;
20
+ export interface DropdownMenuPartProps extends Omit<ViewProps, 'children' | 'style'> {
21
+ children?: ReactNode;
22
+ style?: StyleProp<ViewStyle>;
23
+ }
24
+ /** A run of items under one label, so the separator between groups is structural. */
25
+ export declare function DropdownMenuGroup({ children, ...props }: DropdownMenuPartProps): import("react").JSX.Element;
26
+ export type DropdownMenuItemVariant = 'default' | 'destructive';
27
+ export interface DropdownMenuItemProps {
28
+ variant?: DropdownMenuItemVariant;
29
+ /** Keep the indicator gutter, so the label lines up with checkbox and radio rows. */
30
+ indented?: boolean;
31
+ disabled?: boolean;
32
+ /** Chosen: the menu ticks, runs this, then closes. */
33
+ onSelect?: () => void;
34
+ /** The label, optionally followed by a DropdownMenuShortcut. */
35
+ children?: ReactNode;
36
+ style?: StyleProp<ViewStyle>;
37
+ }
38
+ export declare function DropdownMenuItem(props: DropdownMenuItemProps): import("react").JSX.Element;
39
+ export interface DropdownMenuCheckboxItemProps extends Omit<DropdownMenuItemProps, 'indented'> {
40
+ checked?: boolean;
41
+ onCheckedChange?: (checked: boolean) => void;
42
+ }
43
+ /** A row that toggles: the check lives in the gutter so the label never shifts. */
44
+ export declare function DropdownMenuCheckboxItem({ checked, onCheckedChange, onSelect, ...props }: DropdownMenuCheckboxItemProps): import("react").JSX.Element;
45
+ export interface DropdownMenuRadioGroupProps extends DropdownMenuPartProps {
46
+ value?: string;
47
+ onValueChange?: (value: string) => void;
48
+ }
49
+ /** The exclusive-choice group; pair it with DropdownMenuRadioItem. */
50
+ export declare function DropdownMenuRadioGroup({ value, onValueChange, children, ...props }: DropdownMenuRadioGroupProps): import("react").JSX.Element;
51
+ export interface DropdownMenuRadioItemProps extends Omit<DropdownMenuItemProps, 'indented'> {
52
+ value: string;
53
+ }
54
+ export declare function DropdownMenuRadioItem({ value, onSelect, ...props }: DropdownMenuRadioItemProps): import("react").JSX.Element;
55
+ /** The heading over a run of items, raised to sentence case as the web's `first-letter:uppercase`. */
56
+ export declare function DropdownMenuLabel({ style, children, ...props }: TextProps): import("react").JSX.Element;
57
+ /** The keystroke printed at the right of a row; the row supplies the gap. */
58
+ export declare function DropdownMenuShortcut({ style, ...props }: TextProps): import("react").JSX.Element;
59
+ export declare function DropdownMenuSeparator({ style }: {
60
+ style?: StyleProp<ViewStyle>;
61
+ }): import("react").JSX.Element;
62
+ //#endregion
63
+ //# sourceMappingURL=DropdownMenu.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropdownMenu.d.mts","names":[],"sources":["../../src/components/DropdownMenu.tsx"],"mappings":";;;;iBAyCiB;;EAEf;EACA;EACA,gBAAgB;EAChB,WAAW;;wBAGG,eAAe,MAAM,aAAqB,cAAc,YAAY,oCAAiB,IAAA;;wBAMrF,sBAAsB,SAAS,uBAAuB,SAAS,8BAAW,IAAA;iBAczE;EACf,WAAW;;;wBAIG,sBAAsB,YAAY,2CAAwB,IAAA;iBAWzD,8BAA8B,KAAK;EAClD,WAAW;EACX,QAAQ,UAAU;;;wBAIJ,oBAAoB,aAAa,SAAS,wCAAqB,IAAA;YAInE;iBAEK;EACf,UAAU;;EAEV;EACA;;EAEA;;EAEA,WAAW;EACX,QAAQ,UAAU;;wBA8CJ,iBAAiB,OAAO,wCAAqB,IAAA;iBAI5C,sCAAsC,KAAK;EAC1D;EACA,mBAAmB;;;wBAIL,2BACd,SACA,iBACA,aACG,SACF,gDAA6B,IAAA;iBAef,oCAAoC;EACnD;EACA,iBAAiB;;;wBAIH,yBAAyB,OAAO,eAAe,aAAa,SAAS,8CAA2B,IAAA;iBAU/F,mCAAmC,KAAK;EACvD;;wBAGc,wBAAwB,OAAO,aAAa,SAAS,6CAA0B,IAAA;;wBAkB/E,oBAAoB,OAAO,aAAa,SAAS,4BAAS,IAAA;;wBAU1D,uBAAuB,UAAU,SAAS,4BAAS,IAAA;wBAInD,wBAAwB;EAAW,QAAQ,UAAU;oBAAY,IAAA"}