@comet/mail-react 9.0.0-beta.0 → 9.0.0-beta.2
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 +26 -0
- package/lib/__stories__/examples/CustomNestedFooterTheme.stories.d.ts +5 -0
- package/lib/__stories__/examples/CustomNestedFooterTheme.stories.js +32 -0
- package/lib/__stories__/examples/NotificationEmail.stories.d.ts +5 -0
- package/lib/__stories__/examples/NotificationEmail.stories.js +25 -0
- package/lib/__stories__/examples/TextWithImageEmail.stories.d.ts +5 -0
- package/lib/__stories__/examples/TextWithImageEmail.stories.js +56 -0
- package/lib/client/index.d.ts +1 -0
- package/lib/client/index.js +1 -0
- package/lib/client/renderMailHtml.d.ts +9 -0
- package/lib/client/renderMailHtml.js +7 -0
- package/lib/components/inlineLink/HtmlInlineLink.d.ts +10 -0
- package/lib/components/inlineLink/HtmlInlineLink.js +35 -0
- package/lib/components/inlineLink/__stories__/HtmlInlineLink.stories.d.ts +12 -0
- package/lib/components/inlineLink/__stories__/HtmlInlineLink.stories.js +56 -0
- package/lib/components/mailRoot/MjmlMailRoot.d.ts +22 -0
- package/lib/components/mailRoot/MjmlMailRoot.js +20 -0
- package/lib/components/mailRoot/__stories__/MjmlMailRoot.stories.d.ts +7 -0
- package/lib/components/mailRoot/__stories__/MjmlMailRoot.stories.js +18 -0
- package/lib/components/section/MjmlSection.d.ts +15 -0
- package/lib/components/section/MjmlSection.js +44 -0
- package/lib/components/section/__stories__/MjmlSection.stories.d.ts +9 -0
- package/lib/components/section/__stories__/MjmlSection.stories.js +30 -0
- package/lib/components/text/HtmlText.d.ts +48 -0
- package/lib/components/text/HtmlText.js +47 -0
- package/lib/components/text/MjmlText.d.ts +37 -0
- package/lib/components/text/MjmlText.js +65 -0
- package/lib/components/text/OutlookTextStyleContext.d.ts +9 -0
- package/lib/components/text/OutlookTextStyleContext.js +10 -0
- package/lib/components/text/__stories__/HtmlText.stories.d.ts +12 -0
- package/lib/components/text/__stories__/HtmlText.stories.js +77 -0
- package/lib/components/text/__stories__/MjmlText.stories.d.ts +10 -0
- package/lib/components/text/__stories__/MjmlText.stories.js +71 -0
- package/lib/components/text/__tests__/HtmlText.test.d.ts +1 -0
- package/lib/components/text/__tests__/HtmlText.test.js +157 -0
- package/lib/components/text/__tests__/MjmlText.test.d.ts +1 -0
- package/lib/components/text/__tests__/MjmlText.test.js +112 -0
- package/lib/components/text/textStyles.d.ts +12 -0
- package/lib/components/text/textStyles.js +69 -0
- package/lib/index.d.ts +17 -1
- package/lib/index.js +11 -1
- package/lib/server/index.d.ts +1 -0
- package/lib/server/index.js +1 -0
- package/lib/server/renderMailHtml.d.ts +9 -0
- package/lib/server/renderMailHtml.js +7 -0
- package/lib/server/renderMailHtml.test.d.ts +1 -0
- package/lib/server/renderMailHtml.test.js +43 -0
- package/lib/storybook/CopyMailHtmlButton.d.ts +4 -0
- package/lib/storybook/CopyMailHtmlButton.js +33 -0
- package/lib/storybook/MailRendererDecorator.d.ts +7 -0
- package/lib/storybook/MailRendererDecorator.js +17 -0
- package/lib/storybook/MjmlWarningsPanel.d.ts +7 -0
- package/lib/storybook/MjmlWarningsPanel.js +33 -0
- package/lib/storybook/UsePublicImageUrlsToggle.d.ts +4 -0
- package/lib/storybook/UsePublicImageUrlsToggle.js +14 -0
- package/lib/storybook/index.d.ts +2 -0
- package/lib/storybook/index.js +9 -0
- package/lib/storybook/manager.d.ts +1 -0
- package/lib/storybook/manager.js +25 -0
- package/lib/storybook/preview.d.ts +5 -0
- package/lib/storybook/preview.js +5 -0
- package/lib/storybook/replaceImagesWithPublicUrl.d.ts +1 -0
- package/lib/storybook/replaceImagesWithPublicUrl.js +15 -0
- package/lib/storybook/replaceImagesWithPublicUrl.test.d.ts +1 -0
- package/lib/storybook/replaceImagesWithPublicUrl.test.js +55 -0
- package/lib/styles/Styles.d.ts +6 -0
- package/lib/styles/Styles.js +16 -0
- package/lib/styles/registerStyles.d.ts +19 -0
- package/lib/styles/registerStyles.js +14 -0
- package/lib/theme/ThemeProvider.d.ts +8 -0
- package/lib/theme/ThemeProvider.js +17 -0
- package/lib/theme/__stories__/ThemeProvider.stories.d.ts +7 -0
- package/lib/theme/__stories__/ThemeProvider.stories.js +23 -0
- package/lib/theme/createBreakpoint.d.ts +7 -0
- package/lib/theme/createBreakpoint.js +11 -0
- package/lib/theme/createTheme.d.ts +22 -0
- package/lib/theme/createTheme.js +30 -0
- package/lib/theme/createTheme.test.d.ts +1 -0
- package/lib/theme/createTheme.test.js +52 -0
- package/lib/theme/defaultTheme.d.ts +2 -0
- package/lib/theme/defaultTheme.js +23 -0
- package/lib/theme/responsiveValue.d.ts +31 -0
- package/lib/theme/responsiveValue.js +33 -0
- package/lib/theme/responsiveValue.test.d.ts +1 -0
- package/lib/theme/responsiveValue.test.js +62 -0
- package/lib/theme/themeTypes.d.ts +106 -0
- package/lib/theme/themeTypes.js +1 -0
- package/lib/utils/css.test.d.ts +1 -0
- package/lib/utils/css.test.js +26 -0
- package/package.json +35 -11
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { createTheme } from "./createTheme.js";
|
|
3
|
+
import { getDefaultFromResponsiveValue, getResponsiveOverrides } from "./responsiveValue.js";
|
|
4
|
+
describe("createTheme text", () => {
|
|
5
|
+
it("includes default text values when no overrides given", () => {
|
|
6
|
+
const theme = createTheme();
|
|
7
|
+
expect(theme.text.fontFamily).toBe("Arial, sans-serif");
|
|
8
|
+
expect(theme.text.fontSize).toBe("16px");
|
|
9
|
+
expect(theme.text.lineHeight).toBe("20px");
|
|
10
|
+
expect(theme.text.bottomSpacing).toBe("16px");
|
|
11
|
+
});
|
|
12
|
+
it("shallow-merges text overrides with defaults", () => {
|
|
13
|
+
const theme = createTheme({ text: { fontFamily: "Georgia, serif", fontSize: "18px" } });
|
|
14
|
+
expect(theme.text.fontFamily).toBe("Georgia, serif");
|
|
15
|
+
expect(theme.text.fontSize).toBe("18px");
|
|
16
|
+
expect(theme.text.lineHeight).toBe("20px");
|
|
17
|
+
expect(theme.text.bottomSpacing).toBe("16px");
|
|
18
|
+
});
|
|
19
|
+
it("passes through variant definitions", () => {
|
|
20
|
+
const theme = createTheme({
|
|
21
|
+
text: {
|
|
22
|
+
variants: {
|
|
23
|
+
heading: { fontSize: { default: "32px", mobile: "24px" } },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
expect(theme.text.variants).toBeDefined();
|
|
28
|
+
expect(theme.text.variants?.heading).toEqual({ fontSize: { default: "32px", mobile: "24px" } });
|
|
29
|
+
});
|
|
30
|
+
it("does not set defaultVariant or variants by default", () => {
|
|
31
|
+
const theme = createTheme();
|
|
32
|
+
expect(theme.text.defaultVariant).toBeUndefined();
|
|
33
|
+
expect(theme.text.variants).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("createTheme contentIndentation", () => {
|
|
37
|
+
it("has default contentIndentation with responsive mobile value", () => {
|
|
38
|
+
const theme = createTheme();
|
|
39
|
+
expect(getDefaultFromResponsiveValue(theme.sizes.contentIndentation)).toBe(32);
|
|
40
|
+
expect(getResponsiveOverrides(theme.sizes.contentIndentation)).toContainEqual({ breakpointKey: "mobile", value: 16 });
|
|
41
|
+
});
|
|
42
|
+
it("allows overriding contentIndentation with a plain number", () => {
|
|
43
|
+
const theme = createTheme({ sizes: { contentIndentation: 30 } });
|
|
44
|
+
expect(getDefaultFromResponsiveValue(theme.sizes.contentIndentation)).toBe(30);
|
|
45
|
+
expect(getResponsiveOverrides(theme.sizes.contentIndentation)).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
it("allows overriding contentIndentation with an object", () => {
|
|
48
|
+
const theme = createTheme({ sizes: { contentIndentation: { default: 30, mobile: 15 } } });
|
|
49
|
+
expect(getDefaultFromResponsiveValue(theme.sizes.contentIndentation)).toBe(30);
|
|
50
|
+
expect(getResponsiveOverrides(theme.sizes.contentIndentation)).toContainEqual({ breakpointKey: "mobile", value: 15 });
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createBreakpoint } from "./createBreakpoint.js";
|
|
2
|
+
export const defaultTheme = {
|
|
3
|
+
sizes: {
|
|
4
|
+
bodyWidth: 600,
|
|
5
|
+
contentIndentation: { default: 32, mobile: 16 },
|
|
6
|
+
},
|
|
7
|
+
breakpoints: {
|
|
8
|
+
default: createBreakpoint(600),
|
|
9
|
+
mobile: createBreakpoint(420),
|
|
10
|
+
},
|
|
11
|
+
text: {
|
|
12
|
+
fontFamily: "Arial, sans-serif",
|
|
13
|
+
fontSize: "16px",
|
|
14
|
+
lineHeight: "20px",
|
|
15
|
+
bottomSpacing: "16px",
|
|
16
|
+
},
|
|
17
|
+
colors: {
|
|
18
|
+
background: {
|
|
19
|
+
body: "#F2F2F2",
|
|
20
|
+
content: "#FFFFFF",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ThemeBreakpoints } from "./themeTypes.js";
|
|
2
|
+
/**
|
|
3
|
+
* A value that can vary per breakpoint. A plain `T` is shorthand for
|
|
4
|
+
* `{ default: T }` (inline only, no responsive overrides).
|
|
5
|
+
*
|
|
6
|
+
* The object form requires a `default` key and optional keys matching
|
|
7
|
+
* `ThemeBreakpoints` (including keys added via module augmentation).
|
|
8
|
+
*/
|
|
9
|
+
export type ResponsiveValue<T = number> = T | (Partial<Record<keyof ThemeBreakpoints, T>> & {
|
|
10
|
+
default: T;
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Returns the default (inline) value from a `ResponsiveValue`.
|
|
14
|
+
* For a plain value, returns it directly. For an object, returns the `default` property.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDefaultFromResponsiveValue<T = number>(value: ResponsiveValue<T>): T;
|
|
17
|
+
/**
|
|
18
|
+
* Returns the default value from a `ResponsiveValue`, or `undefined` if the
|
|
19
|
+
* input is `undefined`. Useful for extracting inline prop values from optional
|
|
20
|
+
* theme properties.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDefaultOrUndefined<T>(value: ResponsiveValue<T> | undefined): T | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the non-default breakpoint overrides from a `ResponsiveValue`.
|
|
25
|
+
* For a plain value, returns an empty array. For an object, returns one
|
|
26
|
+
* entry per breakpoint key (excluding `default`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function getResponsiveOverrides<T = number>(value: ResponsiveValue<T>): Array<{
|
|
29
|
+
breakpointKey: keyof ThemeBreakpoints;
|
|
30
|
+
value: T;
|
|
31
|
+
}>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
function isResponsiveObject(value) {
|
|
2
|
+
return typeof value === "object" && value !== null && "default" in value;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Returns the default (inline) value from a `ResponsiveValue`.
|
|
6
|
+
* For a plain value, returns it directly. For an object, returns the `default` property.
|
|
7
|
+
*/
|
|
8
|
+
export function getDefaultFromResponsiveValue(value) {
|
|
9
|
+
return isResponsiveObject(value) ? value.default : value;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Returns the default value from a `ResponsiveValue`, or `undefined` if the
|
|
13
|
+
* input is `undefined`. Useful for extracting inline prop values from optional
|
|
14
|
+
* theme properties.
|
|
15
|
+
*/
|
|
16
|
+
export function getDefaultOrUndefined(value) {
|
|
17
|
+
if (value === undefined)
|
|
18
|
+
return undefined;
|
|
19
|
+
return getDefaultFromResponsiveValue(value);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Returns the non-default breakpoint overrides from a `ResponsiveValue`.
|
|
23
|
+
* For a plain value, returns an empty array. For an object, returns one
|
|
24
|
+
* entry per breakpoint key (excluding `default`).
|
|
25
|
+
*/
|
|
26
|
+
export function getResponsiveOverrides(value) {
|
|
27
|
+
if (!isResponsiveObject(value)) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
return Object.entries(value)
|
|
31
|
+
.filter(([key]) => key !== "default")
|
|
32
|
+
.map(([key, val]) => ({ breakpointKey: key, value: val }));
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { getDefaultFromResponsiveValue, getDefaultOrUndefined, getResponsiveOverrides } from "./responsiveValue.js";
|
|
3
|
+
describe("getDefaultFromResponsiveValue", () => {
|
|
4
|
+
it("returns the value when given a plain number", () => {
|
|
5
|
+
expect(getDefaultFromResponsiveValue(20)).toBe(20);
|
|
6
|
+
});
|
|
7
|
+
it("returns the default property from an object", () => {
|
|
8
|
+
expect(getDefaultFromResponsiveValue({ default: 20, mobile: 10 })).toBe(20);
|
|
9
|
+
});
|
|
10
|
+
it("returns the default property when only default is present", () => {
|
|
11
|
+
expect(getDefaultFromResponsiveValue({ default: 42 })).toBe(42);
|
|
12
|
+
});
|
|
13
|
+
it("works with string type", () => {
|
|
14
|
+
expect(getDefaultFromResponsiveValue({ default: "24px", mobile: "20px" })).toBe("24px");
|
|
15
|
+
});
|
|
16
|
+
it("returns a plain string value", () => {
|
|
17
|
+
expect(getDefaultFromResponsiveValue("24px")).toBe("24px");
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe("getResponsiveOverrides", () => {
|
|
21
|
+
it("returns an empty array for a plain number", () => {
|
|
22
|
+
expect(getResponsiveOverrides(20)).toEqual([]);
|
|
23
|
+
});
|
|
24
|
+
it("returns an empty array for an object with only default", () => {
|
|
25
|
+
expect(getResponsiveOverrides({ default: 42 })).toEqual([]);
|
|
26
|
+
});
|
|
27
|
+
it("returns overrides for non-default keys", () => {
|
|
28
|
+
const result = getResponsiveOverrides({ default: 20, mobile: 10 });
|
|
29
|
+
expect(result).toEqual([{ breakpointKey: "mobile", value: 10 }]);
|
|
30
|
+
});
|
|
31
|
+
it("returns multiple overrides for multiple breakpoint keys", () => {
|
|
32
|
+
const value = { default: 30, mobile: 10 };
|
|
33
|
+
const result = getResponsiveOverrides(value);
|
|
34
|
+
expect(result).toContainEqual({ breakpointKey: "mobile", value: 10 });
|
|
35
|
+
expect(result).not.toContainEqual(expect.objectContaining({ breakpointKey: "default" }));
|
|
36
|
+
});
|
|
37
|
+
it("never includes the default key in overrides", () => {
|
|
38
|
+
const result = getResponsiveOverrides({ default: 20, mobile: 10 });
|
|
39
|
+
expect(result.every((o) => o.breakpointKey !== "default")).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
it("works with string type", () => {
|
|
42
|
+
const result = getResponsiveOverrides({ default: "24px", mobile: "20px" });
|
|
43
|
+
expect(result).toEqual([{ breakpointKey: "mobile", value: "20px" }]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe("getDefaultOrUndefined", () => {
|
|
47
|
+
it("returns undefined when given undefined", () => {
|
|
48
|
+
expect(getDefaultOrUndefined(undefined)).toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
it("returns the value when given a plain value", () => {
|
|
51
|
+
expect(getDefaultOrUndefined(20)).toBe(20);
|
|
52
|
+
});
|
|
53
|
+
it("returns the default property from an object", () => {
|
|
54
|
+
expect(getDefaultOrUndefined({ default: 20, mobile: 10 })).toBe(20);
|
|
55
|
+
});
|
|
56
|
+
it("works with string type", () => {
|
|
57
|
+
expect(getDefaultOrUndefined("24px")).toBe("24px");
|
|
58
|
+
});
|
|
59
|
+
it("returns default from a string responsive object", () => {
|
|
60
|
+
expect(getDefaultOrUndefined({ default: "32px", mobile: "24px" })).toBe("32px");
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { ResponsiveValue } from "./responsiveValue.js";
|
|
2
|
+
/**
|
|
3
|
+
* Single source of truth for text style property names and their value types.
|
|
4
|
+
* Both `TextStyles` and `TextVariantStyles` are derived from this interface.
|
|
5
|
+
*/
|
|
6
|
+
interface TextStyleMap {
|
|
7
|
+
fontFamily: string;
|
|
8
|
+
fontSize: string;
|
|
9
|
+
fontWeight: string | number;
|
|
10
|
+
fontStyle: string;
|
|
11
|
+
lineHeight: string | number;
|
|
12
|
+
letterSpacing: string;
|
|
13
|
+
textDecoration: string;
|
|
14
|
+
textTransform: string;
|
|
15
|
+
color: string;
|
|
16
|
+
bottomSpacing: string;
|
|
17
|
+
}
|
|
18
|
+
/** Base text styles where each property holds a plain value. */
|
|
19
|
+
export type TextStyles = {
|
|
20
|
+
[K in keyof TextStyleMap]?: TextStyleMap[K];
|
|
21
|
+
};
|
|
22
|
+
/** Variant text styles where each property supports responsive values. */
|
|
23
|
+
export type TextVariantStyles = {
|
|
24
|
+
[K in keyof TextStyleMap]?: ResponsiveValue<TextStyleMap[K]>;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Defines the variants available on the `MjmlText` component.
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* declare module "@comet/mail-react" {
|
|
31
|
+
* interface TextVariants {
|
|
32
|
+
* heading: true;
|
|
33
|
+
* body: true;
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export interface TextVariants {
|
|
39
|
+
}
|
|
40
|
+
type VariantsRecord = keyof TextVariants extends never ? Record<string, TextVariantStyles> : {
|
|
41
|
+
[K in keyof TextVariants]?: TextVariantStyles;
|
|
42
|
+
};
|
|
43
|
+
export type VariantName = keyof TextVariants extends never ? string : keyof TextVariants;
|
|
44
|
+
/** Theme configuration for text styles, variants, and default variant. */
|
|
45
|
+
export interface ThemeText extends TextStyles {
|
|
46
|
+
defaultVariant?: VariantName;
|
|
47
|
+
variants?: VariantsRecord;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A resolved breakpoint with its numeric value and a ready-to-use media query
|
|
51
|
+
* string that targets viewports narrower than this breakpoint.
|
|
52
|
+
*/
|
|
53
|
+
export interface ThemeBreakpoint {
|
|
54
|
+
/** The breakpoint width in pixels. */
|
|
55
|
+
value: number;
|
|
56
|
+
/** A CSS media query matching viewports below this breakpoint, e.g. `"@media (max-width: 599px)"`. */
|
|
57
|
+
belowMediaQuery: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Responsive breakpoints used by the email layout.
|
|
61
|
+
*
|
|
62
|
+
* The `default` breakpoint typically matches the body width, while `mobile`
|
|
63
|
+
* defines the narrow viewport threshold.
|
|
64
|
+
*/
|
|
65
|
+
export interface ThemeBreakpoints {
|
|
66
|
+
/** The default breakpoint, usually equal to `sizes.bodyWidth`. */
|
|
67
|
+
default: ThemeBreakpoint;
|
|
68
|
+
/**
|
|
69
|
+
* The mobile breakpoint — the viewport width below which the layout is
|
|
70
|
+
* considered "mobile".
|
|
71
|
+
*
|
|
72
|
+
* When used with `MjmlMailRoot`, this value also controls the MJML
|
|
73
|
+
* responsive breakpoint (`<mj-breakpoint>`), which determines the viewport
|
|
74
|
+
* width at which columns stack vertically.
|
|
75
|
+
*/
|
|
76
|
+
mobile: ThemeBreakpoint;
|
|
77
|
+
}
|
|
78
|
+
/** Numeric size tokens for the email layout. */
|
|
79
|
+
export interface ThemeSizes {
|
|
80
|
+
/** The width of the email body in pixels. */
|
|
81
|
+
bodyWidth: number;
|
|
82
|
+
/** Content indentation (left/right padding) in pixels, supporting per-breakpoint values. */
|
|
83
|
+
contentIndentation: ResponsiveValue;
|
|
84
|
+
}
|
|
85
|
+
/** Background color tokens for usage through the email layout. */
|
|
86
|
+
export interface ThemeBackgroundColors {
|
|
87
|
+
body: string;
|
|
88
|
+
content: string;
|
|
89
|
+
}
|
|
90
|
+
/** Color tokens for usage through the email layout. */
|
|
91
|
+
export interface ThemeColors {
|
|
92
|
+
background: ThemeBackgroundColors;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The root theme object that holds all design tokens for `@comet/mail-react`.
|
|
96
|
+
*
|
|
97
|
+
* Every sub-interface is declared as an `interface` so consumers can
|
|
98
|
+
* extend the theme at any level via TypeScript module augmentation.
|
|
99
|
+
*/
|
|
100
|
+
export interface Theme {
|
|
101
|
+
sizes: ThemeSizes;
|
|
102
|
+
breakpoints: ThemeBreakpoints;
|
|
103
|
+
text: ThemeText;
|
|
104
|
+
colors: ThemeColors;
|
|
105
|
+
}
|
|
106
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { css } from "./css.js";
|
|
3
|
+
describe("css tagged-template helper", () => {
|
|
4
|
+
it("returns static template text exactly", () => {
|
|
5
|
+
const result = css `
|
|
6
|
+
color: red;
|
|
7
|
+
font-size: 16px;
|
|
8
|
+
`;
|
|
9
|
+
expect(result).toBe(`
|
|
10
|
+
color: red;
|
|
11
|
+
font-size: 16px;
|
|
12
|
+
`);
|
|
13
|
+
});
|
|
14
|
+
it("resolves interpolated values correctly", () => {
|
|
15
|
+
const color = "blue";
|
|
16
|
+
const size = 14;
|
|
17
|
+
const result = css `
|
|
18
|
+
color: ${color};
|
|
19
|
+
font-size: ${size}px;
|
|
20
|
+
`;
|
|
21
|
+
expect(result).toBe(`
|
|
22
|
+
color: blue;
|
|
23
|
+
font-size: 14px;
|
|
24
|
+
`);
|
|
25
|
+
});
|
|
26
|
+
});
|
package/package.json
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comet/mail-react",
|
|
3
|
-
"version": "9.0.0-beta.
|
|
3
|
+
"version": "9.0.0-beta.2",
|
|
4
4
|
"description": "Utilities for building HTML emails with React",
|
|
5
5
|
"license": "BSD-2-Clause",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
8
|
-
".":
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
".": "./lib/index.js",
|
|
9
|
+
"./client": "./lib/client/index.js",
|
|
10
|
+
"./server": "./lib/server/index.js",
|
|
11
|
+
"./storybook": "./lib/storybook/index.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"lib/*"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@faire/mjml-react": "^3.5.3"
|
|
17
|
+
"@faire/mjml-react": "^3.5.3",
|
|
18
|
+
"clsx": "^2.1.1",
|
|
19
|
+
"mjml": "^4.18.0",
|
|
20
|
+
"mjml-browser": "^4.18.0"
|
|
18
21
|
},
|
|
19
22
|
"devDependencies": {
|
|
23
|
+
"@fission-ai/openspec": "^1.2.0",
|
|
24
|
+
"@storybook/addon-docs": "^10.3.1",
|
|
25
|
+
"@storybook/react-vite": "^10.3.1",
|
|
26
|
+
"@types/mjml": "^4.7.4",
|
|
27
|
+
"@types/mjml-browser": "^4.15.0",
|
|
20
28
|
"@types/react": "^19.2.10",
|
|
21
29
|
"@types/react-dom": "^19.2.3",
|
|
22
30
|
"chokidar-cli": "^3.0.0",
|
|
@@ -26,12 +34,20 @@
|
|
|
26
34
|
"react": "^19.2.4",
|
|
27
35
|
"react-dom": "^19.2.4",
|
|
28
36
|
"rimraf": "^6.1.2",
|
|
37
|
+
"storybook": "^10.3.1",
|
|
29
38
|
"typescript": "^5.9.3",
|
|
30
|
-
"
|
|
31
|
-
"@comet/
|
|
39
|
+
"vitest": "^4.0.16",
|
|
40
|
+
"@comet/cli": "9.0.0-beta.2",
|
|
41
|
+
"@comet/eslint-config": "9.0.0-beta.2"
|
|
32
42
|
},
|
|
33
43
|
"peerDependencies": {
|
|
34
|
-
"react": "^18.0.0 || ^19.0.0"
|
|
44
|
+
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
45
|
+
"storybook": ">=10.0.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"storybook": {
|
|
49
|
+
"optional": true
|
|
50
|
+
}
|
|
35
51
|
},
|
|
36
52
|
"engines": {
|
|
37
53
|
"node": ">=22.0.0"
|
|
@@ -42,14 +58,22 @@
|
|
|
42
58
|
},
|
|
43
59
|
"scripts": {
|
|
44
60
|
"build": "pnpm run clean && pnpm run generate-block-types && tsc",
|
|
61
|
+
"build-storybook": "storybook build",
|
|
45
62
|
"clean": "rimraf lib 'src/**/*.generated.ts'",
|
|
46
63
|
"dev": "pnpm run clean && pnpm generate-block-types && tsc --watch",
|
|
47
64
|
"generate-block-types": "comet generate-block-types",
|
|
48
65
|
"generate-block-types:watch": "chokidar -s \"**/block-meta.json\" -c \"$npm_execpath generate-block-types\"",
|
|
49
66
|
"lint": "pnpm generate-block-types && run-p lint:prettier lint:eslint lint:tsc",
|
|
50
67
|
"lint:ci": "pnpm run lint",
|
|
51
|
-
"lint:eslint": "eslint --max-warnings 0 src/ **/*.json --no-warn-ignored",
|
|
68
|
+
"lint:eslint": "eslint --max-warnings 0 src/ '**/*.json' --no-warn-ignored",
|
|
69
|
+
"lint:fix": "run-p lint:fix:eslint lint:fix:prettier",
|
|
70
|
+
"lint:fix:eslint": "pnpm run lint:eslint --fix",
|
|
71
|
+
"lint:fix:prettier": "pnpm run lint:prettier --write",
|
|
52
72
|
"lint:prettier": "pnpm exec prettier --check '*.{ts,js,json,md,yml,yaml}'",
|
|
53
|
-
"lint:tsc": "tsc"
|
|
73
|
+
"lint:tsc": "tsc",
|
|
74
|
+
"openspec:install-skills": "openspec init --tools github-copilot,cursor,claude",
|
|
75
|
+
"storybook": "storybook dev -p 6066 --no-open",
|
|
76
|
+
"test": "vitest --run",
|
|
77
|
+
"test:watch": "vitest --watch"
|
|
54
78
|
}
|
|
55
79
|
}
|