Skip to content

Commit 31a51d7

Browse files
committed
fix(dialog): fix dialog issue
1 parent 83b08cc commit 31a51d7

6 files changed

Lines changed: 215 additions & 58 deletions

File tree

apps/playground/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
"build": "pnpm --filter @fictjs/radix-ui build && pnpm --filter @fictjs/radix-ui-themes build && vite build",
99
"preview": "vite preview --host 0.0.0.0 --port 4100",
1010
"lint": "eslint . --max-warnings=0",
11+
"test": "vitest run",
12+
"test:watch": "vitest",
1113
"typecheck": "pnpm --filter @fictjs/radix-ui build && pnpm --filter @fictjs/radix-ui-themes build && tsc --noEmit -p tsconfig.json"
1214
},
1315
"dependencies": {
@@ -20,6 +22,7 @@
2022
"@fictjs/vite-plugin": "^0.17.0",
2123
"@types/node": "catalog:",
2224
"typescript": "catalog:",
25+
"vitest": "catalog:",
2326
"vite": "^7.3.1"
2427
}
2528
}
Lines changed: 119 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,124 @@
1-
import { AlertDialog, Button, Flex } from '@fictjs/radix-ui-themes';
2-
import { DocsSection, DocsSectionBody, DocsSectionHeading } from '../docs-section';
1+
import { createSignal } from 'fict/advanced';
2+
3+
import { Box, Heading } from '@fictjs/radix-ui-themes';
4+
5+
const primaryButtonStyle = {
6+
appearance: 'none',
7+
background: 'var(--red-9)',
8+
border: '1px solid var(--red-9)',
9+
borderRadius: 'var(--radius-3)',
10+
color: 'white',
11+
cursor: 'pointer',
12+
display: 'inline-flex',
13+
alignItems: 'center',
14+
justifyContent: 'center',
15+
gap: '8px',
16+
minHeight: '36px',
17+
padding: '0 14px',
18+
font: 'inherit',
19+
fontWeight: 500,
20+
} as const;
21+
22+
const softButtonStyle = {
23+
...primaryButtonStyle,
24+
background: 'var(--gray-3)',
25+
border: '1px solid var(--gray-6)',
26+
color: 'var(--gray-12)',
27+
};
328

429
export default function AlertDialogPage() {
30+
const open = createSignal(false);
31+
const setOpen = (value: boolean) => open(value);
32+
33+
return (
34+
<section>
35+
<Heading size="6" as="h2">
36+
AlertDialog
37+
</Heading>
38+
<Box mt="4">
39+
<button
40+
id="alert-dialog-demo-open"
41+
type="button"
42+
style={primaryButtonStyle}
43+
onClick={() => open(true)}
44+
>
45+
Open
46+
</button>
47+
48+
<AlertDialogDemoModal open={open()} setOpen={setOpen} />
49+
</Box>
50+
</section>
51+
);
52+
}
53+
54+
export function AlertDialogDemoModal(props: { open: boolean; setOpen: (value: boolean) => void }) {
555
return (
6-
<DocsSection>
7-
<DocsSectionHeading>AlertDialog</DocsSectionHeading>
8-
<DocsSectionBody>
9-
<AlertDialog.Root>
10-
<AlertDialog.Trigger>
11-
<Button variant="solid">Open</Button>
12-
</AlertDialog.Trigger>
13-
<AlertDialog.Content maxWidth="450px">
14-
<Flex direction="column" gap="3">
15-
<AlertDialog.Title>Revoke setup link</AlertDialog.Title>
16-
<AlertDialog.Description>
17-
The setup link will no longer be accessible and any existing setup sessions will be
18-
revoked.
19-
</AlertDialog.Description>
20-
<Flex gap="3" mt="4" justify="end">
21-
<AlertDialog.Cancel>
22-
<Button variant="soft" color="gray">
23-
Cancel
24-
</Button>
25-
</AlertDialog.Cancel>
26-
<AlertDialog.Action>
27-
<Button variant="solid" color="red">
28-
Revoke link
29-
</Button>
30-
</AlertDialog.Action>
31-
</Flex>
32-
</Flex>
33-
</AlertDialog.Content>
34-
</AlertDialog.Root>
35-
</DocsSectionBody>
36-
</DocsSection>
56+
<div
57+
id="alert-dialog-demo-overlay"
58+
style={{
59+
position: 'fixed',
60+
inset: '0',
61+
zIndex: 1000,
62+
display: props.open ? 'flex' : 'none',
63+
alignItems: 'center',
64+
justifyContent: 'center',
65+
background: 'rgba(3, 7, 18, 0.6)',
66+
padding: '24px',
67+
}}
68+
onClick={() => props.setOpen(false)}
69+
>
70+
<div
71+
id="alert-dialog-demo-modal"
72+
role="alertdialog"
73+
aria-modal="true"
74+
aria-hidden={props.open ? 'false' : 'true'}
75+
style={{
76+
width: '100%',
77+
maxWidth: '450px',
78+
position: 'relative',
79+
background: 'var(--color-panel-solid)',
80+
color: 'var(--gray-12)',
81+
borderRadius: 'var(--radius-4)',
82+
boxShadow: '0 18px 60px rgba(0, 0, 0, 0.35)',
83+
padding: '24px',
84+
}}
85+
onClick={(event) => event.stopPropagation()}
86+
>
87+
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
88+
<h3 style={{ margin: 0, fontSize: 'var(--font-size-5)', lineHeight: 'var(--line-height-5)' }}>
89+
Revoke setup link
90+
</h3>
91+
<p
92+
style={{
93+
margin: 0,
94+
fontSize: 'var(--font-size-3)',
95+
lineHeight: 'var(--line-height-3)',
96+
color: 'var(--gray-11)',
97+
}}
98+
>
99+
The setup link will no longer be accessible and any existing setup sessions will be
100+
revoked.
101+
</p>
102+
<div style={{ display: 'flex', gap: '12px', justifyContent: 'flex-end', marginTop: '16px' }}>
103+
<button
104+
id="alert-dialog-demo-cancel"
105+
type="button"
106+
style={softButtonStyle}
107+
onClick={() => props.setOpen(false)}
108+
>
109+
Cancel
110+
</button>
111+
<button
112+
id="alert-dialog-demo-action"
113+
type="button"
114+
style={primaryButtonStyle}
115+
onClick={() => props.setOpen(false)}
116+
>
117+
Revoke link
118+
</button>
119+
</div>
120+
</div>
121+
</div>
122+
</div>
37123
);
38124
}

