@korsolutions/ui 0.0.16 → 0.0.18
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/dist/components/index.d.mts +32 -2
- package/dist/components/index.mjs +10 -17
- package/dist/{index-Dyo-iQyH.d.mts → index-Bfae0NgJ.d.mts} +40 -1
- package/dist/index.mjs +7 -3
- package/dist/primitives/index.d.mts +2 -2
- package/dist/primitives/index.mjs +2 -3
- package/dist/{primitives-BKUnaQrI.mjs → primitives-B4L9y32H.mjs} +110 -4
- package/dist/toast-manager-Vq38WK76.mjs +281 -0
- package/package.json +1 -1
- package/src/components/index.ts +1 -0
- package/src/components/toast/index.ts +7 -0
- package/src/components/toast/toast-manager.tsx +104 -0
- package/src/components/toast/toast.tsx +22 -0
- package/src/components/toast/variants/danger.tsx +31 -0
- package/src/components/toast/variants/default.tsx +30 -0
- package/src/components/toast/variants/index.ts +9 -0
- package/src/components/toast/variants/success.tsx +31 -0
- package/src/index.tsx +2 -0
- package/src/primitives/index.ts +1 -0
- package/src/primitives/toast/context.ts +16 -0
- package/src/primitives/toast/index.ts +14 -0
- package/src/primitives/toast/toast-description.tsx +20 -0
- package/src/primitives/toast/toast-root.tsx +28 -0
- package/src/primitives/toast/toast-title.tsx +20 -0
- package/src/primitives/toast/types.ts +9 -0
- package/dist/portal-jF1KeGnu.mjs +0 -61
- package/dist/themes-pgmHo7MU.mjs +0 -90
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as
|
|
1
|
+
import { B as InputPrimitiveBaseProps, E as SelectRootBaseProps, G as FieldStyles, H as InputStyles, L as ButtonStyles, O as SelectStyles, c as AvatarStyles, p as EmptyStyles, r as ToastStyles, y as CardStyles } from "../index-Bfae0NgJ.mjs";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { ImageSource, TextProps, TextStyle } from "react-native";
|
|
4
4
|
|
|
@@ -166,4 +166,34 @@ interface AvatarProps {
|
|
|
166
166
|
}
|
|
167
167
|
declare function Avatar(props: AvatarProps): React.JSX.Element;
|
|
168
168
|
//#endregion
|
|
169
|
-
|
|
169
|
+
//#region src/components/toast/variants/index.d.ts
|
|
170
|
+
declare const ToastVariants: {
|
|
171
|
+
default: () => ToastStyles;
|
|
172
|
+
success: () => ToastStyles;
|
|
173
|
+
danger: () => ToastStyles;
|
|
174
|
+
};
|
|
175
|
+
//#endregion
|
|
176
|
+
//#region src/components/toast/toast-manager.d.ts
|
|
177
|
+
interface ToastConfig {
|
|
178
|
+
id: string;
|
|
179
|
+
title: string;
|
|
180
|
+
description?: string;
|
|
181
|
+
variant?: keyof typeof ToastVariants;
|
|
182
|
+
duration?: number;
|
|
183
|
+
}
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/components/toast/toast.d.ts
|
|
186
|
+
interface ToastProps {
|
|
187
|
+
title: string;
|
|
188
|
+
description?: string;
|
|
189
|
+
variant?: keyof typeof ToastVariants;
|
|
190
|
+
}
|
|
191
|
+
declare function ToastComponent(props: ToastProps): React.JSX.Element;
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/components/toast/index.d.ts
|
|
194
|
+
declare const Toast: typeof ToastComponent & {
|
|
195
|
+
show: (config: ToastConfig) => string;
|
|
196
|
+
dismiss: (id: string) => void;
|
|
197
|
+
};
|
|
198
|
+
//#endregion
|
|
199
|
+
export { Avatar, AvatarProps, Button, Card, Empty, EmptyProps, Field, FieldProps, Input, Link, LinkProps, Select, SelectOption, SelectProps, Toast, Typography, TypographyProps };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "../
|
|
3
|
-
import { a as ButtonPrimitive, i as SelectPrimitive, n as EmptyPrimitive, o as InputPrimitive, r as CardPrimitive, s as FieldPrimitive, t as AvatarPrimitive } from "../primitives-BKUnaQrI.mjs";
|
|
1
|
+
import { i as useThemedStyles, r as ToastComponent, t as ToastAPI } from "../toast-manager-Vq38WK76.mjs";
|
|
2
|
+
import { a as SelectPrimitive, c as FieldPrimitive, i as CardPrimitive, n as AvatarPrimitive, o as ButtonPrimitive, r as EmptyPrimitive, s as InputPrimitive } from "../primitives-B4L9y32H.mjs";
|
|
4
3
|
import React, { useState } from "react";
|
|
5
4
|
import { Linking, Text } from "react-native";
|
|
6
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -23,19 +22,6 @@ const hslaSetRelativeLightness = (hsla, delta) => {
|
|
|
23
22
|
return hslaSetLightness(hsla, newLightness);
|
|
24
23
|
};
|
|
25
24
|
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region src/utils/use-themed-styles.ts
|
|
28
|
-
const useThemedStyles = (callback) => {
|
|
29
|
-
const theme = useTheme();
|
|
30
|
-
return callback({
|
|
31
|
-
colors: theme.colors,
|
|
32
|
-
radius: theme.radius,
|
|
33
|
-
fontFamily: theme.fontFamily,
|
|
34
|
-
letterSpacing: theme.letterSpacing,
|
|
35
|
-
fontSize: theme.fontSize
|
|
36
|
-
});
|
|
37
|
-
};
|
|
38
|
-
|
|
39
25
|
//#endregion
|
|
40
26
|
//#region src/components/button/variants/default.tsx
|
|
41
27
|
const useButtonVariantDefault = () => {
|
|
@@ -581,4 +567,11 @@ function Avatar(props) {
|
|
|
581
567
|
}
|
|
582
568
|
|
|
583
569
|
//#endregion
|
|
584
|
-
|
|
570
|
+
//#region src/components/toast/index.ts
|
|
571
|
+
const Toast = Object.assign(ToastComponent, {
|
|
572
|
+
show: ToastAPI.show,
|
|
573
|
+
dismiss: ToastAPI.dismiss
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
//#endregion
|
|
577
|
+
export { Avatar, Button, Card, Empty, Field, Input, Link, Select, Toast, Typography };
|
|
@@ -351,4 +351,43 @@ declare const AvatarPrimitive: {
|
|
|
351
351
|
Fallback: typeof AvatarFallback;
|
|
352
352
|
};
|
|
353
353
|
//#endregion
|
|
354
|
-
|
|
354
|
+
//#region src/primitives/toast/toast-title.d.ts
|
|
355
|
+
interface ToastTitleProps {
|
|
356
|
+
children?: string;
|
|
357
|
+
render?: (props: ToastTitleProps) => React$1.ReactNode;
|
|
358
|
+
style?: StyleProp<TextStyle>;
|
|
359
|
+
}
|
|
360
|
+
declare function ToastTitle(props: ToastTitleProps): React$1.JSX.Element;
|
|
361
|
+
//#endregion
|
|
362
|
+
//#region src/primitives/toast/toast-description.d.ts
|
|
363
|
+
interface ToastDescriptionProps {
|
|
364
|
+
children?: string;
|
|
365
|
+
render?: (props: ToastDescriptionProps) => React$1.ReactNode;
|
|
366
|
+
style?: StyleProp<TextStyle>;
|
|
367
|
+
}
|
|
368
|
+
declare function ToastDescription(props: ToastDescriptionProps): React$1.JSX.Element;
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/primitives/toast/types.d.ts
|
|
371
|
+
interface ToastStyles {
|
|
372
|
+
root?: ToastRootProps["style"];
|
|
373
|
+
title?: ToastTitleProps["style"];
|
|
374
|
+
description?: ToastDescriptionProps["style"];
|
|
375
|
+
}
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/primitives/toast/toast-root.d.ts
|
|
378
|
+
interface ToastRootProps {
|
|
379
|
+
children?: React$1.ReactNode;
|
|
380
|
+
render?: (props: ToastRootProps) => React$1.ReactNode;
|
|
381
|
+
style?: StyleProp<ViewStyle>;
|
|
382
|
+
styles?: ToastStyles;
|
|
383
|
+
}
|
|
384
|
+
declare function ToastRoot(props: ToastRootProps): React$1.JSX.Element;
|
|
385
|
+
//#endregion
|
|
386
|
+
//#region src/primitives/toast/index.d.ts
|
|
387
|
+
declare const ToastPrimitive: {
|
|
388
|
+
Root: typeof ToastRoot;
|
|
389
|
+
Title: typeof ToastTitle;
|
|
390
|
+
Description: typeof ToastDescription;
|
|
391
|
+
};
|
|
392
|
+
//#endregion
|
|
393
|
+
export { SelectContentProps as A, InputPrimitiveBaseProps as B, CardHeaderProps as C, SelectRootProps as D, SelectRootBaseProps as E, ButtonPrimitiveRootProps as F, FieldStyles as G, InputStyles as H, ButtonState as I, FieldLabelProps as J, FieldErrorProps as K, ButtonStyles as L, SelectValueProps as M, SelectTriggerProps as N, SelectStyles as O, ButtonPrimitive as P, ButtonPrimitiveLabelProps as R, CardTitleProps as S, SelectPortalProps as T, FieldPrimitive as U, InputPrimitiveProps as V, FieldPrimitiveRootProps as W, CardPrimitive as _, ToastTitleProps as a, CardFooterProps as b, AvatarStyles as c, EmptyPrimitive as d, EmptyRootProps as f, EmptyDescriptionProps as g, EmptyMediaProps as h, ToastDescriptionProps as i, SelectOverlayProps as j, SelectOptionProps as k, AvatarImageProps as l, EmptyTitleProps as m, ToastRootProps as n, AvatarPrimitive as o, EmptyStyles as p, FieldDescriptionProps as q, ToastStyles as r, AvatarRootProps as s, ToastPrimitive as t, AvatarFallbackProps as u, CardRootProps as v, SelectPrimitive as w, CardBodyProps as x, CardStyles as y, InputPrimitive as z };
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import {
|
|
1
|
+
import { a as ThemeProvider, n as ToastContainer, o as useTheme } from "./toast-manager-Vq38WK76.mjs";
|
|
2
|
+
import { l as PortalHost } from "./primitives-B4L9y32H.mjs";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/index.tsx
|
|
6
6
|
const UniversalUIProvider = ({ children }) => {
|
|
7
|
-
return /* @__PURE__ */ jsxs(ThemeProvider, { children: [
|
|
7
|
+
return /* @__PURE__ */ jsxs(ThemeProvider, { children: [
|
|
8
|
+
children,
|
|
9
|
+
/* @__PURE__ */ jsx(PortalHost, {}),
|
|
10
|
+
/* @__PURE__ */ jsx(ToastContainer, {})
|
|
11
|
+
] });
|
|
8
12
|
};
|
|
9
13
|
|
|
10
14
|
//#endregion
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { AvatarFallbackProps, AvatarImageProps, AvatarPrimitive, AvatarRootProps, AvatarStyles, ButtonPrimitive, ButtonPrimitiveLabelProps, ButtonPrimitiveRootProps, ButtonState, ButtonStyles, CardBodyProps, CardFooterProps, CardHeaderProps, CardPrimitive, CardRootProps, CardStyles, CardTitleProps, EmptyDescriptionProps, EmptyMediaProps, EmptyPrimitive, EmptyRootProps, EmptyStyles, EmptyTitleProps, FieldDescriptionProps, FieldErrorProps, FieldLabelProps, FieldPrimitive, FieldPrimitiveRootProps, FieldStyles, InputPrimitive, InputPrimitiveBaseProps, InputPrimitiveProps, InputStyles, SelectContentProps, SelectOptionProps, SelectOverlayProps, SelectPortalProps, SelectPrimitive, SelectRootBaseProps, SelectRootProps, SelectStyles, SelectTriggerProps, SelectValueProps };
|
|
1
|
+
import { A as SelectContentProps, B as InputPrimitiveBaseProps, C as CardHeaderProps, D as SelectRootProps, E as SelectRootBaseProps, F as ButtonPrimitiveRootProps, G as FieldStyles, H as InputStyles, I as ButtonState, J as FieldLabelProps, K as FieldErrorProps, L as ButtonStyles, M as SelectValueProps, N as SelectTriggerProps, O as SelectStyles, P as ButtonPrimitive, R as ButtonPrimitiveLabelProps, S as CardTitleProps, T as SelectPortalProps, U as FieldPrimitive, V as InputPrimitiveProps, W as FieldPrimitiveRootProps, _ as CardPrimitive, a as ToastTitleProps, b as CardFooterProps, c as AvatarStyles, d as EmptyPrimitive, f as EmptyRootProps, g as EmptyDescriptionProps, h as EmptyMediaProps, i as ToastDescriptionProps, j as SelectOverlayProps, k as SelectOptionProps, l as AvatarImageProps, m as EmptyTitleProps, n as ToastRootProps, o as AvatarPrimitive, p as EmptyStyles, q as FieldDescriptionProps, r as ToastStyles, s as AvatarRootProps, t as ToastPrimitive, u as AvatarFallbackProps, v as CardRootProps, w as SelectPrimitive, x as CardBodyProps, y as CardStyles, z as InputPrimitive } from "../index-Bfae0NgJ.mjs";
|
|
2
|
+
export { AvatarFallbackProps, AvatarImageProps, AvatarPrimitive, AvatarRootProps, AvatarStyles, ButtonPrimitive, ButtonPrimitiveLabelProps, ButtonPrimitiveRootProps, ButtonState, ButtonStyles, CardBodyProps, CardFooterProps, CardHeaderProps, CardPrimitive, CardRootProps, CardStyles, CardTitleProps, EmptyDescriptionProps, EmptyMediaProps, EmptyPrimitive, EmptyRootProps, EmptyStyles, EmptyTitleProps, FieldDescriptionProps, FieldErrorProps, FieldLabelProps, FieldPrimitive, FieldPrimitiveRootProps, FieldStyles, InputPrimitive, InputPrimitiveBaseProps, InputPrimitiveProps, InputStyles, SelectContentProps, SelectOptionProps, SelectOverlayProps, SelectPortalProps, SelectPrimitive, SelectRootBaseProps, SelectRootProps, SelectStyles, SelectTriggerProps, SelectValueProps, ToastDescriptionProps, ToastPrimitive, ToastRootProps, ToastStyles, ToastTitleProps };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import { a as ButtonPrimitive, i as SelectPrimitive, n as EmptyPrimitive, o as InputPrimitive, r as CardPrimitive, s as FieldPrimitive, t as AvatarPrimitive } from "../primitives-BKUnaQrI.mjs";
|
|
1
|
+
import { a as SelectPrimitive, c as FieldPrimitive, i as CardPrimitive, n as AvatarPrimitive, o as ButtonPrimitive, r as EmptyPrimitive, s as InputPrimitive, t as ToastPrimitive } from "../primitives-B4L9y32H.mjs";
|
|
3
2
|
|
|
4
|
-
export { AvatarPrimitive, ButtonPrimitive, CardPrimitive, EmptyPrimitive, FieldPrimitive, InputPrimitive, SelectPrimitive };
|
|
3
|
+
export { AvatarPrimitive, ButtonPrimitive, CardPrimitive, EmptyPrimitive, FieldPrimitive, InputPrimitive, SelectPrimitive, ToastPrimitive };
|
|
@@ -1,8 +1,63 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import React, { createContext, useContext, useEffect, useState } from "react";
|
|
1
|
+
import React, { createContext, useContext, useEffect, useState, useSyncExternalStore } from "react";
|
|
3
2
|
import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
|
|
4
|
-
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
5
4
|
|
|
5
|
+
//#region src/primitives/portal/portal.tsx
|
|
6
|
+
const DEFAULT_PORTAL_HOST = "KOR_NATIVE_DEFAULT_HOST_NAME";
|
|
7
|
+
const store = {
|
|
8
|
+
map: (/* @__PURE__ */ new Map()).set(DEFAULT_PORTAL_HOST, /* @__PURE__ */ new Map()),
|
|
9
|
+
listeners: /* @__PURE__ */ new Set()
|
|
10
|
+
};
|
|
11
|
+
function emit() {
|
|
12
|
+
for (const cb of store.listeners) cb();
|
|
13
|
+
}
|
|
14
|
+
function getSnapshot() {
|
|
15
|
+
return store.map;
|
|
16
|
+
}
|
|
17
|
+
function subscribe(cb) {
|
|
18
|
+
store.listeners.add(cb);
|
|
19
|
+
return () => {
|
|
20
|
+
store.listeners.delete(cb);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function updatePortal(hostName, name, children) {
|
|
24
|
+
const next = new Map(store.map);
|
|
25
|
+
const portal = next.get(hostName) ?? /* @__PURE__ */ new Map();
|
|
26
|
+
portal.set(name, children);
|
|
27
|
+
next.set(hostName, portal);
|
|
28
|
+
store.map = next;
|
|
29
|
+
emit();
|
|
30
|
+
}
|
|
31
|
+
function removePortal(hostName, name) {
|
|
32
|
+
const next = new Map(store.map);
|
|
33
|
+
const portal = next.get(hostName) ?? /* @__PURE__ */ new Map();
|
|
34
|
+
portal.delete(name);
|
|
35
|
+
next.set(hostName, portal);
|
|
36
|
+
store.map = next;
|
|
37
|
+
emit();
|
|
38
|
+
}
|
|
39
|
+
function PortalHost({ name = DEFAULT_PORTAL_HOST }) {
|
|
40
|
+
const portalMap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot).get(name) ?? /* @__PURE__ */ new Map();
|
|
41
|
+
if (portalMap.size === 0) return null;
|
|
42
|
+
return /* @__PURE__ */ jsx(Fragment, { children: Array.from(portalMap.values()) });
|
|
43
|
+
}
|
|
44
|
+
function Portal({ name, hostName = DEFAULT_PORTAL_HOST, children }) {
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
updatePortal(hostName, name, children);
|
|
47
|
+
}, [
|
|
48
|
+
hostName,
|
|
49
|
+
name,
|
|
50
|
+
children
|
|
51
|
+
]);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
return () => {
|
|
54
|
+
removePortal(hostName, name);
|
|
55
|
+
};
|
|
56
|
+
}, [hostName, name]);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
6
61
|
//#region src/primitives/field/context.ts
|
|
7
62
|
const FieldContext = createContext(void 0);
|
|
8
63
|
const useField = () => {
|
|
@@ -555,4 +610,55 @@ const AvatarPrimitive = {
|
|
|
555
610
|
};
|
|
556
611
|
|
|
557
612
|
//#endregion
|
|
558
|
-
|
|
613
|
+
//#region src/primitives/toast/context.ts
|
|
614
|
+
const ToastContext = createContext(void 0);
|
|
615
|
+
const useToast = () => {
|
|
616
|
+
const context = useContext(ToastContext);
|
|
617
|
+
if (!context) throw new Error("useToast must be used within a ToastProvider");
|
|
618
|
+
return context;
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
//#endregion
|
|
622
|
+
//#region src/primitives/toast/toast-root.tsx
|
|
623
|
+
function ToastRoot(props) {
|
|
624
|
+
const composedStyle = [props.styles?.root, props.style];
|
|
625
|
+
const Component = props.render ?? View;
|
|
626
|
+
return /* @__PURE__ */ jsx(ToastContext.Provider, {
|
|
627
|
+
value: { styles: props.styles },
|
|
628
|
+
children: /* @__PURE__ */ jsx(Component, {
|
|
629
|
+
...props,
|
|
630
|
+
style: composedStyle
|
|
631
|
+
})
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
//#endregion
|
|
636
|
+
//#region src/primitives/toast/toast-title.tsx
|
|
637
|
+
function ToastTitle(props) {
|
|
638
|
+
const composedStyle = [useToast().styles?.title, props.style];
|
|
639
|
+
return /* @__PURE__ */ jsx(props.render ?? Text, {
|
|
640
|
+
...props,
|
|
641
|
+
style: composedStyle
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
//#endregion
|
|
646
|
+
//#region src/primitives/toast/toast-description.tsx
|
|
647
|
+
function ToastDescription(props) {
|
|
648
|
+
const composedStyle = [useToast().styles?.description, props.style];
|
|
649
|
+
return /* @__PURE__ */ jsx(props.render ?? Text, {
|
|
650
|
+
...props,
|
|
651
|
+
style: composedStyle
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/primitives/toast/index.ts
|
|
657
|
+
const ToastPrimitive = {
|
|
658
|
+
Root: ToastRoot,
|
|
659
|
+
Title: ToastTitle,
|
|
660
|
+
Description: ToastDescription
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
//#endregion
|
|
664
|
+
export { SelectPrimitive as a, FieldPrimitive as c, CardPrimitive as i, PortalHost as l, AvatarPrimitive as n, ButtonPrimitive as o, EmptyPrimitive as r, InputPrimitive as s, ToastPrimitive as t };
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { t as ToastPrimitive } from "./primitives-B4L9y32H.mjs";
|
|
2
|
+
import React, { createContext, useContext, useEffect, useState, useSyncExternalStore } from "react";
|
|
3
|
+
import { StyleSheet, View, useColorScheme } from "react-native";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/themes/default/colors.ts
|
|
7
|
+
const lightColors = {
|
|
8
|
+
background: "hsla(223.81, 100%, 100%, 1)",
|
|
9
|
+
foreground: "hsla(223.81, 0%, 3.94%, 1)",
|
|
10
|
+
primary: "hsla(223.81, 0%, 9.05%, 1)",
|
|
11
|
+
primaryForeground: "hsla(223.81, 0%, 98.03%, 1)",
|
|
12
|
+
secondary: "hsla(223.81, 0%, 96.06%, 1)",
|
|
13
|
+
secondaryForeground: "hsla(223.81, 0%, 9.05%, 1)",
|
|
14
|
+
muted: "hsla(223.81, 0%, 96.06%, 1)",
|
|
15
|
+
mutedForeground: "hsla(223.81, 0%, 45.15%, 1)",
|
|
16
|
+
border: "hsla(223.81, 0%, 89.82%, 1)",
|
|
17
|
+
surface: "hsla(223.81, 100%, 100%, 1)",
|
|
18
|
+
danger: "hsla(0, 84.2%, 60.2%, 1)",
|
|
19
|
+
success: "hsla(173, 58%, 39%, 1)",
|
|
20
|
+
warning: "hsla(43, 74%, 66%, 1)",
|
|
21
|
+
info: "hsla(197, 37%, 24%, 1)"
|
|
22
|
+
};
|
|
23
|
+
const darkColors = {
|
|
24
|
+
background: "hsla(223.81, 0%, 3.94%, 1)",
|
|
25
|
+
foreground: "hsla(223.81, 0%, 98.03%, 1)",
|
|
26
|
+
primary: "hsla(223.81, 0%, 89.82%, 1)",
|
|
27
|
+
primaryForeground: "hsla(223.81, 0%, 9.05%, 1)",
|
|
28
|
+
secondary: "hsla(223.81, 0%, 14.94%, 1)",
|
|
29
|
+
secondaryForeground: "hsla(223.81, 0%, 98.03%, 1)",
|
|
30
|
+
muted: "hsla(223.81, 0%, 14.94%, 1)",
|
|
31
|
+
mutedForeground: "hsla(223.81, 0%, 63.02%, 1)",
|
|
32
|
+
border: "hsla(223.81, 0%, 15.51%, 1)",
|
|
33
|
+
surface: "hsla(223.81, 0%, 9.05%, 1)",
|
|
34
|
+
danger: "hsla(0, 62.8%, 30.6%, 1)",
|
|
35
|
+
success: "hsla(160, 60%, 45%, 1)",
|
|
36
|
+
warning: "hsla(30, 80%, 55%, 1)",
|
|
37
|
+
info: "hsla(220, 70%, 50%, 1)"
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/themes/default/index.ts
|
|
42
|
+
const defaultThemeAssets = {
|
|
43
|
+
colors: {
|
|
44
|
+
light: lightColors,
|
|
45
|
+
dark: darkColors
|
|
46
|
+
},
|
|
47
|
+
radius: 10,
|
|
48
|
+
fontFamily: "System",
|
|
49
|
+
letterSpacing: 0,
|
|
50
|
+
fontSize: 16
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/themes/themes.ts
|
|
55
|
+
const themes = { default: defaultThemeAssets };
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/themes/provider.tsx
|
|
59
|
+
const ThemeContext = createContext(null);
|
|
60
|
+
const ThemeProvider = (props) => {
|
|
61
|
+
const [themeName, setTheme] = useState("default");
|
|
62
|
+
const systemColorScheme = useColorScheme();
|
|
63
|
+
const [colorScheme, setColorScheme] = useState(systemColorScheme ?? "light");
|
|
64
|
+
const themesAssets = themes[themeName];
|
|
65
|
+
const colors = themesAssets.colors[colorScheme];
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (systemColorScheme) setColorScheme(systemColorScheme);
|
|
68
|
+
}, [systemColorScheme]);
|
|
69
|
+
return /* @__PURE__ */ jsx(ThemeContext.Provider, {
|
|
70
|
+
value: {
|
|
71
|
+
themeName,
|
|
72
|
+
setTheme,
|
|
73
|
+
colorScheme,
|
|
74
|
+
setColorScheme,
|
|
75
|
+
colors,
|
|
76
|
+
radius: themesAssets.radius,
|
|
77
|
+
fontFamily: themesAssets.fontFamily,
|
|
78
|
+
letterSpacing: themesAssets.letterSpacing,
|
|
79
|
+
fontSize: themesAssets.fontSize
|
|
80
|
+
},
|
|
81
|
+
children: props.children
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
const useTheme = () => {
|
|
85
|
+
const context = useContext(ThemeContext);
|
|
86
|
+
if (!context) throw new Error("useTheme must be used within a ThemeProvider");
|
|
87
|
+
return context;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/utils/use-themed-styles.ts
|
|
92
|
+
const useThemedStyles = (callback) => {
|
|
93
|
+
const theme = useTheme();
|
|
94
|
+
return callback({
|
|
95
|
+
colors: theme.colors,
|
|
96
|
+
radius: theme.radius,
|
|
97
|
+
fontFamily: theme.fontFamily,
|
|
98
|
+
letterSpacing: theme.letterSpacing,
|
|
99
|
+
fontSize: theme.fontSize
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/components/toast/variants/default.tsx
|
|
105
|
+
const useToastVariantDefault = () => {
|
|
106
|
+
return useThemedStyles(({ colors, radius, fontFamily, fontSize }) => ({
|
|
107
|
+
root: {
|
|
108
|
+
backgroundColor: colors.surface,
|
|
109
|
+
borderWidth: 1,
|
|
110
|
+
borderColor: colors.border,
|
|
111
|
+
borderRadius: radius,
|
|
112
|
+
padding: 16,
|
|
113
|
+
gap: 4,
|
|
114
|
+
minWidth: 300,
|
|
115
|
+
maxWidth: 400
|
|
116
|
+
},
|
|
117
|
+
title: {
|
|
118
|
+
color: colors.foreground,
|
|
119
|
+
fontSize,
|
|
120
|
+
fontWeight: "600",
|
|
121
|
+
fontFamily
|
|
122
|
+
},
|
|
123
|
+
description: {
|
|
124
|
+
color: colors.mutedForeground,
|
|
125
|
+
fontSize: fontSize * .875,
|
|
126
|
+
fontFamily
|
|
127
|
+
}
|
|
128
|
+
}));
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/components/toast/variants/success.tsx
|
|
133
|
+
const useToastVariantSuccess = () => {
|
|
134
|
+
return useThemedStyles(({ colors, radius, fontFamily, fontSize }) => ({
|
|
135
|
+
root: {
|
|
136
|
+
backgroundColor: colors.success,
|
|
137
|
+
borderWidth: 1,
|
|
138
|
+
borderColor: colors.success,
|
|
139
|
+
borderRadius: radius,
|
|
140
|
+
padding: 16,
|
|
141
|
+
gap: 4,
|
|
142
|
+
minWidth: 300,
|
|
143
|
+
maxWidth: 400
|
|
144
|
+
},
|
|
145
|
+
title: {
|
|
146
|
+
color: colors.foreground,
|
|
147
|
+
fontSize,
|
|
148
|
+
fontWeight: "600",
|
|
149
|
+
fontFamily
|
|
150
|
+
},
|
|
151
|
+
description: {
|
|
152
|
+
color: colors.foreground,
|
|
153
|
+
fontSize: fontSize * .875,
|
|
154
|
+
fontFamily,
|
|
155
|
+
opacity: .9
|
|
156
|
+
}
|
|
157
|
+
}));
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/components/toast/variants/danger.tsx
|
|
162
|
+
const useToastVariantDanger = () => {
|
|
163
|
+
return useThemedStyles(({ colors, radius, fontFamily, fontSize }) => ({
|
|
164
|
+
root: {
|
|
165
|
+
backgroundColor: colors.danger,
|
|
166
|
+
borderWidth: 1,
|
|
167
|
+
borderColor: colors.danger,
|
|
168
|
+
borderRadius: radius,
|
|
169
|
+
padding: 16,
|
|
170
|
+
gap: 4,
|
|
171
|
+
minWidth: 300,
|
|
172
|
+
maxWidth: 400
|
|
173
|
+
},
|
|
174
|
+
title: {
|
|
175
|
+
color: colors.foreground,
|
|
176
|
+
fontSize,
|
|
177
|
+
fontWeight: "600",
|
|
178
|
+
fontFamily
|
|
179
|
+
},
|
|
180
|
+
description: {
|
|
181
|
+
color: colors.foreground,
|
|
182
|
+
fontSize: fontSize * .875,
|
|
183
|
+
fontFamily,
|
|
184
|
+
opacity: .9
|
|
185
|
+
}
|
|
186
|
+
}));
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/components/toast/variants/index.ts
|
|
191
|
+
const ToastVariants = {
|
|
192
|
+
default: useToastVariantDefault,
|
|
193
|
+
success: useToastVariantSuccess,
|
|
194
|
+
danger: useToastVariantDanger
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/components/toast/toast.tsx
|
|
199
|
+
function ToastComponent(props) {
|
|
200
|
+
const useVariantStyles = ToastVariants[props.variant || "default"];
|
|
201
|
+
const styles$1 = useVariantStyles();
|
|
202
|
+
return /* @__PURE__ */ jsxs(ToastPrimitive.Root, {
|
|
203
|
+
styles: styles$1,
|
|
204
|
+
children: [/* @__PURE__ */ jsx(ToastPrimitive.Title, { children: props.title }), !!props.description && /* @__PURE__ */ jsx(ToastPrimitive.Description, { children: props.description })]
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/components/toast/toast-manager.tsx
|
|
210
|
+
const store = {
|
|
211
|
+
toasts: [],
|
|
212
|
+
listeners: /* @__PURE__ */ new Set()
|
|
213
|
+
};
|
|
214
|
+
function emit() {
|
|
215
|
+
for (const cb of store.listeners) cb();
|
|
216
|
+
}
|
|
217
|
+
function getSnapshot() {
|
|
218
|
+
return store.toasts;
|
|
219
|
+
}
|
|
220
|
+
function subscribe(cb) {
|
|
221
|
+
store.listeners.add(cb);
|
|
222
|
+
return () => {
|
|
223
|
+
store.listeners.delete(cb);
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function addToast(config) {
|
|
227
|
+
const existingToast = store.toasts.find((t) => t.id === config.id);
|
|
228
|
+
if (existingToast) return existingToast.id;
|
|
229
|
+
const toast = {
|
|
230
|
+
duration: 3e3,
|
|
231
|
+
...config
|
|
232
|
+
};
|
|
233
|
+
store.toasts = [...store.toasts, toast];
|
|
234
|
+
emit();
|
|
235
|
+
if (toast.duration) setTimeout(() => {
|
|
236
|
+
removeToast(toast.id);
|
|
237
|
+
}, toast.duration);
|
|
238
|
+
return toast.id;
|
|
239
|
+
}
|
|
240
|
+
function removeToast(id) {
|
|
241
|
+
store.toasts = store.toasts.filter((t) => t.id !== id);
|
|
242
|
+
emit();
|
|
243
|
+
}
|
|
244
|
+
const ToastAPI = {
|
|
245
|
+
show: addToast,
|
|
246
|
+
dismiss: removeToast
|
|
247
|
+
};
|
|
248
|
+
function ToastContainer() {
|
|
249
|
+
const toasts = useSyncExternalStore(subscribe, getSnapshot);
|
|
250
|
+
if (!toasts.length) return null;
|
|
251
|
+
return /* @__PURE__ */ jsx(View, {
|
|
252
|
+
style: styles.container,
|
|
253
|
+
pointerEvents: "box-none",
|
|
254
|
+
children: toasts.map((toast) => /* @__PURE__ */ jsx(View, {
|
|
255
|
+
style: styles.toastWrapper,
|
|
256
|
+
children: /* @__PURE__ */ jsx(ToastComponent, {
|
|
257
|
+
title: toast.title,
|
|
258
|
+
description: toast.description,
|
|
259
|
+
variant: toast.variant
|
|
260
|
+
})
|
|
261
|
+
}, toast.id))
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
const styles = StyleSheet.create({
|
|
265
|
+
container: {
|
|
266
|
+
position: "absolute",
|
|
267
|
+
top: 50,
|
|
268
|
+
left: 0,
|
|
269
|
+
right: 0,
|
|
270
|
+
alignItems: "center",
|
|
271
|
+
gap: 12,
|
|
272
|
+
zIndex: 9999
|
|
273
|
+
},
|
|
274
|
+
toastWrapper: {
|
|
275
|
+
width: "100%",
|
|
276
|
+
alignItems: "center"
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
//#endregion
|
|
281
|
+
export { ThemeProvider as a, useThemedStyles as i, ToastContainer as n, useTheme as o, ToastComponent as r, ToastAPI as t };
|
package/package.json
CHANGED
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React, { useSyncExternalStore } from "react";
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
|
+
import { ToastComponent } from "./toast";
|
|
4
|
+
import { ToastVariants } from "./variants";
|
|
5
|
+
|
|
6
|
+
export interface ToastConfig {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
variant?: keyof typeof ToastVariants;
|
|
11
|
+
duration?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type ToastStore = {
|
|
15
|
+
toasts: ToastConfig[];
|
|
16
|
+
listeners: Set<() => void>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const store: ToastStore = {
|
|
20
|
+
toasts: [],
|
|
21
|
+
listeners: new Set(),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function emit() {
|
|
25
|
+
for (const cb of store.listeners) cb();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getSnapshot() {
|
|
29
|
+
return store.toasts;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function subscribe(cb: () => void) {
|
|
33
|
+
store.listeners.add(cb);
|
|
34
|
+
return () => {
|
|
35
|
+
store.listeners.delete(cb);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function addToast(config: ToastConfig): string {
|
|
40
|
+
// Check if toast with this ID already exists
|
|
41
|
+
const existingToast = store.toasts.find((t) => t.id === config.id);
|
|
42
|
+
if (existingToast) {
|
|
43
|
+
return existingToast.id;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const toast: ToastConfig = {
|
|
47
|
+
duration: 3000,
|
|
48
|
+
...config,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
store.toasts = [...store.toasts, toast];
|
|
52
|
+
emit();
|
|
53
|
+
|
|
54
|
+
// Auto-dismiss after duration
|
|
55
|
+
if (toast.duration) {
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
removeToast(toast.id);
|
|
58
|
+
}, toast.duration);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return toast.id;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function removeToast(id: string): void {
|
|
65
|
+
store.toasts = store.toasts.filter((t) => t.id !== id);
|
|
66
|
+
emit();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const ToastAPI = {
|
|
70
|
+
show: addToast,
|
|
71
|
+
dismiss: removeToast,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export function ToastContainer() {
|
|
75
|
+
const toasts = useSyncExternalStore(subscribe, getSnapshot);
|
|
76
|
+
|
|
77
|
+
if (!toasts.length) return null;
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<View style={styles.container} pointerEvents="box-none">
|
|
81
|
+
{toasts.map((toast) => (
|
|
82
|
+
<View key={toast.id} style={styles.toastWrapper}>
|
|
83
|
+
<ToastComponent title={toast.title} description={toast.description} variant={toast.variant} />
|
|
84
|
+
</View>
|
|
85
|
+
))}
|
|
86
|
+
</View>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const styles = StyleSheet.create({
|
|
91
|
+
container: {
|
|
92
|
+
position: "absolute",
|
|
93
|
+
top: 50,
|
|
94
|
+
left: 0,
|
|
95
|
+
right: 0,
|
|
96
|
+
alignItems: "center",
|
|
97
|
+
gap: 12,
|
|
98
|
+
zIndex: 9999,
|
|
99
|
+
},
|
|
100
|
+
toastWrapper: {
|
|
101
|
+
width: "100%",
|
|
102
|
+
alignItems: "center",
|
|
103
|
+
},
|
|
104
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ToastPrimitive } from "@/primitives";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { ToastVariants } from "./variants";
|
|
4
|
+
|
|
5
|
+
interface ToastProps {
|
|
6
|
+
title: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
|
|
9
|
+
variant?: keyof typeof ToastVariants;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ToastComponent(props: ToastProps) {
|
|
13
|
+
const useVariantStyles = ToastVariants[props.variant || "default"];
|
|
14
|
+
const styles = useVariantStyles();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<ToastPrimitive.Root styles={styles}>
|
|
18
|
+
<ToastPrimitive.Title>{props.title}</ToastPrimitive.Title>
|
|
19
|
+
{!!props.description && <ToastPrimitive.Description>{props.description}</ToastPrimitive.Description>}
|
|
20
|
+
</ToastPrimitive.Root>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ToastStyles } from "@/primitives";
|
|
2
|
+
import { useThemedStyles } from "@/utils/use-themed-styles";
|
|
3
|
+
|
|
4
|
+
export const useToastVariantDanger = (): ToastStyles => {
|
|
5
|
+
return useThemedStyles(
|
|
6
|
+
({ colors, radius, fontFamily, fontSize }): ToastStyles => ({
|
|
7
|
+
root: {
|
|
8
|
+
backgroundColor: colors.danger,
|
|
9
|
+
borderWidth: 1,
|
|
10
|
+
borderColor: colors.danger,
|
|
11
|
+
borderRadius: radius,
|
|
12
|
+
padding: 16,
|
|
13
|
+
gap: 4,
|
|
14
|
+
minWidth: 300,
|
|
15
|
+
maxWidth: 400,
|
|
16
|
+
},
|
|
17
|
+
title: {
|
|
18
|
+
color: colors.foreground,
|
|
19
|
+
fontSize: fontSize,
|
|
20
|
+
fontWeight: "600",
|
|
21
|
+
fontFamily,
|
|
22
|
+
},
|
|
23
|
+
description: {
|
|
24
|
+
color: colors.foreground,
|
|
25
|
+
fontSize: fontSize * 0.875,
|
|
26
|
+
fontFamily,
|
|
27
|
+
opacity: 0.9,
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ToastStyles } from "@/primitives";
|
|
2
|
+
import { useThemedStyles } from "@/utils/use-themed-styles";
|
|
3
|
+
|
|
4
|
+
export const useToastVariantDefault = (): ToastStyles => {
|
|
5
|
+
return useThemedStyles(
|
|
6
|
+
({ colors, radius, fontFamily, fontSize }): ToastStyles => ({
|
|
7
|
+
root: {
|
|
8
|
+
backgroundColor: colors.surface,
|
|
9
|
+
borderWidth: 1,
|
|
10
|
+
borderColor: colors.border,
|
|
11
|
+
borderRadius: radius,
|
|
12
|
+
padding: 16,
|
|
13
|
+
gap: 4,
|
|
14
|
+
minWidth: 300,
|
|
15
|
+
maxWidth: 400,
|
|
16
|
+
},
|
|
17
|
+
title: {
|
|
18
|
+
color: colors.foreground,
|
|
19
|
+
fontSize: fontSize,
|
|
20
|
+
fontWeight: "600",
|
|
21
|
+
fontFamily,
|
|
22
|
+
},
|
|
23
|
+
description: {
|
|
24
|
+
color: colors.mutedForeground,
|
|
25
|
+
fontSize: fontSize * 0.875,
|
|
26
|
+
fontFamily,
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useToastVariantDefault } from "./default";
|
|
2
|
+
import { useToastVariantSuccess } from "./success";
|
|
3
|
+
import { useToastVariantDanger } from "./danger";
|
|
4
|
+
|
|
5
|
+
export const ToastVariants = {
|
|
6
|
+
default: useToastVariantDefault,
|
|
7
|
+
success: useToastVariantSuccess,
|
|
8
|
+
danger: useToastVariantDanger,
|
|
9
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ToastStyles } from "@/primitives";
|
|
2
|
+
import { useThemedStyles } from "@/utils/use-themed-styles";
|
|
3
|
+
|
|
4
|
+
export const useToastVariantSuccess = (): ToastStyles => {
|
|
5
|
+
return useThemedStyles(
|
|
6
|
+
({ colors, radius, fontFamily, fontSize }): ToastStyles => ({
|
|
7
|
+
root: {
|
|
8
|
+
backgroundColor: colors.success,
|
|
9
|
+
borderWidth: 1,
|
|
10
|
+
borderColor: colors.success,
|
|
11
|
+
borderRadius: radius,
|
|
12
|
+
padding: 16,
|
|
13
|
+
gap: 4,
|
|
14
|
+
minWidth: 300,
|
|
15
|
+
maxWidth: 400,
|
|
16
|
+
},
|
|
17
|
+
title: {
|
|
18
|
+
color: colors.foreground,
|
|
19
|
+
fontSize: fontSize,
|
|
20
|
+
fontWeight: "600",
|
|
21
|
+
fontFamily,
|
|
22
|
+
},
|
|
23
|
+
description: {
|
|
24
|
+
color: colors.foreground,
|
|
25
|
+
fontSize: fontSize * 0.875,
|
|
26
|
+
fontFamily,
|
|
27
|
+
opacity: 0.9,
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
};
|
package/src/index.tsx
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ThemeProvider } from "@/themes";
|
|
2
2
|
import { PortalHost } from "./primitives/portal";
|
|
3
|
+
import { ToastContainer } from "./components/toast/toast-manager";
|
|
3
4
|
|
|
4
5
|
export const UniversalUIProvider = ({ children }: { children: React.ReactNode }) => {
|
|
5
6
|
return (
|
|
6
7
|
<ThemeProvider>
|
|
7
8
|
{children}
|
|
8
9
|
<PortalHost />
|
|
10
|
+
<ToastContainer />
|
|
9
11
|
</ThemeProvider>
|
|
10
12
|
);
|
|
11
13
|
};
|
package/src/primitives/index.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
import { ToastStyles } from "./types";
|
|
3
|
+
|
|
4
|
+
export interface ToastContext {
|
|
5
|
+
styles?: ToastStyles;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const ToastContext = createContext<ToastContext | undefined>(undefined);
|
|
9
|
+
|
|
10
|
+
export const useToast = () => {
|
|
11
|
+
const context = useContext(ToastContext);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error("useToast must be used within a ToastProvider");
|
|
14
|
+
}
|
|
15
|
+
return context;
|
|
16
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ToastRoot } from "./toast-root";
|
|
2
|
+
import { ToastTitle } from "./toast-title";
|
|
3
|
+
import { ToastDescription } from "./toast-description";
|
|
4
|
+
|
|
5
|
+
export const ToastPrimitive = {
|
|
6
|
+
Root: ToastRoot,
|
|
7
|
+
Title: ToastTitle,
|
|
8
|
+
Description: ToastDescription,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type { ToastRootProps } from "./toast-root";
|
|
12
|
+
export type { ToastTitleProps } from "./toast-title";
|
|
13
|
+
export type { ToastDescriptionProps } from "./toast-description";
|
|
14
|
+
export type { ToastStyles } from "./types";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { StyleProp, Text, TextStyle } from "react-native";
|
|
3
|
+
import { useToast } from "./context";
|
|
4
|
+
|
|
5
|
+
export interface ToastDescriptionProps {
|
|
6
|
+
children?: string;
|
|
7
|
+
|
|
8
|
+
render?: (props: ToastDescriptionProps) => React.ReactNode;
|
|
9
|
+
|
|
10
|
+
style?: StyleProp<TextStyle>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ToastDescription(props: ToastDescriptionProps) {
|
|
14
|
+
const toast = useToast();
|
|
15
|
+
|
|
16
|
+
const composedStyle = [toast.styles?.description, props.style];
|
|
17
|
+
|
|
18
|
+
const Component = props.render ?? Text;
|
|
19
|
+
return <Component {...props} style={composedStyle} />;
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { StyleProp, View, ViewStyle } from "react-native";
|
|
3
|
+
import { ToastStyles } from "./types";
|
|
4
|
+
import { ToastContext } from "./context";
|
|
5
|
+
|
|
6
|
+
export interface ToastRootProps {
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
|
|
9
|
+
render?: (props: ToastRootProps) => React.ReactNode;
|
|
10
|
+
|
|
11
|
+
style?: StyleProp<ViewStyle>;
|
|
12
|
+
styles?: ToastStyles;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function ToastRoot(props: ToastRootProps) {
|
|
16
|
+
const composedStyle = [props.styles?.root, props.style];
|
|
17
|
+
|
|
18
|
+
const Component = props.render ?? View;
|
|
19
|
+
return (
|
|
20
|
+
<ToastContext.Provider
|
|
21
|
+
value={{
|
|
22
|
+
styles: props.styles,
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<Component {...props} style={composedStyle} />
|
|
26
|
+
</ToastContext.Provider>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { StyleProp, Text, TextStyle } from "react-native";
|
|
3
|
+
import { useToast } from "./context";
|
|
4
|
+
|
|
5
|
+
export interface ToastTitleProps {
|
|
6
|
+
children?: string;
|
|
7
|
+
|
|
8
|
+
render?: (props: ToastTitleProps) => React.ReactNode;
|
|
9
|
+
|
|
10
|
+
style?: StyleProp<TextStyle>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ToastTitle(props: ToastTitleProps) {
|
|
14
|
+
const toast = useToast();
|
|
15
|
+
|
|
16
|
+
const composedStyle = [toast.styles?.title, props.style];
|
|
17
|
+
|
|
18
|
+
const Component = props.render ?? Text;
|
|
19
|
+
return <Component {...props} style={composedStyle} />;
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ToastRootProps } from "./toast-root";
|
|
2
|
+
import { ToastTitleProps } from "./toast-title";
|
|
3
|
+
import { ToastDescriptionProps } from "./toast-description";
|
|
4
|
+
|
|
5
|
+
export interface ToastStyles {
|
|
6
|
+
root?: ToastRootProps["style"];
|
|
7
|
+
title?: ToastTitleProps["style"];
|
|
8
|
+
description?: ToastDescriptionProps["style"];
|
|
9
|
+
}
|
package/dist/portal-jF1KeGnu.mjs
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, useSyncExternalStore } from "react";
|
|
2
|
-
import "react-native";
|
|
3
|
-
import { Fragment, jsx } from "react/jsx-runtime";
|
|
4
|
-
|
|
5
|
-
//#region src/primitives/portal/portal.tsx
|
|
6
|
-
const DEFAULT_PORTAL_HOST = "KOR_NATIVE_DEFAULT_HOST_NAME";
|
|
7
|
-
const store = {
|
|
8
|
-
map: (/* @__PURE__ */ new Map()).set(DEFAULT_PORTAL_HOST, /* @__PURE__ */ new Map()),
|
|
9
|
-
listeners: /* @__PURE__ */ new Set()
|
|
10
|
-
};
|
|
11
|
-
function emit() {
|
|
12
|
-
for (const cb of store.listeners) cb();
|
|
13
|
-
}
|
|
14
|
-
function getSnapshot() {
|
|
15
|
-
return store.map;
|
|
16
|
-
}
|
|
17
|
-
function subscribe(cb) {
|
|
18
|
-
store.listeners.add(cb);
|
|
19
|
-
return () => {
|
|
20
|
-
store.listeners.delete(cb);
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
function updatePortal(hostName, name, children) {
|
|
24
|
-
const next = new Map(store.map);
|
|
25
|
-
const portal = next.get(hostName) ?? /* @__PURE__ */ new Map();
|
|
26
|
-
portal.set(name, children);
|
|
27
|
-
next.set(hostName, portal);
|
|
28
|
-
store.map = next;
|
|
29
|
-
emit();
|
|
30
|
-
}
|
|
31
|
-
function removePortal(hostName, name) {
|
|
32
|
-
const next = new Map(store.map);
|
|
33
|
-
const portal = next.get(hostName) ?? /* @__PURE__ */ new Map();
|
|
34
|
-
portal.delete(name);
|
|
35
|
-
next.set(hostName, portal);
|
|
36
|
-
store.map = next;
|
|
37
|
-
emit();
|
|
38
|
-
}
|
|
39
|
-
function PortalHost({ name = DEFAULT_PORTAL_HOST }) {
|
|
40
|
-
const portalMap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot).get(name) ?? /* @__PURE__ */ new Map();
|
|
41
|
-
if (portalMap.size === 0) return null;
|
|
42
|
-
return /* @__PURE__ */ jsx(Fragment, { children: Array.from(portalMap.values()) });
|
|
43
|
-
}
|
|
44
|
-
function Portal({ name, hostName = DEFAULT_PORTAL_HOST, children }) {
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
updatePortal(hostName, name, children);
|
|
47
|
-
}, [
|
|
48
|
-
hostName,
|
|
49
|
-
name,
|
|
50
|
-
children
|
|
51
|
-
]);
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
return () => {
|
|
54
|
-
removePortal(hostName, name);
|
|
55
|
-
};
|
|
56
|
-
}, [hostName, name]);
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
//#endregion
|
|
61
|
-
export { PortalHost as n, Portal as t };
|
package/dist/themes-pgmHo7MU.mjs
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext, useEffect, useState } from "react";
|
|
2
|
-
import { useColorScheme } from "react-native";
|
|
3
|
-
import { jsx } from "react/jsx-runtime";
|
|
4
|
-
|
|
5
|
-
//#region src/themes/default/colors.ts
|
|
6
|
-
const lightColors = {
|
|
7
|
-
background: "hsla(223.81, 100%, 100%, 1)",
|
|
8
|
-
foreground: "hsla(223.81, 0%, 3.94%, 1)",
|
|
9
|
-
primary: "hsla(223.81, 0%, 9.05%, 1)",
|
|
10
|
-
primaryForeground: "hsla(223.81, 0%, 98.03%, 1)",
|
|
11
|
-
secondary: "hsla(223.81, 0%, 96.06%, 1)",
|
|
12
|
-
secondaryForeground: "hsla(223.81, 0%, 9.05%, 1)",
|
|
13
|
-
muted: "hsla(223.81, 0%, 96.06%, 1)",
|
|
14
|
-
mutedForeground: "hsla(223.81, 0%, 45.15%, 1)",
|
|
15
|
-
border: "hsla(223.81, 0%, 89.82%, 1)",
|
|
16
|
-
surface: "hsla(223.81, 100%, 100%, 1)",
|
|
17
|
-
danger: "hsla(0, 84.2%, 60.2%, 1)",
|
|
18
|
-
success: "hsla(173, 58%, 39%, 1)",
|
|
19
|
-
warning: "hsla(43, 74%, 66%, 1)",
|
|
20
|
-
info: "hsla(197, 37%, 24%, 1)"
|
|
21
|
-
};
|
|
22
|
-
const darkColors = {
|
|
23
|
-
background: "hsla(223.81, 0%, 3.94%, 1)",
|
|
24
|
-
foreground: "hsla(223.81, 0%, 98.03%, 1)",
|
|
25
|
-
primary: "hsla(223.81, 0%, 89.82%, 1)",
|
|
26
|
-
primaryForeground: "hsla(223.81, 0%, 9.05%, 1)",
|
|
27
|
-
secondary: "hsla(223.81, 0%, 14.94%, 1)",
|
|
28
|
-
secondaryForeground: "hsla(223.81, 0%, 98.03%, 1)",
|
|
29
|
-
muted: "hsla(223.81, 0%, 14.94%, 1)",
|
|
30
|
-
mutedForeground: "hsla(223.81, 0%, 63.02%, 1)",
|
|
31
|
-
border: "hsla(223.81, 0%, 15.51%, 1)",
|
|
32
|
-
surface: "hsla(223.81, 0%, 9.05%, 1)",
|
|
33
|
-
danger: "hsla(0, 62.8%, 30.6%, 1)",
|
|
34
|
-
success: "hsla(160, 60%, 45%, 1)",
|
|
35
|
-
warning: "hsla(30, 80%, 55%, 1)",
|
|
36
|
-
info: "hsla(220, 70%, 50%, 1)"
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region src/themes/default/index.ts
|
|
41
|
-
const defaultThemeAssets = {
|
|
42
|
-
colors: {
|
|
43
|
-
light: lightColors,
|
|
44
|
-
dark: darkColors
|
|
45
|
-
},
|
|
46
|
-
radius: 10,
|
|
47
|
-
fontFamily: "System",
|
|
48
|
-
letterSpacing: 0,
|
|
49
|
-
fontSize: 16
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
//#endregion
|
|
53
|
-
//#region src/themes/themes.ts
|
|
54
|
-
const themes = { default: defaultThemeAssets };
|
|
55
|
-
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/themes/provider.tsx
|
|
58
|
-
const ThemeContext = createContext(null);
|
|
59
|
-
const ThemeProvider = (props) => {
|
|
60
|
-
const [themeName, setTheme] = useState("default");
|
|
61
|
-
const systemColorScheme = useColorScheme();
|
|
62
|
-
const [colorScheme, setColorScheme] = useState(systemColorScheme ?? "light");
|
|
63
|
-
const themesAssets = themes[themeName];
|
|
64
|
-
const colors = themesAssets.colors[colorScheme];
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
if (systemColorScheme) setColorScheme(systemColorScheme);
|
|
67
|
-
}, [systemColorScheme]);
|
|
68
|
-
return /* @__PURE__ */ jsx(ThemeContext.Provider, {
|
|
69
|
-
value: {
|
|
70
|
-
themeName,
|
|
71
|
-
setTheme,
|
|
72
|
-
colorScheme,
|
|
73
|
-
setColorScheme,
|
|
74
|
-
colors,
|
|
75
|
-
radius: themesAssets.radius,
|
|
76
|
-
fontFamily: themesAssets.fontFamily,
|
|
77
|
-
letterSpacing: themesAssets.letterSpacing,
|
|
78
|
-
fontSize: themesAssets.fontSize
|
|
79
|
-
},
|
|
80
|
-
children: props.children
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
const useTheme = () => {
|
|
84
|
-
const context = useContext(ThemeContext);
|
|
85
|
-
if (!context) throw new Error("useTheme must be used within a ThemeProvider");
|
|
86
|
-
return context;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
//#endregion
|
|
90
|
-
export { useTheme as n, ThemeProvider as t };
|