@indietabletop/appkit 3.2.0-9 → 3.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/lib/DialogTrigger/index.tsx +36 -0
- package/lib/Letterhead/style.css.ts +10 -2
- package/lib/LetterheadForm/style.css.ts +5 -0
- package/lib/ModalDialog/index.tsx +28 -0
- package/lib/ModalDialog/style.css.ts +87 -0
- package/lib/client.ts +31 -0
- package/lib/failureMessages.test.ts +31 -0
- package/lib/failureMessages.ts +55 -23
- package/lib/globals.css.ts +12 -0
- package/lib/index.ts +4 -0
- package/lib/random.ts +7 -0
- package/lib/validations.ts +25 -0
- package/package.json +2 -2
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DialogProvider,
|
|
3
|
+
useDialogContext,
|
|
4
|
+
useStoreState,
|
|
5
|
+
} from "@ariakit/react";
|
|
6
|
+
import type { ReactElement, ReactNode } from "react";
|
|
7
|
+
|
|
8
|
+
function DialogGuard(props: { children: ReactNode }) {
|
|
9
|
+
const dialog = useDialogContext();
|
|
10
|
+
const isMounted = useStoreState(dialog, (store) => store?.mounted);
|
|
11
|
+
if (!isMounted) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return props.children;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Wraps AriaKit's DialogProvider, but take a tuple of Dialog a DialogDisclosure
|
|
19
|
+
* elements as children, and makes sense that the Dialog component is not
|
|
20
|
+
* rendered when it is hidden.
|
|
21
|
+
*
|
|
22
|
+
* This is important in cases where the dialog contains a form that should only
|
|
23
|
+
* be initialized and re-initialized when the dialog opens, not when it is first
|
|
24
|
+
* rendered.
|
|
25
|
+
*/
|
|
26
|
+
export function DialogTrigger(props: {
|
|
27
|
+
children: [ReactElement, ReactElement];
|
|
28
|
+
}) {
|
|
29
|
+
const [dialog, button] = props.children;
|
|
30
|
+
return (
|
|
31
|
+
<DialogProvider>
|
|
32
|
+
<DialogGuard>{dialog}</DialogGuard>
|
|
33
|
+
{button}
|
|
34
|
+
</DialogProvider>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -2,7 +2,7 @@ import { createTheme, style } from "@vanilla-extract/css";
|
|
|
2
2
|
import { recipe } from "@vanilla-extract/recipes";
|
|
3
3
|
import { textVariants } from "../atomic.css.ts";
|
|
4
4
|
import { manofa, minion } from "../common.css.ts";
|
|
5
|
-
import { Hover } from "../media.ts";
|
|
5
|
+
import { Hover, MinWidth } from "../media.ts";
|
|
6
6
|
|
|
7
7
|
const align = {
|
|
8
8
|
start: textVariants({ textAlign: "start" }),
|
|
@@ -11,7 +11,7 @@ const align = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export const [letterheadTheme, { padding, footerMargin }] = createTheme({
|
|
14
|
-
padding: "
|
|
14
|
+
padding: "1.25rem",
|
|
15
15
|
footerMargin: "3rem",
|
|
16
16
|
});
|
|
17
17
|
|
|
@@ -25,6 +25,14 @@ export const letterhead = recipe({
|
|
|
25
25
|
borderRadius: "1rem",
|
|
26
26
|
marginInline: "auto",
|
|
27
27
|
maxInlineSize: "36rem",
|
|
28
|
+
|
|
29
|
+
"@media": {
|
|
30
|
+
[MinWidth.SMALL]: {
|
|
31
|
+
vars: {
|
|
32
|
+
[padding]: `clamp(1.5rem, 8%, 4rem)`,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
28
36
|
},
|
|
29
37
|
],
|
|
30
38
|
|
|
@@ -19,6 +19,7 @@ export const fieldLabel = style([
|
|
|
19
19
|
fontSize: "0.75rem",
|
|
20
20
|
fontWeight: 600,
|
|
21
21
|
marginBottom: "0.5rem",
|
|
22
|
+
textAlign: "start",
|
|
22
23
|
},
|
|
23
24
|
]);
|
|
24
25
|
|
|
@@ -31,6 +32,7 @@ export const fieldInput = style([
|
|
|
31
32
|
fontSize: "1rem",
|
|
32
33
|
lineHeight: "1.25rem",
|
|
33
34
|
padding: "1rem 0 1rem 1rem",
|
|
35
|
+
textAlign: "start",
|
|
34
36
|
|
|
35
37
|
":read-only": {
|
|
36
38
|
backgroundColor: "hsl(0 0% 0% / 0.05)",
|
|
@@ -50,6 +52,7 @@ export const fieldIssue = style({
|
|
|
50
52
|
color: Color.PURPLE,
|
|
51
53
|
fontSize: "0.875rem",
|
|
52
54
|
marginTop: "0.5rem",
|
|
55
|
+
textAlign: "start",
|
|
53
56
|
|
|
54
57
|
":empty": {
|
|
55
58
|
display: "none",
|
|
@@ -60,6 +63,7 @@ export const fieldHint = style({
|
|
|
60
63
|
color: Color.MID_GRAY,
|
|
61
64
|
fontSize: "0.875rem",
|
|
62
65
|
marginTop: "0.5rem",
|
|
66
|
+
textAlign: "start",
|
|
63
67
|
|
|
64
68
|
selectors: {
|
|
65
69
|
[`${fieldIssue}:not(:empty) + &`]: {
|
|
@@ -73,6 +77,7 @@ export const submitError = style({
|
|
|
73
77
|
color: Color.PURPLE,
|
|
74
78
|
backgroundColor: Color.PALE_GRAY,
|
|
75
79
|
borderRadius: "0.75rem",
|
|
80
|
+
textAlign: "start",
|
|
76
81
|
|
|
77
82
|
":empty": {
|
|
78
83
|
display: "none",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Dialog, type DialogProps } from "@ariakit/react";
|
|
2
|
+
import type { RecipeVariants } from "@vanilla-extract/recipes";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { cx } from "../class-names.ts";
|
|
5
|
+
import * as css from "./style.css.ts";
|
|
6
|
+
|
|
7
|
+
type Size = NonNullable<NonNullable<RecipeVariants<typeof css.dialog>>["size"]>;
|
|
8
|
+
|
|
9
|
+
export type ModalDialogProps = Omit<DialogProps, "modal" | "backdrop"> & {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
size: Size;
|
|
12
|
+
backdropClassName?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function ModalDialog(props: ModalDialogProps) {
|
|
16
|
+
const { size, backdropClassName, className, ...dialogProps } = props;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Dialog
|
|
20
|
+
{...dialogProps}
|
|
21
|
+
{...cx(className, css.dialog({ size }))}
|
|
22
|
+
backdrop={<div {...cx(css.backdrop, backdropClassName)} />}
|
|
23
|
+
modal
|
|
24
|
+
>
|
|
25
|
+
{props.children}
|
|
26
|
+
</Dialog>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { style } from "@vanilla-extract/css";
|
|
2
|
+
import { recipe } from "@vanilla-extract/recipes";
|
|
3
|
+
import { MinWidth } from "../media.ts";
|
|
4
|
+
|
|
5
|
+
const scaleTransition = {
|
|
6
|
+
transition: "transform 200ms, opacity 200ms",
|
|
7
|
+
transform: "scale(1.1)",
|
|
8
|
+
|
|
9
|
+
selectors: {
|
|
10
|
+
"&[data-enter]": {
|
|
11
|
+
opacity: 1,
|
|
12
|
+
transform: "scale(1)",
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
"&[data-leave]": {
|
|
16
|
+
opacity: 0,
|
|
17
|
+
transform: "scale(0.9)",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const translateTransition = {
|
|
23
|
+
transition: "transform 200ms, opacity 200ms",
|
|
24
|
+
transform: "translateY(5rem)",
|
|
25
|
+
|
|
26
|
+
selectors: {
|
|
27
|
+
"&[data-enter]": {
|
|
28
|
+
opacity: 1,
|
|
29
|
+
transform: "translateY(0)",
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
"&[data-leave]": {
|
|
33
|
+
opacity: 0,
|
|
34
|
+
transform: "translateY(5rem)",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const dialog = recipe({
|
|
40
|
+
base: {
|
|
41
|
+
position: "fixed",
|
|
42
|
+
inset: 0,
|
|
43
|
+
zIndex: 100,
|
|
44
|
+
margin: "auto",
|
|
45
|
+
overflow: "auto",
|
|
46
|
+
opacity: 0,
|
|
47
|
+
backgroundColor: "white",
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
variants: {
|
|
51
|
+
size: {
|
|
52
|
+
large: {
|
|
53
|
+
...translateTransition,
|
|
54
|
+
inlineSize: "100%",
|
|
55
|
+
blockSize: "100%",
|
|
56
|
+
|
|
57
|
+
"@media": {
|
|
58
|
+
[MinWidth.MEDIUM]: {
|
|
59
|
+
...scaleTransition,
|
|
60
|
+
blockSize: "fit-content",
|
|
61
|
+
maxInlineSize: "40rem",
|
|
62
|
+
maxBlockSize: "90%",
|
|
63
|
+
borderRadius: "1rem",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
small: {
|
|
69
|
+
...scaleTransition,
|
|
70
|
+
inlineSize: "min(24rem, 90svw)",
|
|
71
|
+
blockSize: "fit-content",
|
|
72
|
+
borderRadius: "1rem",
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export const backdrop = style({
|
|
79
|
+
backgroundColor: "black",
|
|
80
|
+
opacity: 0,
|
|
81
|
+
transition: "opacity 200ms",
|
|
82
|
+
selectors: {
|
|
83
|
+
"&[data-enter]": {
|
|
84
|
+
opacity: 0.4,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
});
|
package/lib/client.ts
CHANGED
|
@@ -285,4 +285,35 @@ export class IndieTabletopClient {
|
|
|
285
285
|
|
|
286
286
|
return result;
|
|
287
287
|
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Uploads a file given S3 presigned config.
|
|
291
|
+
*/
|
|
292
|
+
async uploadFile(
|
|
293
|
+
file: File,
|
|
294
|
+
presigned: { url: string; key: string; fields: Record<string, string> },
|
|
295
|
+
): Promise<Success<string> | Failure<FailurePayload>> {
|
|
296
|
+
const formData = new FormData();
|
|
297
|
+
|
|
298
|
+
for (const [key, value] of Object.entries(presigned.fields)) {
|
|
299
|
+
formData.append(key, value);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
formData.append("file", file);
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
const upload = await fetch(presigned.url, {
|
|
306
|
+
method: "POST",
|
|
307
|
+
body: formData,
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
if (!upload.ok) {
|
|
311
|
+
return new Failure({ type: "API_ERROR", code: upload.status });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return new Success(`/${presigned.key}`);
|
|
315
|
+
} catch {
|
|
316
|
+
return new Failure({ type: "NETWORK_ERROR" });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
288
319
|
}
|
|
@@ -10,6 +10,11 @@ describe("getFetchFailureMessages", () => {
|
|
|
10
10
|
|
|
11
11
|
expect(result).toMatchInlineSnapshot(`
|
|
12
12
|
{
|
|
13
|
+
"action": {
|
|
14
|
+
"href": "~/",
|
|
15
|
+
"label": "Go back",
|
|
16
|
+
"type": "LINK",
|
|
17
|
+
},
|
|
13
18
|
"description": "The link you have followed might be broken.",
|
|
14
19
|
"title": "Not found",
|
|
15
20
|
}
|
|
@@ -21,6 +26,10 @@ describe("getFetchFailureMessages", () => {
|
|
|
21
26
|
|
|
22
27
|
expect(result).toMatchInlineSnapshot(`
|
|
23
28
|
{
|
|
29
|
+
"action": {
|
|
30
|
+
"label": "Reload app",
|
|
31
|
+
"type": "RELOAD",
|
|
32
|
+
},
|
|
24
33
|
"description": "This is probably an issue with our servers. You can try refreshing.",
|
|
25
34
|
"title": "Ooops, something went wrong",
|
|
26
35
|
}
|
|
@@ -35,6 +44,11 @@ describe("getFetchFailureMessages", () => {
|
|
|
35
44
|
|
|
36
45
|
expect(result).toMatchInlineSnapshot(`
|
|
37
46
|
{
|
|
47
|
+
"action": {
|
|
48
|
+
"href": "~/",
|
|
49
|
+
"label": "Go back",
|
|
50
|
+
"type": "LINK",
|
|
51
|
+
},
|
|
38
52
|
"description": "The link you have followed might be broken.",
|
|
39
53
|
"title": "Army not found",
|
|
40
54
|
}
|
|
@@ -54,6 +68,11 @@ describe("getFetchFailureMessages", () => {
|
|
|
54
68
|
|
|
55
69
|
expect(result).toMatchInlineSnapshot(`
|
|
56
70
|
{
|
|
71
|
+
"action": {
|
|
72
|
+
"href": "~/",
|
|
73
|
+
"label": "Go back",
|
|
74
|
+
"type": "LINK",
|
|
75
|
+
},
|
|
57
76
|
"description": "It might have been deleted.",
|
|
58
77
|
"title": "Army not found",
|
|
59
78
|
}
|
|
@@ -65,6 +84,10 @@ describe("getFetchFailureMessages", () => {
|
|
|
65
84
|
|
|
66
85
|
expect(result).toMatchInlineSnapshot(`
|
|
67
86
|
{
|
|
87
|
+
"action": {
|
|
88
|
+
"label": "Retry request",
|
|
89
|
+
"type": "REFETCH",
|
|
90
|
+
},
|
|
68
91
|
"description": "Check your interent connection and try again.",
|
|
69
92
|
"title": "No connection",
|
|
70
93
|
}
|
|
@@ -76,6 +99,10 @@ describe("getFetchFailureMessages", () => {
|
|
|
76
99
|
|
|
77
100
|
expect(result).toMatchInlineSnapshot(`
|
|
78
101
|
{
|
|
102
|
+
"action": {
|
|
103
|
+
"label": "Reload app",
|
|
104
|
+
"type": "RELOAD",
|
|
105
|
+
},
|
|
79
106
|
"description": "This is probably an issue on our side. You can try refreshing.",
|
|
80
107
|
"title": "Ooops, something went wrong",
|
|
81
108
|
}
|
|
@@ -87,6 +114,10 @@ describe("getFetchFailureMessages", () => {
|
|
|
87
114
|
|
|
88
115
|
expect(result).toMatchInlineSnapshot(`
|
|
89
116
|
{
|
|
117
|
+
"action": {
|
|
118
|
+
"label": "Reload app",
|
|
119
|
+
"type": "RELOAD",
|
|
120
|
+
},
|
|
90
121
|
"description": "This is probably an issue on our side. You can try refreshing.",
|
|
91
122
|
"title": "Ooops, something went wrong",
|
|
92
123
|
}
|
package/lib/failureMessages.ts
CHANGED
|
@@ -29,31 +29,63 @@ function createFailureMessageGetter<T>(
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export
|
|
33
|
-
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
export type FetchFailureAction =
|
|
33
|
+
| {
|
|
34
|
+
type: "LINK";
|
|
35
|
+
href: string;
|
|
36
|
+
label: string;
|
|
37
|
+
}
|
|
38
|
+
| {
|
|
39
|
+
type: "RELOAD" | "REFETCH";
|
|
40
|
+
label: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type FetchFailureMessages = {
|
|
44
|
+
title: string;
|
|
45
|
+
description: string;
|
|
46
|
+
action: FetchFailureAction;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const getFetchFailureMessages =
|
|
50
|
+
createFailureMessageGetter<FetchFailureMessages>(
|
|
51
|
+
{
|
|
52
|
+
401: {
|
|
53
|
+
title: "Not logged in",
|
|
54
|
+
description: "You must be logged in to view this page.",
|
|
55
|
+
action: { type: "LINK", href: "~/login", label: "Go to login" },
|
|
56
|
+
},
|
|
57
|
+
403: {
|
|
58
|
+
title: "Not authorized",
|
|
59
|
+
description: "You might be logged into the wrong account.",
|
|
60
|
+
action: { type: "LINK", href: "~/login", label: "Go to login" },
|
|
61
|
+
},
|
|
62
|
+
404: {
|
|
63
|
+
title: `Not found`,
|
|
64
|
+
description: `The link you have followed might be broken.`,
|
|
65
|
+
action: { type: "LINK", href: "~/", label: "Go back" },
|
|
66
|
+
},
|
|
67
|
+
500: {
|
|
68
|
+
title: `Ooops, something went wrong`,
|
|
69
|
+
description: `This is probably an issue with our servers. You can try refreshing.`,
|
|
70
|
+
action: { type: "RELOAD", label: "Reload app" },
|
|
71
|
+
},
|
|
72
|
+
connection: {
|
|
73
|
+
title: `No connection`,
|
|
74
|
+
description: `Check your interent connection and try again.`,
|
|
75
|
+
action: { type: "REFETCH", label: "Retry request" },
|
|
76
|
+
},
|
|
77
|
+
fallback: {
|
|
78
|
+
title: `Ooops, something went wrong`,
|
|
79
|
+
description: `This is probably an issue on our side. You can try refreshing.`,
|
|
80
|
+
action: { type: "RELOAD", label: "Reload app" },
|
|
81
|
+
},
|
|
49
82
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
83
|
+
{
|
|
84
|
+
onOverride(fallback, override) {
|
|
85
|
+
return { ...fallback, ...override };
|
|
86
|
+
},
|
|
54
87
|
},
|
|
55
|
-
|
|
56
|
-
);
|
|
88
|
+
);
|
|
57
89
|
|
|
58
90
|
export const getSubmitFailureMessage = createFailureMessageGetter(
|
|
59
91
|
{
|
package/lib/globals.css.ts
CHANGED
|
@@ -8,6 +8,7 @@ globalStyle(":root", {
|
|
|
8
8
|
textRendering: "optimizeLegibility",
|
|
9
9
|
WebkitFontSmoothing: "antialiased",
|
|
10
10
|
MozOsxFontSmoothing: "grayscale",
|
|
11
|
+
WebkitTapHighlightColor: "transparent",
|
|
11
12
|
});
|
|
12
13
|
|
|
13
14
|
globalStyle("*", {
|
|
@@ -43,3 +44,14 @@ globalStyle("body, h1, h2, h3, h4, h5, h6, p, ul, li, ol", {
|
|
|
43
44
|
margin: 0,
|
|
44
45
|
padding: 0,
|
|
45
46
|
});
|
|
47
|
+
|
|
48
|
+
// Fathom SPA support depends on this image being added to the DOM, but they
|
|
49
|
+
// are sloppy about taking out of the document flow, meaning that on pages
|
|
50
|
+
// that are 100vh, there is a scrollbar flicker as the img element is added
|
|
51
|
+
// to the DOM and then removed. This fixes said issue.
|
|
52
|
+
globalStyle(`img[src^="https://cdn.usefathom.com/"]`, {
|
|
53
|
+
position: "absolute",
|
|
54
|
+
top: 0,
|
|
55
|
+
left: 0,
|
|
56
|
+
opacity: 0.01,
|
|
57
|
+
});
|
package/lib/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Components
|
|
2
|
+
export * from "./DialogTrigger/index.tsx";
|
|
2
3
|
export * from "./ExternalLink.tsx";
|
|
3
4
|
export * from "./FormSubmitButton.tsx";
|
|
4
5
|
export * from "./FullscreenDismissBlocker.tsx";
|
|
@@ -6,6 +7,7 @@ export * from "./IndieTabletopClubSymbol.tsx";
|
|
|
6
7
|
export * from "./Letterhead/index.tsx";
|
|
7
8
|
export * from "./LetterheadForm/index.tsx";
|
|
8
9
|
export * from "./LoadingIndicator.tsx";
|
|
10
|
+
export * from "./ModalDialog/index.tsx";
|
|
9
11
|
export * from "./ServiceWorkerHandler.tsx";
|
|
10
12
|
|
|
11
13
|
// Hooks
|
|
@@ -25,5 +27,7 @@ export * from "./class-names.ts";
|
|
|
25
27
|
export * from "./client.ts";
|
|
26
28
|
export * from "./failureMessages.ts";
|
|
27
29
|
export * from "./media.ts";
|
|
30
|
+
export * from "./random.ts";
|
|
28
31
|
export * from "./structs.ts";
|
|
29
32
|
export * from "./types.ts";
|
|
33
|
+
export * from "./validations.ts";
|
package/lib/random.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const EMAIL_REGEX = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
|
|
2
|
+
|
|
3
|
+
export const validEmail = (value: string) => {
|
|
4
|
+
if (value && !EMAIL_REGEX.test(value)) {
|
|
5
|
+
return "This doesn't look like a valid email.";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return null;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const validPassword = (value: string) => {
|
|
12
|
+
if (value) {
|
|
13
|
+
if (value.length < 8) {
|
|
14
|
+
return "A password has to be at least 8 characters long.";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (value.length > 256) {
|
|
18
|
+
return "A password cannot be longer than 256 characters.";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return null;
|
|
25
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indietabletop/appkit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "A collection of modules used in apps built by Indie Tabletop Club",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@storybook/addon-docs": "^9.0.4",
|
|
29
29
|
"@storybook/react-vite": "^9.0.4",
|
|
30
|
-
"@types/react": "^19.
|
|
30
|
+
"@types/react": "^19.1.8",
|
|
31
31
|
"np": "^10.1.0",
|
|
32
32
|
"storybook": "^9.0.4",
|
|
33
33
|
"typescript": "^5.8.2",
|