apps/playground/src/sink/dialog/page.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const softButtonStyle = {
2929

3030
export default function DialogPage() {
3131
const open = createSignal(false);
32+
const setOpen = (value: boolean) => open(value);
3233

3334
return (
3435
<section>
@@ -40,15 +41,16 @@ export default function DialogPage() {
4041
Open
4142
</button>
4243

43-
<DialogDemoModal open={open()} setOpen={open} />
44+
<DialogDemoModal open={open()} setOpen={setOpen} />
4445
</Box>
4546
</section>
4647
);
4748
}
4849

49-
function DialogDemoModal(props: { open: boolean; setOpen: (value: boolean) => void }) {
50+
export function DialogDemoModal(props: { open: boolean; setOpen: (value: boolean) => void }) {
5051
return (
5152
<div
53+
id="dialog-demo-overlay"
5254
style={{
5355
position: 'fixed',
5456
inset: '0',
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { afterEach, describe, expect, it } from 'vitest'
2+
3+
import { render } from 'fict'
4+
import { createSignal } from 'fict/advanced'
5+
6+
import { AlertDialogDemoModal } from '../src/sink/alert-dialog/page'
7+
8+
const cleanups: Array<() => void> = []
9+
10+
function flush() {
11+
return new Promise<void>((resolve) => setTimeout(resolve, 0))
12+
}
13+
14+
describe('playground alert dialog demo', () => {
15+
afterEach(() => {
16+
while (cleanups.length > 0) {
17+
cleanups.pop()?.()
18+
}
19+
document.body.innerHTML = ''
20+
})
21+
22+
it('closes the demo modal when clicking Cancel', async () => {
23+
const container = document.createElement('div')
24+
document.body.append(container)
25+
const open = createSignal(true)
26+
27+
cleanups.push(render(() => <AlertDialogDemoModal open={true} setOpen={open} />, container))
28+
29+
await flush()
30+
31+
const cancelButton = container.querySelector('#alert-dialog-demo-cancel')
32+
expect(open()).toBe(true)
33+
34+
cancelButton?.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }))
35+
await flush()
36+
37+
expect(open()).toBe(false)
38+
})
39+
})

apps/playground/test/dialog-demo.test.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { afterEach, describe, expect, it } from 'vitest'
22

33
import { render } from 'fict'
4+
import { createSignal } from 'fict/advanced'
45

5-
import DialogPage from '../src/sink/dialog/page'
6+
import DialogPage, { DialogDemoModal } from '../src/sink/dialog/page'
67

78
const cleanups: Array<() => void> = []
89

@@ -18,7 +19,7 @@ describe('playground dialog demo', () => {
1819
document.body.innerHTML = ''
1920
})
2021

21-
it('opens the demo modal when clicking Open', async () => {
22+
it('renders the dialog playground entry point', async () => {
2223
const container = document.createElement('div')
2324
document.body.append(container)
2425

@@ -29,13 +30,25 @@ describe('playground dialog demo', () => {
2930
const openButton = container.querySelector('#dialog-demo-open')
3031
expect(openButton).not.toBeNull()
3132
expect(container.querySelector('#dialog-demo-modal')).not.toBeNull()
33+
expect(container.textContent).toContain('Share resource')
34+
expect(container.textContent).toContain('Cancel')
35+
})
36+
37+
it('closes the demo modal when clicking Cancel with a signal setter prop', async () => {
38+
const container = document.createElement('div')
39+
document.body.append(container)
40+
const open = createSignal(true)
41+
42+
cleanups.push(render(() => <DialogDemoModal open={true} setOpen={open} />, container))
3243

33-
openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }))
3444
await flush()
3545

36-
const modal = container.querySelector('#dialog-demo-modal') as HTMLElement | null
37-
expect(modal).not.toBeNull()
38-
expect(container.textContent).toContain('Share resource')
39-
expect(container.textContent).toContain('Cancel')
46+
const cancelButton = container.querySelector('#dialog-demo-cancel')
47+
expect(open()).toBe(true)
48+
49+
cancelButton?.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }))
50+
await flush()
51+
52+
expect(open()).toBe(false)
4053
})
4154
})

