3636 border-radius : 4px ;
3737}
3838</ style >
39+ < script src ="https://cdn.jsdelivr.net/npm/prompts-js "> </ script >
3940</ head >
4041< body >
4142< h1 > Prompts.js</ h1 >
@@ -55,267 +56,6 @@ <h1>Prompts.js</h1>
5556< div id ="resultArea " class ="result "> </ div >
5657
5758< script type ="module ">
58- const Prompts = ( function ( ) {
59- let modalOpen = false ;
60- let previouslyFocusedElement = null ;
61-
62- // Common styles
63- const overlayStyle = {
64- position : 'fixed' ,
65- top : '0' , left : '0' , right : '0' , bottom : '0' ,
66- backgroundColor : 'rgba(0,0,0,0.5)' ,
67- display : 'flex' ,
68- alignItems : 'center' ,
69- justifyContent : 'center' ,
70- zIndex : '999999' ,
71- } ;
72-
73- const modalStyle = {
74- backgroundColor : '#fff' ,
75- borderRadius : '6px' ,
76- padding : '20px' ,
77- minWidth : '300px' ,
78- maxWidth : '80%' ,
79- boxSizing : 'border-box' ,
80- fontFamily : 'sans-serif' ,
81- boxShadow : '0 2px 10px rgba(0,0,0,0.2)' ,
82- } ;
83-
84- const messageStyle = {
85- marginBottom : '20px' ,
86- fontSize : '16px' ,
87- color : '#333' ,
88- wordWrap : 'break-word' ,
89- whiteSpace : 'pre-wrap' ,
90- } ;
91-
92- const buttonRowStyle = {
93- textAlign : 'right' ,
94- marginTop : '20px' ,
95- } ;
96-
97- const buttonStyle = {
98- backgroundColor : '#007bff' ,
99- color : '#fff' ,
100- border : 'none' ,
101- borderRadius : '4px' ,
102- padding : '8px 12px' ,
103- fontSize : '14px' ,
104- cursor : 'pointer' ,
105- marginLeft : '8px' ,
106- } ;
107-
108- const inputStyle = {
109- width : '100%' ,
110- boxSizing : 'border-box' ,
111- padding : '8px' ,
112- fontSize : '14px' ,
113- marginBottom : '20px' ,
114- borderRadius : '4px' ,
115- border : '1px solid #ccc' ,
116- } ;
117-
118- function applyStyles ( element , styles ) {
119- for ( const prop in styles ) {
120- element . style [ prop ] = styles [ prop ] ;
121- }
122- }
123-
124- function createModal ( message ) {
125- const overlay = document . createElement ( 'div' ) ;
126- applyStyles ( overlay , overlayStyle ) ;
127-
128- const modal = document . createElement ( 'div' ) ;
129- applyStyles ( modal , modalStyle ) ;
130-
131- const form = document . createElement ( 'form' ) ;
132- form . setAttribute ( 'novalidate' , 'true' ) ;
133- modal . appendChild ( form ) ;
134-
135- const msg = document . createElement ( 'div' ) ;
136- applyStyles ( msg , messageStyle ) ;
137- msg . textContent = message ;
138-
139- form . appendChild ( msg ) ;
140- overlay . appendChild ( modal ) ;
141-
142- return { overlay, modal, form } ;
143- }
144-
145- function createButton ( label , onClick , type = 'button' ) {
146- const btn = document . createElement ( 'button' ) ;
147- applyStyles ( btn , buttonStyle ) ;
148- btn . type = type ;
149- btn . textContent = label ;
150- if ( onClick ) {
151- btn . addEventListener ( 'click' , onClick ) ;
152- }
153- return btn ;
154- }
155-
156- function showModal ( overlay , onClose ) {
157- if ( modalOpen ) return ; // Prevent multiple modals
158- modalOpen = true ;
159-
160- previouslyFocusedElement = document . activeElement ;
161- document . body . appendChild ( overlay ) ;
162-
163- // Focus trap and ESC handler
164- const focusableElements = overlay . querySelectorAll ( 'button, input, [href], select, textarea, [tabindex]:not([tabindex="-1"])' ) ;
165- const firstFocusable = focusableElements [ 0 ] ;
166- const lastFocusable = focusableElements [ focusableElements . length - 1 ] ;
167-
168- function keyHandler ( e ) {
169- if ( e . key === 'Escape' ) {
170- e . preventDefault ( ) ;
171- cleanup ( ) ;
172- onClose ( 'escape' ) ;
173- } else if ( e . key === 'Tab' ) {
174- // Focus trapping
175- if ( focusableElements . length === 1 ) {
176- e . preventDefault ( ) ; // Only one focusable element, cycle back to it.
177- } else {
178- if ( e . shiftKey && document . activeElement === firstFocusable ) {
179- // If Shift+Tab on first element, go to last
180- e . preventDefault ( ) ;
181- lastFocusable . focus ( ) ;
182- } else if ( ! e . shiftKey && document . activeElement === lastFocusable ) {
183- // If Tab on last element, go to first
184- e . preventDefault ( ) ;
185- firstFocusable . focus ( ) ;
186- }
187- }
188- }
189- }
190-
191- document . addEventListener ( 'keydown' , keyHandler ) ;
192-
193- function cleanup ( ) {
194- document . removeEventListener ( 'keydown' , keyHandler ) ;
195- if ( overlay . parentNode ) {
196- document . body . removeChild ( overlay ) ;
197- }
198- modalOpen = false ;
199- if ( previouslyFocusedElement && previouslyFocusedElement . focus ) {
200- previouslyFocusedElement . focus ( ) ;
201- }
202- }
203-
204- return { cleanup, firstFocusable, focusableElements } ;
205- }
206-
207- async function alert ( message ) {
208- return new Promise ( ( resolve ) => {
209- const { overlay, form } = createModal ( message ) ;
210-
211- const buttonRow = document . createElement ( 'div' ) ;
212- applyStyles ( buttonRow , buttonRowStyle ) ;
213-
214- // OK button submits the form
215- const okBtn = createButton ( 'OK' , null , 'submit' ) ;
216- buttonRow . appendChild ( okBtn ) ;
217- form . appendChild ( buttonRow ) ;
218-
219- form . onsubmit = ( e ) => {
220- e . preventDefault ( ) ;
221- cleanup ( ) ;
222- resolve ( ) ;
223- } ;
224-
225- const { cleanup, firstFocusable } = showModal ( overlay , ( reason ) => {
226- // Escape pressed
227- resolve ( ) ;
228- } ) ;
229-
230- // Move focus to OK button
231- firstFocusable . focus ( ) ;
232- } ) ;
233- }
234-
235- async function confirm ( message ) {
236- return new Promise ( ( resolve ) => {
237- const { overlay, form } = createModal ( message ) ;
238-
239- const buttonRow = document . createElement ( 'div' ) ;
240- applyStyles ( buttonRow , buttonRowStyle ) ;
241-
242- const cancelBtn = createButton ( 'Cancel' , ( e ) => {
243- e . preventDefault ( ) ;
244- cleanup ( ) ;
245- resolve ( false ) ;
246- } ) ;
247- cancelBtn . style . backgroundColor = '#6c757d' ;
248-
249- const okBtn = createButton ( 'OK' , null , 'submit' ) ;
250-
251- buttonRow . appendChild ( cancelBtn ) ;
252- buttonRow . appendChild ( okBtn ) ;
253- form . appendChild ( buttonRow ) ;
254-
255- form . onsubmit = ( e ) => {
256- e . preventDefault ( ) ;
257- // Enter key (submit) is treated as clicking OK
258- cleanup ( ) ;
259- resolve ( true ) ;
260- } ;
261-
262- const { cleanup, focusableElements } = showModal ( overlay , ( reason ) => {
263- // If escaped, treat as cancel
264- resolve ( false ) ;
265- } ) ;
266-
267- // Move focus to OK button (second button)
268- focusableElements [ 1 ] . focus ( ) ;
269- } ) ;
270- }
271-
272- async function prompt ( message ) {
273- return new Promise ( ( resolve ) => {
274- const { overlay, form } = createModal ( message ) ;
275-
276- const input = document . createElement ( 'input' ) ;
277- applyStyles ( input , inputStyle ) ;
278- input . type = 'text' ;
279- input . name = 'promptInput' ;
280- form . appendChild ( input ) ;
281-
282- const buttonRow = document . createElement ( 'div' ) ;
283- applyStyles ( buttonRow , buttonRowStyle ) ;
284-
285- const cancelBtn = createButton ( 'Cancel' , ( e ) => {
286- e . preventDefault ( ) ;
287- cleanup ( ) ;
288- resolve ( null ) ;
289- } ) ;
290- cancelBtn . style . backgroundColor = '#6c757d' ;
291-
292- const okBtn = createButton ( 'OK' , null , 'submit' ) ;
293-
294- buttonRow . appendChild ( cancelBtn ) ;
295- buttonRow . appendChild ( okBtn ) ;
296- form . appendChild ( buttonRow ) ;
297-
298- form . onsubmit = ( e ) => {
299- e . preventDefault ( ) ;
300- const val = input . value ;
301- cleanup ( ) ;
302- resolve ( val ) ;
303- } ;
304-
305- const { cleanup, firstFocusable } = showModal ( overlay , ( reason ) => {
306- // If escaped, treat as cancel
307- resolve ( null ) ;
308- } ) ;
309-
310- // Focus on the input for convenience
311- input . focus ( ) ;
312- } ) ;
313- }
314-
315- return { alert, confirm, prompt } ;
316- } ) ( ) ;
317-
318-
31959const resultArea = document . getElementById ( 'resultArea' ) ;
32060
32161document . getElementById ( 'alertBtn' ) . addEventListener ( 'click' , async ( ) => {
0 commit comments