@multiplatform.one/theme 7.37.0 → 7.39.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/package.json +5 -5
- package/src/theme/IconSlot.spec.tsx +88 -0
- package/src/theme/IconSlot.tsx +51 -0
- package/src/theme/index.ts +2 -0
- package/types/theme/IconSlot.d.ts +11 -0
- package/types/theme/IconSlot.d.ts.map +1 -0
- package/types/theme/index.d.ts +1 -0
- package/types/theme/index.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/theme",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.39.0",
|
|
4
4
|
"description": "Tamagui theme system for multiplatform.one",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"multiplatform",
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"access": "public"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@multiplatform.one/platform": "^7.
|
|
63
|
-
"@multiplatform.one/store": "^7.
|
|
62
|
+
"@multiplatform.one/platform": "^7.39.0",
|
|
63
|
+
"@multiplatform.one/store": "^7.39.0",
|
|
64
64
|
"@tamagui/animations-react-native": "2.7.6",
|
|
65
65
|
"@tamagui/colors": "2.7.6",
|
|
66
66
|
"@tamagui/config": "2.7.6",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"react-cookie": "^8.1.2"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@multiplatform.one/config": "7.
|
|
77
|
-
"@multiplatform.one/test-utils": "7.
|
|
76
|
+
"@multiplatform.one/config": "7.39.0",
|
|
77
|
+
"@multiplatform.one/test-utils": "7.39.0",
|
|
78
78
|
"@tamagui/animations-css": "2.7.6",
|
|
79
79
|
"@tamagui/animations-reanimated": "2.7.6",
|
|
80
80
|
"@tamagui/font-inter": "2.7.6",
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
2
|
+
import { forwardRef, memo } from "react";
|
|
3
|
+
import { getVariableValue, TamaguiProvider, useTheme } from "tamagui";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { createDefaultThemeConfig } from "./createDefaultThemeConfig";
|
|
6
|
+
import { IconSlot } from "./IconSlot";
|
|
7
|
+
|
|
8
|
+
const platform = vi.hoisted(() => ({ web: false }));
|
|
9
|
+
vi.mock("tamagui", async (original) => ({
|
|
10
|
+
...(await original<typeof import("tamagui")>()),
|
|
11
|
+
get isWeb() {
|
|
12
|
+
return platform.web;
|
|
13
|
+
},
|
|
14
|
+
}));
|
|
15
|
+
const config = createDefaultThemeConfig();
|
|
16
|
+
function Probe({ color, size }: { color?: string; size?: number }) {
|
|
17
|
+
const theme = useTheme();
|
|
18
|
+
return (
|
|
19
|
+
<span
|
|
20
|
+
data-testid="icon"
|
|
21
|
+
data-color={color ?? "black"}
|
|
22
|
+
data-size={size}
|
|
23
|
+
data-ink={String(getVariableValue(theme.color))}
|
|
24
|
+
data-muted={String(getVariableValue(theme.color11))}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const Memo = memo(Probe);
|
|
29
|
+
const Forward = forwardRef<HTMLSpanElement, { color?: string; size?: number }>((props, _ref) => (
|
|
30
|
+
<Probe {...props} />
|
|
31
|
+
));
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
cleanup();
|
|
34
|
+
platform.web = false;
|
|
35
|
+
});
|
|
36
|
+
describe("IconSlot", () => {
|
|
37
|
+
it.each(["light", "dark"] as const)(
|
|
38
|
+
"%s resolves functions, memo, forwardRef, elements and fragments",
|
|
39
|
+
(scheme) => {
|
|
40
|
+
render(
|
|
41
|
+
<TamaguiProvider config={config.tamagui} defaultTheme={scheme} disableInjectCSS>
|
|
42
|
+
<IconSlot icon={Probe} />
|
|
43
|
+
<IconSlot icon={Memo} />
|
|
44
|
+
<IconSlot icon={Forward} />
|
|
45
|
+
<IconSlot icon={<Probe color="currentColor" />} />
|
|
46
|
+
<IconSlot
|
|
47
|
+
icon={
|
|
48
|
+
<>
|
|
49
|
+
<Probe />
|
|
50
|
+
</>
|
|
51
|
+
}
|
|
52
|
+
/>
|
|
53
|
+
</TamaguiProvider>,
|
|
54
|
+
);
|
|
55
|
+
for (const icon of screen.getAllByTestId("icon"))
|
|
56
|
+
expect(icon.dataset.color).toBe(icon.dataset.ink);
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
it("resolves an explicit token and preserves literal ink", () => {
|
|
60
|
+
render(
|
|
61
|
+
<TamaguiProvider config={config.tamagui} defaultTheme="dark" disableInjectCSS>
|
|
62
|
+
<IconSlot icon={<Probe color="$color11" />} size={20} />
|
|
63
|
+
<IconSlot icon={<Probe color="rebeccapurple" />} />
|
|
64
|
+
</TamaguiProvider>,
|
|
65
|
+
);
|
|
66
|
+
const [token, literal] = screen.getAllByTestId("icon");
|
|
67
|
+
expect(token.dataset.color).toBe(token.dataset.muted);
|
|
68
|
+
expect(token.dataset.size).toBe("20");
|
|
69
|
+
expect(literal.dataset.color).toBe("rebeccapurple");
|
|
70
|
+
});
|
|
71
|
+
it("preserves explicit element size", () => {
|
|
72
|
+
render(
|
|
73
|
+
<TamaguiProvider config={config.tamagui} defaultTheme="dark" disableInjectCSS>
|
|
74
|
+
<IconSlot icon={<Probe size={12} />} size={20} />
|
|
75
|
+
</TamaguiProvider>,
|
|
76
|
+
);
|
|
77
|
+
expect(screen.getByTestId("icon").dataset.size).toBe("12");
|
|
78
|
+
});
|
|
79
|
+
it("keeps web inheritance", () => {
|
|
80
|
+
platform.web = true;
|
|
81
|
+
render(
|
|
82
|
+
<TamaguiProvider config={config.tamagui} defaultTheme="dark" disableInjectCSS>
|
|
83
|
+
<IconSlot icon={<Probe color="currentColor" />} />
|
|
84
|
+
</TamaguiProvider>,
|
|
85
|
+
);
|
|
86
|
+
expect(screen.getByTestId("icon").dataset.color).toBe("currentColor");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
Fragment,
|
|
4
|
+
cloneElement,
|
|
5
|
+
createElement,
|
|
6
|
+
isValidElement,
|
|
7
|
+
type ComponentType,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { isWeb, useTheme } from "tamagui";
|
|
11
|
+
import { resolveGlyphPaint } from "./glyphPaint";
|
|
12
|
+
|
|
13
|
+
export type IconSlotValue = ReactNode | ComponentType<{ size?: number; color?: string }>;
|
|
14
|
+
|
|
15
|
+
export function IconSlot({
|
|
16
|
+
icon,
|
|
17
|
+
color,
|
|
18
|
+
size,
|
|
19
|
+
}: {
|
|
20
|
+
icon: IconSlotValue;
|
|
21
|
+
color?: string;
|
|
22
|
+
size?: number;
|
|
23
|
+
}) {
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
const ink = (value?: string) =>
|
|
26
|
+
resolveGlyphPaint(
|
|
27
|
+
theme,
|
|
28
|
+
value && value !== "currentColor" ? value : color === "currentColor" ? undefined : color,
|
|
29
|
+
);
|
|
30
|
+
const render = (value: IconSlotValue): ReactNode => {
|
|
31
|
+
if (isValidElement<{ color?: string; size?: number; children?: ReactNode }>(value)) {
|
|
32
|
+
if (value.type === Fragment)
|
|
33
|
+
return cloneElement(value, {}, Children.map(value.props.children, render));
|
|
34
|
+
return cloneElement(value, {
|
|
35
|
+
...(size == null || value.props.size != null ? {} : { size }),
|
|
36
|
+
...(!isWeb ? { color: ink(value.props.color) } : {}),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (
|
|
40
|
+
typeof value === "function" ||
|
|
41
|
+
(value && typeof value === "object" && "$$typeof" in value)
|
|
42
|
+
) {
|
|
43
|
+
return createElement(value as ComponentType<{ size?: number; color?: string }>, {
|
|
44
|
+
size,
|
|
45
|
+
...(!isWeb ? { color: ink() } : {}),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return value as ReactNode;
|
|
49
|
+
};
|
|
50
|
+
return render(icon);
|
|
51
|
+
}
|
package/src/theme/index.ts
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ComponentType, type ReactNode } from "react";
|
|
2
|
+
export type IconSlotValue = ReactNode | ComponentType<{
|
|
3
|
+
size?: number;
|
|
4
|
+
color?: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function IconSlot({ icon, color, size, }: {
|
|
7
|
+
icon: IconSlotValue;
|
|
8
|
+
color?: string;
|
|
9
|
+
size?: number;
|
|
10
|
+
}): ReactNode;
|
|
11
|
+
//# sourceMappingURL=IconSlot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconSlot.d.ts","sourceRoot":"","sources":["../../src/theme/IconSlot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEzF,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,IAAI,GACL,EAAE;IACD,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,aA4BA"}
|
package/types/theme/index.d.ts
CHANGED
|
@@ -51,4 +51,5 @@ export * from "./overlaySurfaces";
|
|
|
51
51
|
export * from "./motion";
|
|
52
52
|
export { animationConfig as cssAnimationConfig, animationDurations, motionStops, type MotionStop, } from "./animations/css";
|
|
53
53
|
export { animationConfig as nativeAnimationConfig } from "./animations/reactNative";
|
|
54
|
+
export * from "./IconSlot";
|
|
54
55
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,YAAY,EAAE,MAAM,IAAI,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACjF,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAElC,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAElC,cAAc,UAAU,CAAC;AACzB,OAAO,EACL,eAAe,IAAI,kBAAkB,EACrC,kBAAkB,EAClB,WAAW,EACX,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,IAAI,qBAAqB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,YAAY,EAAE,MAAM,IAAI,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACjF,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAElC,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAElC,cAAc,UAAU,CAAC;AACzB,OAAO,EACL,eAAe,IAAI,kBAAkB,EACrC,kBAAkB,EAClB,WAAW,EACX,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,IAAI,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEpF,cAAc,YAAY,CAAC"}
|