@seed-design/lynx-react 0.7.0 → 0.7.1
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/components/AppBar/AppBar.d.ts.map +1 -1
- package/lib/components/AppBar/AppBar.jsx +7 -2
- package/lib/components/Icon/Icon.d.ts.map +1 -1
- package/lib/components/Icon/Icon.jsx +1 -1
- package/lib/hooks/useScaleFeedback.d.ts +1 -1
- package/lib/hooks/useScaleFeedback.js +1 -1
- package/package.json +3 -3
- package/src/components/ActionButton/ActionButton.test.tsx +7 -7
- package/src/components/AppBar/AppBar.test.tsx +26 -0
- package/src/components/AppBar/AppBar.tsx +4 -1
- package/src/components/Icon/Icon.test.tsx +57 -2
- package/src/components/Icon/Icon.tsx +5 -1
- package/src/components/ReactionButton/ReactionButton.test.tsx +1 -1
- package/src/hooks/useScaleFeedback.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppBar.d.ts","sourceRoot":"","sources":["../../../src/components/AppBar/AppBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,4CAA4C,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAGxC,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EAEtB,aAAa,EAEd,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"AppBar.d.ts","sourceRoot":"","sources":["../../../src/components/AppBar/AppBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,4CAA4C,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAGxC,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EAEtB,aAAa,EAEd,MAAM,aAAa,CAAC;AAqCrB,MAAM,WAAW,eAAgB,SAAQ,kBAAkB,EAAE,sBAAsB;CAAG;AAEtF,eAAO,MAAM,UAAU,iFA2BrB,CAAC;AAKH,MAAM,WAAW,eAAgB,SAAQ,sBAAsB;IAC7D,gBAAgB,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CACtD;AAED,eAAO,MAAM,UAAU,iFA4BrB,CAAC;AAGH,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D,gBAAgB,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CACtD;AAED,eAAO,MAAM,WAAW,kFA4BtB,CAAC;AAKH,MAAM,WAAW,eAAgB,SAAQ,sBAAsB,EAAE,sBAAsB;CAAG;AAE1F,eAAO,MAAM,UAAU,iFAmCrB,CAAC;AAGH,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;CAAG;AAE7D,eAAO,MAAM,WAAW,kFAYtB,CAAC;AAGH,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;CAAG;AAEhE,eAAO,MAAM,cAAc,qFAYzB,CAAC;AAKH,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB,EAAE,kBAAkB;IACjF,IAAI,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC;IAChD,qBAAqB,CAAC,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC7D,uBAAuB,CAAC,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;IACjE,sBAAsB,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;CAChE;AAED,eAAO,MAAM,gBAAgB,uFA6B3B,CAAC;AAGH,MAAM,WAAW,eAAgB,SAAQ,sBAAsB;CAAG;AAElE,eAAO,MAAM,UAAU,iFAYrB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mergeProps } from "../../utils/merge-props.js";
|
|
2
2
|
import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context.jsx";
|
|
3
|
-
import { Icon } from "../Icon/Icon.jsx";
|
|
3
|
+
import { Icon, IconSlotProvider } from "../Icon/Icon.jsx";
|
|
4
4
|
import { AppBarProvider, useAppBarContext } from "./context.js";
|
|
5
5
|
import { getLayoutWidth, getMainLayoutStyle, useAppBar } from "./useAppBar.js";
|
|
6
6
|
import * as React from "@lynx-js/react";
|
|
@@ -117,7 +117,12 @@ var AppBarIconButton = React.forwardRef((props, ref) => {
|
|
|
117
117
|
const classNames = useAppBarClassNames("AppBarIconButton");
|
|
118
118
|
if (process.env.NODE_ENV !== "production" && accessibilityElement && !accessibilityLabel) console.warn("AppBarIconButton requires `accessibility-label` for accessibility.");
|
|
119
119
|
return <view {...mergeProps(ref ? { ref } : {}, nativeProps)} accessibility-element={accessibilityElement} accessibility-label={accessibilityLabel} accessibility-traits={accessibilityTraits} className={clsx(classNames.iconButton, className)}>
|
|
120
|
-
|
|
120
|
+
<IconSlotProvider value={{
|
|
121
|
+
classNames: { icon: classNames.icon },
|
|
122
|
+
deps: [classNames.icon]
|
|
123
|
+
}}>
|
|
124
|
+
{icon ? <Icon icon={icon} /> : children}
|
|
125
|
+
</IconSlotProvider>
|
|
121
126
|
</view>;
|
|
122
127
|
});
|
|
123
128
|
AppBarIconButton.displayName = "AppBarIconButton";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../../../src/components/Icon/Icon.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAe,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGnF,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,YAAY,CAAC;AAIhE,UAAU,oBAAoB;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAWD,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB,qBAyCA;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,qBAEA;AAeD,wBAAgB,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,GAAG,YAAY,GAAG,IAAI,CAI1E;AAaD,MAAM,WAAW,SAAU,SAAQ,sBAAsB;IACvD,IAAI,EAAE,YAAY,CAAC,oBAAoB,CAAC,CAAC;IACzC,IAAI,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;IACrC,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;CAAG;AAErD,MAAM,WAAW,eAAgB,SAAQ,SAAS;CAAG;
|
|
1
|
+
{"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../../../src/components/Icon/Icon.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAe,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGnF,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,YAAY,CAAC;AAIhE,UAAU,oBAAoB;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAWD,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB,qBAyCA;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,qBAEA;AAeD,wBAAgB,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,GAAG,YAAY,GAAG,IAAI,CAI1E;AAaD,MAAM,WAAW,SAAU,SAAQ,sBAAsB;IACvD,IAAI,EAAE,YAAY,CAAC,oBAAoB,CAAC,CAAC;IACzC,IAAI,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;IACrC,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;CAAG;AAErD,MAAM,WAAW,eAAgB,SAAQ,SAAS;CAAG;AA+GrD,eAAO,MAAM,IAAI,2EAA8D,CAAC;AAChF,eAAO,MAAM,UAAU,iFAItB,CAAC;AACF,eAAO,MAAM,UAAU,iFAItB,CAAC;AAIF,MAAM,WAAW,iBAAkB,SAAQ,sBAAsB;IAC/D,IAAI,EAAE,YAAY,CAAC,oBAAoB,CAAC,CAAC;IACzC,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAED,eAAO,MAAM,YAAY,mFA6BvB,CAAC"}
|
|
@@ -101,7 +101,7 @@ var IconSlotBase = React.forwardRef((props, ref) => {
|
|
|
101
101
|
slot
|
|
102
102
|
]);
|
|
103
103
|
if (!hasValidIcon) return null;
|
|
104
|
-
return <view {...mergeProps({ "main-thread:ref": sourceRef }, ref ? { ref } : {}, nativeProps)} className={clsx(baseClassName, slotClassName, className)} style={mergeWrapperStyle({
|
|
104
|
+
return <view {...mergeProps({ "main-thread:ref": sourceRef }, ref ? { ref } : {}, nativeProps)} className={clsx(slotClassName && baseClassName ? `${baseClassName}-slot` : baseClassName, slotClassName, className)} style={mergeWrapperStyle({
|
|
105
105
|
size,
|
|
106
106
|
color,
|
|
107
107
|
style
|
|
@@ -39,7 +39,7 @@ export interface UseScaleFeedbackReturn {
|
|
|
39
39
|
* The target's transform is owned by this hook. Use a separate content layer
|
|
40
40
|
* when the element already uses translate, rotate, or another transform.
|
|
41
41
|
*
|
|
42
|
-
* Supported on Lynx Engine 3.
|
|
42
|
+
* Supported on Lynx Engine 3.6 and later. Missing or unknown
|
|
43
43
|
* `GlobalProps.motion` values preserve the default motion; only the exact
|
|
44
44
|
* `"reduced"` value disables scaling.
|
|
45
45
|
*/
|
|
@@ -42,7 +42,7 @@ function readScaleFeedbackScale(target) {
|
|
|
42
42
|
* The target's transform is owned by this hook. Use a separate content layer
|
|
43
43
|
* when the element already uses translate, rotate, or another transform.
|
|
44
44
|
*
|
|
45
|
-
* Supported on Lynx Engine 3.
|
|
45
|
+
* Supported on Lynx Engine 3.6 and later. Missing or unknown
|
|
46
46
|
* `GlobalProps.motion` values preserve the default motion; only the exact
|
|
47
47
|
* `"reduced"` value disables scaling.
|
|
48
48
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seed-design/lynx-react",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/daangn/seed-design.git",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@lynx-js/react": ">=0.117.0",
|
|
36
36
|
"@lynx-js/types": ">=3.9.0",
|
|
37
|
-
"@seed-design/lynx-css": "0.0.0 || >=0.11.
|
|
37
|
+
"@seed-design/lynx-css": "0.0.0 || >=0.11.1 <1.0.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@lynx-js/react": "^0.117.0",
|
|
41
41
|
"@lynx-js/types": "^3.9.0",
|
|
42
|
-
"@seed-design/lynx-css": "0.11.
|
|
42
|
+
"@seed-design/lynx-css": "0.11.1",
|
|
43
43
|
"@testing-library/jest-dom": "^6.9.1",
|
|
44
44
|
"jsdom": "^29.0.2",
|
|
45
45
|
"preact": "npm:@lynx-js/internal-preact@10.28.4-ee7bb26",
|
|
@@ -88,9 +88,9 @@ describe("ActionButton", () => {
|
|
|
88
88
|
const { getByText } = getRenderedQueries();
|
|
89
89
|
const root = getRenderedRoot();
|
|
90
90
|
|
|
91
|
-
expect(root.querySelector(".seed-prefix-icon")).toHaveClass("seed-action-button__prefixIcon");
|
|
92
|
-
expect(root.querySelector(".seed-suffix-icon")).toHaveClass("seed-action-button__suffixIcon");
|
|
93
|
-
expect(root.querySelector(".seed-prefix-icon image")).toHaveStyle({
|
|
91
|
+
expect(root.querySelector(".seed-prefix-icon-slot")).toHaveClass("seed-action-button__prefixIcon");
|
|
92
|
+
expect(root.querySelector(".seed-suffix-icon-slot")).toHaveClass("seed-action-button__suffixIcon");
|
|
93
|
+
expect(root.querySelector(".seed-prefix-icon-slot image")).toHaveStyle({
|
|
94
94
|
width: "100%",
|
|
95
95
|
height: "100%",
|
|
96
96
|
});
|
|
@@ -106,8 +106,8 @@ describe("ActionButton", () => {
|
|
|
106
106
|
|
|
107
107
|
const root = getRenderedRoot();
|
|
108
108
|
|
|
109
|
-
expect(root.querySelector(".seed-prefix-icon")).toHaveClass("seed-action-button__prefixIcon");
|
|
110
|
-
expect(root.querySelector(".seed-suffix-icon")).toHaveClass("seed-action-button__suffixIcon");
|
|
109
|
+
expect(root.querySelector(".seed-prefix-icon-slot")).toHaveClass("seed-action-button__prefixIcon");
|
|
110
|
+
expect(root.querySelector(".seed-suffix-icon-slot")).toHaveClass("seed-action-button__suffixIcon");
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
it("supports icon-only child slot", () => {
|
|
@@ -119,7 +119,7 @@ describe("ActionButton", () => {
|
|
|
119
119
|
|
|
120
120
|
const root = getRenderedRoot();
|
|
121
121
|
|
|
122
|
-
expect(root.querySelector(".seed-icon")).toHaveClass("seed-action-button__icon");
|
|
122
|
+
expect(root.querySelector(".seed-icon-slot")).toHaveClass("seed-action-button__icon");
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
it("maps accessibility props to the root view", () => {
|
|
@@ -141,7 +141,7 @@ describe("ActionButton", () => {
|
|
|
141
141
|
|
|
142
142
|
const root = getRenderedRoot();
|
|
143
143
|
|
|
144
|
-
expect(root.querySelector(".seed-icon")).toHaveClass("seed-action-button__icon");
|
|
144
|
+
expect(root.querySelector(".seed-icon-slot")).toHaveClass("seed-action-button__icon");
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
it("throws in development when icon-only layout has no Icon child", () => {
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import "@testing-library/jest-dom";
|
|
2
|
+
import * as React from "@lynx-js/react";
|
|
3
|
+
import type { MainThread } from "@lynx-js/types";
|
|
4
|
+
import type { LynxIconElementProps } from "../../types";
|
|
2
5
|
import {
|
|
3
6
|
act,
|
|
4
7
|
fireEvent,
|
|
@@ -9,6 +12,7 @@ import {
|
|
|
9
12
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
10
13
|
|
|
11
14
|
import * as AppBar from "./AppBar.namespace";
|
|
15
|
+
import { Icon } from "../Icon/Icon";
|
|
12
16
|
|
|
13
17
|
type TestSystemInfo = { platform?: string };
|
|
14
18
|
|
|
@@ -268,3 +272,25 @@ describe("AppBar", () => {
|
|
|
268
272
|
});
|
|
269
273
|
});
|
|
270
274
|
});
|
|
275
|
+
|
|
276
|
+
describe("AppBar icon recipe ownership", () => {
|
|
277
|
+
const TestIcon = React.forwardRef<MainThread.Element, LynxIconElementProps>((props, ref) => (
|
|
278
|
+
<image {...props} {...(ref ? { "main-thread:ref": ref } : {})} />
|
|
279
|
+
));
|
|
280
|
+
it.each(["prop", "children"])("connects the %s icon without fallback styles", (mode) => {
|
|
281
|
+
const icon = <TestIcon />;
|
|
282
|
+
const { container } = render(
|
|
283
|
+
<AppBar.Root theme="cupertino">
|
|
284
|
+
<AppBar.Left>
|
|
285
|
+
<AppBar.IconButton accessibility-label="Close" {...(mode === "prop" ? { icon } : {})}>
|
|
286
|
+
{mode === "children" ? <Icon icon={icon} /> : null}
|
|
287
|
+
</AppBar.IconButton>
|
|
288
|
+
</AppBar.Left>
|
|
289
|
+
</AppBar.Root>,
|
|
290
|
+
);
|
|
291
|
+
const wrapper = container.querySelector(".seed-app-bar__icon")!;
|
|
292
|
+
expect(wrapper).not.toBeNull();
|
|
293
|
+
expect(wrapper.classList.contains("seed-icon-slot")).toBe(true);
|
|
294
|
+
expect(wrapper.classList.contains("seed-icon")).toBe(false);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
} from "../../types";
|
|
18
18
|
import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context";
|
|
19
19
|
import { Icon } from "../Icon";
|
|
20
|
+
import { IconSlotProvider } from "../Icon/Icon";
|
|
20
21
|
import { AppBarProvider, useAppBarContext } from "./context";
|
|
21
22
|
import { getLayoutWidth, getMainLayoutStyle, useAppBar } from "./useAppBar";
|
|
22
23
|
import { mergeProps } from "../../utils/merge-props";
|
|
@@ -263,7 +264,9 @@ export const AppBarIconButton = React.forwardRef<unknown, AppBarIconButtonProps>
|
|
|
263
264
|
accessibility-traits={accessibilityTraits}
|
|
264
265
|
className={clsx(classNames.iconButton, className)}
|
|
265
266
|
>
|
|
266
|
-
|
|
267
|
+
<IconSlotProvider value={{ classNames: { icon: classNames.icon }, deps: [classNames.icon] }}>
|
|
268
|
+
{icon ? <Icon icon={icon} /> : children}
|
|
269
|
+
</IconSlotProvider>
|
|
267
270
|
</view>
|
|
268
271
|
);
|
|
269
272
|
});
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
|
|
1
4
|
import * as React from "@lynx-js/react";
|
|
2
5
|
import { act, render, waitSchedule } from "@lynx-js/react/testing-library";
|
|
3
6
|
import type { MainThread } from "@lynx-js/types";
|
|
4
7
|
import { describe, expect, it } from "vitest";
|
|
5
8
|
|
|
6
9
|
import type { LynxIconElementProps } from "../../types";
|
|
7
|
-
import { InternalIcon, PrefixIcon } from "./Icon";
|
|
10
|
+
import { Icon, IconSlotProvider, InternalIcon, PrefixIcon, SuffixIcon } from "./Icon";
|
|
8
11
|
|
|
9
12
|
const TestIcon = React.forwardRef<
|
|
10
13
|
MainThread.Element,
|
|
@@ -101,7 +104,8 @@ describe("InternalIcon", () => {
|
|
|
101
104
|
await waitSchedule();
|
|
102
105
|
|
|
103
106
|
expect(frames.size).toBe(1);
|
|
104
|
-
|
|
107
|
+
// The immediate read uses the old native style; the next frame must refresh it.
|
|
108
|
+
expect(image.getAttribute("tint-color")).toBe("rgb(134, 139, 148)");
|
|
105
109
|
|
|
106
110
|
computedColor = "rgb(255, 102, 0)";
|
|
107
111
|
runNextFrame();
|
|
@@ -149,3 +153,54 @@ describe("PrefixIcon", () => {
|
|
|
149
153
|
expect(getSourceAndImage().image.getAttribute("tint-color")).toBeNull();
|
|
150
154
|
});
|
|
151
155
|
});
|
|
156
|
+
|
|
157
|
+
describe("icon recipe ownership", () => {
|
|
158
|
+
it.each([
|
|
159
|
+
[Icon, "icon", "seed-icon"],
|
|
160
|
+
[PrefixIcon, "prefixIcon", "seed-prefix-icon"],
|
|
161
|
+
[SuffixIcon, "suffixIcon", "seed-suffix-icon"],
|
|
162
|
+
] as const)("keeps fallback styles exclusive to unbound %s", (Component, slot, baseClass) => {
|
|
163
|
+
const { container, rerender } = render(<Component icon={<TestIcon />} />);
|
|
164
|
+
expect(container.querySelector(`.${baseClass}`)).not.toBeNull();
|
|
165
|
+
rerender(
|
|
166
|
+
<IconSlotProvider value={{ classNames: { [slot]: "test-recipe-icon" }, deps: [] }}>
|
|
167
|
+
<Component size={28} color="#2475e8" className="user-icon" icon={<TestIcon />} />
|
|
168
|
+
</IconSlotProvider>,
|
|
169
|
+
);
|
|
170
|
+
const wrapper = container.querySelector(".test-recipe-icon")!;
|
|
171
|
+
expect(wrapper.classList.contains(`${baseClass}-slot`)).toBe(true);
|
|
172
|
+
expect(wrapper.classList.contains("user-icon")).toBe(true);
|
|
173
|
+
expect(wrapper.classList.contains(baseClass)).toBe(false);
|
|
174
|
+
expect(wrapper.getAttribute("style")).toContain("28px");
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// This checks generated CSS cascade only; native state/theme invalidation is verified separately.
|
|
179
|
+
describe("generated icon CSS import order", () => {
|
|
180
|
+
const { JSDOM } = createRequire(`${process.cwd()}/package.json`)("jsdom") as {
|
|
181
|
+
JSDOM: new (html: string) => { window: Window & typeof globalThis };
|
|
182
|
+
};
|
|
183
|
+
const base = readFileSync("../lynx-css/base.css", "utf8");
|
|
184
|
+
const recipe = readFileSync("../lynx-css/recipes/callout.css", "utf8");
|
|
185
|
+
|
|
186
|
+
it("keeps the legacy standalone fallback selectors", () => {
|
|
187
|
+
const dom = new JSDOM(`<style>${base}</style><div class="seed-suffix-icon"></div>`);
|
|
188
|
+
const style = dom.window.getComputedStyle(dom.window.document.querySelector("div")!);
|
|
189
|
+
expect(style.width).toBe("var(--seed-suffix-icon-size)");
|
|
190
|
+
expect(style.height).toBe("var(--seed-suffix-icon-size)");
|
|
191
|
+
expect(style.color).toBe("var(--seed-suffix-icon-color, currentcolor)");
|
|
192
|
+
dom.window.close();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it.each(["base-first", "recipe-first"])("preserves Callout slot styles with %s", (order) => {
|
|
196
|
+
const dom = new JSDOM(`<style>${order === "base-first" ? base + recipe : recipe + base}</style>
|
|
197
|
+
<div class="seed-suffix-icon-slot seed-callout__suffixIcon seed-callout__suffixIcon--tone_neutral"></div>`);
|
|
198
|
+
const icon = dom.window.document.querySelector("div")!;
|
|
199
|
+
const style = dom.window.getComputedStyle(icon);
|
|
200
|
+
expect(style.width).toBe("var(--seed-dimension-x4)");
|
|
201
|
+
expect(style.height).toBe("var(--seed-dimension-x4)");
|
|
202
|
+
expect(style.color).toBe("var(--seed-color-fg-neutral)");
|
|
203
|
+
expect(style.flexShrink).toBe("0");
|
|
204
|
+
dom.window.close();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
@@ -205,7 +205,11 @@ const IconSlotBase = React.forwardRef<unknown, IconSlotBaseProps>((props, ref) =
|
|
|
205
205
|
ref ? { ref: ref as LynxViewRef } : {},
|
|
206
206
|
nativeProps,
|
|
207
207
|
)}
|
|
208
|
-
className={clsx(
|
|
208
|
+
className={clsx(
|
|
209
|
+
slotClassName && baseClassName ? `${baseClassName}-slot` : baseClassName,
|
|
210
|
+
slotClassName,
|
|
211
|
+
className,
|
|
212
|
+
)}
|
|
209
213
|
style={mergeWrapperStyle({ size, color, style })}
|
|
210
214
|
>
|
|
211
215
|
{cloneElement(icon, {
|
|
@@ -69,7 +69,7 @@ describe("ReactionButton", () => {
|
|
|
69
69
|
const queries = getQueriesForElement(getRenderedRoot());
|
|
70
70
|
|
|
71
71
|
expect(root).toHaveClass("seed-reaction-button__root--size_small");
|
|
72
|
-
expect(root.querySelector(".seed-prefix-icon")).toHaveClass("seed-reaction-button__prefixIcon");
|
|
72
|
+
expect(root.querySelector(".seed-prefix-icon-slot")).toHaveClass("seed-reaction-button__prefixIcon");
|
|
73
73
|
expect(queries.getByText("좋아요")).toHaveClass("seed-reaction-button__label");
|
|
74
74
|
expect(queries.getByText("12")).toHaveClass("seed-count", "seed-reaction-button__count");
|
|
75
75
|
|
|
@@ -119,7 +119,7 @@ function readScaleFeedbackScale(target: ScaleFeedbackElement | null): number | n
|
|
|
119
119
|
* The target's transform is owned by this hook. Use a separate content layer
|
|
120
120
|
* when the element already uses translate, rotate, or another transform.
|
|
121
121
|
*
|
|
122
|
-
* Supported on Lynx Engine 3.
|
|
122
|
+
* Supported on Lynx Engine 3.6 and later. Missing or unknown
|
|
123
123
|
* `GlobalProps.motion` values preserve the default motion; only the exact
|
|
124
124
|
* `"reduced"` value disables scaling.
|
|
125
125
|
*/
|