22import styles from './styles.module.css'
33import { Head } from "#components/Head"
44import type { RouteMeta } from "#router"
5- import { useId , type MouseEvent } from "react"
5+ import { useId , type MouseEvent , type ReactNode } from "react"
66import src from './lorem.jpg'
77
88export const meta : RouteMeta = {
@@ -22,61 +22,138 @@ export default function SilkyModalPage() {
2222 < >
2323 < div className = { styles . main } >
2424 < Head />
25- { /* <First /> */ }
25+ </ div >
26+ < div className = { styles . examples } >
2627 < Second />
28+ < BottomSheet />
29+ < SideSheet />
30+ < HorizontalStartModal />
2731 </ div >
2832 </ >
2933 )
3034}
3135
3236const onClose = ( e : MouseEvent ) => {
3337 e . preventDefault ( )
34- e . currentTarget . closest < HTMLDialogElement > ( 'dialog' ) ! . scrollTo ( { top : 0 , behavior : 'smooth' } )
38+ const dialog = e . currentTarget . closest < HTMLDialogElement > ( 'dialog' ) !
39+ if ( dialog . dataset . orientation === 'vertical' ) {
40+ if ( dialog . dataset . align === 'start' ) {
41+ dialog . scrollTo ( { top : dialog . offsetHeight , behavior : 'smooth' } )
42+ } else {
43+ dialog . scrollTo ( { top : 0 , behavior : 'smooth' } )
44+ }
45+ } else {
46+ if ( dialog . dataset . align === 'start' ) {
47+ dialog . scrollTo ( { left : dialog . offsetWidth , behavior : 'smooth' } )
48+ } else {
49+ dialog . scrollTo ( { left : 0 , behavior : 'smooth' } )
50+ }
51+ }
3552}
3653
37- function First ( ) {
54+
55+ function Second ( ) {
56+ const id = useId ( )
57+
3858 return (
39- < div className = { styles . first } >
40- < button commandfor = "mydialog" command = "show-modal" > Show modal dialog</ button >
41- < dialog id = "mydialog" ref = { ( e ) => {
42- if ( ! e ) return
43- const content = e . querySelector < HTMLDivElement > ( '[data-dialog-area]' ) !
44- let visible = false
45- const observer = new IntersectionObserver ( ( [ entry ] ) => {
46- visible = entry . isIntersecting
47- if ( ! visible ) e . close ( )
48- } )
49- observer . observe ( content )
50- return ( ) => observer . disconnect ( )
51- } } >
52- < div data-dialog-bumper = "top" />
53- < div data-dialog-area onClick = { onClose } >
54- < div data-dialog-content onClick = { ( e ) => e . stopPropagation ( ) } >
55- < Content id = "mydialog" />
56- </ div >
57- </ div >
58- < div data-dialog-bumper = "bottom" />
59- </ dialog >
60- </ div >
59+ < >
60+ < button commandfor = { id } command = "show-modal" > Vertical center sheet</ button >
61+ < Dialog
62+ id = { id }
63+ orientation = "vertical"
64+ align = "center"
65+ className = { styles . verticalCenter }
66+ >
67+ < Content id = { id } />
68+ </ Dialog >
69+ </ >
6170 )
6271}
6372
73+ function BottomSheet ( ) {
74+ const id = useId ( )
6475
65- function Second ( ) {
76+ return (
77+ < >
78+ < button commandfor = { id } command = "show-modal" > Vertical end sheet</ button >
79+ < Dialog
80+ id = { id }
81+ orientation = "vertical"
82+ align = "end"
83+ className = { styles . verticalBottom }
84+ >
85+ < Content id = { id } />
86+ </ Dialog >
87+ </ >
88+ )
89+ }
90+
91+ function SideSheet ( ) {
92+ const id = useId ( )
93+
94+ return (
95+ < >
96+ < button commandfor = { id } command = "show-modal" > Horizontal end sheet</ button >
97+ < Dialog
98+ id = { id }
99+ orientation = "horizontal"
100+ align = "end"
101+ className = { styles . horizontalEnd }
102+ >
103+ < Content id = { id } />
104+ </ Dialog >
105+ </ >
106+ )
107+ }
108+
109+ function HorizontalStartModal ( ) {
66110 const id = useId ( )
67111
68112 return (
69- < div className = { styles . second } >
70- < button commandfor = { id } command = "show-modal" > Show modal dialog</ button >
71- < dialog id = { id } ref = { ( e ) => {
113+ < >
114+ < button commandfor = { id } command = "show-modal" > Horizontal start sheet</ button >
115+ < Dialog
116+ id = { id }
117+ orientation = "horizontal"
118+ align = "start"
119+ className = { styles . horizontalStart }
120+ >
121+ < Content id = { id } />
122+ </ Dialog >
123+ </ >
124+ )
125+ }
126+
127+ function Dialog ( {
128+ id,
129+ children,
130+ className,
131+ orientation = 'vertical' ,
132+ align = 'center'
133+ } : {
134+ id : string
135+ children : ReactNode
136+ className ?: string
137+ orientation ?: 'horizontal' | 'vertical'
138+ align ?: 'start' | 'center' | 'end'
139+ } ) {
140+ return (
141+ < dialog
142+ className = { styles . dialog }
143+ id = { id }
144+ data-orientation = { orientation }
145+ data-align = { align }
146+ ref = { ( e ) => {
72147 if ( ! e ) return
73148 const observer = new IntersectionObserver ( ( [ entry ] ) => ! entry . isIntersecting && e . close ( ) , { rootMargin : '-1px' } )
74149 const area = e . querySelector < HTMLDivElement > ( '[data-dialog-area]' ) !
75- observer . observe ( area )
150+ const content = area . querySelector < HTMLDivElement > ( '[data-dialog-content]' ) !
151+ observer . observe ( content )
76152 const controller = new AbortController ( )
77153 e . addEventListener ( 'beforetoggle' , ( event ) => {
78154 if ( event . newState === 'open' ) requestAnimationFrame ( ( ) => {
79155 e . scrollTop = area . offsetTop
156+ e . scrollLeft = area . offsetLeft
80157 e . querySelector < HTMLDivElement > ( '[data-dialog-content]' ) ! . scrollTop = 0
81158 } )
82159 } , { signal : controller . signal } )
@@ -85,13 +162,12 @@ function Second() {
85162 observer . disconnect ( )
86163 }
87164 } } >
88- < div data-dialog-area onClick = { onClose } >
89- < div data-dialog-content onClick = { ( e ) => e . stopPropagation ( ) } >
90- < Content id = { id } />
91- </ div >
165+ < div data-dialog-area onClick = { onClose } >
166+ < div className = { className } data-dialog-content onClick = { ( e ) => e . stopPropagation ( ) } >
167+ { children }
92168 </ div >
93- </ dialog >
94- </ div >
169+ </ div >
170+ </ dialog >
95171 )
96172}
97173
0 commit comments