Skip to content

Commit a2689b4

Browse files
committed
fix: update select component
1 parent 3e7997b commit a2689b4

8 files changed

Lines changed: 335 additions & 43 deletions

File tree

apps/docs/src/containers/theme-studio/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ const ThemeStudioPage = (): React.ReactElement => {
156156
<Select
157157
className="theme-studio__select"
158158
value={draft.presetId}
159+
showSearch
160+
filterOption={(inputValue, option) => {
161+
const query = inputValue.toLowerCase();
162+
const label = typeof option.label === 'string' ? option.label : '';
163+
return label.toLowerCase().includes(query) || option.value.toLowerCase().includes(query);
164+
}}
159165
onChange={(value) => handlePresetChange(value)}
160166
>
161167
{THEME_EDITOR_PRESETS.map((preset) => (

apps/docs/src/containers/theme-studio/runtime-presets.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@ function buildPresetDescription(source: TweakcnRuntimePresetSource): string {
1818
: 'Imported from tweakcn runtime preset.';
1919
}
2020

21-
function mapRuntimeStylesToFields(styles: RuntimeStyles): Partial<ThemeEditorFields> {
21+
function readRuntimeStyle(styles: RuntimeStyles, key: string, fallbackStyles?: RuntimeStyles): string | undefined {
22+
return styles[key] ?? fallbackStyles?.[key];
23+
}
24+
25+
function mapRuntimeStylesToFields(
26+
styles: RuntimeStyles,
27+
typographyFallbackStyles?: RuntimeStyles,
28+
): Partial<ThemeEditorFields> {
2229
const radius = styles.radius ?? DEFAULT_FIELDS.radius;
2330
const ring = styles.ring ?? styles.primary ?? DEFAULT_FIELDS.ring;
2431
const statusPalette = deriveStatusPalette(styles);
@@ -62,9 +69,9 @@ function mapRuntimeStylesToFields(styles: RuntimeStyles): Partial<ThemeEditorFie
6269
sidebarAccentForeground: styles['sidebar-accent-foreground'] ?? DEFAULT_FIELDS.sidebarAccentForeground,
6370
sidebarBorder: styles['sidebar-border'] ?? DEFAULT_FIELDS.sidebarBorder,
6471
sidebarRing: styles['sidebar-ring'] ?? DEFAULT_FIELDS.sidebarRing,
65-
fontSans: styles['font-sans'] ?? DEFAULT_FIELDS.fontSans,
66-
fontMono: styles['font-mono'] ?? DEFAULT_FIELDS.fontMono,
67-
letterSpacing: styles['letter-spacing'] ?? DEFAULT_FIELDS.letterSpacing,
72+
fontSans: readRuntimeStyle(styles, 'font-sans', typographyFallbackStyles) ?? DEFAULT_FIELDS.fontSans,
73+
fontMono: readRuntimeStyle(styles, 'font-mono', typographyFallbackStyles) ?? DEFAULT_FIELDS.fontMono,
74+
letterSpacing: readRuntimeStyle(styles, 'letter-spacing', typographyFallbackStyles) ?? DEFAULT_FIELDS.letterSpacing,
6875
radius,
6976
shadowCard: buildShadow(styles),
7077
shadowFocus: `0 0 0 3px ${toRgba(ring, 0.24)}`,
@@ -78,7 +85,7 @@ function buildPresetFromRuntimeSource(source: TweakcnRuntimePresetSource): Theme
7885
const lightStyles = source.styles.light;
7986
const darkStyles = source.styles.dark;
8087
const lightFields = mapRuntimeStylesToFields(lightStyles);
81-
const darkFields = mapRuntimeStylesToFields(darkStyles);
88+
const darkFields = mapRuntimeStylesToFields(darkStyles, lightStyles);
8289

8390
return {
8491
id: source.id,

apps/docs/src/containers/theme-studio/theme-studio.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
}
9393

9494
.theme-studio__topbar-actions .theme-studio__select {
95-
min-width: 180px;
95+
width: 220px;
9696
}
9797

9898
.theme-studio__eyebrow {

packages/react/src/popup/__tests__/popup.test.tsx

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,73 @@
11
import React from 'react';
22
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
3+
import { createPopper } from '@popperjs/core';
34
import Popup from '../index';
45

6+
jest.mock('@popperjs/core', () => ({
7+
createPopper: jest.fn(),
8+
}));
9+
510
describe('<Popup />', () => {
11+
beforeEach(() => {
12+
(createPopper as jest.Mock).mockImplementation(
13+
(_target: HTMLElement, popup: HTMLElement, options) => {
14+
const applyReactStyles = () => {
15+
options.modifiers
16+
.find((modifier: { name: string }) => modifier.name === 'reactApplyStyles')
17+
?.fn({
18+
state: {
19+
styles: {
20+
popper: {
21+
position: 'absolute',
22+
left: '37px',
23+
top: '575px',
24+
margin: '0px',
25+
},
26+
arrow: {
27+
position: 'absolute',
28+
left: '8px',
29+
},
30+
},
31+
attributes: {
32+
popper: {
33+
'data-popper-placement': 'bottom',
34+
},
35+
arrow: {},
36+
},
37+
},
38+
});
39+
};
40+
return {
41+
state: {
42+
elements: {
43+
popper: popup,
44+
},
45+
},
46+
forceUpdate: jest.fn(applyReactStyles),
47+
destroy: jest.fn(),
48+
};
49+
}
50+
);
51+
});
52+
53+
afterEach(() => {
54+
jest.clearAllMocks();
55+
});
56+
657
it('should match the snapshot', () => {
758
const { asFragment } = render(
8-
<Popup content="Popup content"><button>Trigger</button></Popup>
59+
<Popup content="Popup content">
60+
<button>Trigger</button>
61+
</Popup>
962
);
1063
expect(asFragment()).toMatchSnapshot();
1164
});
1265

1366
it('should render trigger element', () => {
1467
const { getByText } = render(
15-
<Popup content="Content"><button>Trigger</button></Popup>
68+
<Popup content="Content">
69+
<button>Trigger</button>
70+
</Popup>
1671
);
1772
expect(getByText('Trigger')).toBeInTheDocument();
1873
});
@@ -54,4 +109,28 @@ describe('<Popup />', () => {
54109

55110
expect(screen.getByText('Controlled popup')).toBeInTheDocument();
56111
});
112+
113+
it('should keep popup content mounted during exit transition', () => {
114+
const { rerender } = render(
115+
<Popup visible={true} trigger="manual" content={<div>Controlled popup</div>}>
116+
<button>Trigger</button>
117+
</Popup>
118+
);
119+
120+
const openPopup = document.querySelector('.ty-popup') as HTMLDivElement;
121+
expect(openPopup.style.left).toBe('37px');
122+
expect(openPopup.style.top).toBe('575px');
123+
124+
rerender(
125+
<Popup visible={false} trigger="manual" content={<div>Controlled popup</div>}>
126+
<button>Trigger</button>
127+
</Popup>
128+
);
129+
130+
const closingPopup = document.querySelector('.ty-popup') as HTMLDivElement;
131+
expect(closingPopup).toBeInTheDocument();
132+
expect(screen.getByText('Controlled popup')).toBeInTheDocument();
133+
expect(closingPopup.style.left).toBe('37px');
134+
expect(closingPopup.style.top).toBe('575px');
135+
});
57136
});

0 commit comments

Comments
 (0)