@indietabletop/appkit 3.2.0-4 → 3.2.0-6
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/FormSubmitButton.tsx +10 -0
- package/lib/Letterhead/index.tsx +85 -0
- package/lib/Letterhead/stories.tsx +45 -0
- package/lib/Letterhead/style.css.ts +141 -0
- package/lib/atomic.css.ts +10 -2
- package/lib/class-names.ts +30 -5
- package/lib/common.css.ts +2 -0
- package/lib/index.ts +1 -2
- package/lib/internal.css.ts +0 -16
- package/package.json +3 -2
- package/lib/Letterhead.tsx +0 -33
- package/lib/LetterheadFooter.tsx +0 -37
package/lib/FormSubmitButton.tsx
CHANGED
|
@@ -12,6 +12,16 @@ export type FormSubmitButtonProps = FormSubmitProps & {
|
|
|
12
12
|
loading: ReactNode;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Renders Ariakit FormSubmit component.
|
|
17
|
+
*
|
|
18
|
+
* It's main responsibility is to render the loading component (provided via
|
|
19
|
+
* the `loading` prop) when the form is in the submitting state. This component
|
|
20
|
+
* will be rendered over the usual content of the button, which will be hidden
|
|
21
|
+
* as long as the form is submitting.
|
|
22
|
+
*
|
|
23
|
+
* @remarks Must be rendered within Ariakit Form Context.
|
|
24
|
+
*/
|
|
15
25
|
export function FormSubmitButton(props: FormSubmitButtonProps) {
|
|
16
26
|
const { children, className, style, loading, ...submitProps } = props;
|
|
17
27
|
const form = useFormContext();
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Heading, type HeadingProps } from "@ariakit/react";
|
|
2
|
+
import type { RecipeVariants } from "@vanilla-extract/recipes";
|
|
3
|
+
import type { ComponentProps, ReactNode } from "react";
|
|
4
|
+
import { cx } from "../class-names.ts";
|
|
5
|
+
import { interactiveText } from "../common.css.ts";
|
|
6
|
+
import { ExternalLink } from "../ExternalLink.tsx";
|
|
7
|
+
import {
|
|
8
|
+
FormSubmitButton,
|
|
9
|
+
type FormSubmitButtonProps,
|
|
10
|
+
} from "../FormSubmitButton.tsx";
|
|
11
|
+
import { IndieTabletopClubLogo } from "../IndieTabletopClubLogo.tsx";
|
|
12
|
+
import { IndieTabletopClubSymbol } from "../IndieTabletopClubSymbol.tsx";
|
|
13
|
+
import { LoadingIndicator } from "../LoadingIndicator.tsx";
|
|
14
|
+
import * as css from "./style.css.ts";
|
|
15
|
+
|
|
16
|
+
export type LetterheadHeadingProps = RecipeVariants<typeof css.heading> &
|
|
17
|
+
HeadingProps;
|
|
18
|
+
|
|
19
|
+
export function LetterheadHeading(props: LetterheadHeadingProps) {
|
|
20
|
+
const { align, margin, ...rest } = props;
|
|
21
|
+
return <Heading {...rest} {...cx(props, css.heading({ align, margin }))} />;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type LetterheadParagraphProps = RecipeVariants<typeof css.paragraph> &
|
|
25
|
+
ComponentProps<"p">;
|
|
26
|
+
|
|
27
|
+
export function LetterheadParagraph(props: LetterheadParagraphProps) {
|
|
28
|
+
const { size, align, ...rest } = props;
|
|
29
|
+
return <p {...rest} {...cx(props, css.paragraph({ size, align }))} />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type LetterheadFooterProps = ComponentProps<"div">;
|
|
33
|
+
|
|
34
|
+
export function LetterheadFooter(props: LetterheadFooterProps) {
|
|
35
|
+
return (
|
|
36
|
+
<div {...props} {...cx(props, css.letterheadFooter)}>
|
|
37
|
+
<IndieTabletopClubLogo {...cx(css.letterheadFooterLogo)} />
|
|
38
|
+
|
|
39
|
+
<LetterheadParagraph {...cx(css.letterheadFooterInfo)} size="small">
|
|
40
|
+
Indie Tabletop Club supports independent game creators with premium
|
|
41
|
+
digital tools.{" "}
|
|
42
|
+
<ExternalLink
|
|
43
|
+
href="https://indietabletop.club"
|
|
44
|
+
className={interactiveText}
|
|
45
|
+
>
|
|
46
|
+
Learn more
|
|
47
|
+
</ExternalLink>
|
|
48
|
+
.
|
|
49
|
+
</LetterheadParagraph>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type LetterheadSubmitButton = RecipeVariants<typeof css.button> &
|
|
55
|
+
Omit<FormSubmitButtonProps, "loading">;
|
|
56
|
+
|
|
57
|
+
export function LetterheadSubmitButton(props: LetterheadSubmitButton) {
|
|
58
|
+
const { marginBlockStart, ...rest } = props;
|
|
59
|
+
return (
|
|
60
|
+
<FormSubmitButton
|
|
61
|
+
{...rest}
|
|
62
|
+
{...cx(css.button({ marginBlockStart }), props)}
|
|
63
|
+
loading={<LoadingIndicator />}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type LetterheadProps = RecipeVariants<typeof css.letterhead> & {
|
|
69
|
+
headerIcon?: ReactNode;
|
|
70
|
+
children: ReactNode;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export function Letterhead(props: LetterheadProps) {
|
|
74
|
+
const { children, textAlign, headerIcon = true } = props;
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className={css.letterhead({ textAlign })}>
|
|
78
|
+
{headerIcon && <IndieTabletopClubSymbol {...cx(css.letterheadSymbol)} />}
|
|
79
|
+
|
|
80
|
+
{children}
|
|
81
|
+
|
|
82
|
+
<LetterheadFooter />
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { FormProvider } from "@ariakit/react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
3
|
+
import {
|
|
4
|
+
Letterhead,
|
|
5
|
+
LetterheadHeading,
|
|
6
|
+
LetterheadParagraph,
|
|
7
|
+
LetterheadSubmitButton,
|
|
8
|
+
} from "./index.tsx";
|
|
9
|
+
|
|
10
|
+
const meta = {
|
|
11
|
+
title: "Letterhead",
|
|
12
|
+
component: Letterhead,
|
|
13
|
+
tags: ["autodocs"],
|
|
14
|
+
args: {
|
|
15
|
+
textAlign: "start",
|
|
16
|
+
},
|
|
17
|
+
} satisfies Meta<typeof Letterhead>;
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
|
|
21
|
+
type Story = StoryObj<typeof meta>;
|
|
22
|
+
|
|
23
|
+
export const Default: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
children: (
|
|
26
|
+
<>
|
|
27
|
+
<LetterheadHeading align="center" margin="letterhead">
|
|
28
|
+
Lorem ipsum dolor
|
|
29
|
+
</LetterheadHeading>
|
|
30
|
+
|
|
31
|
+
<LetterheadParagraph>
|
|
32
|
+
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut enim ad
|
|
33
|
+
minima veniam, quis <em>nostrum</em> exercitationem ullam corporis
|
|
34
|
+
suscipit laboriosam.
|
|
35
|
+
</LetterheadParagraph>
|
|
36
|
+
|
|
37
|
+
<FormProvider>
|
|
38
|
+
<LetterheadSubmitButton marginBlockStart="footerMargin">
|
|
39
|
+
Lorem ipsum
|
|
40
|
+
</LetterheadSubmitButton>
|
|
41
|
+
</FormProvider>
|
|
42
|
+
</>
|
|
43
|
+
),
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { createTheme, style } from "@vanilla-extract/css";
|
|
2
|
+
import { recipe } from "@vanilla-extract/recipes";
|
|
3
|
+
import { textVariants } from "../atomic.css.ts";
|
|
4
|
+
import { manofa, minion } from "../common.css.ts";
|
|
5
|
+
import { Hover } from "../media.ts";
|
|
6
|
+
|
|
7
|
+
const align = {
|
|
8
|
+
start: textVariants({ textAlign: "start" }),
|
|
9
|
+
center: textVariants({ textAlign: "center" }),
|
|
10
|
+
end: textVariants({ textAlign: "end" }),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const [letterheadTheme, { padding, footerMargin }] = createTheme({
|
|
14
|
+
padding: "clamp(1rem, 8vw, 4rem)",
|
|
15
|
+
footerMargin: "3rem",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const letterhead = recipe({
|
|
19
|
+
base: [
|
|
20
|
+
letterheadTheme,
|
|
21
|
+
minion,
|
|
22
|
+
{
|
|
23
|
+
backgroundColor: "white",
|
|
24
|
+
padding: `calc(${padding} / 2) ${padding} ${padding}`,
|
|
25
|
+
borderRadius: "1rem",
|
|
26
|
+
marginInline: "auto",
|
|
27
|
+
maxInlineSize: "36rem",
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
textAlign: "center",
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
variants: {
|
|
36
|
+
textAlign: align,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const letterheadSymbol = style({
|
|
41
|
+
marginBlockEnd: "0.5rem",
|
|
42
|
+
marginInline: "auto",
|
|
43
|
+
display: "block",
|
|
44
|
+
inlineSize: "2.5rem",
|
|
45
|
+
blockSize: "2.5rem",
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const heading = recipe({
|
|
49
|
+
base: [
|
|
50
|
+
manofa,
|
|
51
|
+
{
|
|
52
|
+
fontWeight: 400,
|
|
53
|
+
fontSize: "1.5rem",
|
|
54
|
+
marginBlockEnd: "1rem",
|
|
55
|
+
lineHeight: 1.2,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
|
|
59
|
+
variants: {
|
|
60
|
+
align,
|
|
61
|
+
|
|
62
|
+
margin: {
|
|
63
|
+
letterhead: {
|
|
64
|
+
marginBlockEnd: `min(calc(${padding} / 2), 1.5rem)`,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export const paragraph = recipe({
|
|
71
|
+
base: [
|
|
72
|
+
minion,
|
|
73
|
+
{
|
|
74
|
+
lineHeight: 1.5,
|
|
75
|
+
selectors: {
|
|
76
|
+
"& + &": { marginTop: "0.5lh" },
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
|
|
81
|
+
defaultVariants: {
|
|
82
|
+
size: "default",
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
variants: {
|
|
86
|
+
size: {
|
|
87
|
+
small: { fontSize: "0.875rem" },
|
|
88
|
+
default: { fontSize: "1rem" },
|
|
89
|
+
},
|
|
90
|
+
align,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
export const button = recipe({
|
|
95
|
+
base: [
|
|
96
|
+
manofa,
|
|
97
|
+
{
|
|
98
|
+
letterSpacing: 0,
|
|
99
|
+
textTransform: "uppercase",
|
|
100
|
+
backgroundColor: "black",
|
|
101
|
+
color: "white",
|
|
102
|
+
width: "100%",
|
|
103
|
+
border: "none",
|
|
104
|
+
borderRadius: "0.5rem",
|
|
105
|
+
padding: "1rem 1.5rem",
|
|
106
|
+
fontSize: "0.875rem",
|
|
107
|
+
|
|
108
|
+
"@media": {
|
|
109
|
+
[Hover.HOVER]: {
|
|
110
|
+
transition: "box-shadow 400ms",
|
|
111
|
+
|
|
112
|
+
":hover": {
|
|
113
|
+
boxShadow: "inset 0 0 0 2px hsl(0 0% 100% / 0.5)",
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
|
|
120
|
+
variants: {
|
|
121
|
+
marginBlockStart: {
|
|
122
|
+
footerMargin: { marginBlockStart: `calc(${footerMargin} - 0.5rem)` },
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export const letterheadFooter = style({
|
|
128
|
+
textAlign: "center",
|
|
129
|
+
marginBlockStart: footerMargin,
|
|
130
|
+
paddingBlockStart: "2rem",
|
|
131
|
+
borderBlockStart: "1px solid #ececec",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export const letterheadFooterLogo = style({
|
|
135
|
+
margin: "0 auto 1.125rem",
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export const letterheadFooterInfo = style({
|
|
139
|
+
margin: "0 auto",
|
|
140
|
+
maxInlineSize: "25rem",
|
|
141
|
+
});
|
package/lib/atomic.css.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
import { createSprinkles } from "@vanilla-extract/sprinkles";
|
|
1
|
+
import { createSprinkles, defineProperties } from "@vanilla-extract/sprinkles";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const atomic = defineProperties({
|
|
4
|
+
properties: {
|
|
5
|
+
textAlign: ["start", "center", "end"],
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const textVariants = createSprinkles(atomic);
|
|
10
|
+
|
|
11
|
+
export type TextVariants = Parameters<typeof textVariants>[0];
|
package/lib/class-names.ts
CHANGED
|
@@ -1,8 +1,33 @@
|
|
|
1
|
+
type Falsy = false | null | undefined;
|
|
2
|
+
|
|
3
|
+
type PropsWithClassName = {
|
|
4
|
+
className?: ClassName;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
type ClassName = string | PropsWithClassName | Falsy;
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
|
-
* Combines a list of strings
|
|
10
|
+
* Combines a list of strings or objects with className property into a single
|
|
11
|
+
* string. Falsy values are ignored.
|
|
3
12
|
*/
|
|
4
|
-
export function classNames(
|
|
5
|
-
|
|
6
|
-
)
|
|
7
|
-
|
|
13
|
+
export function classNames(...classNames: ClassName[]) {
|
|
14
|
+
return classNames
|
|
15
|
+
.filter((cn) => !!cn)
|
|
16
|
+
.map((cn) => (typeof cn === "object" ? cn?.className : cn))
|
|
17
|
+
.join(" ");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Given a list of strings or objects with the className property, returns an
|
|
22
|
+
* object with className property and combined className. Falsy values will
|
|
23
|
+
* be filtered out.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* <h1 {...clx(props, 'heading', 'bold')}>Hello world!</h1>
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
export function cx(...cns: ClassName[]) {
|
|
30
|
+
return {
|
|
31
|
+
className: classNames(...cns),
|
|
32
|
+
};
|
|
8
33
|
}
|
package/lib/common.css.ts
CHANGED
package/lib/index.ts
CHANGED
|
@@ -3,8 +3,7 @@ export * from "./ExternalLink.tsx";
|
|
|
3
3
|
export * from "./FormSubmitButton.tsx";
|
|
4
4
|
export * from "./FullscreenDismissBlocker.tsx";
|
|
5
5
|
export * from "./IndieTabletopClubSymbol.tsx";
|
|
6
|
-
export * from "./Letterhead.tsx";
|
|
7
|
-
export * from "./LetterheadFooter.tsx";
|
|
6
|
+
export * from "./Letterhead/index.tsx";
|
|
8
7
|
export * from "./LoadingIndicator.tsx";
|
|
9
8
|
export * from "./ServiceWorkerHandler.tsx";
|
|
10
9
|
|
package/lib/internal.css.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createVar, style } from "@vanilla-extract/css";
|
|
2
2
|
import { bounce } from "./animations.css.ts";
|
|
3
|
-
import { minion } from "./common.css.ts";
|
|
4
3
|
|
|
5
4
|
export const animationDelay = createVar();
|
|
6
5
|
|
|
@@ -9,18 +8,3 @@ export const dot = style({
|
|
|
9
8
|
opacity: 0.8,
|
|
10
9
|
animation: `${bounce} 2s ${animationDelay} infinite`,
|
|
11
10
|
});
|
|
12
|
-
|
|
13
|
-
export const padding = createVar();
|
|
14
|
-
|
|
15
|
-
export const letterhead = style([
|
|
16
|
-
minion,
|
|
17
|
-
{
|
|
18
|
-
vars: { [padding]: "clamp(1rem, 8vw, 4rem)" },
|
|
19
|
-
|
|
20
|
-
backgroundColor: "white",
|
|
21
|
-
padding: `max(1rem, calc(${padding} - .5rem)) ${padding} ${padding}`,
|
|
22
|
-
borderRadius: "1rem",
|
|
23
|
-
marginInline: "auto",
|
|
24
|
-
maxInlineSize: "36rem",
|
|
25
|
-
},
|
|
26
|
-
]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indietabletop/appkit",
|
|
3
|
-
"version": "3.2.0-
|
|
3
|
+
"version": "3.2.0-6",
|
|
4
4
|
"description": "A collection of modules used in apps built by Indie Tabletop Club",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"exports": {
|
|
15
15
|
".": "./lib/index.ts",
|
|
16
|
-
"
|
|
16
|
+
"./*.css.ts": "./lib/*.css.ts"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"/lib"
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"@indietabletop/tooling": "^5.0.0",
|
|
40
40
|
"@vanilla-extract/css": "^1.17.2",
|
|
41
41
|
"@vanilla-extract/dynamic": "^2.1.3",
|
|
42
|
+
"@vanilla-extract/recipes": "^0.5.7",
|
|
42
43
|
"@vanilla-extract/sprinkles": "^1.6.3",
|
|
43
44
|
"superstruct": "^2.0.2"
|
|
44
45
|
}
|
package/lib/Letterhead.tsx
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
import { IndieTabletopClubSymbol } from "./IndieTabletopClubSymbol.tsx";
|
|
3
|
-
import { letterhead } from "./internal.css.ts";
|
|
4
|
-
import { LetterheadFooter } from "./LetterheadFooter.tsx";
|
|
5
|
-
|
|
6
|
-
export type LetterheadProps = {
|
|
7
|
-
headerIcon?: boolean;
|
|
8
|
-
children: ReactNode;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export function Letterhead(props: LetterheadProps) {
|
|
12
|
-
const { children, headerIcon = true } = props;
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<div className={letterhead}>
|
|
16
|
-
{headerIcon && (
|
|
17
|
-
<IndieTabletopClubSymbol
|
|
18
|
-
style={{
|
|
19
|
-
marginBlock: "-1rem 1rem",
|
|
20
|
-
marginInline: "auto",
|
|
21
|
-
display: "block",
|
|
22
|
-
inlineSize: "2.5rem",
|
|
23
|
-
blockSize: "2.5rem",
|
|
24
|
-
}}
|
|
25
|
-
/>
|
|
26
|
-
)}
|
|
27
|
-
|
|
28
|
-
{children}
|
|
29
|
-
|
|
30
|
-
<LetterheadFooter />
|
|
31
|
-
</div>
|
|
32
|
-
);
|
|
33
|
-
}
|
package/lib/LetterheadFooter.tsx
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { interactiveText } from "./common.css.ts";
|
|
2
|
-
import { ExternalLink } from "./ExternalLink.tsx";
|
|
3
|
-
import { IndieTabletopClubLogo } from "./IndieTabletopClubLogo.tsx";
|
|
4
|
-
|
|
5
|
-
export function LetterheadFooter() {
|
|
6
|
-
return (
|
|
7
|
-
<div
|
|
8
|
-
style={{
|
|
9
|
-
textAlign: "center",
|
|
10
|
-
paddingBlockStart: "2rem",
|
|
11
|
-
borderBlockStart: "1px solid #ececec",
|
|
12
|
-
marginBlockStart: "3rem",
|
|
13
|
-
}}
|
|
14
|
-
>
|
|
15
|
-
<IndieTabletopClubLogo style={{ margin: "0 auto 1.125rem" }} />
|
|
16
|
-
<p
|
|
17
|
-
style={{
|
|
18
|
-
margin: "0 auto",
|
|
19
|
-
maxInlineSize: "25rem",
|
|
20
|
-
fontSize: "0.875rem",
|
|
21
|
-
lineHeight: "1.25rem",
|
|
22
|
-
fontFamily: "minion-pro, serif",
|
|
23
|
-
}}
|
|
24
|
-
>
|
|
25
|
-
Indie Tabletop Club supports independent game creators with high‑quality
|
|
26
|
-
digital tools.{" "}
|
|
27
|
-
<ExternalLink
|
|
28
|
-
href="https://indietabletop.club"
|
|
29
|
-
className={interactiveText}
|
|
30
|
-
>
|
|
31
|
-
Learn more
|
|
32
|
-
</ExternalLink>
|
|
33
|
-
.
|
|
34
|
-
</p>
|
|
35
|
-
</div>
|
|
36
|
-
);
|
|
37
|
-
}
|