@nexub/patterns 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/chunk-27N33TGN.js +61 -0
- package/dist/chunk-33Z2ZPO7.js +71 -0
- package/dist/chunk-64PSI75E.js +83 -0
- package/dist/chunk-7QCJC2DV.js +113 -0
- package/dist/chunk-CJBHDX2U.js +42 -0
- package/dist/chunk-CWFZA7ZQ.js +1 -0
- package/dist/chunk-CZR6NZDH.js +134 -0
- package/dist/chunk-M3OHX4F4.js +42 -0
- package/dist/chunk-OC4XY3US.js +87 -0
- package/dist/chunk-RFCPEZGF.js +1 -0
- package/dist/chunk-UNQD426H.js +101 -0
- package/dist/{chunk-WIHNK7RT.js → chunk-Z4FCC42C.js} +18 -13
- package/dist/components/ActivityPage/index.js +11 -0
- package/dist/components/ChatPage/index.js +9 -0
- package/dist/components/CheckoutPage/index.js +9 -0
- package/dist/components/DashboardPage/index.js +10 -0
- package/dist/components/PageFrame/index.js +14 -0
- package/dist/components/PaywallPage/index.js +8 -0
- package/dist/components/SettingsLayout/index.js +1 -1
- package/dist/components/SettingsPage/index.js +8 -0
- package/dist/components/SignInPage/index.js +9 -0
- package/dist/components/TransactionDetailPage/index.js +9 -0
- package/dist/index.d.ts +332 -1
- package/dist/index.js +65 -19
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -6,7 +6,10 @@ Composite UI patterns for the Nexub Design System, built on `@nexub/react`.
|
|
|
6
6
|
pnpm add @nexub/patterns @nexub/react @nexub/icons @nexub/themes
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Like `@nexub/react`, the patterns are styled with Tailwind classes your app compiles
|
|
9
|
+
Like `@nexub/react`, the patterns are styled with Tailwind classes your app compiles, on Tailwind 3 or 4. Import `@nexub/themes/base` plus a palette (e.g. `@nexub/themes/light` and `@nexub/themes/dark`), then:
|
|
10
|
+
|
|
11
|
+
- **Tailwind 3:** add `node_modules/@nexub/patterns/dist/**/*.js` to your Tailwind `content` and use the `@nexub/tokens/tailwind` preset.
|
|
12
|
+
- **Tailwind 4:** `@import "@nexub/tokens/tailwind.css";` after `@import "tailwindcss";`, add `@source "../node_modules/@nexub/patterns/dist";`, and import the theme CSS with `layer(base)` so Tailwind's utilities still win over it. See [Getting Started](https://nexub-ds-docs.pages.dev/getting-started) for the full snippet.
|
|
10
13
|
|
|
11
14
|
## AppHeader
|
|
12
15
|
|
|
@@ -123,6 +126,8 @@ Search opens with the button, **⌘K / Ctrl+K** anywhere, or **/** when focus is
|
|
|
123
126
|
</SettingsLayout>
|
|
124
127
|
```
|
|
125
128
|
|
|
129
|
+
`navFooter` pins a line to the bottom of the section sidebar and the phone menu while the items scroll, e.g. `navFooter="v1.2.0 · Updated 21 Oct 2026"`. In your own `Sidebar`, use `Sidebar.Footer` for the same.
|
|
130
|
+
|
|
126
131
|
### Strict CSP
|
|
127
132
|
|
|
128
133
|
The header injects no `<style>` tags and sets no inline styles of its own: the search palette locks page scroll with a class (`scrollLock="class"`), and the org and account menus are non-modal. One known gap: the colour Nexub mark inside `Logo` still sets `style` on its gradient stops, so under `style-src 'self'` a server-rendered mark loses its colours until that is fixed.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
PageFrame,
|
|
4
|
+
usePageMessages
|
|
5
|
+
} from "./chunk-7QCJC2DV.js";
|
|
6
|
+
|
|
7
|
+
// src/components/SettingsPage/SettingsPage.tsx
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { cn } from "@nexub/react";
|
|
10
|
+
import { ChevronRight } from "@nexub/icons";
|
|
11
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
function Row({ item }) {
|
|
13
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14
|
+
item.leading && /* @__PURE__ */ jsx("span", { className: "flex shrink-0 text-[var(--color-on-surface-variant)]", children: item.leading }),
|
|
15
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col text-start", children: [
|
|
16
|
+
/* @__PURE__ */ jsx(
|
|
17
|
+
"span",
|
|
18
|
+
{
|
|
19
|
+
className: cn(
|
|
20
|
+
"text-body-md font-medium",
|
|
21
|
+
item.destructive ? "text-[var(--color-error)]" : "text-[var(--color-on-surface)]"
|
|
22
|
+
),
|
|
23
|
+
children: item.title
|
|
24
|
+
}
|
|
25
|
+
),
|
|
26
|
+
item.subtitle && /* @__PURE__ */ jsx("span", { className: "text-body-sm text-[var(--color-on-surface-muted)]", children: item.subtitle })
|
|
27
|
+
] }),
|
|
28
|
+
item.value != null && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-body-md text-[var(--color-on-surface-muted)]", children: item.value }),
|
|
29
|
+
(item.href || item.onSelect) && !item.destructive && /* @__PURE__ */ jsx(ChevronRight, { size: "sm", "aria-hidden": "true", className: "shrink-0 text-[var(--color-on-surface-muted)] rtl:-scale-x-100" })
|
|
30
|
+
] });
|
|
31
|
+
const row = "flex min-h-[56px] w-full items-center gap-3 px-4 py-3";
|
|
32
|
+
if (item.href)
|
|
33
|
+
return /* @__PURE__ */ jsx("a", { href: item.href, onClick: item.onSelect && ((e) => {
|
|
34
|
+
e.preventDefault();
|
|
35
|
+
item.onSelect?.();
|
|
36
|
+
}), className: cn(row, "nx-state-layer"), children: content });
|
|
37
|
+
if (item.onSelect)
|
|
38
|
+
return /* @__PURE__ */ jsx("button", { type: "button", onClick: item.onSelect, className: cn(row, "nx-state-layer"), children: content });
|
|
39
|
+
return /* @__PURE__ */ jsxs("div", { className: row, children: [
|
|
40
|
+
content,
|
|
41
|
+
item.control && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: item.control })
|
|
42
|
+
] });
|
|
43
|
+
}
|
|
44
|
+
var SettingsPage = React.forwardRef(function SettingsPage2({ groups, header, title, messages, ...props }, ref) {
|
|
45
|
+
const m = usePageMessages(messages);
|
|
46
|
+
return /* @__PURE__ */ jsxs(PageFrame, { ref, title: title ?? m.settings, ...props, children: [
|
|
47
|
+
header,
|
|
48
|
+
groups.map((g, i) => {
|
|
49
|
+
const id = `settings-group-${i}`;
|
|
50
|
+
return /* @__PURE__ */ jsxs("section", { "aria-labelledby": g.header ? id : void 0, className: "flex flex-col gap-2", children: [
|
|
51
|
+
g.header && /* @__PURE__ */ jsx("h2", { id, className: "px-4 text-label-lg text-[var(--color-on-surface-variant)]", children: g.header }),
|
|
52
|
+
/* @__PURE__ */ jsx("ul", { className: "overflow-hidden rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)]", children: g.items.map((it) => /* @__PURE__ */ jsx("li", { className: "border-t border-[var(--color-outline-variant)] first:border-t-0", children: /* @__PURE__ */ jsx(Row, { item: it }) }, it.title)) }),
|
|
53
|
+
g.footer && /* @__PURE__ */ jsx("p", { className: "px-4 text-body-sm text-[var(--color-on-surface-muted)]", children: g.footer })
|
|
54
|
+
] }, g.header ?? i);
|
|
55
|
+
})
|
|
56
|
+
] });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
SettingsPage
|
|
61
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
StatCard
|
|
4
|
+
} from "./chunk-INKX2GYA.js";
|
|
5
|
+
import {
|
|
6
|
+
TransactionRow
|
|
7
|
+
} from "./chunk-OC4XY3US.js";
|
|
8
|
+
import {
|
|
9
|
+
PageFrame,
|
|
10
|
+
usePageMessages,
|
|
11
|
+
useTemplateLocale
|
|
12
|
+
} from "./chunk-7QCJC2DV.js";
|
|
13
|
+
|
|
14
|
+
// src/components/DashboardPage/DashboardPage.tsx
|
|
15
|
+
import * as React from "react";
|
|
16
|
+
import { Amount, Button, Card } from "@nexub/react";
|
|
17
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
+
function Panel({ title, action, children }) {
|
|
19
|
+
const id = React.useId();
|
|
20
|
+
return /* @__PURE__ */ jsxs("section", { "aria-labelledby": id, className: "flex flex-col gap-3", children: [
|
|
21
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
22
|
+
/* @__PURE__ */ jsx("h2", { id, className: "text-title-md text-[var(--color-on-surface)]", children: title }),
|
|
23
|
+
action
|
|
24
|
+
] }),
|
|
25
|
+
children
|
|
26
|
+
] });
|
|
27
|
+
}
|
|
28
|
+
var DashboardPage = React.forwardRef(function DashboardPage2({
|
|
29
|
+
title,
|
|
30
|
+
balance,
|
|
31
|
+
quickActions = [],
|
|
32
|
+
stats = [],
|
|
33
|
+
recent = [],
|
|
34
|
+
onSelectTransaction,
|
|
35
|
+
onSeeAllActivity,
|
|
36
|
+
insights = [],
|
|
37
|
+
messages,
|
|
38
|
+
...props
|
|
39
|
+
}, ref) {
|
|
40
|
+
const m = usePageMessages(messages);
|
|
41
|
+
const locale = useTemplateLocale();
|
|
42
|
+
return /* @__PURE__ */ jsx(PageFrame, { ref, width: "lg", title, ...props, children: /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-3", children: [
|
|
43
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-6 lg:col-span-2", children: [
|
|
44
|
+
/* @__PURE__ */ jsxs(Card, { className: "flex flex-col gap-5 p-6", children: [
|
|
45
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
46
|
+
/* @__PURE__ */ jsx("p", { className: "text-label-lg text-[var(--color-on-surface-variant)]", children: balance.label ?? m.totalBalance }),
|
|
47
|
+
/* @__PURE__ */ jsx(Amount, { value: balance.value, currency: balance.currency, locale, size: "display" })
|
|
48
|
+
] }),
|
|
49
|
+
quickActions.length > 0 && /* @__PURE__ */ jsx("ul", { "aria-label": m.quickActions, className: "grid grid-cols-2 gap-2 sm:grid-cols-4", children: quickActions.map((a) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Button, { variant: "secondary", fullWidth: true, onClick: a.onSelect, leadingIcon: a.icon, children: a.label }) }, a.id)) })
|
|
50
|
+
] }),
|
|
51
|
+
stats.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3", children: stats.map((s) => /* @__PURE__ */ jsx(StatCard, { ...s }, s.label)) }),
|
|
52
|
+
recent.length > 0 && /* @__PURE__ */ jsx(
|
|
53
|
+
Panel,
|
|
54
|
+
{
|
|
55
|
+
title: m.recentActivity,
|
|
56
|
+
action: onSeeAllActivity && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onSeeAllActivity, children: m.seeAll }),
|
|
57
|
+
children: /* @__PURE__ */ jsx("ul", { className: "overflow-hidden rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)]", children: recent.map((t) => /* @__PURE__ */ jsx(TransactionRow, { t, onSelect: onSelectTransaction, m, locale }, t.id)) })
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
] }),
|
|
61
|
+
insights.length > 0 && /* @__PURE__ */ jsx(Panel, { title: m.insights, children: /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-3", children: insights.map((i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Card, { className: "flex flex-col gap-2 p-4", children: [
|
|
62
|
+
/* @__PURE__ */ jsx("h3", { className: "text-title-sm text-[var(--color-on-surface)]", children: i.title }),
|
|
63
|
+
/* @__PURE__ */ jsx("p", { className: "text-body-sm text-[var(--color-on-surface-muted)]", children: i.body }),
|
|
64
|
+
i.action && /* @__PURE__ */ jsx(Button, { variant: "link", size: "sm", className: "self-start px-0", onClick: i.action.onSelect, children: i.action.label })
|
|
65
|
+
] }) }, i.id)) }) })
|
|
66
|
+
] }) });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
DashboardPage
|
|
71
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
Conversation
|
|
4
|
+
} from "./chunk-WRP73TXG.js";
|
|
5
|
+
import {
|
|
6
|
+
usePageMessages
|
|
7
|
+
} from "./chunk-7QCJC2DV.js";
|
|
8
|
+
|
|
9
|
+
// src/components/ChatPage/ChatPage.tsx
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import { MessageBubble, PromptInput, ThinkingIndicator, cn } from "@nexub/react";
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
var ChatPage = React.forwardRef(function ChatPage2({
|
|
14
|
+
messages: list,
|
|
15
|
+
onSend,
|
|
16
|
+
onStop,
|
|
17
|
+
thinking,
|
|
18
|
+
placeholder,
|
|
19
|
+
empty,
|
|
20
|
+
assistantAvatar,
|
|
21
|
+
title,
|
|
22
|
+
showTitle = false,
|
|
23
|
+
as: Tag = "main",
|
|
24
|
+
strings,
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
}, ref) {
|
|
28
|
+
const m = usePageMessages(strings);
|
|
29
|
+
const [draft, setDraft] = React.useState("");
|
|
30
|
+
const streaming = list.at(-1)?.streaming ?? false;
|
|
31
|
+
const headingId = React.useId();
|
|
32
|
+
return /* @__PURE__ */ jsxs(
|
|
33
|
+
Tag,
|
|
34
|
+
{
|
|
35
|
+
ref,
|
|
36
|
+
"aria-labelledby": headingId,
|
|
37
|
+
className: cn("flex h-full min-h-0 w-full flex-col", className),
|
|
38
|
+
...props,
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx("h1", { id: headingId, className: showTitle ? "px-4 pt-4 text-title-lg text-[var(--color-on-surface)]" : "sr-only", children: title ?? m.chat }),
|
|
41
|
+
/* @__PURE__ */ jsx(
|
|
42
|
+
Conversation,
|
|
43
|
+
{
|
|
44
|
+
className: "min-h-0 flex-1",
|
|
45
|
+
composer: /* @__PURE__ */ jsx(
|
|
46
|
+
PromptInput,
|
|
47
|
+
{
|
|
48
|
+
value: draft,
|
|
49
|
+
onValueChange: setDraft,
|
|
50
|
+
placeholder,
|
|
51
|
+
status: streaming ? "streaming" : thinking ? "submitting" : "idle",
|
|
52
|
+
onStop,
|
|
53
|
+
onSubmit: (text) => {
|
|
54
|
+
const t = text.trim();
|
|
55
|
+
if (!t) return;
|
|
56
|
+
onSend(t);
|
|
57
|
+
setDraft("");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
children: list.length === 0 && !thinking ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center py-16 text-center text-body-md text-[var(--color-on-surface-muted)]", children: empty ?? m.chatEmpty }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
62
|
+
list.map((msg) => /* @__PURE__ */ jsx(
|
|
63
|
+
MessageBubble,
|
|
64
|
+
{
|
|
65
|
+
from: msg.role,
|
|
66
|
+
avatar: msg.role === "assistant" ? assistantAvatar : void 0,
|
|
67
|
+
"aria-busy": msg.streaming || void 0,
|
|
68
|
+
children: msg.text
|
|
69
|
+
},
|
|
70
|
+
msg.id
|
|
71
|
+
)),
|
|
72
|
+
thinking && /* @__PURE__ */ jsx(ThinkingIndicator, {})
|
|
73
|
+
] })
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
ChatPage
|
|
83
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// src/components/PageFrame/PageFrame.tsx
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { Badge, cn, useLocale, useNexubMessages } from "@nexub/react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
var defaultPageTemplateMessages = {
|
|
8
|
+
activity: "Activity",
|
|
9
|
+
noActivityTitle: "No activity yet",
|
|
10
|
+
noActivityDescription: "Your payments and transfers will show up here.",
|
|
11
|
+
loadMore: "Load more",
|
|
12
|
+
refresh: "Refresh",
|
|
13
|
+
pending: "Pending",
|
|
14
|
+
failed: "Failed",
|
|
15
|
+
completed: "Completed",
|
|
16
|
+
date: "Date",
|
|
17
|
+
details: "Details",
|
|
18
|
+
back: "Back",
|
|
19
|
+
settings: "Settings",
|
|
20
|
+
signIn: "Sign in",
|
|
21
|
+
email: "Email",
|
|
22
|
+
password: "Password",
|
|
23
|
+
forgotPassword: "Forgot password?",
|
|
24
|
+
createAccount: "Create an account",
|
|
25
|
+
howMuch: "How much?",
|
|
26
|
+
amountToSend: "Amount to send",
|
|
27
|
+
balance: (b) => `Balance ${b}`,
|
|
28
|
+
overBalance: (b) => `More than your balance (${b})`,
|
|
29
|
+
fee: "Fee",
|
|
30
|
+
rate: "Rate",
|
|
31
|
+
recipientGets: "Recipient gets",
|
|
32
|
+
arrives: "Arrives",
|
|
33
|
+
continue: "Continue",
|
|
34
|
+
checkDetails: "Check the details",
|
|
35
|
+
edit: "Edit",
|
|
36
|
+
done: "Done",
|
|
37
|
+
stepOf: (s, t) => `Step ${s} of ${t}`,
|
|
38
|
+
sent: "Sent",
|
|
39
|
+
chat: "Chat",
|
|
40
|
+
chatEmpty: "Ask anything to get started.",
|
|
41
|
+
restorePurchases: "Restore purchases",
|
|
42
|
+
choosePlan: "Choose a plan",
|
|
43
|
+
totalBalance: "Total balance",
|
|
44
|
+
quickActions: "Quick actions",
|
|
45
|
+
recentActivity: "Recent activity",
|
|
46
|
+
seeAll: "See all",
|
|
47
|
+
insights: "Insights"
|
|
48
|
+
};
|
|
49
|
+
function usePageMessages(overrides) {
|
|
50
|
+
const provided = useNexubMessages();
|
|
51
|
+
const out = { ...defaultPageTemplateMessages };
|
|
52
|
+
for (const key of Object.keys(out)) {
|
|
53
|
+
const v = overrides?.[key] ?? provided[key];
|
|
54
|
+
if (v !== void 0 && typeof v === typeof out[key]) out[key] = v;
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
function formatMoney(value, currency, locale, opts) {
|
|
59
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency, ...opts }).format(value);
|
|
60
|
+
}
|
|
61
|
+
function groupByDay(transactions, locale) {
|
|
62
|
+
const day = new Intl.DateTimeFormat(locale, { dateStyle: "medium" });
|
|
63
|
+
const map = /* @__PURE__ */ new Map();
|
|
64
|
+
for (const t of [...transactions].sort((a, b) => +b.date - +a.date)) {
|
|
65
|
+
const key = day.format(t.date);
|
|
66
|
+
map.set(key, [...map.get(key) ?? [], t]);
|
|
67
|
+
}
|
|
68
|
+
return [...map].map(([title, data]) => ({ title, data }));
|
|
69
|
+
}
|
|
70
|
+
function useTemplateLocale() {
|
|
71
|
+
return useLocale().locale;
|
|
72
|
+
}
|
|
73
|
+
function StatusBadge({ status, m, dot }) {
|
|
74
|
+
if (!status) return null;
|
|
75
|
+
return /* @__PURE__ */ jsxs(Badge, { tone: status === "failed" ? "danger" : "warning", size: "sm", children: [
|
|
76
|
+
dot && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "me-1 inline-block h-1.5 w-1.5 rounded-full bg-current" }),
|
|
77
|
+
status === "failed" ? m.failed : m.pending
|
|
78
|
+
] });
|
|
79
|
+
}
|
|
80
|
+
var widths = { sm: "max-w-[480px]", md: "max-w-3xl", lg: "max-w-6xl" };
|
|
81
|
+
var PageFrame = React.forwardRef(function PageFrame2({ as: Tag = "main", title, description, actions, eyebrow, width = "md", className, children, ...props }, ref) {
|
|
82
|
+
const headingId = React.useId();
|
|
83
|
+
return /* @__PURE__ */ jsxs(
|
|
84
|
+
Tag,
|
|
85
|
+
{
|
|
86
|
+
ref,
|
|
87
|
+
"aria-labelledby": title ? headingId : void 0,
|
|
88
|
+
className: cn("mx-auto flex w-full flex-col gap-6 px-4 py-6 sm:px-6 lg:py-10", widths[width], className),
|
|
89
|
+
...props,
|
|
90
|
+
children: [
|
|
91
|
+
(title || actions || eyebrow) && /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-2", children: [
|
|
92
|
+
eyebrow,
|
|
93
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
94
|
+
title && /* @__PURE__ */ jsx("h1", { id: headingId, className: "text-headline-sm text-[var(--color-on-surface)]", children: title }),
|
|
95
|
+
actions && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: actions })
|
|
96
|
+
] }),
|
|
97
|
+
description && /* @__PURE__ */ jsx("p", { className: "text-body-md text-[var(--color-on-surface-muted)]", children: description })
|
|
98
|
+
] }),
|
|
99
|
+
children
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
defaultPageTemplateMessages,
|
|
107
|
+
usePageMessages,
|
|
108
|
+
formatMoney,
|
|
109
|
+
groupByDay,
|
|
110
|
+
useTemplateLocale,
|
|
111
|
+
StatusBadge,
|
|
112
|
+
PageFrame
|
|
113
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
InfoList
|
|
4
|
+
} from "./chunk-WPNT5JOU.js";
|
|
5
|
+
import {
|
|
6
|
+
PageFrame,
|
|
7
|
+
usePageMessages,
|
|
8
|
+
useTemplateLocale
|
|
9
|
+
} from "./chunk-7QCJC2DV.js";
|
|
10
|
+
|
|
11
|
+
// src/components/TransactionDetailPage/TransactionDetailPage.tsx
|
|
12
|
+
import * as React from "react";
|
|
13
|
+
import { Amount, Avatar, Badge, Button } from "@nexub/react";
|
|
14
|
+
import { ArrowLeft } from "@nexub/icons";
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
var TransactionDetailPage = React.forwardRef(
|
|
17
|
+
function TransactionDetailPage2({ transaction: t, rows = [], footer, onBack, messages, ...props }, ref) {
|
|
18
|
+
const m = usePageMessages(messages);
|
|
19
|
+
const locale = useTemplateLocale();
|
|
20
|
+
const headingId = React.useId();
|
|
21
|
+
const when = new Intl.DateTimeFormat(locale, { dateStyle: "full", timeStyle: "short" }).format(t.date);
|
|
22
|
+
return /* @__PURE__ */ jsxs(PageFrame, { ref, width: "sm", "aria-labelledby": headingId, ...props, children: [
|
|
23
|
+
onBack && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "self-start", onClick: onBack, leadingIcon: /* @__PURE__ */ jsx(ArrowLeft, { size: "sm", className: "rtl:-scale-x-100", "aria-hidden": "true" }), children: m.back }),
|
|
24
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-4 text-center", children: [
|
|
25
|
+
/* @__PURE__ */ jsx(Avatar, { name: t.title, src: t.image, size: "xl" }),
|
|
26
|
+
/* @__PURE__ */ jsx("h1", { id: headingId, className: "text-title-lg text-[var(--color-on-surface)]", children: t.title }),
|
|
27
|
+
/* @__PURE__ */ jsx(Amount, { value: t.amount, currency: t.currency, locale, size: "display", tone: "auto", signDisplay: "exceptZero" }),
|
|
28
|
+
/* @__PURE__ */ jsx(Badge, { tone: t.status === "failed" ? "danger" : t.status === "pending" ? "warning" : "success", children: t.status === "failed" ? m.failed : t.status === "pending" ? m.pending : m.completed })
|
|
29
|
+
] }),
|
|
30
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)] px-4", children: /* @__PURE__ */ jsxs(InfoList.Root, { children: [
|
|
31
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.date, value: when }),
|
|
32
|
+
t.subtitle && /* @__PURE__ */ jsx(InfoList.Item, { label: m.details, value: t.subtitle }),
|
|
33
|
+
rows.map((r) => /* @__PURE__ */ jsx(InfoList.Item, { label: r.label, value: r.value }, r.label))
|
|
34
|
+
] }) }),
|
|
35
|
+
footer && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 sm:flex-row sm:justify-center", children: footer })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
TransactionDetailPage
|
|
42
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use client';
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
InfoList
|
|
4
|
+
} from "./chunk-WPNT5JOU.js";
|
|
5
|
+
import {
|
|
6
|
+
PageFrame,
|
|
7
|
+
formatMoney,
|
|
8
|
+
usePageMessages,
|
|
9
|
+
useTemplateLocale
|
|
10
|
+
} from "./chunk-7QCJC2DV.js";
|
|
11
|
+
|
|
12
|
+
// src/components/CheckoutPage/CheckoutPage.tsx
|
|
13
|
+
import * as React from "react";
|
|
14
|
+
import { Alert, Amount, Button, FormField, MoneyInput, Progress } from "@nexub/react";
|
|
15
|
+
import { CheckCircle2, ShieldCheck } from "@nexub/icons";
|
|
16
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
17
|
+
var CheckoutPage = React.forwardRef(function CheckoutPage2({
|
|
18
|
+
from,
|
|
19
|
+
to,
|
|
20
|
+
balance,
|
|
21
|
+
quote,
|
|
22
|
+
reviewRows,
|
|
23
|
+
confirmLabel,
|
|
24
|
+
confirmHint,
|
|
25
|
+
onConfirm,
|
|
26
|
+
resultTitle,
|
|
27
|
+
resultDescription,
|
|
28
|
+
onDone,
|
|
29
|
+
messages,
|
|
30
|
+
...props
|
|
31
|
+
}, ref) {
|
|
32
|
+
const m = usePageMessages(messages);
|
|
33
|
+
const locale = useTemplateLocale();
|
|
34
|
+
const [step, setStep] = React.useState("amount");
|
|
35
|
+
const [amount, setAmount] = React.useState(null);
|
|
36
|
+
const [busy, setBusy] = React.useState(false);
|
|
37
|
+
const [error, setError] = React.useState();
|
|
38
|
+
const headingRef = React.useRef(null);
|
|
39
|
+
const fmt = (n, c) => formatMoney(n, c, locale);
|
|
40
|
+
const over = amount != null && amount > balance;
|
|
41
|
+
const q = amount && !over ? quote(amount) : void 0;
|
|
42
|
+
const index = step === "amount" ? 1 : step === "review" ? 2 : 3;
|
|
43
|
+
const first = React.useRef(true);
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
if (first.current) {
|
|
46
|
+
first.current = false;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
headingRef.current?.focus();
|
|
50
|
+
}, [step]);
|
|
51
|
+
const rows = amount && q ? reviewRows?.(amount, q) ?? [
|
|
52
|
+
{ label: m.amountToSend, value: fmt(amount, from) },
|
|
53
|
+
{ label: m.fee, value: fmt(q.fee, from) },
|
|
54
|
+
{ label: m.rate, value: `1 ${from} = ${q.rate} ${to}` },
|
|
55
|
+
{ label: m.recipientGets, value: fmt((amount - q.fee) * q.rate, to) },
|
|
56
|
+
{ label: m.arrives, value: q.arrives }
|
|
57
|
+
] : [];
|
|
58
|
+
const confirm = async () => {
|
|
59
|
+
if (!amount) return;
|
|
60
|
+
setBusy(true);
|
|
61
|
+
setError(void 0);
|
|
62
|
+
try {
|
|
63
|
+
await onConfirm(amount);
|
|
64
|
+
setStep("done");
|
|
65
|
+
} catch (e) {
|
|
66
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
67
|
+
} finally {
|
|
68
|
+
setBusy(false);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const title = step === "amount" ? m.howMuch : step === "review" ? m.checkDetails : resultTitle ?? m.sent;
|
|
72
|
+
return /* @__PURE__ */ jsxs(PageFrame, { ref, width: "sm", ...props, children: [
|
|
73
|
+
step !== "done" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
74
|
+
/* @__PURE__ */ jsx(Progress, { value: index, max: 3, "aria-label": m.stepOf(index, 3) }),
|
|
75
|
+
/* @__PURE__ */ jsx("p", { className: "text-label-md text-[var(--color-on-surface-variant)]", children: m.stepOf(index, 3) })
|
|
76
|
+
] }),
|
|
77
|
+
step === "done" ? /* @__PURE__ */ jsxs("div", { role: "status", className: "flex flex-col items-center gap-4 py-8 text-center", children: [
|
|
78
|
+
/* @__PURE__ */ jsx("span", { className: "grid h-20 w-20 place-items-center rounded-full bg-[var(--color-success-container)] text-[var(--color-success)]", children: /* @__PURE__ */ jsx(CheckCircle2, { size: 40, "aria-hidden": "true" }) }),
|
|
79
|
+
/* @__PURE__ */ jsx("h1", { ref: headingRef, tabIndex: -1, className: "text-headline-sm text-[var(--color-on-surface)] outline-none", children: title }),
|
|
80
|
+
amount != null && /* @__PURE__ */ jsx(Amount, { value: amount, currency: from, locale, size: "display" }),
|
|
81
|
+
resultDescription && /* @__PURE__ */ jsx("p", { className: "text-body-md text-[var(--color-on-surface-muted)]", children: resultDescription }),
|
|
82
|
+
/* @__PURE__ */ jsx(Button, { size: "lg", fullWidth: true, onClick: onDone, children: m.done })
|
|
83
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
84
|
+
/* @__PURE__ */ jsx("h1", { ref: headingRef, tabIndex: -1, className: "text-headline-sm text-[var(--color-on-surface)] outline-none", children: title }),
|
|
85
|
+
step === "amount" && /* @__PURE__ */ jsxs(
|
|
86
|
+
"form",
|
|
87
|
+
{
|
|
88
|
+
className: "flex flex-col gap-6",
|
|
89
|
+
onSubmit: (e) => {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
if (amount && !over) setStep("review");
|
|
92
|
+
},
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsxs(FormField.Root, { invalid: over, children: [
|
|
95
|
+
/* @__PURE__ */ jsx(FormField.Label, { children: m.amountToSend }),
|
|
96
|
+
/* @__PURE__ */ jsx(FormField.Control, { children: /* @__PURE__ */ jsx(MoneyInput, { currency: from, locale, value: amount, onValueChange: setAmount }) }),
|
|
97
|
+
over ? /* @__PURE__ */ jsx(FormField.Error, { children: m.overBalance(fmt(balance, from)) }) : /* @__PURE__ */ jsx(FormField.Description, { children: m.balance(fmt(balance, from)) })
|
|
98
|
+
] }),
|
|
99
|
+
q && amount && /* @__PURE__ */ jsx("div", { "aria-live": "polite", className: "rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)] px-4", children: /* @__PURE__ */ jsxs(InfoList.Root, { children: [
|
|
100
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.fee, value: fmt(q.fee, from) }),
|
|
101
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.rate, value: `1 ${from} = ${q.rate} ${to}` }),
|
|
102
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.recipientGets, value: fmt((amount - q.fee) * q.rate, to) }),
|
|
103
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.arrives, value: q.arrives })
|
|
104
|
+
] }) }),
|
|
105
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", size: "lg", fullWidth: true, disabled: !amount || over, children: m.continue })
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
step === "review" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
110
|
+
error && /* @__PURE__ */ jsx(Alert, { tone: "danger", role: "alert", children: error }),
|
|
111
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)] px-4", children: /* @__PURE__ */ jsx(InfoList.Root, { children: rows.map((r) => /* @__PURE__ */ jsx(InfoList.Item, { label: r.label, value: r.value }, r.label)) }) }),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
Button,
|
|
115
|
+
{
|
|
116
|
+
size: "lg",
|
|
117
|
+
fullWidth: true,
|
|
118
|
+
loading: busy,
|
|
119
|
+
leadingIcon: confirmHint ? /* @__PURE__ */ jsx(ShieldCheck, { size: "sm", "aria-hidden": "true" }) : void 0,
|
|
120
|
+
onClick: confirm,
|
|
121
|
+
children: confirmLabel
|
|
122
|
+
}
|
|
123
|
+
),
|
|
124
|
+
confirmHint && /* @__PURE__ */ jsx("p", { className: "text-center text-body-sm text-[var(--color-on-surface-muted)]", children: confirmHint }),
|
|
125
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "lg", fullWidth: true, disabled: busy, onClick: () => setStep("amount"), children: m.edit })
|
|
126
|
+
] })
|
|
127
|
+
] })
|
|
128
|
+
] })
|
|
129
|
+
] });
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
CheckoutPage
|
|
134
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
PageFrame,
|
|
4
|
+
usePageMessages
|
|
5
|
+
} from "./chunk-7QCJC2DV.js";
|
|
6
|
+
|
|
7
|
+
// src/components/PaywallPage/PaywallPage.tsx
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { Badge, Button, RadioCard, RadioCardGroup } from "@nexub/react";
|
|
10
|
+
import { Check } from "@nexub/icons";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
var PaywallPage = React.forwardRef(function PaywallPage2({ title, description, plans, defaultPlan, onSubscribe, onRestore, terms, loading, messages, ...props }, ref) {
|
|
13
|
+
const m = usePageMessages(messages);
|
|
14
|
+
const [plan, setPlan] = React.useState(defaultPlan ?? plans[0]?.id);
|
|
15
|
+
return /* @__PURE__ */ jsxs(PageFrame, { ref, width: "sm", title, description, ...props, children: [
|
|
16
|
+
/* @__PURE__ */ jsx(RadioCardGroup, { value: plan, onValueChange: setPlan, "aria-label": m.choosePlan, columns: 1, children: plans.map((p) => /* @__PURE__ */ jsx(
|
|
17
|
+
RadioCard,
|
|
18
|
+
{
|
|
19
|
+
value: p.id,
|
|
20
|
+
title: /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [
|
|
21
|
+
p.name,
|
|
22
|
+
p.badge && /* @__PURE__ */ jsx(Badge, { tone: "info", size: "sm", children: p.badge })
|
|
23
|
+
] }),
|
|
24
|
+
description: p.price,
|
|
25
|
+
children: /* @__PURE__ */ jsx("ul", { className: "mt-2 flex flex-col gap-1.5", children: p.features.map((f) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2 text-body-sm text-[var(--color-on-surface-variant)]", children: [
|
|
26
|
+
/* @__PURE__ */ jsx(Check, { size: "sm", "aria-hidden": "true", className: "mt-0.5 shrink-0 text-[var(--color-success)]" }),
|
|
27
|
+
f
|
|
28
|
+
] }, f)) })
|
|
29
|
+
},
|
|
30
|
+
p.id
|
|
31
|
+
)) }),
|
|
32
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
33
|
+
/* @__PURE__ */ jsx(Button, { size: "lg", fullWidth: true, loading, disabled: !plan, onClick: () => plan && onSubscribe(plan), children: m.continue }),
|
|
34
|
+
onRestore && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "lg", fullWidth: true, onClick: onRestore, children: m.restorePurchases }),
|
|
35
|
+
terms && /* @__PURE__ */ jsx("p", { className: "text-center text-label-sm text-[var(--color-on-surface-muted)]", children: terms })
|
|
36
|
+
] })
|
|
37
|
+
] });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
PaywallPage
|
|
42
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
PageFrame,
|
|
4
|
+
StatusBadge,
|
|
5
|
+
groupByDay,
|
|
6
|
+
usePageMessages,
|
|
7
|
+
useTemplateLocale
|
|
8
|
+
} from "./chunk-7QCJC2DV.js";
|
|
9
|
+
|
|
10
|
+
// src/components/ActivityPage/ActivityPage.tsx
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import { Amount, Avatar, Button, EmptyState, cn } from "@nexub/react";
|
|
13
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
function TransactionRow({
|
|
15
|
+
t,
|
|
16
|
+
onSelect,
|
|
17
|
+
actions,
|
|
18
|
+
m,
|
|
19
|
+
locale
|
|
20
|
+
}) {
|
|
21
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22
|
+
/* @__PURE__ */ jsx(Avatar, { name: t.title, src: t.image }),
|
|
23
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col text-start", children: [
|
|
24
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-body-md font-medium text-[var(--color-on-surface)]", children: t.title }),
|
|
25
|
+
t.subtitle && /* @__PURE__ */ jsx("span", { className: "truncate text-body-sm text-[var(--color-on-surface-muted)]", children: t.subtitle })
|
|
26
|
+
] }),
|
|
27
|
+
/* @__PURE__ */ jsxs("span", { className: "flex shrink-0 flex-col items-end gap-1", children: [
|
|
28
|
+
/* @__PURE__ */ jsx(Amount, { value: t.amount, currency: t.currency, locale, tone: "auto", signDisplay: "exceptZero" }),
|
|
29
|
+
/* @__PURE__ */ jsx(StatusBadge, { status: t.status, m })
|
|
30
|
+
] })
|
|
31
|
+
] });
|
|
32
|
+
const row = "flex w-full items-center gap-3 px-4 py-3";
|
|
33
|
+
return /* @__PURE__ */ jsxs("li", { className: "flex items-center border-t border-[var(--color-outline-variant)] first:border-t-0", children: [
|
|
34
|
+
onSelect ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onSelect(t), className: cn(row, "nx-state-layer min-h-[56px]"), children: body }) : /* @__PURE__ */ jsx("div", { className: row, children: body }),
|
|
35
|
+
actions && /* @__PURE__ */ jsx("div", { className: "shrink-0 pe-2", children: actions })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
var ActivityPage = React.forwardRef(function ActivityPage2({
|
|
39
|
+
transactions,
|
|
40
|
+
onSelect,
|
|
41
|
+
onRefresh,
|
|
42
|
+
refreshing,
|
|
43
|
+
onLoadMore,
|
|
44
|
+
hasMore,
|
|
45
|
+
loadingMore,
|
|
46
|
+
rowActions,
|
|
47
|
+
toolbar,
|
|
48
|
+
empty,
|
|
49
|
+
title,
|
|
50
|
+
actions,
|
|
51
|
+
messages,
|
|
52
|
+
...props
|
|
53
|
+
}, ref) {
|
|
54
|
+
const m = usePageMessages(messages);
|
|
55
|
+
const locale = useTemplateLocale();
|
|
56
|
+
const sections = React.useMemo(() => groupByDay(transactions, locale), [transactions, locale]);
|
|
57
|
+
return /* @__PURE__ */ jsxs(
|
|
58
|
+
PageFrame,
|
|
59
|
+
{
|
|
60
|
+
ref,
|
|
61
|
+
title: title ?? m.activity,
|
|
62
|
+
actions: (actions || onRefresh) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
63
|
+
actions,
|
|
64
|
+
onRefresh && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onRefresh, loading: refreshing, children: m.refresh })
|
|
65
|
+
] }),
|
|
66
|
+
...props,
|
|
67
|
+
children: [
|
|
68
|
+
toolbar,
|
|
69
|
+
sections.length === 0 ? empty ?? /* @__PURE__ */ jsxs(EmptyState.Root, { children: [
|
|
70
|
+
/* @__PURE__ */ jsx(EmptyState.Title, { children: m.noActivityTitle }),
|
|
71
|
+
/* @__PURE__ */ jsx(EmptyState.Description, { children: m.noActivityDescription })
|
|
72
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", "aria-busy": refreshing || void 0, children: [
|
|
73
|
+
sections.map((s) => /* @__PURE__ */ jsxs("section", { "aria-label": s.title, className: "flex flex-col gap-2", children: [
|
|
74
|
+
/* @__PURE__ */ jsx("h2", { className: "px-1 text-title-sm text-[var(--color-on-surface-variant)]", children: s.title }),
|
|
75
|
+
/* @__PURE__ */ jsx("ul", { className: "overflow-hidden rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)]", children: s.data.map((t) => /* @__PURE__ */ jsx(TransactionRow, { t, onSelect, actions: rowActions?.(t), m, locale }, t.id)) })
|
|
76
|
+
] }, s.title)),
|
|
77
|
+
onLoadMore && hasMore && /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "self-center", onClick: onLoadMore, loading: loadingMore, children: m.loadMore })
|
|
78
|
+
] })
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
TransactionRow,
|
|
86
|
+
ActivityPage
|
|
87
|
+
};
|