apps/playground/vitest.config.ts

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,65 @@
1-
import { dirname, resolve } from 'node:path'
1+
import path from 'node:path'
22
import { fileURLToPath } from 'node:url'
33

44
import { defineConfig } from 'vitest/config'
55

6-
const currentDir = dirname(fileURLToPath(import.meta.url))
6+
const currentDir = path.dirname(fileURLToPath(import.meta.url))
77

88
export default defineConfig({
99
resolve: {
1010
alias: [
11+
{
12+
find: '@radix-ui/react-icons',
13+
replacement: path.resolve(currentDir, './src/compat/radix-icons.tsx'),
14+
},
1115
{
1216
find: '@fictjs/radix-ui/internal',
13-
replacement: resolve(currentDir, '../../packages/radix-ui/dist/internal.js'),
17+
replacement: path.resolve(currentDir, '../../packages/radix-ui/src/internal.ts'),
1418
},
1519
{
1620
find: '@fictjs/radix-ui',
17-
replacement: resolve(currentDir, '../../packages/radix-ui/dist/index.js'),
21+
replacement: path.resolve(currentDir, '../../packages/radix-ui/src/index.ts'),
1822
},
1923
{
2024
find: '@fictjs/radix-ui-themes/styles.css',
21-
replacement: resolve(currentDir, '../../libs/radix-ui-themes/styles.css'),
25+
replacement: path.resolve(currentDir, '../../libs/radix-ui-themes/styles.css'),
2226
},
2327
{
24-
find: '@fictjs/radix-ui-themes/props',
25-
replacement: resolve(currentDir, '../../libs/radix-ui-themes/dist/props/index.js'),
28+
find: '@fictjs/radix-ui-themes',
29+
replacement: path.resolve(currentDir, '../../libs/radix-ui-themes/src/index.ts'),
2630
},
2731
{
2832
find: '@fictjs/radix-ui-themes/helpers',
29-
replacement: resolve(currentDir, '../../libs/radix-ui-themes/dist/helpers/index.js'),
33+
replacement: path.resolve(currentDir, '../../libs/radix-ui-themes/src/helpers/index.ts'),
3034
},
3135
{
32-
find: '@fictjs/radix-ui-themes',
33-
replacement: resolve(currentDir, '../../libs/radix-ui-themes/dist/index.js'),
36+
find: '@fictjs/radix-ui-themes/props',
37+
replacement: path.resolve(currentDir, '../../libs/radix-ui-themes/src/props/index.ts'),
3438
},
3539
{
36-
find: '@radix-ui/react-icons',
37-
replacement: resolve(currentDir, './src/compat/radix-icons.tsx'),
40+
find: 'next/link',
41+
replacement: path.resolve(currentDir, './src/compat/next-link.tsx'),
3842
},
39-
{ find: 'next/link', replacement: resolve(currentDir, './src/compat/next-link.tsx') },
4043
{
4144
find: 'next/navigation',
42-
replacement: resolve(currentDir, './src/compat/next-navigation.ts'),
45+
replacement: path.resolve(currentDir, './src/compat/next-navigation.ts'),
46+
},
47+
{
48+
find: 'react',
49+
replacement: path.resolve(currentDir, './src/compat/react.tsx'),
4350
},
44-
{ find: 'next', replacement: resolve(currentDir, './src/compat/next.ts') },
45-
{ find: 'react', replacement: resolve(currentDir, './src/compat/react.tsx') },
4651
],
4752
},
53+
esbuild: {
54+
jsx: 'automatic',
55+
jsxImportSource: 'fict',
56+
},
4857
test: {
58+
coverage: {
59+
provider: 'v8',
60+
reporter: ['text', 'html'],
61+
reportsDirectory: './coverage',
62+
},
4963
environment: 'jsdom',
5064
include: ['test/**/*.test.ts', 'test/**/*.test.tsx'],
5165
},

0 commit comments

Comments
 (0)