@adelalawdi/fnon2 2.0.0
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/README.md +1167 -0
- package/fnon.min.css +1 -0
- package/fnon.min.js +1 -0
- package/index.html +3888 -0
- package/package.json +27 -0
package/index.html
ADDED
|
@@ -0,0 +1,3888 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Fnon.js v2 — Playground & Demos</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
+
<link
|
|
10
|
+
href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap"
|
|
11
|
+
rel="stylesheet"
|
|
12
|
+
/>
|
|
13
|
+
<link rel="stylesheet" href="fnon.min.css" />
|
|
14
|
+
<style>
|
|
15
|
+
* {
|
|
16
|
+
margin: 0;
|
|
17
|
+
padding: 0;
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
}
|
|
20
|
+
body {
|
|
21
|
+
font-family: "Quicksand", sans-serif;
|
|
22
|
+
background: #f5f7fa;
|
|
23
|
+
color: #222f3e;
|
|
24
|
+
}
|
|
25
|
+
.container {
|
|
26
|
+
max-width: 1100px;
|
|
27
|
+
margin: 0 auto;
|
|
28
|
+
padding: 2rem 1rem;
|
|
29
|
+
}
|
|
30
|
+
.header {
|
|
31
|
+
position: sticky;
|
|
32
|
+
top: 0px;
|
|
33
|
+
z-index: 9;
|
|
34
|
+
padding-bottom: 1rem;
|
|
35
|
+
padding-top: 1rem;
|
|
36
|
+
background: #f5f7fa;
|
|
37
|
+
}
|
|
38
|
+
[data-theme="dark"] .header {
|
|
39
|
+
background: #0f172a;
|
|
40
|
+
}
|
|
41
|
+
h1 {
|
|
42
|
+
font-size: 1.8rem;
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
gap: 10px;
|
|
46
|
+
flex-wrap: wrap;
|
|
47
|
+
}
|
|
48
|
+
h1 small {
|
|
49
|
+
font-weight: 400;
|
|
50
|
+
font-size: 0.8rem;
|
|
51
|
+
color: #718096;
|
|
52
|
+
}
|
|
53
|
+
.sub {
|
|
54
|
+
color: #718096;
|
|
55
|
+
font-size: 0.9rem;
|
|
56
|
+
margin-bottom: 1.5rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
section {
|
|
60
|
+
margin-bottom: 2rem;
|
|
61
|
+
}
|
|
62
|
+
section > h2 {
|
|
63
|
+
font-size: 1.2rem;
|
|
64
|
+
font-weight: 600;
|
|
65
|
+
margin-bottom: 0.2rem;
|
|
66
|
+
}
|
|
67
|
+
section > p.section-desc {
|
|
68
|
+
font-size: 0.82rem;
|
|
69
|
+
color: #718096;
|
|
70
|
+
margin-bottom: 0.75rem;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.demo-grid {
|
|
74
|
+
display: grid;
|
|
75
|
+
grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
|
|
76
|
+
gap: 1rem;
|
|
77
|
+
}
|
|
78
|
+
.demo-card {
|
|
79
|
+
background: #fff;
|
|
80
|
+
border-radius: 8px;
|
|
81
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
82
|
+
overflow: hidden;
|
|
83
|
+
}
|
|
84
|
+
.demo-card .card-body {
|
|
85
|
+
padding: 1rem;
|
|
86
|
+
}
|
|
87
|
+
.demo-card .card-actions {
|
|
88
|
+
display: flex;
|
|
89
|
+
flex-wrap: wrap;
|
|
90
|
+
gap: 0.4rem;
|
|
91
|
+
align-items: center;
|
|
92
|
+
}
|
|
93
|
+
.demo-card h3 {
|
|
94
|
+
font-size: 0.85rem;
|
|
95
|
+
font-weight: 600;
|
|
96
|
+
margin-bottom: 0.15rem;
|
|
97
|
+
}
|
|
98
|
+
.demo-card p.desc {
|
|
99
|
+
font-size: 0.73rem;
|
|
100
|
+
color: #718096;
|
|
101
|
+
margin-bottom: 0.5rem;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.demo-card button {
|
|
105
|
+
font-family: "Quicksand", sans-serif;
|
|
106
|
+
font-size: 0.75rem;
|
|
107
|
+
padding: 0.35rem 0.75rem;
|
|
108
|
+
border: 1px solid #e2e8f0;
|
|
109
|
+
border-radius: 6px;
|
|
110
|
+
background: #fff;
|
|
111
|
+
color: #2d3748;
|
|
112
|
+
cursor: pointer;
|
|
113
|
+
transition: all 0.15s;
|
|
114
|
+
}
|
|
115
|
+
.demo-card button:hover {
|
|
116
|
+
border-color: #029eff;
|
|
117
|
+
color: #029eff;
|
|
118
|
+
background: #ebf8ff;
|
|
119
|
+
}
|
|
120
|
+
.demo-card button:focus-visible {
|
|
121
|
+
outline: 2px solid #029eff;
|
|
122
|
+
outline-offset: 2px;
|
|
123
|
+
}
|
|
124
|
+
.demo-card button.pri {
|
|
125
|
+
background: #029eff;
|
|
126
|
+
color: #fff;
|
|
127
|
+
border-color: #029eff;
|
|
128
|
+
}
|
|
129
|
+
.demo-card button.pri:hover {
|
|
130
|
+
background: #0288e0;
|
|
131
|
+
}
|
|
132
|
+
.demo-card button.suc {
|
|
133
|
+
background: #39da8a;
|
|
134
|
+
color: #fff;
|
|
135
|
+
border-color: #39da8a;
|
|
136
|
+
}
|
|
137
|
+
.demo-card button.war {
|
|
138
|
+
background: #fdd347;
|
|
139
|
+
color: #222f3e;
|
|
140
|
+
border-color: #fdd347;
|
|
141
|
+
}
|
|
142
|
+
.demo-card button.dan {
|
|
143
|
+
background: #ff6b6b;
|
|
144
|
+
color: #fff;
|
|
145
|
+
border-color: #ff6b6b;
|
|
146
|
+
}
|
|
147
|
+
.demo-card button.inf {
|
|
148
|
+
background: #48dbfb;
|
|
149
|
+
color: #222f3e;
|
|
150
|
+
border-color: #48dbfb;
|
|
151
|
+
}
|
|
152
|
+
.demo-card button.drk {
|
|
153
|
+
background: #222f3e;
|
|
154
|
+
color: #fff;
|
|
155
|
+
border-color: #222f3e;
|
|
156
|
+
}
|
|
157
|
+
.demo-card button:disabled {
|
|
158
|
+
opacity: 0.5;
|
|
159
|
+
cursor: not-allowed;
|
|
160
|
+
}
|
|
161
|
+
.demo-card button.small {
|
|
162
|
+
font-size: 0.65rem;
|
|
163
|
+
padding: 0.25rem 0.5rem;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.code {
|
|
167
|
+
font-size: 0.65rem;
|
|
168
|
+
background: #1a202c;
|
|
169
|
+
color: #a0aec0;
|
|
170
|
+
padding: 0.5rem 0.6rem;
|
|
171
|
+
border-radius: 0 0 6px 6px;
|
|
172
|
+
overflow-x: auto;
|
|
173
|
+
line-height: 1.5;
|
|
174
|
+
font-family: "Consolas", "Courier New", monospace;
|
|
175
|
+
user-select: all;
|
|
176
|
+
border-top: 1px solid #2d3748;
|
|
177
|
+
white-space: pre-wrap;
|
|
178
|
+
}
|
|
179
|
+
.code .kw {
|
|
180
|
+
color: #63b3ed;
|
|
181
|
+
}
|
|
182
|
+
.code .str {
|
|
183
|
+
color: #9ae6b4;
|
|
184
|
+
}
|
|
185
|
+
.code .fn {
|
|
186
|
+
color: #f6ad55;
|
|
187
|
+
}
|
|
188
|
+
.code .cm {
|
|
189
|
+
color: #718096;
|
|
190
|
+
font-style: italic;
|
|
191
|
+
}
|
|
192
|
+
.code .num {
|
|
193
|
+
color: #fbbf24;
|
|
194
|
+
}
|
|
195
|
+
.code .pr {
|
|
196
|
+
color: #fc8181;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.ref-section {
|
|
200
|
+
background: #1a202c;
|
|
201
|
+
border-radius: 8px;
|
|
202
|
+
padding: 1rem;
|
|
203
|
+
margin-top: 0.5rem;
|
|
204
|
+
overflow-x: auto;
|
|
205
|
+
}
|
|
206
|
+
.ref-section h3 {
|
|
207
|
+
color: #e2e8f0;
|
|
208
|
+
font-size: 0.85rem;
|
|
209
|
+
margin-bottom: 0.5rem;
|
|
210
|
+
}
|
|
211
|
+
.ref-section pre {
|
|
212
|
+
font-family: "Consolas", "Courier New", monospace;
|
|
213
|
+
font-size: 0.72rem;
|
|
214
|
+
color: #a0aec0;
|
|
215
|
+
line-height: 1.6;
|
|
216
|
+
white-space: pre-wrap;
|
|
217
|
+
}
|
|
218
|
+
.ref-table {
|
|
219
|
+
width: 100%;
|
|
220
|
+
border-collapse: collapse;
|
|
221
|
+
font-size: 0.72rem;
|
|
222
|
+
font-family: "Consolas", "Courier New", monospace;
|
|
223
|
+
}
|
|
224
|
+
.ref-table th {
|
|
225
|
+
color: #e2e8f0;
|
|
226
|
+
text-align: left;
|
|
227
|
+
padding: 6px 8px;
|
|
228
|
+
border-bottom: 1px solid #2d3748;
|
|
229
|
+
font-size: 0.7rem;
|
|
230
|
+
text-transform: uppercase;
|
|
231
|
+
letter-spacing: 0.05em;
|
|
232
|
+
}
|
|
233
|
+
.ref-table td {
|
|
234
|
+
color: #a0aec0;
|
|
235
|
+
padding: 5px 8px;
|
|
236
|
+
border-bottom: 1px solid #1f2937;
|
|
237
|
+
}
|
|
238
|
+
.ref-table td:first-child {
|
|
239
|
+
color: #63b3ed;
|
|
240
|
+
}
|
|
241
|
+
.ref-table td:nth-child(2) {
|
|
242
|
+
color: #9ae6b4;
|
|
243
|
+
}
|
|
244
|
+
.ref-table td:nth-child(3) {
|
|
245
|
+
color: #fbbf24;
|
|
246
|
+
}
|
|
247
|
+
.ref-table td:nth-child(4) {
|
|
248
|
+
color: #6b7280;
|
|
249
|
+
font-style: italic;
|
|
250
|
+
}
|
|
251
|
+
.ref-table tr:hover td {
|
|
252
|
+
background: #1f2937;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.toc {
|
|
256
|
+
display: flex;
|
|
257
|
+
flex-wrap: wrap;
|
|
258
|
+
gap: 6px;
|
|
259
|
+
margin-bottom: 1.5rem;
|
|
260
|
+
}
|
|
261
|
+
.toc a {
|
|
262
|
+
font-size: 0.75rem;
|
|
263
|
+
padding: 0.3rem 0.6rem;
|
|
264
|
+
background: #e2e8f0;
|
|
265
|
+
border-radius: 6px;
|
|
266
|
+
color: #4a5568;
|
|
267
|
+
text-decoration: none;
|
|
268
|
+
transition: all 0.15s;
|
|
269
|
+
}
|
|
270
|
+
.toc a:hover {
|
|
271
|
+
background: #029eff;
|
|
272
|
+
color: #fff;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.badge {
|
|
276
|
+
font-size: 0.6rem;
|
|
277
|
+
background: #ebf8ff;
|
|
278
|
+
color: #029eff;
|
|
279
|
+
padding: 0.15rem 0.5rem;
|
|
280
|
+
border-radius: 99px;
|
|
281
|
+
font-weight: 600;
|
|
282
|
+
margin-left: 6px;
|
|
283
|
+
vertical-align: middle;
|
|
284
|
+
white-space: nowrap;
|
|
285
|
+
}
|
|
286
|
+
hr {
|
|
287
|
+
border: none;
|
|
288
|
+
border-top: 1px solid #e2e8f0;
|
|
289
|
+
margin: 2rem 0;
|
|
290
|
+
}
|
|
291
|
+
footer {
|
|
292
|
+
text-align: center;
|
|
293
|
+
font-size: 0.78rem;
|
|
294
|
+
color: #a0aec0;
|
|
295
|
+
padding-bottom: 2rem;
|
|
296
|
+
}
|
|
297
|
+
#box-target {
|
|
298
|
+
position: relative;
|
|
299
|
+
min-height: 80px;
|
|
300
|
+
background: #fff;
|
|
301
|
+
border-radius: 8px;
|
|
302
|
+
border: 2px dashed #e2e8f0;
|
|
303
|
+
display: flex;
|
|
304
|
+
align-items: center;
|
|
305
|
+
justify-content: center;
|
|
306
|
+
color: #a0aec0;
|
|
307
|
+
font-size: 0.82rem;
|
|
308
|
+
margin-top: 0.5rem;
|
|
309
|
+
transition: min-height 0.2s;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* ── Sandbox form styles ── */
|
|
313
|
+
.sandbox {
|
|
314
|
+
background: #fff;
|
|
315
|
+
border-radius: 8px;
|
|
316
|
+
border: 2px solid #e2e8f0;
|
|
317
|
+
padding: 1rem;
|
|
318
|
+
margin-top: 0.75rem;
|
|
319
|
+
}
|
|
320
|
+
.sandbox h3 {
|
|
321
|
+
font-size: 0.9rem;
|
|
322
|
+
font-weight: 600;
|
|
323
|
+
margin-bottom: 0.2rem;
|
|
324
|
+
color: #2d3748;
|
|
325
|
+
}
|
|
326
|
+
.sandbox > p {
|
|
327
|
+
font-size: 0.73rem;
|
|
328
|
+
color: #718096;
|
|
329
|
+
margin-bottom: 0.75rem;
|
|
330
|
+
}
|
|
331
|
+
.sandbox-grid {
|
|
332
|
+
display: grid;
|
|
333
|
+
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
334
|
+
gap: 0.5rem 0.75rem;
|
|
335
|
+
}
|
|
336
|
+
.sandbox-row {
|
|
337
|
+
display: flex;
|
|
338
|
+
flex-direction: column;
|
|
339
|
+
gap: 2px;
|
|
340
|
+
}
|
|
341
|
+
.sandbox-row label {
|
|
342
|
+
font-size: 0.7rem;
|
|
343
|
+
font-weight: 600;
|
|
344
|
+
color: #4a5568;
|
|
345
|
+
text-transform: uppercase;
|
|
346
|
+
letter-spacing: 0.03em;
|
|
347
|
+
}
|
|
348
|
+
.sandbox-row input,
|
|
349
|
+
.sandbox-row select {
|
|
350
|
+
font-family: "Quicksand", sans-serif;
|
|
351
|
+
font-size: 0.78rem;
|
|
352
|
+
padding: 0.35rem 0.5rem;
|
|
353
|
+
border: 1px solid #e2e8f0;
|
|
354
|
+
border-radius: 5px;
|
|
355
|
+
background: #f7fafc;
|
|
356
|
+
color: #2d3748;
|
|
357
|
+
transition: border-color 0.15s;
|
|
358
|
+
}
|
|
359
|
+
.sandbox-row input:focus,
|
|
360
|
+
.sandbox-row select:focus {
|
|
361
|
+
outline: none;
|
|
362
|
+
border-color: #029eff;
|
|
363
|
+
background: #fff;
|
|
364
|
+
}
|
|
365
|
+
.sandbox-row input[type="checkbox"] {
|
|
366
|
+
width: 18px;
|
|
367
|
+
height: 18px;
|
|
368
|
+
accent-color: #029eff;
|
|
369
|
+
cursor: pointer;
|
|
370
|
+
}
|
|
371
|
+
.sandbox-row input[type="color"] {
|
|
372
|
+
height: 34px;
|
|
373
|
+
cursor: pointer;
|
|
374
|
+
padding: 2px;
|
|
375
|
+
}
|
|
376
|
+
.sandbox-row .chk-row {
|
|
377
|
+
display: flex;
|
|
378
|
+
align-items: center;
|
|
379
|
+
gap: 6px;
|
|
380
|
+
padding-top: 4px;
|
|
381
|
+
}
|
|
382
|
+
.sandbox-row .chk-row label {
|
|
383
|
+
text-transform: none;
|
|
384
|
+
font-weight: 400;
|
|
385
|
+
font-size: 0.78rem;
|
|
386
|
+
cursor: pointer;
|
|
387
|
+
}
|
|
388
|
+
.sandbox-actions {
|
|
389
|
+
display: flex;
|
|
390
|
+
gap: 0.5rem;
|
|
391
|
+
align-items: center;
|
|
392
|
+
margin-top: 0.75rem;
|
|
393
|
+
padding-top: 0.75rem;
|
|
394
|
+
border-top: 1px solid #e2e8f0;
|
|
395
|
+
}
|
|
396
|
+
.sandbox-actions button {
|
|
397
|
+
font-family: "Quicksand", sans-serif;
|
|
398
|
+
font-size: 0.8rem;
|
|
399
|
+
padding: 0.4rem 1rem;
|
|
400
|
+
border: 1px solid #e2e8f0;
|
|
401
|
+
border-radius: 6px;
|
|
402
|
+
background: #fff;
|
|
403
|
+
color: #2d3748;
|
|
404
|
+
cursor: pointer;
|
|
405
|
+
transition: all 0.15s;
|
|
406
|
+
}
|
|
407
|
+
.sandbox-actions button:hover {
|
|
408
|
+
border-color: #029eff;
|
|
409
|
+
color: #029eff;
|
|
410
|
+
background: #ebf8ff;
|
|
411
|
+
}
|
|
412
|
+
.sandbox-actions button:focus-visible {
|
|
413
|
+
outline: 2px solid #029eff;
|
|
414
|
+
outline-offset: 2px;
|
|
415
|
+
}
|
|
416
|
+
.sandbox-actions button.pri {
|
|
417
|
+
background: #029eff;
|
|
418
|
+
color: #fff;
|
|
419
|
+
border-color: #029eff;
|
|
420
|
+
}
|
|
421
|
+
.sandbox-actions button.pri:hover {
|
|
422
|
+
background: #0288e0;
|
|
423
|
+
}
|
|
424
|
+
.sandbox-actions button.dan {
|
|
425
|
+
background: #ff6b6b;
|
|
426
|
+
color: #fff;
|
|
427
|
+
border-color: #ff6b6b;
|
|
428
|
+
}
|
|
429
|
+
.sandbox-actions button.dan:hover {
|
|
430
|
+
background: #e05555;
|
|
431
|
+
}
|
|
432
|
+
.sandbox-section-label {
|
|
433
|
+
grid-column: 1 / -1;
|
|
434
|
+
font-size: 0.68rem;
|
|
435
|
+
font-weight: 600;
|
|
436
|
+
color: #a0aec0;
|
|
437
|
+
text-transform: uppercase;
|
|
438
|
+
letter-spacing: 0.05em;
|
|
439
|
+
padding-top: 0.4rem;
|
|
440
|
+
border-top: 1px solid #edf2f7;
|
|
441
|
+
margin-top: 0.2rem;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/* ── Theme toggle ── */
|
|
445
|
+
.theme-toggle, .rtl-toggle {
|
|
446
|
+
margin-left: auto;
|
|
447
|
+
background: none;
|
|
448
|
+
border: 2px solid #e2e8f0;
|
|
449
|
+
border-radius: 50%;
|
|
450
|
+
width: 36px;
|
|
451
|
+
height: 36px;
|
|
452
|
+
font-size: 1.1rem;
|
|
453
|
+
cursor: pointer;
|
|
454
|
+
display: inline-flex;
|
|
455
|
+
align-items: center;
|
|
456
|
+
justify-content: center;
|
|
457
|
+
transition: all 0.2s;
|
|
458
|
+
flex-shrink: 0;
|
|
459
|
+
line-height: 1;
|
|
460
|
+
padding: 0;
|
|
461
|
+
}
|
|
462
|
+
.theme-toggle:hover, .rtl-toggle:hover {
|
|
463
|
+
border-color: #029eff;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/* ── Dark theme ── */
|
|
467
|
+
[data-theme="dark"] body {
|
|
468
|
+
background: #0f172a;
|
|
469
|
+
color: #e2e8f0;
|
|
470
|
+
}
|
|
471
|
+
[data-theme="dark"] .demo-card {
|
|
472
|
+
background: #1e293b;
|
|
473
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
|
474
|
+
}
|
|
475
|
+
[data-theme="dark"] .demo-card h3 {
|
|
476
|
+
color: #e2e8f0;
|
|
477
|
+
}
|
|
478
|
+
[data-theme="dark"] .demo-card p.desc {
|
|
479
|
+
color: #94a3b8;
|
|
480
|
+
}
|
|
481
|
+
[data-theme="dark"] .demo-card button {
|
|
482
|
+
background: #334155;
|
|
483
|
+
border-color: #475569;
|
|
484
|
+
color: #e2e8f0;
|
|
485
|
+
}
|
|
486
|
+
[data-theme="dark"] .demo-card button:hover {
|
|
487
|
+
border-color: #38bdf8;
|
|
488
|
+
color: #38bdf8;
|
|
489
|
+
background: #1e293b;
|
|
490
|
+
}
|
|
491
|
+
[data-theme="dark"] .demo-card button.pri {
|
|
492
|
+
background: #0284c7;
|
|
493
|
+
border-color: #0284c7;
|
|
494
|
+
color: #fff;
|
|
495
|
+
}
|
|
496
|
+
[data-theme="dark"] .demo-card button.pri:hover {
|
|
497
|
+
background: #0369a1;
|
|
498
|
+
}
|
|
499
|
+
[data-theme="dark"] .demo-card button.suc {
|
|
500
|
+
background: #16a34a;
|
|
501
|
+
border-color: #16a34a;
|
|
502
|
+
}
|
|
503
|
+
[data-theme="dark"] .demo-card button.suc:hover {
|
|
504
|
+
background: #15803d;
|
|
505
|
+
}
|
|
506
|
+
[data-theme="dark"] .demo-card button.war {
|
|
507
|
+
background: #ca8a04;
|
|
508
|
+
border-color: #ca8a04;
|
|
509
|
+
color: #fff;
|
|
510
|
+
}
|
|
511
|
+
[data-theme="dark"] .demo-card button.war:hover {
|
|
512
|
+
background: #a16207;
|
|
513
|
+
}
|
|
514
|
+
[data-theme="dark"] .demo-card button.dan {
|
|
515
|
+
background: #dc2626;
|
|
516
|
+
border-color: #dc2626;
|
|
517
|
+
}
|
|
518
|
+
[data-theme="dark"] .demo-card button.dan:hover {
|
|
519
|
+
background: #b91c1c;
|
|
520
|
+
}
|
|
521
|
+
[data-theme="dark"] .demo-card button.inf {
|
|
522
|
+
background: #0284c7;
|
|
523
|
+
border-color: #0284c7;
|
|
524
|
+
}
|
|
525
|
+
[data-theme="dark"] .demo-card button.inf:hover {
|
|
526
|
+
background: #0369a1;
|
|
527
|
+
}
|
|
528
|
+
[data-theme="dark"] .demo-card button.drk {
|
|
529
|
+
background: #64748b;
|
|
530
|
+
border-color: #64748b;
|
|
531
|
+
}
|
|
532
|
+
[data-theme="dark"] .demo-card button.drk:hover {
|
|
533
|
+
background: #475569;
|
|
534
|
+
}
|
|
535
|
+
[data-theme="dark"] h1 small {
|
|
536
|
+
color: #64748b;
|
|
537
|
+
}
|
|
538
|
+
[data-theme="dark"] .sub {
|
|
539
|
+
color: #94a3b8;
|
|
540
|
+
}
|
|
541
|
+
[data-theme="dark"] section > p.section-desc {
|
|
542
|
+
color: #94a3b8;
|
|
543
|
+
}
|
|
544
|
+
[data-theme="dark"] .toc a {
|
|
545
|
+
background: #334155;
|
|
546
|
+
color: #cbd5e1;
|
|
547
|
+
}
|
|
548
|
+
[data-theme="dark"] .toc a:hover {
|
|
549
|
+
background: #0284c7;
|
|
550
|
+
color: #fff;
|
|
551
|
+
}
|
|
552
|
+
[data-theme="dark"] .badge {
|
|
553
|
+
background: #0f172a;
|
|
554
|
+
color: #38bdf8;
|
|
555
|
+
}
|
|
556
|
+
[data-theme="dark"] hr {
|
|
557
|
+
border-color: #334155;
|
|
558
|
+
}
|
|
559
|
+
[data-theme="dark"] footer {
|
|
560
|
+
color: #64748b;
|
|
561
|
+
}
|
|
562
|
+
[data-theme="dark"] #box-target {
|
|
563
|
+
background: #1e293b;
|
|
564
|
+
border-color: #334155;
|
|
565
|
+
color: #64748b;
|
|
566
|
+
}
|
|
567
|
+
[data-theme="dark"] .sandbox {
|
|
568
|
+
background: #1e293b;
|
|
569
|
+
border-color: #334155;
|
|
570
|
+
}
|
|
571
|
+
[data-theme="dark"] .sandbox h3 {
|
|
572
|
+
color: #e2e8f0;
|
|
573
|
+
}
|
|
574
|
+
[data-theme="dark"] .sandbox > p {
|
|
575
|
+
color: #94a3b8;
|
|
576
|
+
}
|
|
577
|
+
[data-theme="dark"] .sandbox-row label {
|
|
578
|
+
color: #94a3b8;
|
|
579
|
+
}
|
|
580
|
+
[data-theme="dark"] .sandbox-row input,
|
|
581
|
+
[data-theme="dark"] .sandbox-row select {
|
|
582
|
+
background: #0f172a;
|
|
583
|
+
border-color: #475569;
|
|
584
|
+
color: #e2e8f0;
|
|
585
|
+
}
|
|
586
|
+
[data-theme="dark"] .sandbox-row input:focus,
|
|
587
|
+
[data-theme="dark"] .sandbox-row select:focus {
|
|
588
|
+
border-color: #38bdf8;
|
|
589
|
+
background: #0f172a;
|
|
590
|
+
}
|
|
591
|
+
[data-theme="dark"] .sandbox-actions {
|
|
592
|
+
border-color: #334155;
|
|
593
|
+
}
|
|
594
|
+
[data-theme="dark"] .sandbox-actions button {
|
|
595
|
+
background: #334155;
|
|
596
|
+
border-color: #475569;
|
|
597
|
+
color: #e2e8f0;
|
|
598
|
+
}
|
|
599
|
+
[data-theme="dark"] .sandbox-actions button:hover {
|
|
600
|
+
border-color: #38bdf8;
|
|
601
|
+
color: #38bdf8;
|
|
602
|
+
background: #1e293b;
|
|
603
|
+
}
|
|
604
|
+
[data-theme="dark"] .sandbox-actions button.pri {
|
|
605
|
+
background: #0284c7;
|
|
606
|
+
border-color: #0284c7;
|
|
607
|
+
color: #fff;
|
|
608
|
+
}
|
|
609
|
+
[data-theme="dark"] .sandbox-actions button.pri:hover {
|
|
610
|
+
background: #0369a1;
|
|
611
|
+
}
|
|
612
|
+
[data-theme="dark"] .sandbox-actions button.dan {
|
|
613
|
+
background: #dc2626;
|
|
614
|
+
border-color: #dc2626;
|
|
615
|
+
color: #fff;
|
|
616
|
+
}
|
|
617
|
+
[data-theme="dark"] .sandbox-actions button.dan:hover {
|
|
618
|
+
background: #b91c1c;
|
|
619
|
+
}
|
|
620
|
+
[data-theme="dark"] .theme-toggle, [data-theme="dark"] .rtl-toggle {
|
|
621
|
+
border-color: #475569;
|
|
622
|
+
}
|
|
623
|
+
[data-theme="dark"] .theme-toggle:hover, [data-theme="dark"] .rtl-toggle:hover {
|
|
624
|
+
border-color: #38bdf8;
|
|
625
|
+
}
|
|
626
|
+
</style>
|
|
627
|
+
</head>
|
|
628
|
+
<body>
|
|
629
|
+
<div class="container">
|
|
630
|
+
<div class="header">
|
|
631
|
+
<h1>
|
|
632
|
+
Fnon.js v2.0.0
|
|
633
|
+
<small
|
|
634
|
+
>Interactive Playground — all APIs, live sandbox, Init
|
|
635
|
+
reference</small
|
|
636
|
+
>
|
|
637
|
+
<button
|
|
638
|
+
id="theme-toggle"
|
|
639
|
+
class="theme-toggle"
|
|
640
|
+
onclick="toggleTheme()"
|
|
641
|
+
title="Toggle dark/light mode"
|
|
642
|
+
>
|
|
643
|
+
🌙
|
|
644
|
+
</button>
|
|
645
|
+
<button
|
|
646
|
+
id="rtl-toggle"
|
|
647
|
+
class="rtl-toggle"
|
|
648
|
+
onclick="toggleRtl()"
|
|
649
|
+
title="Toggle RTL/LTR direction"
|
|
650
|
+
>
|
|
651
|
+
→
|
|
652
|
+
</button>
|
|
653
|
+
</h1>
|
|
654
|
+
<p class="sub">
|
|
655
|
+
Seven feature sections. Each has code examples (try instantly), an
|
|
656
|
+
Init() config reference table, an Async explanation, and a live
|
|
657
|
+
sandbox form. Open browser console for lifecycle logs.
|
|
658
|
+
</p>
|
|
659
|
+
<div class="toc">
|
|
660
|
+
<a href="#hint">1 Hint</a>
|
|
661
|
+
<a href="#wait">2 Wait</a>
|
|
662
|
+
<a href="#box">3 Box</a>
|
|
663
|
+
<a href="#alert">4 Alert</a>
|
|
664
|
+
<a href="#ask">5 Ask</a>
|
|
665
|
+
<a href="#dialogue">6 Dialogue</a>
|
|
666
|
+
<a href="#breaking">7 Breaking</a>
|
|
667
|
+
<a href="#datepicker">8 DatePicker</a>
|
|
668
|
+
<a href="#contextmenu">9 ContextMenu</a>
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
<!-- ══════════════════════════ HINT ══════════════════════════ -->
|
|
675
|
+
<section id="hint">
|
|
676
|
+
<h2>
|
|
677
|
+
1. Hint <span class="badge">Fnon.Hint.Theme(msg, titleOrOpts?)</span>
|
|
678
|
+
</h2>
|
|
679
|
+
<p class="section-desc">
|
|
680
|
+
Toast-style notifications. Auto-dismisses after 4 seconds. 7 themes, 9
|
|
681
|
+
positions, customizable width/font/progress bar.
|
|
682
|
+
</p>
|
|
683
|
+
|
|
684
|
+
<div class="demo-grid">
|
|
685
|
+
<div class="demo-card">
|
|
686
|
+
<div class="card-body">
|
|
687
|
+
<h3>String + title</h3>
|
|
688
|
+
<p class="desc">
|
|
689
|
+
Fnon.Hint.Theme(message, title). Auto-dismisses after 4s.
|
|
690
|
+
</p>
|
|
691
|
+
<div class="card-actions">
|
|
692
|
+
<button
|
|
693
|
+
class="pri"
|
|
694
|
+
onclick="Fnon.Hint.Primary('Hello!', 'Title')"
|
|
695
|
+
>
|
|
696
|
+
Primary
|
|
697
|
+
</button>
|
|
698
|
+
<button
|
|
699
|
+
class="suc"
|
|
700
|
+
onclick="Fnon.Hint.Success('Saved!', 'Title')"
|
|
701
|
+
>
|
|
702
|
+
Success
|
|
703
|
+
</button>
|
|
704
|
+
<button
|
|
705
|
+
class="dan"
|
|
706
|
+
onclick="Fnon.Hint.Danger('Error!', 'Title')"
|
|
707
|
+
>
|
|
708
|
+
Danger
|
|
709
|
+
</button>
|
|
710
|
+
<button
|
|
711
|
+
class="war"
|
|
712
|
+
onclick="Fnon.Hint.Warning('Warning!', 'Title')"
|
|
713
|
+
>
|
|
714
|
+
Warning
|
|
715
|
+
</button>
|
|
716
|
+
<button
|
|
717
|
+
class="inf"
|
|
718
|
+
onclick="Fnon.Hint.Info('Info!', 'Title')"
|
|
719
|
+
>
|
|
720
|
+
Info
|
|
721
|
+
</button>
|
|
722
|
+
<button
|
|
723
|
+
class="dar"
|
|
724
|
+
onclick="Fnon.Hint.Dark('Dark!', 'Title')"
|
|
725
|
+
>
|
|
726
|
+
Dark
|
|
727
|
+
</button>
|
|
728
|
+
<button
|
|
729
|
+
onclick="Fnon.Hint.Light('Light!', 'Title')"
|
|
730
|
+
>
|
|
731
|
+
Light
|
|
732
|
+
</button>
|
|
733
|
+
</div>
|
|
734
|
+
</div>
|
|
735
|
+
<div class="code">
|
|
736
|
+
<span class="kw">Fnon</span>.Hint.Success(<span class="str"
|
|
737
|
+
>'Message'</span
|
|
738
|
+
>, <span class="str">'Title'</span>)
|
|
739
|
+
<span class="kw">Fnon</span>.Hint.Warning(<span class="str"
|
|
740
|
+
>'Message'</span
|
|
741
|
+
>, <span class="str">'Title'</span>)
|
|
742
|
+
<span class="kw">Fnon</span>.Hint.Danger(<span class="str"
|
|
743
|
+
>'Message'</span
|
|
744
|
+
>, <span class="str">'Title'</span>)
|
|
745
|
+
</div>
|
|
746
|
+
</div>
|
|
747
|
+
|
|
748
|
+
<div class="demo-card">
|
|
749
|
+
<div class="card-body">
|
|
750
|
+
<h3>Position options</h3>
|
|
751
|
+
<p class="desc">
|
|
752
|
+
Pass object as 2nd arg: <code>{ position: 'left-top' }</code>. 9
|
|
753
|
+
positions available.
|
|
754
|
+
</p>
|
|
755
|
+
<div class="card-actions">
|
|
756
|
+
<button
|
|
757
|
+
onclick="
|
|
758
|
+
Fnon.Hint.Primary('right-top', { position: 'right-top' })
|
|
759
|
+
"
|
|
760
|
+
>
|
|
761
|
+
R-Top
|
|
762
|
+
</button>
|
|
763
|
+
<button
|
|
764
|
+
onclick="
|
|
765
|
+
Fnon.Hint.Primary('left-top', { position: 'left-top' })
|
|
766
|
+
"
|
|
767
|
+
>
|
|
768
|
+
L-Top
|
|
769
|
+
</button>
|
|
770
|
+
<button
|
|
771
|
+
onclick="
|
|
772
|
+
Fnon.Hint.Primary('center-top', { position: 'center-top' })
|
|
773
|
+
"
|
|
774
|
+
>
|
|
775
|
+
C-Top
|
|
776
|
+
</button>
|
|
777
|
+
<button
|
|
778
|
+
onclick="
|
|
779
|
+
Fnon.Hint.Primary('right-bottom', {
|
|
780
|
+
position: 'right-bottom',
|
|
781
|
+
})
|
|
782
|
+
"
|
|
783
|
+
>
|
|
784
|
+
R-Bottom
|
|
785
|
+
</button>
|
|
786
|
+
<button
|
|
787
|
+
onclick="
|
|
788
|
+
Fnon.Hint.Primary('center-center', {
|
|
789
|
+
position: 'center-center',
|
|
790
|
+
})
|
|
791
|
+
"
|
|
792
|
+
>
|
|
793
|
+
Center
|
|
794
|
+
</button>
|
|
795
|
+
</div>
|
|
796
|
+
</div>
|
|
797
|
+
<div class="code">
|
|
798
|
+
<span class="kw">Fnon</span>.Hint.Primary(<span class="str"
|
|
799
|
+
>'msg'</span
|
|
800
|
+
>, { <span class="str">position</span>:
|
|
801
|
+
<span class="str">'left-top'</span> })
|
|
802
|
+
</div>
|
|
803
|
+
</div>
|
|
804
|
+
|
|
805
|
+
<div class="demo-card">
|
|
806
|
+
<div class="card-body">
|
|
807
|
+
<h3>closable + timeOut</h3>
|
|
808
|
+
<p class="desc">
|
|
809
|
+
Disable the X button or control auto-dismiss timeout.
|
|
810
|
+
</p>
|
|
811
|
+
<div class="card-actions">
|
|
812
|
+
<button
|
|
813
|
+
onclick="
|
|
814
|
+
Fnon.Hint.Primary('No close btn, 3s', {
|
|
815
|
+
closable: false,
|
|
816
|
+
timeOut: 3000,
|
|
817
|
+
})
|
|
818
|
+
"
|
|
819
|
+
>
|
|
820
|
+
No Close / 3s
|
|
821
|
+
</button>
|
|
822
|
+
<button
|
|
823
|
+
onclick="Fnon.Hint.Success('10 seconds', { timeOut: 10000 })"
|
|
824
|
+
>
|
|
825
|
+
10 seconds
|
|
826
|
+
</button>
|
|
827
|
+
</div>
|
|
828
|
+
</div>
|
|
829
|
+
<div class="code">
|
|
830
|
+
<span class="kw">Fnon</span>.Hint.Primary(<span class="str"
|
|
831
|
+
>'msg'</span
|
|
832
|
+
>, { <span class="str">closable</span>:
|
|
833
|
+
<span class="pr">false</span>, <span class="str">timeOut</span>:
|
|
834
|
+
<span class="num">3000</span> })
|
|
835
|
+
</div>
|
|
836
|
+
</div>
|
|
837
|
+
|
|
838
|
+
<div class="demo-card">
|
|
839
|
+
<div class="card-body">
|
|
840
|
+
<h3>width + fontSize + spacing</h3>
|
|
841
|
+
<p class="desc">
|
|
842
|
+
Control hint dimensions and gap between stacked hints.
|
|
843
|
+
</p>
|
|
844
|
+
<div class="card-actions">
|
|
845
|
+
<button
|
|
846
|
+
onclick="
|
|
847
|
+
Fnon.Hint.Primary('Wide hint', 'Wide', {
|
|
848
|
+
width: '500px',
|
|
849
|
+
timeOut: 4000,
|
|
850
|
+
})
|
|
851
|
+
"
|
|
852
|
+
>
|
|
853
|
+
Wide (500px)
|
|
854
|
+
</button>
|
|
855
|
+
<button
|
|
856
|
+
onclick="
|
|
857
|
+
Fnon.Hint.Success('Large text', 'Big', {
|
|
858
|
+
fontSize: '1.1rem',
|
|
859
|
+
timeOut: 3000,
|
|
860
|
+
})
|
|
861
|
+
"
|
|
862
|
+
>
|
|
863
|
+
Large Font
|
|
864
|
+
</button>
|
|
865
|
+
<button
|
|
866
|
+
onclick="
|
|
867
|
+
Fnon.Hint.Warning('Extra spacing', 'Space', {
|
|
868
|
+
spacing: '24px',
|
|
869
|
+
timeOut: 3000,
|
|
870
|
+
})
|
|
871
|
+
"
|
|
872
|
+
>
|
|
873
|
+
Spacing (24px)
|
|
874
|
+
</button>
|
|
875
|
+
</div>
|
|
876
|
+
</div>
|
|
877
|
+
<div class="code">
|
|
878
|
+
<span class="kw">Fnon</span>.Hint.Primary(<span class="str"
|
|
879
|
+
>'msg'</span
|
|
880
|
+
>, { <span class="str">width</span>:
|
|
881
|
+
<span class="str">'500px'</span> })
|
|
882
|
+
</div>
|
|
883
|
+
</div>
|
|
884
|
+
|
|
885
|
+
<div class="demo-card">
|
|
886
|
+
<div class="card-body">
|
|
887
|
+
<h3>Progress bar + Hint.Init</h3>
|
|
888
|
+
<p class="desc">
|
|
889
|
+
Progress bar shows remaining time. Use Init() to set global
|
|
890
|
+
defaults.
|
|
891
|
+
</p>
|
|
892
|
+
<div class="card-actions">
|
|
893
|
+
<button
|
|
894
|
+
class="pri"
|
|
895
|
+
onclick="
|
|
896
|
+
Fnon.Hint.Primary('6 second progress', 'Progress', {
|
|
897
|
+
timeOut: 6000,
|
|
898
|
+
})
|
|
899
|
+
"
|
|
900
|
+
>
|
|
901
|
+
6s Progress
|
|
902
|
+
</button>
|
|
903
|
+
<button
|
|
904
|
+
onclick="
|
|
905
|
+
Fnon.Hint.Init({ timeOut: 6000, position: 'left-top' });
|
|
906
|
+
Fnon.Hint.Success('Defaults changed!', '.Init');
|
|
907
|
+
"
|
|
908
|
+
>
|
|
909
|
+
Apply .Init
|
|
910
|
+
</button>
|
|
911
|
+
<button
|
|
912
|
+
onclick="
|
|
913
|
+
Fnon.Hint.Init({ timeOut: 4000, position: 'right-top' });
|
|
914
|
+
Fnon.Hint.Info('Reset');
|
|
915
|
+
"
|
|
916
|
+
>
|
|
917
|
+
Reset
|
|
918
|
+
</button>
|
|
919
|
+
</div>
|
|
920
|
+
</div>
|
|
921
|
+
<div class="code">
|
|
922
|
+
<span class="kw">Fnon</span>.Hint.<span class="fn">Init</span>({
|
|
923
|
+
<span class="str">timeOut</span>: <span class="num">6000</span> })
|
|
924
|
+
</div>
|
|
925
|
+
</div>
|
|
926
|
+
</div>
|
|
927
|
+
|
|
928
|
+
<div class="ref-section">
|
|
929
|
+
<h3>HintOptions — Init() config reference</h3>
|
|
930
|
+
<table class="ref-table">
|
|
931
|
+
<tr>
|
|
932
|
+
<th>Option</th>
|
|
933
|
+
<th>Default</th>
|
|
934
|
+
<th>Type</th>
|
|
935
|
+
<th>Description</th>
|
|
936
|
+
</tr>
|
|
937
|
+
<tr>
|
|
938
|
+
<td>type</td>
|
|
939
|
+
<td>'Primary'</td>
|
|
940
|
+
<td>ThemeName</td>
|
|
941
|
+
<td>Theme key (set automatically by shortcut)</td>
|
|
942
|
+
</tr>
|
|
943
|
+
<tr>
|
|
944
|
+
<td>title</td>
|
|
945
|
+
<td>—</td>
|
|
946
|
+
<td>string | HTMLElement</td>
|
|
947
|
+
<td>Dialog title</td>
|
|
948
|
+
</tr>
|
|
949
|
+
<tr>
|
|
950
|
+
<td>position</td>
|
|
951
|
+
<td>'right-top'</td>
|
|
952
|
+
<td>string</td>
|
|
953
|
+
<td>
|
|
954
|
+
right-top, right-center, right-bottom, left-top, left-center,
|
|
955
|
+
left-bottom, center-top, center-center, center-bottom
|
|
956
|
+
</td>
|
|
957
|
+
</tr>
|
|
958
|
+
<tr>
|
|
959
|
+
<td>timeOut</td>
|
|
960
|
+
<td>4000</td>
|
|
961
|
+
<td>number (ms)</td>
|
|
962
|
+
<td>Auto-dismiss after N ms (0 = no dismiss)</td>
|
|
963
|
+
</tr>
|
|
964
|
+
<tr>
|
|
965
|
+
<td>closable</td>
|
|
966
|
+
<td>true</td>
|
|
967
|
+
<td>boolean</td>
|
|
968
|
+
<td>Show/hide the X button</td>
|
|
969
|
+
</tr>
|
|
970
|
+
<tr>
|
|
971
|
+
<td>width</td>
|
|
972
|
+
<td>'360px'</td>
|
|
973
|
+
<td>string</td>
|
|
974
|
+
<td>Hint container max-width</td>
|
|
975
|
+
</tr>
|
|
976
|
+
<tr>
|
|
977
|
+
<td>fontSize</td>
|
|
978
|
+
<td>'0.88rem'</td>
|
|
979
|
+
<td>string</td>
|
|
980
|
+
<td>Hint text size</td>
|
|
981
|
+
</tr>
|
|
982
|
+
<tr>
|
|
983
|
+
<td>fontFamily</td>
|
|
984
|
+
<td>'Quicksand', sans-serif</td>
|
|
985
|
+
<td>string</td>
|
|
986
|
+
<td>Font family</td>
|
|
987
|
+
</tr>
|
|
988
|
+
<tr>
|
|
989
|
+
<td>spacing</td>
|
|
990
|
+
<td>'8px'</td>
|
|
991
|
+
<td>string</td>
|
|
992
|
+
<td>Gap between stacked hints</td>
|
|
993
|
+
</tr>
|
|
994
|
+
<tr>
|
|
995
|
+
<td>animation</td>
|
|
996
|
+
<td>'slide-left'</td>
|
|
997
|
+
<td>string</td>
|
|
998
|
+
<td>CSS animation class</td>
|
|
999
|
+
</tr>
|
|
1000
|
+
<tr>
|
|
1001
|
+
<td>animationDuration</td>
|
|
1002
|
+
<td>'0.3s'</td>
|
|
1003
|
+
<td>string</td>
|
|
1004
|
+
<td>Enter/exit transition duration</td>
|
|
1005
|
+
</tr>
|
|
1006
|
+
<tr>
|
|
1007
|
+
<td>progressColor</td>
|
|
1008
|
+
<td>—</td>
|
|
1009
|
+
<td>color</td>
|
|
1010
|
+
<td>Progress bar color (defaults to theme borderColor)</td>
|
|
1011
|
+
</tr>
|
|
1012
|
+
<tr>
|
|
1013
|
+
<td>svg</td>
|
|
1014
|
+
<td>—</td>
|
|
1015
|
+
<td>string</td>
|
|
1016
|
+
<td>Custom icon SVG HTML</td>
|
|
1017
|
+
</tr>
|
|
1018
|
+
<tr>
|
|
1019
|
+
<td>svgSize</td>
|
|
1020
|
+
<td>{w:20,h:20}</td>
|
|
1021
|
+
<td>object</td>
|
|
1022
|
+
<td>Icon dimensions in px</td>
|
|
1023
|
+
</tr>
|
|
1024
|
+
<tr>
|
|
1025
|
+
<td>appendTo</td>
|
|
1026
|
+
<td>body</td>
|
|
1027
|
+
<td>selector</td>
|
|
1028
|
+
<td>Mount container element</td>
|
|
1029
|
+
</tr>
|
|
1030
|
+
<tr>
|
|
1031
|
+
<td>onClose</td>
|
|
1032
|
+
<td>—</td>
|
|
1033
|
+
<td>() => void</td>
|
|
1034
|
+
<td>Called when hint is dismissed</td>
|
|
1035
|
+
</tr>
|
|
1036
|
+
<tr>
|
|
1037
|
+
<td>onclosed</td>
|
|
1038
|
+
<td>—</td>
|
|
1039
|
+
<td>() => void</td>
|
|
1040
|
+
<td>Called after hint is fully removed</td>
|
|
1041
|
+
</tr>
|
|
1042
|
+
</table>
|
|
1043
|
+
</div>
|
|
1044
|
+
|
|
1045
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
1046
|
+
<strong>Async:</strong>
|
|
1047
|
+
<code>Fnon.Hint.Theme.Async(message, title?)</code> returns a
|
|
1048
|
+
<code>Promise<void></code> that resolves when the hint closes
|
|
1049
|
+
(auto or manual). Useful for sequencing notifications.
|
|
1050
|
+
</p>
|
|
1051
|
+
|
|
1052
|
+
<div class="sandbox">
|
|
1053
|
+
<h3>Sandbox — Hint</h3>
|
|
1054
|
+
<p>Fill in the fields and click Run to see the hint live.</p>
|
|
1055
|
+
<div class="sandbox-grid">
|
|
1056
|
+
<div class="sandbox-row">
|
|
1057
|
+
<label>Message</label>
|
|
1058
|
+
<input
|
|
1059
|
+
type="text"
|
|
1060
|
+
id="hint-msg"
|
|
1061
|
+
value="Hello from the sandbox!"
|
|
1062
|
+
/>
|
|
1063
|
+
</div>
|
|
1064
|
+
<div class="sandbox-row">
|
|
1065
|
+
<label>Title</label>
|
|
1066
|
+
<input type="text" id="hint-title" value="Sandbox" />
|
|
1067
|
+
</div>
|
|
1068
|
+
<div class="sandbox-row">
|
|
1069
|
+
<label>Theme</label>
|
|
1070
|
+
<select id="hint-theme">
|
|
1071
|
+
<option>Primary</option>
|
|
1072
|
+
<option>Success</option>
|
|
1073
|
+
<option>Warning</option>
|
|
1074
|
+
<option>Danger</option>
|
|
1075
|
+
<option>Info</option>
|
|
1076
|
+
<option>Light</option>
|
|
1077
|
+
<option>Dark</option>
|
|
1078
|
+
</select>
|
|
1079
|
+
</div>
|
|
1080
|
+
<div class="sandbox-row">
|
|
1081
|
+
<label>Position</label>
|
|
1082
|
+
<select id="hint-position">
|
|
1083
|
+
<option>right-top</option>
|
|
1084
|
+
<option>right-center</option>
|
|
1085
|
+
<option>right-bottom</option>
|
|
1086
|
+
<option>left-top</option>
|
|
1087
|
+
<option>left-center</option>
|
|
1088
|
+
<option>left-bottom</option>
|
|
1089
|
+
<option>center-top</option>
|
|
1090
|
+
<option>center-center</option>
|
|
1091
|
+
<option>center-bottom</option>
|
|
1092
|
+
</select>
|
|
1093
|
+
</div>
|
|
1094
|
+
<div class="sandbox-row">
|
|
1095
|
+
<label>timeOut (ms)</label>
|
|
1096
|
+
<input type="number" id="hint-timeout" value="4000" />
|
|
1097
|
+
</div>
|
|
1098
|
+
<div class="sandbox-row">
|
|
1099
|
+
<label>Width</label>
|
|
1100
|
+
<input type="text" id="hint-width" value="360px" />
|
|
1101
|
+
</div>
|
|
1102
|
+
<div class="sandbox-row">
|
|
1103
|
+
<label>Font size</label>
|
|
1104
|
+
<input type="text" id="hint-fontsize" value="0.88rem" />
|
|
1105
|
+
</div>
|
|
1106
|
+
<div class="sandbox-row">
|
|
1107
|
+
<label>Progress color</label>
|
|
1108
|
+
<input type="color" id="hint-progresscolor" value="#029eff" />
|
|
1109
|
+
</div>
|
|
1110
|
+
<div class="sandbox-row">
|
|
1111
|
+
<div class="chk-row">
|
|
1112
|
+
<input type="checkbox" id="hint-closable" checked />
|
|
1113
|
+
<label for="hint-closable">Closable (show X button)</label>
|
|
1114
|
+
</div>
|
|
1115
|
+
</div>
|
|
1116
|
+
</div>
|
|
1117
|
+
<div class="sandbox-actions">
|
|
1118
|
+
<button class="pri" onclick="runHintSandbox()">Run Hint</button>
|
|
1119
|
+
<button
|
|
1120
|
+
onclick="
|
|
1121
|
+
(async () => {
|
|
1122
|
+
await Fnon.Hint.Primary.Async('Async resolved!', 'Async');
|
|
1123
|
+
Fnon.Hint.Success('Promise resolved!');
|
|
1124
|
+
})()
|
|
1125
|
+
"
|
|
1126
|
+
>
|
|
1127
|
+
Try .Async
|
|
1128
|
+
</button>
|
|
1129
|
+
</div>
|
|
1130
|
+
</div>
|
|
1131
|
+
</section>
|
|
1132
|
+
|
|
1133
|
+
<!-- ══════════════════════════ WAIT ══════════════════════════ -->
|
|
1134
|
+
<section id="wait">
|
|
1135
|
+
<h2>2. Wait <span class="badge">Fnon.Wait.Type(text?, opts?)</span></h2>
|
|
1136
|
+
<p class="section-desc">
|
|
1137
|
+
Full-page spinner overlay. 5 spinner types (Orbit, Spin / Infinity, Ripple, Typing).
|
|
1138
|
+
Supports clickToClose, text label, custom color, and Remove/Change
|
|
1139
|
+
controls.
|
|
1140
|
+
</p>
|
|
1141
|
+
|
|
1142
|
+
<div class="demo-grid">
|
|
1143
|
+
<div class="demo-card">
|
|
1144
|
+
<div class="card-body">
|
|
1145
|
+
<h3>CSS spinners — Orbit, Spin</h3>
|
|
1146
|
+
<p class="desc">
|
|
1147
|
+
Lightweight CSS-only spinners with
|
|
1148
|
+
<code>clickToClose: true</code> for dismiss.
|
|
1149
|
+
</p>
|
|
1150
|
+
<div class="card-actions">
|
|
1151
|
+
<button
|
|
1152
|
+
onclick="Fnon.Wait.Orbit('Orbit', { clickToClose: true })"
|
|
1153
|
+
>
|
|
1154
|
+
Orbit
|
|
1155
|
+
</button>
|
|
1156
|
+
<button
|
|
1157
|
+
onclick="Fnon.Wait.Spin('Spin', { clickToClose: true })"
|
|
1158
|
+
>
|
|
1159
|
+
Spin
|
|
1160
|
+
</button>
|
|
1161
|
+
</div>
|
|
1162
|
+
</div>
|
|
1163
|
+
<div class="code">
|
|
1164
|
+
<span class="kw">Fnon</span>.Wait.Orbit(<span class="str"
|
|
1165
|
+
>'Loading'</span
|
|
1166
|
+
>, { <span class="str">clickToClose</span>:
|
|
1167
|
+
<span class="pr">true</span> })
|
|
1168
|
+
</div>
|
|
1169
|
+
</div>
|
|
1170
|
+
|
|
1171
|
+
<div class="demo-card">
|
|
1172
|
+
<div class="card-body">
|
|
1173
|
+
<h3>SVG spanners (Infinity, Ripple, Typing)</h3>
|
|
1174
|
+
<p class="desc">
|
|
1175
|
+
Lightweight SVG spinners: Infinity, Ripple, Typing.
|
|
1176
|
+
</p>
|
|
1177
|
+
<div class="card-actions" style="gap: 0.25rem">
|
|
1178
|
+
<button
|
|
1179
|
+
class="small"
|
|
1180
|
+
onclick="
|
|
1181
|
+
Fnon.Wait.Infinity('Infinity', { clickToClose: true })
|
|
1182
|
+
"
|
|
1183
|
+
>
|
|
1184
|
+
∞
|
|
1185
|
+
</button>
|
|
1186
|
+
<button
|
|
1187
|
+
class="small"
|
|
1188
|
+
onclick="Fnon.Wait.Ripple('Ripple', { clickToClose: true })"
|
|
1189
|
+
>
|
|
1190
|
+
Ripple
|
|
1191
|
+
</button>
|
|
1192
|
+
<button
|
|
1193
|
+
class="small"
|
|
1194
|
+
onclick="Fnon.Wait.Typing('Typing', { clickToClose: true })"
|
|
1195
|
+
>
|
|
1196
|
+
Typing
|
|
1197
|
+
</button>
|
|
1198
|
+
</div>
|
|
1199
|
+
</div>
|
|
1200
|
+
<div class="code">
|
|
1201
|
+
<span class="kw">Fnon</span>.Wait.Infinity(<span class="str"
|
|
1202
|
+
>'Loading'</span
|
|
1203
|
+
>, { <span class="str">clickToClose</span>:
|
|
1204
|
+
<span class="pr">true</span> })
|
|
1205
|
+
</div>
|
|
1206
|
+
</div>
|
|
1207
|
+
|
|
1208
|
+
<div class="demo-card">
|
|
1209
|
+
<div class="card-body">
|
|
1210
|
+
<h3>Custom color + containerSize</h3>
|
|
1211
|
+
<p class="desc">
|
|
1212
|
+
Override <code>svgColor</code> and <code>containerSize</code> to
|
|
1213
|
+
match your brand.
|
|
1214
|
+
</p>
|
|
1215
|
+
<div class="card-actions">
|
|
1216
|
+
<button
|
|
1217
|
+
onclick="
|
|
1218
|
+
Fnon.Wait.Orbit('Red', {
|
|
1219
|
+
svgColor: '#ff6b6b',
|
|
1220
|
+
clickToClose: true,
|
|
1221
|
+
})
|
|
1222
|
+
"
|
|
1223
|
+
>
|
|
1224
|
+
Red Orbit
|
|
1225
|
+
</button>
|
|
1226
|
+
<button
|
|
1227
|
+
onclick="
|
|
1228
|
+
Fnon.Wait.Orbit('Wide', {
|
|
1229
|
+
containerSize: '400px',
|
|
1230
|
+
clickToClose: true,
|
|
1231
|
+
})
|
|
1232
|
+
"
|
|
1233
|
+
>
|
|
1234
|
+
Wide Orbit
|
|
1235
|
+
</button>
|
|
1236
|
+
</div>
|
|
1237
|
+
</div>
|
|
1238
|
+
<div class="code">
|
|
1239
|
+
<span class="kw">Fnon</span>.Wait.Orbit(<span class="str"
|
|
1240
|
+
>'Loading'</span
|
|
1241
|
+
>, { <span class="str">svgColor</span>:
|
|
1242
|
+
<span class="str">'#ff6b6b'</span> })
|
|
1243
|
+
</div>
|
|
1244
|
+
</div>
|
|
1245
|
+
|
|
1246
|
+
<div class="demo-card">
|
|
1247
|
+
<div class="card-body">
|
|
1248
|
+
<h3>Wait controls + Wait.Init</h3>
|
|
1249
|
+
<p class="desc">
|
|
1250
|
+
Remove(), Change(text), and Init() for global defaults.
|
|
1251
|
+
</p>
|
|
1252
|
+
<div class="card-actions">
|
|
1253
|
+
<button
|
|
1254
|
+
class="pri"
|
|
1255
|
+
onclick="
|
|
1256
|
+
Fnon.Wait.Orbit('Working...');
|
|
1257
|
+
setTimeout(() => Fnon.Wait.Change('Almost done...'), 1500);
|
|
1258
|
+
setTimeout(() => Fnon.Wait.Remove(), 3000);
|
|
1259
|
+
"
|
|
1260
|
+
>
|
|
1261
|
+
3s demo
|
|
1262
|
+
</button>
|
|
1263
|
+
<button
|
|
1264
|
+
onclick="
|
|
1265
|
+
Fnon.Wait.Init({ svgColor: '#39DA8A' });
|
|
1266
|
+
Fnon.Wait.Spin('Green', { clickToClose: true });
|
|
1267
|
+
"
|
|
1268
|
+
>
|
|
1269
|
+
Green Init
|
|
1270
|
+
</button>
|
|
1271
|
+
<button
|
|
1272
|
+
onclick="
|
|
1273
|
+
Fnon.Wait.Init({ svgColor: '#029eff' });
|
|
1274
|
+
Fnon.Hint.Info('Reset');
|
|
1275
|
+
"
|
|
1276
|
+
>
|
|
1277
|
+
Reset
|
|
1278
|
+
</button>
|
|
1279
|
+
</div>
|
|
1280
|
+
</div>
|
|
1281
|
+
<div class="code">
|
|
1282
|
+
<span class="kw">Fnon</span>.Wait.Pulse(<span class="str"
|
|
1283
|
+
>'Working'</span
|
|
1284
|
+
>)<br /><span class="kw">Fnon</span>.Wait.<span class="fn"
|
|
1285
|
+
>Change</span
|
|
1286
|
+
>(<span class="str">'New text'</span>)<br /><span class="kw"
|
|
1287
|
+
>Fnon</span
|
|
1288
|
+
>.Wait.<span class="fn">Remove</span>()
|
|
1289
|
+
</div>
|
|
1290
|
+
</div>
|
|
1291
|
+
|
|
1292
|
+
<div class="demo-card">
|
|
1293
|
+
<div class="card-body">
|
|
1294
|
+
<h3>Wait.Async</h3>
|
|
1295
|
+
<p class="desc">
|
|
1296
|
+
Returns a Promise that resolves when Remove() is called or the
|
|
1297
|
+
spinner is dismissed.
|
|
1298
|
+
</p>
|
|
1299
|
+
<div class="card-actions">
|
|
1300
|
+
<button
|
|
1301
|
+
class="pri"
|
|
1302
|
+
onclick="
|
|
1303
|
+
(async () => {
|
|
1304
|
+
Fnon.Wait.Orbit.Async('Working...').then(() =>
|
|
1305
|
+
Fnon.Hint.Success('Done!'),
|
|
1306
|
+
);
|
|
1307
|
+
setTimeout(() => Fnon.Wait.Remove(), 2000);
|
|
1308
|
+
})()
|
|
1309
|
+
"
|
|
1310
|
+
>
|
|
1311
|
+
Wait.Async (2s)
|
|
1312
|
+
</button>
|
|
1313
|
+
</div>
|
|
1314
|
+
</div>
|
|
1315
|
+
<div class="code">
|
|
1316
|
+
<span class="kw">Fnon</span>.Wait.Orbit.<span class="fn"
|
|
1317
|
+
>Async</span
|
|
1318
|
+
>(<span class="str">'Working'</span>)<br /> .then(() =>
|
|
1319
|
+
<span class="kw">Fnon</span>.Hint.Success(<span class="str"
|
|
1320
|
+
>'Done!'</span
|
|
1321
|
+
>))
|
|
1322
|
+
</div>
|
|
1323
|
+
</div>
|
|
1324
|
+
</div>
|
|
1325
|
+
|
|
1326
|
+
<div class="ref-section">
|
|
1327
|
+
<h3>SpinnerOptions — Wait</h3>
|
|
1328
|
+
<table class="ref-table">
|
|
1329
|
+
<tr>
|
|
1330
|
+
<th>Option</th>
|
|
1331
|
+
<th>Default</th>
|
|
1332
|
+
<th>Type</th>
|
|
1333
|
+
<th>Description</th>
|
|
1334
|
+
</tr>
|
|
1335
|
+
<tr>
|
|
1336
|
+
<td>text</td>
|
|
1337
|
+
<td>''</td>
|
|
1338
|
+
<td>string</td>
|
|
1339
|
+
<td>Label text below the spinner</td>
|
|
1340
|
+
</tr>
|
|
1341
|
+
<tr>
|
|
1342
|
+
<td>clickToClose</td>
|
|
1343
|
+
<td>false</td>
|
|
1344
|
+
<td>boolean</td>
|
|
1345
|
+
<td>Click the overlay to dismiss</td>
|
|
1346
|
+
</tr>
|
|
1347
|
+
<tr>
|
|
1348
|
+
<td>svgColor</td>
|
|
1349
|
+
<td>'#029eff'</td>
|
|
1350
|
+
<td>color</td>
|
|
1351
|
+
<td>Spinner / accent color</td>
|
|
1352
|
+
</tr>
|
|
1353
|
+
<tr>
|
|
1354
|
+
<td>fontFamily</td>
|
|
1355
|
+
<td>'Quicksand', sans-serif</td>
|
|
1356
|
+
<td>string</td>
|
|
1357
|
+
<td>Font family for text</td>
|
|
1358
|
+
</tr>
|
|
1359
|
+
<tr>
|
|
1360
|
+
<td>containerSize</td>
|
|
1361
|
+
<td>—</td>
|
|
1362
|
+
<td>string</td>
|
|
1363
|
+
<td>Spinner box width (e.g. '400px')</td>
|
|
1364
|
+
</tr>
|
|
1365
|
+
<tr>
|
|
1366
|
+
<td>appendTarget</td>
|
|
1367
|
+
<td>body</td>
|
|
1368
|
+
<td>selector</td>
|
|
1369
|
+
<td>Mount container</td>
|
|
1370
|
+
</tr>
|
|
1371
|
+
<tr>
|
|
1372
|
+
<td colspan="4" style="color: #63b3ed; text-align: center">
|
|
1373
|
+
Spinner types: Orbit, Spin (CSS) • Infinity,
|
|
1374
|
+
Ripple, Typing (SVG)
|
|
1375
|
+
</td>
|
|
1376
|
+
</tr>
|
|
1377
|
+
</table>
|
|
1378
|
+
</div>
|
|
1379
|
+
|
|
1380
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
1381
|
+
<strong>Async:</strong>
|
|
1382
|
+
<code>Fnon.Wait.Type.Async(text?, opts?)</code> returns
|
|
1383
|
+
<code>Promise<boolean></code> (resolves <code>true</code> when
|
|
1384
|
+
<code>Remove()</code> is called or the spinner is dismissed).
|
|
1385
|
+
</p>
|
|
1386
|
+
|
|
1387
|
+
<div class="sandbox">
|
|
1388
|
+
<h3>Sandbox — Wait</h3>
|
|
1389
|
+
<p>Select a spinner type, configure options, and launch.</p>
|
|
1390
|
+
<div class="sandbox-grid">
|
|
1391
|
+
<div class="sandbox-row">
|
|
1392
|
+
<label>Text</label>
|
|
1393
|
+
<input type="text" id="wait-text" value="Loading..." />
|
|
1394
|
+
</div>
|
|
1395
|
+
<div class="sandbox-row">
|
|
1396
|
+
<label>Spinner type</label>
|
|
1397
|
+
<select id="wait-type">
|
|
1398
|
+
<option>Orbit</option>
|
|
1399
|
+
<option>Spin</option>
|
|
1400
|
+
<option>Infinity</option>
|
|
1401
|
+
<option>Ripple</option>
|
|
1402
|
+
<option>Typing</option>
|
|
1403
|
+
</select>
|
|
1404
|
+
</div>
|
|
1405
|
+
<div class="sandbox-row">
|
|
1406
|
+
<label>svgColor</label>
|
|
1407
|
+
<input type="color" id="wait-svgcolor" value="#029eff" />
|
|
1408
|
+
</div>
|
|
1409
|
+
<div class="sandbox-row">
|
|
1410
|
+
<label>Container size</label>
|
|
1411
|
+
<input
|
|
1412
|
+
type="text"
|
|
1413
|
+
id="wait-containersize"
|
|
1414
|
+
placeholder="e.g. 400px"
|
|
1415
|
+
/>
|
|
1416
|
+
</div>
|
|
1417
|
+
<div class="sandbox-row">
|
|
1418
|
+
<label>Font family</label>
|
|
1419
|
+
<input
|
|
1420
|
+
type="text"
|
|
1421
|
+
id="wait-fontfamily"
|
|
1422
|
+
value="'Quicksand', sans-serif"
|
|
1423
|
+
/>
|
|
1424
|
+
</div>
|
|
1425
|
+
<div class="sandbox-row">
|
|
1426
|
+
<div class="chk-row">
|
|
1427
|
+
<input type="checkbox" id="wait-clicktoclose" />
|
|
1428
|
+
<label for="wait-clicktoclose">Click to close</label>
|
|
1429
|
+
</div>
|
|
1430
|
+
</div>
|
|
1431
|
+
</div>
|
|
1432
|
+
<div class="sandbox-actions">
|
|
1433
|
+
<button class="pri" onclick="runWaitSandbox()">Run Wait</button>
|
|
1434
|
+
<button class="dan" onclick="Fnon.Wait.Remove()">
|
|
1435
|
+
Remove Wait
|
|
1436
|
+
</button>
|
|
1437
|
+
</div>
|
|
1438
|
+
</div>
|
|
1439
|
+
</section>
|
|
1440
|
+
|
|
1441
|
+
<!-- ══════════════════════════ BOX ══════════════════════════ -->
|
|
1442
|
+
<section id="box">
|
|
1443
|
+
<h2>
|
|
1444
|
+
3. Box
|
|
1445
|
+
<span class="badge">Fnon.Box.Type(selector, text?, opts?)</span>
|
|
1446
|
+
</h2>
|
|
1447
|
+
<p class="section-desc">
|
|
1448
|
+
Container-bound spinner overlay. Same 5 spinner types as Wait, but
|
|
1449
|
+
rendered inside a specific DOM element instead of full-screen.
|
|
1450
|
+
</p>
|
|
1451
|
+
|
|
1452
|
+
<div class="demo-grid">
|
|
1453
|
+
<div class="demo-card">
|
|
1454
|
+
<div class="card-body">
|
|
1455
|
+
<h3>Spinner in container</h3>
|
|
1456
|
+
<p class="desc">
|
|
1457
|
+
First arg is a CSS selector. Spinner appears inside that
|
|
1458
|
+
element.
|
|
1459
|
+
</p>
|
|
1460
|
+
<div class="card-actions">
|
|
1461
|
+
<button onclick="Fnon.Box.Orbit('#box-target', 'Loading')">
|
|
1462
|
+
Orbit
|
|
1463
|
+
</button>
|
|
1464
|
+
<button onclick="Fnon.Box.Spin('#box-target', 'Working')">
|
|
1465
|
+
Spin
|
|
1466
|
+
</button>
|
|
1467
|
+
<button onclick="Fnon.Box.Infinity('#box-target', '∞')">
|
|
1468
|
+
Infinity
|
|
1469
|
+
</button>
|
|
1470
|
+
<button class="dan" onclick="Fnon.Box.Remove('#box-target')">
|
|
1471
|
+
Remove
|
|
1472
|
+
</button>
|
|
1473
|
+
</div>
|
|
1474
|
+
</div>
|
|
1475
|
+
<div class="code">
|
|
1476
|
+
<span class="kw">Fnon</span>.Box.Orbit(<span class="str"
|
|
1477
|
+
>'#box-target'</span
|
|
1478
|
+
>, <span class="str">'Loading'</span>)
|
|
1479
|
+
</div>
|
|
1480
|
+
</div>
|
|
1481
|
+
|
|
1482
|
+
<div class="demo-card">
|
|
1483
|
+
<div class="card-body">
|
|
1484
|
+
<h3>Custom color + svgSize</h3>
|
|
1485
|
+
<p class="desc">
|
|
1486
|
+
Override <code>svgColor</code> and <code>svgSize</code> for the
|
|
1487
|
+
box spinner.
|
|
1488
|
+
</p>
|
|
1489
|
+
<div class="card-actions">
|
|
1490
|
+
<button
|
|
1491
|
+
onclick="
|
|
1492
|
+
Fnon.Box.Spin('#box-target', 'Red', {
|
|
1493
|
+
svgColor: '#ff6b6b',
|
|
1494
|
+
});
|
|
1495
|
+
setTimeout(() => Fnon.Box.Remove('#box-target'), 2000);
|
|
1496
|
+
"
|
|
1497
|
+
>
|
|
1498
|
+
Red Spin
|
|
1499
|
+
</button>
|
|
1500
|
+
<button
|
|
1501
|
+
onclick="
|
|
1502
|
+
Fnon.Box.Orbit('#box-target', 'Big', {
|
|
1503
|
+
svgSize: { w: 80, h: 80 },
|
|
1504
|
+
});
|
|
1505
|
+
setTimeout(() => Fnon.Box.Remove('#box-target'), 2000);
|
|
1506
|
+
"
|
|
1507
|
+
>
|
|
1508
|
+
Big Orbit
|
|
1509
|
+
</button>
|
|
1510
|
+
</div>
|
|
1511
|
+
</div>
|
|
1512
|
+
<div class="code">
|
|
1513
|
+
<span class="kw">Fnon</span>.Box.Orbit(<span class="str"
|
|
1514
|
+
>'#box-target'</span
|
|
1515
|
+
>, <span class="str">'Loading'</span>, {
|
|
1516
|
+
<span class="str">svgSize</span>: { <span class="str">w</span>:
|
|
1517
|
+
<span class="num">80</span>, <span class="str">h</span>:
|
|
1518
|
+
<span class="num">80</span> } })
|
|
1519
|
+
</div>
|
|
1520
|
+
</div>
|
|
1521
|
+
|
|
1522
|
+
<div class="demo-card">
|
|
1523
|
+
<div class="card-body">
|
|
1524
|
+
<h3>Box.Init + Box.Async</h3>
|
|
1525
|
+
<p class="desc">
|
|
1526
|
+
<code>Box.Init</code> sets global defaults.
|
|
1527
|
+
<code>Box.Async</code> returns a Promise.
|
|
1528
|
+
</p>
|
|
1529
|
+
<div class="card-actions">
|
|
1530
|
+
<button
|
|
1531
|
+
onclick="
|
|
1532
|
+
Fnon.Box.Init({ svgColor: '#39DA8A' });
|
|
1533
|
+
Fnon.Box.Spin('#box-target', 'Green');
|
|
1534
|
+
setTimeout(() => Fnon.Box.Remove('#box-target'), 2000);
|
|
1535
|
+
"
|
|
1536
|
+
>
|
|
1537
|
+
Green Init
|
|
1538
|
+
</button>
|
|
1539
|
+
<button
|
|
1540
|
+
onclick="
|
|
1541
|
+
Fnon.Box.Init({ svgColor: '#029eff' });
|
|
1542
|
+
Fnon.Hint.Info('Reset');
|
|
1543
|
+
"
|
|
1544
|
+
>
|
|
1545
|
+
Reset
|
|
1546
|
+
</button>
|
|
1547
|
+
<button
|
|
1548
|
+
class="pri"
|
|
1549
|
+
onclick="
|
|
1550
|
+
(async () => {
|
|
1551
|
+
Fnon.Box.Pulse.Async('#box-target', 'Working...').then(
|
|
1552
|
+
() => Fnon.Hint.Success('Box done!'),
|
|
1553
|
+
);
|
|
1554
|
+
setTimeout(() => Fnon.Box.Remove('#box-target'), 1500);
|
|
1555
|
+
})()
|
|
1556
|
+
"
|
|
1557
|
+
>
|
|
1558
|
+
Box.Async (1.5s)
|
|
1559
|
+
</button>
|
|
1560
|
+
</div>
|
|
1561
|
+
</div>
|
|
1562
|
+
<div class="code">
|
|
1563
|
+
<span class="kw">Fnon</span>.Box.<span class="fn">Init</span>({
|
|
1564
|
+
<span class="str">svgColor</span>:
|
|
1565
|
+
<span class="str">'#39DA8A'</span> })
|
|
1566
|
+
</div>
|
|
1567
|
+
</div>
|
|
1568
|
+
</div>
|
|
1569
|
+
|
|
1570
|
+
<div id="box-target">#box-target — spinners appear here</div>
|
|
1571
|
+
|
|
1572
|
+
<div class="ref-section">
|
|
1573
|
+
<h3>BoxOptions — Box</h3>
|
|
1574
|
+
<table class="ref-table">
|
|
1575
|
+
<tr>
|
|
1576
|
+
<th>Option</th>
|
|
1577
|
+
<th>Default</th>
|
|
1578
|
+
<th>Type</th>
|
|
1579
|
+
<th>Description</th>
|
|
1580
|
+
</tr>
|
|
1581
|
+
<tr>
|
|
1582
|
+
<td>selector</td>
|
|
1583
|
+
<td>—</td>
|
|
1584
|
+
<td>string</td>
|
|
1585
|
+
<td>CSS selector for the target element</td>
|
|
1586
|
+
</tr>
|
|
1587
|
+
<tr>
|
|
1588
|
+
<td>text</td>
|
|
1589
|
+
<td>''</td>
|
|
1590
|
+
<td>string</td>
|
|
1591
|
+
<td>Label below the spinner</td>
|
|
1592
|
+
</tr>
|
|
1593
|
+
<tr>
|
|
1594
|
+
<td>svgColor</td>
|
|
1595
|
+
<td>'#029eff'</td>
|
|
1596
|
+
<td>color</td>
|
|
1597
|
+
<td>Spinner accent color</td>
|
|
1598
|
+
</tr>
|
|
1599
|
+
<tr>
|
|
1600
|
+
<td>svgSize</td>
|
|
1601
|
+
<td>—</td>
|
|
1602
|
+
<td>{w,h}</td>
|
|
1603
|
+
<td>Spinner SVG dimensions in px</td>
|
|
1604
|
+
</tr>
|
|
1605
|
+
<tr>
|
|
1606
|
+
<td>fontFamily</td>
|
|
1607
|
+
<td>'Quicksand', sans-serif</td>
|
|
1608
|
+
<td>string</td>
|
|
1609
|
+
<td>Font family for text</td>
|
|
1610
|
+
</tr>
|
|
1611
|
+
<tr>
|
|
1612
|
+
<td>containerSize</td>
|
|
1613
|
+
<td>—</td>
|
|
1614
|
+
<td>string</td>
|
|
1615
|
+
<td>Spinner box width</td>
|
|
1616
|
+
</tr>
|
|
1617
|
+
<tr>
|
|
1618
|
+
<td colspan="4" style="color: #63b3ed; text-align: center">
|
|
1619
|
+
Same 5 spinner types as Wait: Orbit, Spin, Infinity,
|
|
1620
|
+
Ripple, Typing
|
|
1621
|
+
</td>
|
|
1622
|
+
</tr>
|
|
1623
|
+
</table>
|
|
1624
|
+
</div>
|
|
1625
|
+
|
|
1626
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
1627
|
+
<strong>Async:</strong>
|
|
1628
|
+
<code>Fnon.Box.Type.Async(selector, text?, opts?)</code> returns
|
|
1629
|
+
<code>Promise<boolean></code> (resolves <code>true</code> when
|
|
1630
|
+
<code>Box.Remove(selector)</code> is called).
|
|
1631
|
+
</p>
|
|
1632
|
+
|
|
1633
|
+
<div class="sandbox">
|
|
1634
|
+
<h3>Sandbox — Box</h3>
|
|
1635
|
+
<p>Enter a CSS selector and configure the spinner.</p>
|
|
1636
|
+
<div class="sandbox-grid">
|
|
1637
|
+
<div class="sandbox-row">
|
|
1638
|
+
<label>CSS selector</label>
|
|
1639
|
+
<input type="text" id="box-selector" value="#box-target" />
|
|
1640
|
+
</div>
|
|
1641
|
+
<div class="sandbox-row">
|
|
1642
|
+
<label>Text</label>
|
|
1643
|
+
<input type="text" id="box-text" value="Working..." />
|
|
1644
|
+
</div>
|
|
1645
|
+
<div class="sandbox-row">
|
|
1646
|
+
<label>Spinner type</label>
|
|
1647
|
+
<select id="box-type">
|
|
1648
|
+
<option>Orbit</option>
|
|
1649
|
+
<option>Spin</option>
|
|
1650
|
+
<option>Infinity</option>
|
|
1651
|
+
<option>Ripple</option>
|
|
1652
|
+
<option>Typing</option>
|
|
1653
|
+
</select>
|
|
1654
|
+
</div>
|
|
1655
|
+
<div class="sandbox-row">
|
|
1656
|
+
<label>svgColor</label>
|
|
1657
|
+
<input type="color" id="box-svgcolor" value="#029eff" />
|
|
1658
|
+
</div>
|
|
1659
|
+
<div class="sandbox-row">
|
|
1660
|
+
<label>svgSize w</label>
|
|
1661
|
+
<input
|
|
1662
|
+
type="number"
|
|
1663
|
+
id="box-svgw"
|
|
1664
|
+
value="40"
|
|
1665
|
+
placeholder="width"
|
|
1666
|
+
/>
|
|
1667
|
+
</div>
|
|
1668
|
+
<div class="sandbox-row">
|
|
1669
|
+
<label>svgSize h</label>
|
|
1670
|
+
<input
|
|
1671
|
+
type="number"
|
|
1672
|
+
id="box-svgh"
|
|
1673
|
+
value="40"
|
|
1674
|
+
placeholder="height"
|
|
1675
|
+
/>
|
|
1676
|
+
</div>
|
|
1677
|
+
</div>
|
|
1678
|
+
<div class="sandbox-actions">
|
|
1679
|
+
<button class="pri" onclick="runBoxSandbox()">Run Box</button>
|
|
1680
|
+
<button
|
|
1681
|
+
class="dan"
|
|
1682
|
+
onclick="
|
|
1683
|
+
Fnon.Box.Remove(
|
|
1684
|
+
document.getElementById('box-selector').value ||
|
|
1685
|
+
'#box-target',
|
|
1686
|
+
)
|
|
1687
|
+
"
|
|
1688
|
+
>
|
|
1689
|
+
Remove Box
|
|
1690
|
+
</button>
|
|
1691
|
+
</div>
|
|
1692
|
+
</div>
|
|
1693
|
+
</section>
|
|
1694
|
+
|
|
1695
|
+
<!-- ══════════════════════════ ALERT ══════════════════════════ -->
|
|
1696
|
+
<section id="alert">
|
|
1697
|
+
<h2>
|
|
1698
|
+
4. Alert
|
|
1699
|
+
<span class="badge"
|
|
1700
|
+
>Fnon.Alert.Theme(msg, title?, btnOkText?, callback?)</span
|
|
1701
|
+
>
|
|
1702
|
+
</h2>
|
|
1703
|
+
<p class="section-desc">
|
|
1704
|
+
A one-button modal for simple messages. Supports both positional args
|
|
1705
|
+
and a single options object.
|
|
1706
|
+
</p>
|
|
1707
|
+
|
|
1708
|
+
<div class="demo-grid">
|
|
1709
|
+
<div class="demo-card">
|
|
1710
|
+
<div class="card-body">
|
|
1711
|
+
<h3>String message</h3>
|
|
1712
|
+
<p class="desc">
|
|
1713
|
+
Three positional args: message, title, button text.
|
|
1714
|
+
</p>
|
|
1715
|
+
<div class="card-actions">
|
|
1716
|
+
<button
|
|
1717
|
+
class="pri"
|
|
1718
|
+
onclick="
|
|
1719
|
+
Fnon.Alert.Primary('Hello from Fnon!', 'Greeting', 'OK')
|
|
1720
|
+
"
|
|
1721
|
+
>
|
|
1722
|
+
Primary
|
|
1723
|
+
</button>
|
|
1724
|
+
<button
|
|
1725
|
+
class="suc"
|
|
1726
|
+
onclick="Fnon.Alert.Success('Saved!', 'Success', 'OK')"
|
|
1727
|
+
>
|
|
1728
|
+
Success
|
|
1729
|
+
</button>
|
|
1730
|
+
<button
|
|
1731
|
+
class="dan"
|
|
1732
|
+
onclick="Fnon.Alert.Danger('Error!', 'Error', 'OK')"
|
|
1733
|
+
>
|
|
1734
|
+
Danger
|
|
1735
|
+
</button>
|
|
1736
|
+
</div>
|
|
1737
|
+
</div>
|
|
1738
|
+
<div class="code">
|
|
1739
|
+
<span class="kw">Fnon</span>.Alert.Primary(<span class="str"
|
|
1740
|
+
>'Hello!'</span
|
|
1741
|
+
>, <span class="str">'Title'</span>,
|
|
1742
|
+
<span class="str">'OK'</span>)
|
|
1743
|
+
</div>
|
|
1744
|
+
</div>
|
|
1745
|
+
|
|
1746
|
+
<div class="demo-card">
|
|
1747
|
+
<div class="card-body">
|
|
1748
|
+
<h3>Object args</h3>
|
|
1749
|
+
<p class="desc">
|
|
1750
|
+
Access every option by passing a single object.
|
|
1751
|
+
</p>
|
|
1752
|
+
<div class="card-actions">
|
|
1753
|
+
<button
|
|
1754
|
+
class="pri"
|
|
1755
|
+
onclick="
|
|
1756
|
+
Fnon.Alert.Primary({
|
|
1757
|
+
message: 'Object mode!',
|
|
1758
|
+
title: 'Object Args',
|
|
1759
|
+
btnOkText: 'Got it',
|
|
1760
|
+
width: 'sm',
|
|
1761
|
+
})
|
|
1762
|
+
"
|
|
1763
|
+
>
|
|
1764
|
+
sm object
|
|
1765
|
+
</button>
|
|
1766
|
+
<button
|
|
1767
|
+
class="suc"
|
|
1768
|
+
onclick="
|
|
1769
|
+
Fnon.Alert.Success({
|
|
1770
|
+
message: 'Wide modal',
|
|
1771
|
+
title: 'Wide',
|
|
1772
|
+
width: 'xl',
|
|
1773
|
+
closeButton: false,
|
|
1774
|
+
})
|
|
1775
|
+
"
|
|
1776
|
+
>
|
|
1777
|
+
xl, no close
|
|
1778
|
+
</button>
|
|
1779
|
+
</div>
|
|
1780
|
+
</div>
|
|
1781
|
+
<div class="code">
|
|
1782
|
+
<span class="kw">Fnon</span>.Alert.Primary({
|
|
1783
|
+
<span class="str">message</span>:
|
|
1784
|
+
<span class="str">'Object mode!'</span>,
|
|
1785
|
+
<span class="str">width</span>: <span class="str">'sm'</span> })
|
|
1786
|
+
</div>
|
|
1787
|
+
</div>
|
|
1788
|
+
|
|
1789
|
+
<div class="demo-card">
|
|
1790
|
+
<div class="card-body">
|
|
1791
|
+
<h3>delButtons + autoFocus</h3>
|
|
1792
|
+
<p class="desc">
|
|
1793
|
+
<code>delButtons: true</code> removes footer.
|
|
1794
|
+
<code>autoFocus: true</code> highlights the button.
|
|
1795
|
+
</p>
|
|
1796
|
+
<div class="card-actions">
|
|
1797
|
+
<button
|
|
1798
|
+
onclick="
|
|
1799
|
+
Fnon.Alert.Primary({
|
|
1800
|
+
message: 'No footer buttons',
|
|
1801
|
+
title: 'No Buttons',
|
|
1802
|
+
delButtons: true,
|
|
1803
|
+
})
|
|
1804
|
+
"
|
|
1805
|
+
>
|
|
1806
|
+
delButtons
|
|
1807
|
+
</button>
|
|
1808
|
+
<button
|
|
1809
|
+
class="pri"
|
|
1810
|
+
onclick="
|
|
1811
|
+
Fnon.Alert.Primary({
|
|
1812
|
+
message: 'Button auto-focused',
|
|
1813
|
+
autoFocus: true,
|
|
1814
|
+
})
|
|
1815
|
+
"
|
|
1816
|
+
>
|
|
1817
|
+
autoFocus
|
|
1818
|
+
</button>
|
|
1819
|
+
</div>
|
|
1820
|
+
</div>
|
|
1821
|
+
<div class="code">
|
|
1822
|
+
<span class="kw">Fnon</span>.Alert.Primary({
|
|
1823
|
+
<span class="str">delButtons</span>:
|
|
1824
|
+
<span class="pr">true</span> })
|
|
1825
|
+
</div>
|
|
1826
|
+
</div>
|
|
1827
|
+
|
|
1828
|
+
<div class="demo-card">
|
|
1829
|
+
<div class="card-body">
|
|
1830
|
+
<h3>Button styling overrides</h3>
|
|
1831
|
+
<p class="desc">
|
|
1832
|
+
Custom colors, background, shadow, border for the OK button.
|
|
1833
|
+
</p>
|
|
1834
|
+
<div class="card-actions">
|
|
1835
|
+
<button
|
|
1836
|
+
onclick="
|
|
1837
|
+
Fnon.Alert.Primary({
|
|
1838
|
+
message: 'Styled!',
|
|
1839
|
+
btnOkColor: '#fff',
|
|
1840
|
+
btnOkBackground: '#6c5ce7',
|
|
1841
|
+
btnOkShadow: '0 4px 12px rgba(108,92,231,.4)',
|
|
1842
|
+
})
|
|
1843
|
+
"
|
|
1844
|
+
>
|
|
1845
|
+
Styled
|
|
1846
|
+
</button>
|
|
1847
|
+
</div>
|
|
1848
|
+
</div>
|
|
1849
|
+
<div class="code">
|
|
1850
|
+
<span class="kw">Fnon</span>.Alert.Primary({
|
|
1851
|
+
<span class="str">btnOkColor</span>:
|
|
1852
|
+
<span class="str">'#fff'</span>,
|
|
1853
|
+
<span class="str">btnOkBackground</span>:
|
|
1854
|
+
<span class="str">'#6c5ce7'</span> })
|
|
1855
|
+
</div>
|
|
1856
|
+
</div>
|
|
1857
|
+
|
|
1858
|
+
<div class="demo-card">
|
|
1859
|
+
<div class="card-body">
|
|
1860
|
+
<h3>.Async + .Init</h3>
|
|
1861
|
+
<p class="desc">
|
|
1862
|
+
<code>.Async</code> returns a Promise. <code>.Init</code> sets
|
|
1863
|
+
global defaults.
|
|
1864
|
+
</p>
|
|
1865
|
+
<div class="card-actions">
|
|
1866
|
+
<button
|
|
1867
|
+
class="pri"
|
|
1868
|
+
onclick="
|
|
1869
|
+
(async () => {
|
|
1870
|
+
await Fnon.Alert.Primary.Async(
|
|
1871
|
+
'Promise resolved!',
|
|
1872
|
+
'Async',
|
|
1873
|
+
);
|
|
1874
|
+
Fnon.Hint.Success('Resolved!');
|
|
1875
|
+
})()
|
|
1876
|
+
"
|
|
1877
|
+
>
|
|
1878
|
+
Alert.Async
|
|
1879
|
+
</button>
|
|
1880
|
+
<button
|
|
1881
|
+
onclick="
|
|
1882
|
+
Fnon.Alert.Init({ btnOkText: 'Got it!' });
|
|
1883
|
+
Fnon.Alert.Primary('Button changed!', '.Init');
|
|
1884
|
+
"
|
|
1885
|
+
>
|
|
1886
|
+
Apply .Init
|
|
1887
|
+
</button>
|
|
1888
|
+
<button
|
|
1889
|
+
onclick="
|
|
1890
|
+
Fnon.Alert.Init({ btnOkText: void 0 });
|
|
1891
|
+
Fnon.Hint.Info('Reset');
|
|
1892
|
+
"
|
|
1893
|
+
>
|
|
1894
|
+
Reset
|
|
1895
|
+
</button>
|
|
1896
|
+
</div>
|
|
1897
|
+
</div>
|
|
1898
|
+
<div class="code">
|
|
1899
|
+
<span class="kw">await</span>
|
|
1900
|
+
<span class="kw">Fnon</span>.Alert.Primary.<span class="fn"
|
|
1901
|
+
>Async</span
|
|
1902
|
+
>(<span class="str">'msg'</span>,
|
|
1903
|
+
<span class="str">'title'</span>)
|
|
1904
|
+
</div>
|
|
1905
|
+
</div>
|
|
1906
|
+
</div>
|
|
1907
|
+
|
|
1908
|
+
<div class="ref-section">
|
|
1909
|
+
<h3>Alert — common ModalOptions</h3>
|
|
1910
|
+
<table class="ref-table">
|
|
1911
|
+
<tr>
|
|
1912
|
+
<th>Option</th>
|
|
1913
|
+
<th>Default</th>
|
|
1914
|
+
<th>Type</th>
|
|
1915
|
+
<th>Description</th>
|
|
1916
|
+
</tr>
|
|
1917
|
+
<tr>
|
|
1918
|
+
<td>message</td>
|
|
1919
|
+
<td>—</td>
|
|
1920
|
+
<td>string | HTMLElement | VNode</td>
|
|
1921
|
+
<td>Body content</td>
|
|
1922
|
+
</tr>
|
|
1923
|
+
<tr>
|
|
1924
|
+
<td>title</td>
|
|
1925
|
+
<td>—</td>
|
|
1926
|
+
<td>string</td>
|
|
1927
|
+
<td>Dialog title</td>
|
|
1928
|
+
</tr>
|
|
1929
|
+
<tr>
|
|
1930
|
+
<td>btnOkText</td>
|
|
1931
|
+
<td>'OK'</td>
|
|
1932
|
+
<td>string</td>
|
|
1933
|
+
<td>OK button label</td>
|
|
1934
|
+
</tr>
|
|
1935
|
+
<tr>
|
|
1936
|
+
<td>width</td>
|
|
1937
|
+
<td>—</td>
|
|
1938
|
+
<td>'sm' | 'lg' | 'xl' | 'fl'</td>
|
|
1939
|
+
<td>Width mode (360/640/800/full px)</td>
|
|
1940
|
+
</tr>
|
|
1941
|
+
<tr>
|
|
1942
|
+
<td>closeButton</td>
|
|
1943
|
+
<td>true</td>
|
|
1944
|
+
<td>boolean</td>
|
|
1945
|
+
<td>Show/hide X button</td>
|
|
1946
|
+
</tr>
|
|
1947
|
+
<tr>
|
|
1948
|
+
<td>showClose</td>
|
|
1949
|
+
<td>—</td>
|
|
1950
|
+
<td>boolean</td>
|
|
1951
|
+
<td>Alias for closeButton</td>
|
|
1952
|
+
</tr>
|
|
1953
|
+
<tr>
|
|
1954
|
+
<td>delButtons</td>
|
|
1955
|
+
<td>false</td>
|
|
1956
|
+
<td>boolean</td>
|
|
1957
|
+
<td>Remove all footer buttons</td>
|
|
1958
|
+
</tr>
|
|
1959
|
+
<tr>
|
|
1960
|
+
<td>autoFocus</td>
|
|
1961
|
+
<td>false</td>
|
|
1962
|
+
<td>boolean</td>
|
|
1963
|
+
<td>Auto-focus first matching element</td>
|
|
1964
|
+
</tr>
|
|
1965
|
+
<tr>
|
|
1966
|
+
<td>autoFocusTag</td>
|
|
1967
|
+
<td>'input:not([disabled])'</td>
|
|
1968
|
+
<td>selector</td>
|
|
1969
|
+
<td>Focus target selector</td>
|
|
1970
|
+
</tr>
|
|
1971
|
+
<tr>
|
|
1972
|
+
<td>fontFamily</td>
|
|
1973
|
+
<td>'Quicksand', sans-serif</td>
|
|
1974
|
+
<td>string</td>
|
|
1975
|
+
<td>CSS font-family</td>
|
|
1976
|
+
</tr>
|
|
1977
|
+
<tr>
|
|
1978
|
+
<td>animation</td>
|
|
1979
|
+
<td>'slide-top'</td>
|
|
1980
|
+
<td>string</td>
|
|
1981
|
+
<td>CSS animation class</td>
|
|
1982
|
+
</tr>
|
|
1983
|
+
<tr>
|
|
1984
|
+
<td>color</td>
|
|
1985
|
+
<td>'#2b2b2b'</td>
|
|
1986
|
+
<td>color</td>
|
|
1987
|
+
<td>Body text color</td>
|
|
1988
|
+
</tr>
|
|
1989
|
+
<tr>
|
|
1990
|
+
<td>background</td>
|
|
1991
|
+
<td>'rgba(0,0,0,0.4)'</td>
|
|
1992
|
+
<td>color</td>
|
|
1993
|
+
<td>Overlay background</td>
|
|
1994
|
+
</tr>
|
|
1995
|
+
<tr>
|
|
1996
|
+
<td>titleColor</td>
|
|
1997
|
+
<td>—</td>
|
|
1998
|
+
<td>color</td>
|
|
1999
|
+
<td>Title text color</td>
|
|
2000
|
+
</tr>
|
|
2001
|
+
<tr>
|
|
2002
|
+
<td>titleBackground</td>
|
|
2003
|
+
<td>—</td>
|
|
2004
|
+
<td>color</td>
|
|
2005
|
+
<td>Title bar background</td>
|
|
2006
|
+
</tr>
|
|
2007
|
+
<tr>
|
|
2008
|
+
<td>zIndex</td>
|
|
2009
|
+
<td>4000</td>
|
|
2010
|
+
<td>number</td>
|
|
2011
|
+
<td>Overlay z-index</td>
|
|
2012
|
+
</tr>
|
|
2013
|
+
<tr>
|
|
2014
|
+
<td>showIcon</td>
|
|
2015
|
+
<td>false</td>
|
|
2016
|
+
<td>boolean</td>
|
|
2017
|
+
<td>Show an icon in the body</td>
|
|
2018
|
+
</tr>
|
|
2019
|
+
<tr>
|
|
2020
|
+
<td>data</td>
|
|
2021
|
+
<td>—</td>
|
|
2022
|
+
<td>object</td>
|
|
2023
|
+
<td>Shared mutable data for lifecycle callbacks</td>
|
|
2024
|
+
</tr>
|
|
2025
|
+
<tr>
|
|
2026
|
+
<td>focusTrap</td>
|
|
2027
|
+
<td>true</td>
|
|
2028
|
+
<td>boolean</td>
|
|
2029
|
+
<td>Lock Tab focus inside the modal</td>
|
|
2030
|
+
</tr>
|
|
2031
|
+
<tr>
|
|
2032
|
+
<td>isDark</td>
|
|
2033
|
+
<td>—</td>
|
|
2034
|
+
<td>boolean | ()=>boolean</td>
|
|
2035
|
+
<td>Enable dark mode for body & footer</td>
|
|
2036
|
+
</tr>
|
|
2037
|
+
<tr>
|
|
2038
|
+
<td>darkBgColor</td>
|
|
2039
|
+
<td>'#1a202c'</td>
|
|
2040
|
+
<td>color</td>
|
|
2041
|
+
<td>Dark mode background color</td>
|
|
2042
|
+
</tr>
|
|
2043
|
+
<tr>
|
|
2044
|
+
<td>onOpen</td>
|
|
2045
|
+
<td>—</td>
|
|
2046
|
+
<td>(el,data)=>void</td>
|
|
2047
|
+
<td>After modal opens</td>
|
|
2048
|
+
</tr>
|
|
2049
|
+
<tr>
|
|
2050
|
+
<td>onClose</td>
|
|
2051
|
+
<td>—</td>
|
|
2052
|
+
<td>(data)=>void</td>
|
|
2053
|
+
<td>When modal closes</td>
|
|
2054
|
+
</tr>
|
|
2055
|
+
<tr>
|
|
2056
|
+
<td>onInit</td>
|
|
2057
|
+
<td>—</td>
|
|
2058
|
+
<td>(el,data)=>void</td>
|
|
2059
|
+
<td>After element built, before DOM append</td>
|
|
2060
|
+
</tr>
|
|
2061
|
+
<tr>
|
|
2062
|
+
<td>onClosed</td>
|
|
2063
|
+
<td>—</td>
|
|
2064
|
+
<td>(data)=>void</td>
|
|
2065
|
+
<td>After modal fully removed</td>
|
|
2066
|
+
</tr>
|
|
2067
|
+
</table>
|
|
2068
|
+
</div>
|
|
2069
|
+
|
|
2070
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
2071
|
+
<strong>Async:</strong>
|
|
2072
|
+
<code>Fnon.Alert.Theme.Async(message, title?, btnOkText?)</code>
|
|
2073
|
+
returns <code>Promise<void></code> that resolves when OK is
|
|
2074
|
+
clicked or the modal is closed.
|
|
2075
|
+
</p>
|
|
2076
|
+
|
|
2077
|
+
<div class="sandbox">
|
|
2078
|
+
<h3>Sandbox — Alert</h3>
|
|
2079
|
+
<p>Configure and launch an Alert modal.</p>
|
|
2080
|
+
<div class="sandbox-grid">
|
|
2081
|
+
<div class="sandbox-row">
|
|
2082
|
+
<label>Message</label>
|
|
2083
|
+
<input
|
|
2084
|
+
type="text"
|
|
2085
|
+
id="alert-msg"
|
|
2086
|
+
value="Hello from the sandbox!"
|
|
2087
|
+
/>
|
|
2088
|
+
</div>
|
|
2089
|
+
<div class="sandbox-row">
|
|
2090
|
+
<label>Title</label>
|
|
2091
|
+
<input type="text" id="alert-title" value="Alert Sandbox" />
|
|
2092
|
+
</div>
|
|
2093
|
+
<div class="sandbox-row">
|
|
2094
|
+
<label>btnOkText</label>
|
|
2095
|
+
<input type="text" id="alert-btnok" value="OK" />
|
|
2096
|
+
</div>
|
|
2097
|
+
<div class="sandbox-row">
|
|
2098
|
+
<label>Theme</label>
|
|
2099
|
+
<select id="alert-theme">
|
|
2100
|
+
<option>Primary</option>
|
|
2101
|
+
<option>Success</option>
|
|
2102
|
+
<option>Warning</option>
|
|
2103
|
+
<option>Danger</option>
|
|
2104
|
+
<option>Info</option>
|
|
2105
|
+
<option>Light</option>
|
|
2106
|
+
<option>Dark</option>
|
|
2107
|
+
</select>
|
|
2108
|
+
</div>
|
|
2109
|
+
<div class="sandbox-row">
|
|
2110
|
+
<label>Width</label>
|
|
2111
|
+
<select id="alert-width">
|
|
2112
|
+
<option value="">Normal</option>
|
|
2113
|
+
<option>sm</option>
|
|
2114
|
+
<option>lg</option>
|
|
2115
|
+
<option>xl</option>
|
|
2116
|
+
<option>fl</option>
|
|
2117
|
+
</select>
|
|
2118
|
+
</div>
|
|
2119
|
+
<div class="sandbox-row">
|
|
2120
|
+
<label>Font family</label>
|
|
2121
|
+
<input
|
|
2122
|
+
type="text"
|
|
2123
|
+
id="alert-fontfamily"
|
|
2124
|
+
value="'Quicksand', sans-serif"
|
|
2125
|
+
/>
|
|
2126
|
+
</div>
|
|
2127
|
+
<div class="sandbox-row">
|
|
2128
|
+
<div class="chk-row">
|
|
2129
|
+
<input type="checkbox" id="alert-showclose" checked /><label
|
|
2130
|
+
for="alert-showclose"
|
|
2131
|
+
>Show close button</label
|
|
2132
|
+
>
|
|
2133
|
+
</div>
|
|
2134
|
+
</div>
|
|
2135
|
+
<div class="sandbox-row">
|
|
2136
|
+
<div class="chk-row">
|
|
2137
|
+
<input type="checkbox" id="alert-autofocus" /><label
|
|
2138
|
+
for="alert-autofocus"
|
|
2139
|
+
>Auto-focus</label
|
|
2140
|
+
>
|
|
2141
|
+
</div>
|
|
2142
|
+
</div>
|
|
2143
|
+
</div>
|
|
2144
|
+
<div class="sandbox-actions">
|
|
2145
|
+
<button class="pri" onclick="runAlertSandbox()">Run Alert</button>
|
|
2146
|
+
</div>
|
|
2147
|
+
</div>
|
|
2148
|
+
</section>
|
|
2149
|
+
|
|
2150
|
+
<!-- ══════════════════════════ ASK ══════════════════════════ -->
|
|
2151
|
+
<section id="ask">
|
|
2152
|
+
<h2>
|
|
2153
|
+
5. Ask
|
|
2154
|
+
<span class="badge"
|
|
2155
|
+
>Fnon.Ask.Theme(msg, title?, okText?, cancelText?, callback?)</span
|
|
2156
|
+
>
|
|
2157
|
+
</h2>
|
|
2158
|
+
<p class="section-desc">
|
|
2159
|
+
A two-button confirm modal (OK / Cancel). The callback receives
|
|
2160
|
+
<code>true</code> or <code>false</code>. Supports object args and
|
|
2161
|
+
async.
|
|
2162
|
+
</p>
|
|
2163
|
+
|
|
2164
|
+
<div class="demo-grid">
|
|
2165
|
+
<div class="demo-card">
|
|
2166
|
+
<div class="card-body">
|
|
2167
|
+
<h3>Positional args</h3>
|
|
2168
|
+
<p class="desc">
|
|
2169
|
+
message, title, OK text, Cancel text, callback(result).
|
|
2170
|
+
</p>
|
|
2171
|
+
<div class="card-actions">
|
|
2172
|
+
<button
|
|
2173
|
+
class="pri"
|
|
2174
|
+
onclick="
|
|
2175
|
+
Fnon.Ask.Primary('Proceed?', 'Confirm', 'Yes', 'No', (r) =>
|
|
2176
|
+
Fnon.Hint.Primary(r ? 'Yes' : 'No'),
|
|
2177
|
+
)
|
|
2178
|
+
"
|
|
2179
|
+
>
|
|
2180
|
+
Primary
|
|
2181
|
+
</button>
|
|
2182
|
+
<button
|
|
2183
|
+
class="dan"
|
|
2184
|
+
onclick="
|
|
2185
|
+
Fnon.Ask.Danger(
|
|
2186
|
+
'Delete file?',
|
|
2187
|
+
'Delete',
|
|
2188
|
+
'Delete',
|
|
2189
|
+
'Keep',
|
|
2190
|
+
(r) => Fnon.Hint.Danger(r ? 'Deleted' : 'Kept'),
|
|
2191
|
+
)
|
|
2192
|
+
"
|
|
2193
|
+
>
|
|
2194
|
+
Danger
|
|
2195
|
+
</button>
|
|
2196
|
+
</div>
|
|
2197
|
+
</div>
|
|
2198
|
+
<div class="code">
|
|
2199
|
+
<span class="kw">Fnon</span>.Ask.Primary(<span class="str"
|
|
2200
|
+
>'Proceed?'</span
|
|
2201
|
+
>, <span class="str">'Confirm'</span>,
|
|
2202
|
+
<span class="str">'Yes'</span>, <span class="str">'No'</span>, r
|
|
2203
|
+
=> {})
|
|
2204
|
+
</div>
|
|
2205
|
+
</div>
|
|
2206
|
+
|
|
2207
|
+
<div class="demo-card">
|
|
2208
|
+
<div class="card-body">
|
|
2209
|
+
<h3>Object args</h3>
|
|
2210
|
+
<p class="desc">Pass a single options object for full control.</p>
|
|
2211
|
+
<div class="card-actions">
|
|
2212
|
+
<button
|
|
2213
|
+
class="pri"
|
|
2214
|
+
onclick="
|
|
2215
|
+
Fnon.Ask.Primary({
|
|
2216
|
+
message: 'Object mode!',
|
|
2217
|
+
btnOkText: 'Sure',
|
|
2218
|
+
btnCancelText: 'Nah',
|
|
2219
|
+
})
|
|
2220
|
+
"
|
|
2221
|
+
>
|
|
2222
|
+
Object
|
|
2223
|
+
</button>
|
|
2224
|
+
</div>
|
|
2225
|
+
</div>
|
|
2226
|
+
<div class="code">
|
|
2227
|
+
<span class="kw">Fnon</span>.Ask.Primary({
|
|
2228
|
+
<span class="str">message</span>:
|
|
2229
|
+
<span class="str">'Object mode!'</span>,
|
|
2230
|
+
<span class="str">btnOkText</span>:
|
|
2231
|
+
<span class="str">'Sure'</span> })
|
|
2232
|
+
</div>
|
|
2233
|
+
</div>
|
|
2234
|
+
|
|
2235
|
+
<div class="demo-card">
|
|
2236
|
+
<div class="card-body">
|
|
2237
|
+
<h3>Button styling overrides</h3>
|
|
2238
|
+
<p class="desc">Custom colors for both OK and Cancel buttons.</p>
|
|
2239
|
+
<div class="card-actions">
|
|
2240
|
+
<button
|
|
2241
|
+
onclick="
|
|
2242
|
+
Fnon.Ask.Primary({
|
|
2243
|
+
message: 'Styled!',
|
|
2244
|
+
btnOkColor: '#fff',
|
|
2245
|
+
btnOkBackground: '#6c5ce7',
|
|
2246
|
+
btnOkShadow: '0 4px 12px rgba(108,92,231,.4)',
|
|
2247
|
+
btnCancelColor: '#fff',
|
|
2248
|
+
btnCancelBackground: '#e17055',
|
|
2249
|
+
})
|
|
2250
|
+
"
|
|
2251
|
+
>
|
|
2252
|
+
Styled
|
|
2253
|
+
</button>
|
|
2254
|
+
</div>
|
|
2255
|
+
</div>
|
|
2256
|
+
<div class="code">
|
|
2257
|
+
<span class="kw">Fnon</span>.Ask.Primary({
|
|
2258
|
+
<span class="str">btnOkColor</span>:
|
|
2259
|
+
<span class="str">'#fff'</span>,
|
|
2260
|
+
<span class="str">btnOkBackground</span>:
|
|
2261
|
+
<span class="str">'#6c5ce7'</span> })
|
|
2262
|
+
</div>
|
|
2263
|
+
</div>
|
|
2264
|
+
|
|
2265
|
+
<div class="demo-card">
|
|
2266
|
+
<div class="card-body">
|
|
2267
|
+
<h3>.Async + .Init</h3>
|
|
2268
|
+
<p class="desc">
|
|
2269
|
+
<code>.Async</code> resolves <code>true</code> or
|
|
2270
|
+
<code>false</code>. <code>.Init</code> sets global defaults.
|
|
2271
|
+
</p>
|
|
2272
|
+
<div class="card-actions">
|
|
2273
|
+
<button
|
|
2274
|
+
class="pri"
|
|
2275
|
+
onclick="
|
|
2276
|
+
(async () => {
|
|
2277
|
+
let r = await Fnon.Ask.Primary.Async(
|
|
2278
|
+
'Continue?',
|
|
2279
|
+
'Async',
|
|
2280
|
+
'Yes',
|
|
2281
|
+
'No',
|
|
2282
|
+
);
|
|
2283
|
+
Fnon.Hint.Primary(r ? 'Yes' : 'No');
|
|
2284
|
+
})()
|
|
2285
|
+
"
|
|
2286
|
+
>
|
|
2287
|
+
Ask.Async
|
|
2288
|
+
</button>
|
|
2289
|
+
<button
|
|
2290
|
+
onclick="
|
|
2291
|
+
Fnon.Ask.Init({ btnOkText: 'Sure' });
|
|
2292
|
+
Fnon.Ask.Primary('Button changed!');
|
|
2293
|
+
"
|
|
2294
|
+
>
|
|
2295
|
+
Apply .Init
|
|
2296
|
+
</button>
|
|
2297
|
+
<button
|
|
2298
|
+
onclick="
|
|
2299
|
+
Fnon.Ask.Init({ btnOkText: void 0 });
|
|
2300
|
+
Fnon.Hint.Info('Reset');
|
|
2301
|
+
"
|
|
2302
|
+
>
|
|
2303
|
+
Reset
|
|
2304
|
+
</button>
|
|
2305
|
+
</div>
|
|
2306
|
+
</div>
|
|
2307
|
+
<div class="code">
|
|
2308
|
+
<span class="kw">let</span> r = <span class="kw">await</span>
|
|
2309
|
+
<span class="kw">Fnon</span>.Ask.Primary.<span class="fn"
|
|
2310
|
+
>Async</span
|
|
2311
|
+
>(<span class="str">'Continue?'</span>)
|
|
2312
|
+
</div>
|
|
2313
|
+
</div>
|
|
2314
|
+
</div>
|
|
2315
|
+
|
|
2316
|
+
<div class="ref-section">
|
|
2317
|
+
<h3>Ask — common ModalOptions</h3>
|
|
2318
|
+
<table class="ref-table">
|
|
2319
|
+
<tr>
|
|
2320
|
+
<th>Option</th>
|
|
2321
|
+
<th>Default</th>
|
|
2322
|
+
<th>Type</th>
|
|
2323
|
+
<th>Description</th>
|
|
2324
|
+
</tr>
|
|
2325
|
+
<tr>
|
|
2326
|
+
<td>message</td>
|
|
2327
|
+
<td>—</td>
|
|
2328
|
+
<td>string | HTMLElement | VNode</td>
|
|
2329
|
+
<td>Body content</td>
|
|
2330
|
+
</tr>
|
|
2331
|
+
<tr>
|
|
2332
|
+
<td>title</td>
|
|
2333
|
+
<td>—</td>
|
|
2334
|
+
<td>string</td>
|
|
2335
|
+
<td>Dialog title</td>
|
|
2336
|
+
</tr>
|
|
2337
|
+
<tr>
|
|
2338
|
+
<td>btnOkText</td>
|
|
2339
|
+
<td>'OK'</td>
|
|
2340
|
+
<td>string</td>
|
|
2341
|
+
<td>OK button label</td>
|
|
2342
|
+
</tr>
|
|
2343
|
+
<tr>
|
|
2344
|
+
<td>btnCancelText</td>
|
|
2345
|
+
<td>'Cancel'</td>
|
|
2346
|
+
<td>string</td>
|
|
2347
|
+
<td>Cancel button label</td>
|
|
2348
|
+
</tr>
|
|
2349
|
+
<tr>
|
|
2350
|
+
<td>width</td>
|
|
2351
|
+
<td>—</td>
|
|
2352
|
+
<td>'sm' | 'lg' | 'xl' | 'fl'</td>
|
|
2353
|
+
<td>Width mode</td>
|
|
2354
|
+
</tr>
|
|
2355
|
+
<tr>
|
|
2356
|
+
<td>closeButton</td>
|
|
2357
|
+
<td>true</td>
|
|
2358
|
+
<td>boolean</td>
|
|
2359
|
+
<td>Show/hide X button</td>
|
|
2360
|
+
</tr>
|
|
2361
|
+
<tr>
|
|
2362
|
+
<td>showClose</td>
|
|
2363
|
+
<td>—</td>
|
|
2364
|
+
<td>boolean</td>
|
|
2365
|
+
<td>Alias for closeButton</td>
|
|
2366
|
+
</tr>
|
|
2367
|
+
<tr>
|
|
2368
|
+
<td>autoFocus</td>
|
|
2369
|
+
<td>false</td>
|
|
2370
|
+
<td>boolean</td>
|
|
2371
|
+
<td>Auto-focus first matching element</td>
|
|
2372
|
+
</tr>
|
|
2373
|
+
<tr>
|
|
2374
|
+
<td>fontFamily</td>
|
|
2375
|
+
<td>'Quicksand', sans-serif</td>
|
|
2376
|
+
<td>string</td>
|
|
2377
|
+
<td>CSS font-family</td>
|
|
2378
|
+
</tr>
|
|
2379
|
+
<tr>
|
|
2380
|
+
<td>color</td>
|
|
2381
|
+
<td>'#2b2b2b'</td>
|
|
2382
|
+
<td>color</td>
|
|
2383
|
+
<td>Body text color</td>
|
|
2384
|
+
</tr>
|
|
2385
|
+
<tr>
|
|
2386
|
+
<td>btnOkColor</td>
|
|
2387
|
+
<td>—</td>
|
|
2388
|
+
<td>color</td>
|
|
2389
|
+
<td>OK button text color</td>
|
|
2390
|
+
</tr>
|
|
2391
|
+
<tr>
|
|
2392
|
+
<td>btnOkBackground</td>
|
|
2393
|
+
<td>—</td>
|
|
2394
|
+
<td>color</td>
|
|
2395
|
+
<td>OK button background</td>
|
|
2396
|
+
</tr>
|
|
2397
|
+
<tr>
|
|
2398
|
+
<td>btnOkShadow</td>
|
|
2399
|
+
<td>—</td>
|
|
2400
|
+
<td>string</td>
|
|
2401
|
+
<td>OK button box-shadow</td>
|
|
2402
|
+
</tr>
|
|
2403
|
+
<tr>
|
|
2404
|
+
<td>btnCancelColor</td>
|
|
2405
|
+
<td>—</td>
|
|
2406
|
+
<td>color</td>
|
|
2407
|
+
<td>Cancel button text color</td>
|
|
2408
|
+
</tr>
|
|
2409
|
+
<tr>
|
|
2410
|
+
<td>btnCancelBackground</td>
|
|
2411
|
+
<td>—</td>
|
|
2412
|
+
<td>color</td>
|
|
2413
|
+
<td>Cancel button background</td>
|
|
2414
|
+
</tr>
|
|
2415
|
+
<tr>
|
|
2416
|
+
<td>focusTrap</td>
|
|
2417
|
+
<td>true</td>
|
|
2418
|
+
<td>boolean</td>
|
|
2419
|
+
<td>Lock Tab focus inside the modal</td>
|
|
2420
|
+
</tr>
|
|
2421
|
+
<tr>
|
|
2422
|
+
<td>isDark</td>
|
|
2423
|
+
<td>—</td>
|
|
2424
|
+
<td>boolean | ()=>boolean</td>
|
|
2425
|
+
<td>Enable dark mode for body & footer</td>
|
|
2426
|
+
</tr>
|
|
2427
|
+
<tr>
|
|
2428
|
+
<td>darkBgColor</td>
|
|
2429
|
+
<td>'#1a202c'</td>
|
|
2430
|
+
<td>color</td>
|
|
2431
|
+
<td>Dark mode background color</td>
|
|
2432
|
+
</tr>
|
|
2433
|
+
</table>
|
|
2434
|
+
</div>
|
|
2435
|
+
|
|
2436
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
2437
|
+
<strong>Async:</strong>
|
|
2438
|
+
<code
|
|
2439
|
+
>Fnon.Ask.Theme.Async(message, title?, okText?, cancelText?)</code
|
|
2440
|
+
>
|
|
2441
|
+
returns <code>Promise<boolean></code> — <code>true</code> on OK,
|
|
2442
|
+
<code>false</code> on Cancel or close.
|
|
2443
|
+
</p>
|
|
2444
|
+
|
|
2445
|
+
<div class="sandbox">
|
|
2446
|
+
<h3>Sandbox — Ask</h3>
|
|
2447
|
+
<p>Configure and launch a confirmation modal.</p>
|
|
2448
|
+
<div class="sandbox-grid">
|
|
2449
|
+
<div class="sandbox-row">
|
|
2450
|
+
<label>Message</label>
|
|
2451
|
+
<input
|
|
2452
|
+
type="text"
|
|
2453
|
+
id="ask-msg"
|
|
2454
|
+
value="Proceed with this action?"
|
|
2455
|
+
/>
|
|
2456
|
+
</div>
|
|
2457
|
+
<div class="sandbox-row">
|
|
2458
|
+
<label>Title</label>
|
|
2459
|
+
<input type="text" id="ask-title" value="Confirm" />
|
|
2460
|
+
</div>
|
|
2461
|
+
<div class="sandbox-row">
|
|
2462
|
+
<label>btnOkText</label>
|
|
2463
|
+
<input type="text" id="ask-btnok" value="Yes" />
|
|
2464
|
+
</div>
|
|
2465
|
+
<div class="sandbox-row">
|
|
2466
|
+
<label>btnCancelText</label>
|
|
2467
|
+
<input type="text" id="ask-btncancel" value="No" />
|
|
2468
|
+
</div>
|
|
2469
|
+
<div class="sandbox-row">
|
|
2470
|
+
<label>Theme</label>
|
|
2471
|
+
<select id="ask-theme">
|
|
2472
|
+
<option>Primary</option>
|
|
2473
|
+
<option>Success</option>
|
|
2474
|
+
<option>Warning</option>
|
|
2475
|
+
<option>Danger</option>
|
|
2476
|
+
<option>Info</option>
|
|
2477
|
+
<option>Light</option>
|
|
2478
|
+
<option>Dark</option>
|
|
2479
|
+
</select>
|
|
2480
|
+
</div>
|
|
2481
|
+
<div class="sandbox-row">
|
|
2482
|
+
<label>Width</label>
|
|
2483
|
+
<select id="ask-width">
|
|
2484
|
+
<option value="">Normal</option>
|
|
2485
|
+
<option>sm</option>
|
|
2486
|
+
<option>lg</option>
|
|
2487
|
+
<option>xl</option>
|
|
2488
|
+
<option>fl</option>
|
|
2489
|
+
</select>
|
|
2490
|
+
</div>
|
|
2491
|
+
<div class="sandbox-row">
|
|
2492
|
+
<div class="chk-row">
|
|
2493
|
+
<input type="checkbox" id="ask-showclose" checked /><label
|
|
2494
|
+
for="ask-showclose"
|
|
2495
|
+
>Show close button</label
|
|
2496
|
+
>
|
|
2497
|
+
</div>
|
|
2498
|
+
</div>
|
|
2499
|
+
</div>
|
|
2500
|
+
<div class="sandbox-actions">
|
|
2501
|
+
<button class="pri" onclick="runAskSandbox()">Run Ask</button>
|
|
2502
|
+
</div>
|
|
2503
|
+
</div>
|
|
2504
|
+
</section>
|
|
2505
|
+
|
|
2506
|
+
<!-- ══════════════════════════ DIALOGUE ══════════════════════════ -->
|
|
2507
|
+
<section id="dialogue">
|
|
2508
|
+
<h2>
|
|
2509
|
+
6. Dialogue
|
|
2510
|
+
<span class="badge"
|
|
2511
|
+
>Fnon.Dialogue(opts) · Fnon.Dialogue.Theme(...)</span
|
|
2512
|
+
>
|
|
2513
|
+
</h2>
|
|
2514
|
+
<p class="section-desc">
|
|
2515
|
+
The most flexible modal. Custom buttons, full lifecycle hooks,
|
|
2516
|
+
minimize/maximize, drag, and raw options control.
|
|
2517
|
+
</p>
|
|
2518
|
+
|
|
2519
|
+
<div class="demo-grid">
|
|
2520
|
+
<div class="demo-card">
|
|
2521
|
+
<div class="card-body">
|
|
2522
|
+
<h3>Custom buttons</h3>
|
|
2523
|
+
<p class="desc">
|
|
2524
|
+
Define buttons with text, style, and callback. Callback receives
|
|
2525
|
+
<code>close()</code>.
|
|
2526
|
+
</p>
|
|
2527
|
+
<div class="card-actions">
|
|
2528
|
+
<button
|
|
2529
|
+
class="pri"
|
|
2530
|
+
onclick="
|
|
2531
|
+
Fnon.Dialogue({
|
|
2532
|
+
message: 'Two custom buttons',
|
|
2533
|
+
title: 'Dialogue',
|
|
2534
|
+
buttons: [
|
|
2535
|
+
{
|
|
2536
|
+
text: 'Save',
|
|
2537
|
+
style: 'Success',
|
|
2538
|
+
callback: (c) => {
|
|
2539
|
+
Fnon.Hint.Success('Saved!');
|
|
2540
|
+
c();
|
|
2541
|
+
},
|
|
2542
|
+
},
|
|
2543
|
+
{
|
|
2544
|
+
text: 'Cancel',
|
|
2545
|
+
style: 'Light',
|
|
2546
|
+
callback: (c) => {
|
|
2547
|
+
Fnon.Hint.Light('Cancelled');
|
|
2548
|
+
c();
|
|
2549
|
+
},
|
|
2550
|
+
},
|
|
2551
|
+
],
|
|
2552
|
+
})
|
|
2553
|
+
"
|
|
2554
|
+
>
|
|
2555
|
+
Custom Btns
|
|
2556
|
+
</button>
|
|
2557
|
+
</div>
|
|
2558
|
+
</div>
|
|
2559
|
+
<div class="code">
|
|
2560
|
+
<span class="kw">Fnon</span>.Dialogue({
|
|
2561
|
+
<span class="str">buttons</span>: [{
|
|
2562
|
+
<span class="str">text</span>: <span class="str">'Save'</span>,
|
|
2563
|
+
<span class="fn">callback</span>: c => c() }] })
|
|
2564
|
+
</div>
|
|
2565
|
+
</div>
|
|
2566
|
+
|
|
2567
|
+
<div class="demo-card">
|
|
2568
|
+
<div class="card-body">
|
|
2569
|
+
<h3>Themed shortcut + prevent close</h3>
|
|
2570
|
+
<p class="desc">
|
|
2571
|
+
Positional shortcut: msg, title, OK, Cancel, callback(close,
|
|
2572
|
+
html). Return <code>false</code> to stay open.
|
|
2573
|
+
</p>
|
|
2574
|
+
<div class="card-actions">
|
|
2575
|
+
<button
|
|
2576
|
+
class="pri"
|
|
2577
|
+
onclick="
|
|
2578
|
+
Fnon.Dialogue.Primary(
|
|
2579
|
+
'Shortcut!',
|
|
2580
|
+
'Dialogue',
|
|
2581
|
+
'OK',
|
|
2582
|
+
'Cancel',
|
|
2583
|
+
(c) => {
|
|
2584
|
+
Fnon.Hint.Success('OK!');
|
|
2585
|
+
c();
|
|
2586
|
+
},
|
|
2587
|
+
)
|
|
2588
|
+
"
|
|
2589
|
+
>
|
|
2590
|
+
Positional
|
|
2591
|
+
</button>
|
|
2592
|
+
<button
|
|
2593
|
+
class="dan"
|
|
2594
|
+
onclick="
|
|
2595
|
+
Fnon.Dialogue({
|
|
2596
|
+
message: 'Return false to stay open',
|
|
2597
|
+
title: 'Prevent',
|
|
2598
|
+
buttons: [
|
|
2599
|
+
{
|
|
2600
|
+
text: 'Stay open',
|
|
2601
|
+
style: 'Danger',
|
|
2602
|
+
callback: () => {
|
|
2603
|
+
Fnon.Hint.Warning('Prevented!');
|
|
2604
|
+
return false;
|
|
2605
|
+
},
|
|
2606
|
+
},
|
|
2607
|
+
{
|
|
2608
|
+
text: 'Close',
|
|
2609
|
+
style: 'Primary',
|
|
2610
|
+
callback: (c) => c(),
|
|
2611
|
+
},
|
|
2612
|
+
],
|
|
2613
|
+
})
|
|
2614
|
+
"
|
|
2615
|
+
>
|
|
2616
|
+
Prevent Close
|
|
2617
|
+
</button>
|
|
2618
|
+
</div>
|
|
2619
|
+
</div>
|
|
2620
|
+
<div class="code">
|
|
2621
|
+
<span class="cm">// Return false to prevent close</span
|
|
2622
|
+
><br />callback: (c, html) => { <span class="kw">return</span>
|
|
2623
|
+
<span class="pr">false</span> }
|
|
2624
|
+
</div>
|
|
2625
|
+
</div>
|
|
2626
|
+
|
|
2627
|
+
<div class="demo-card">
|
|
2628
|
+
<div class="card-body">
|
|
2629
|
+
<h3>Minimize / Maximize</h3>
|
|
2630
|
+
<p class="desc">
|
|
2631
|
+
<code>showMin</code> and <code>showMaxMin</code> add window
|
|
2632
|
+
controls to the title bar. Minimized modals go to a task bar.
|
|
2633
|
+
</p>
|
|
2634
|
+
<div class="card-actions">
|
|
2635
|
+
<button
|
|
2636
|
+
onclick="
|
|
2637
|
+
Fnon.Dialogue({
|
|
2638
|
+
message: 'Click _ to minimize, ⛶ to maximize',
|
|
2639
|
+
title: 'Min/Max',
|
|
2640
|
+
showMin: true,
|
|
2641
|
+
showMaxMin: true,
|
|
2642
|
+
buttons: [
|
|
2643
|
+
{ text: 'OK', style: 'Primary', callback: (c) => c() },
|
|
2644
|
+
],
|
|
2645
|
+
})
|
|
2646
|
+
"
|
|
2647
|
+
>
|
|
2648
|
+
Open
|
|
2649
|
+
</button>
|
|
2650
|
+
</div>
|
|
2651
|
+
</div>
|
|
2652
|
+
<div class="code">
|
|
2653
|
+
<span class="kw">Fnon</span>.Dialogue({
|
|
2654
|
+
<span class="str">showMin</span>: <span class="pr">true</span>,
|
|
2655
|
+
<span class="str">showMaxMin</span>:
|
|
2656
|
+
<span class="pr">true</span> })
|
|
2657
|
+
</div>
|
|
2658
|
+
</div>
|
|
2659
|
+
|
|
2660
|
+
<div class="demo-card">
|
|
2661
|
+
<div class="card-body">
|
|
2662
|
+
<h3>Lifecycle hooks + data</h3>
|
|
2663
|
+
<p class="desc">
|
|
2664
|
+
onInit → beforeShow → afterShow → onOpen → onClosing → onClose →
|
|
2665
|
+
onClosed. All receive <code>(el, data)</code>.
|
|
2666
|
+
</p>
|
|
2667
|
+
<div class="card-actions">
|
|
2668
|
+
<button
|
|
2669
|
+
class="pri"
|
|
2670
|
+
onclick="
|
|
2671
|
+
Fnon.Dialogue({
|
|
2672
|
+
message: 'Watch console',
|
|
2673
|
+
title: 'Lifecycle',
|
|
2674
|
+
onInit: (el, d) => console.log('1 onInit', d),
|
|
2675
|
+
beforeShow: (el, d) => console.log('2 beforeShow', d),
|
|
2676
|
+
afterShow: (el, d) => console.log('3 afterShow', d),
|
|
2677
|
+
onOpen: (el, d) => console.log('4 onOpen', d),
|
|
2678
|
+
onClosing: (el, d) => console.log('5 onClosing', d),
|
|
2679
|
+
onClose: (d) => console.log('6 onClose', d),
|
|
2680
|
+
onClosed: (d) => console.log('7 onClosed', d),
|
|
2681
|
+
})
|
|
2682
|
+
"
|
|
2683
|
+
>
|
|
2684
|
+
Lifecycle Demo
|
|
2685
|
+
</button>
|
|
2686
|
+
</div>
|
|
2687
|
+
</div>
|
|
2688
|
+
<div class="code">
|
|
2689
|
+
<span class="kw">Fnon</span>.Dialogue({
|
|
2690
|
+
<span class="str">onInit</span>: (el, data) => {},
|
|
2691
|
+
<span class="str">onOpen</span>: (el, data) => {} })
|
|
2692
|
+
</div>
|
|
2693
|
+
</div>
|
|
2694
|
+
|
|
2695
|
+
<div class="demo-card">
|
|
2696
|
+
<div class="card-body">
|
|
2697
|
+
<h3>Custom styling + drag</h3>
|
|
2698
|
+
<p class="desc">
|
|
2699
|
+
Override colors, font, width. All modals are draggable by the
|
|
2700
|
+
title bar.
|
|
2701
|
+
</p>
|
|
2702
|
+
<div class="card-actions">
|
|
2703
|
+
<button
|
|
2704
|
+
onclick="
|
|
2705
|
+
Fnon.Dialogue({
|
|
2706
|
+
message: 'Drag me!',
|
|
2707
|
+
title: 'Styled',
|
|
2708
|
+
width: 'sm',
|
|
2709
|
+
titleColor: '#fff',
|
|
2710
|
+
titleBackground: '#6c5ce7',
|
|
2711
|
+
color: '#2d3748',
|
|
2712
|
+
fontFamily: 'monospace',
|
|
2713
|
+
})
|
|
2714
|
+
"
|
|
2715
|
+
>
|
|
2716
|
+
Styled
|
|
2717
|
+
</button>
|
|
2718
|
+
<button
|
|
2719
|
+
onclick="
|
|
2720
|
+
Fnon.Dialogue({
|
|
2721
|
+
message: 'Full width',
|
|
2722
|
+
title: 'Full',
|
|
2723
|
+
width: 'fl',
|
|
2724
|
+
showClose: false,
|
|
2725
|
+
delButtons: true,
|
|
2726
|
+
})
|
|
2727
|
+
"
|
|
2728
|
+
>
|
|
2729
|
+
Full width
|
|
2730
|
+
</button>
|
|
2731
|
+
</div>
|
|
2732
|
+
</div>
|
|
2733
|
+
<div class="code">
|
|
2734
|
+
<span class="kw">Fnon</span>.Dialogue({
|
|
2735
|
+
<span class="str">titleColor</span>:
|
|
2736
|
+
<span class="str">'#fff'</span>, <span class="str">width</span>:
|
|
2737
|
+
<span class="str">'sm'</span> })
|
|
2738
|
+
</div>
|
|
2739
|
+
</div>
|
|
2740
|
+
</div>
|
|
2741
|
+
|
|
2742
|
+
<div class="ref-section">
|
|
2743
|
+
<h3>Dialogue — ModalOptions (full reference)</h3>
|
|
2744
|
+
<table class="ref-table">
|
|
2745
|
+
<tr>
|
|
2746
|
+
<th>Option</th>
|
|
2747
|
+
<th>Default</th>
|
|
2748
|
+
<th>Type</th>
|
|
2749
|
+
<th>Description</th>
|
|
2750
|
+
</tr>
|
|
2751
|
+
<tr>
|
|
2752
|
+
<td>message</td>
|
|
2753
|
+
<td>—</td>
|
|
2754
|
+
<td>string | HTMLElement | VNode</td>
|
|
2755
|
+
<td>Body content</td>
|
|
2756
|
+
</tr>
|
|
2757
|
+
<tr>
|
|
2758
|
+
<td>title</td>
|
|
2759
|
+
<td>—</td>
|
|
2760
|
+
<td>string</td>
|
|
2761
|
+
<td>Dialog title</td>
|
|
2762
|
+
</tr>
|
|
2763
|
+
<tr>
|
|
2764
|
+
<td>buttons</td>
|
|
2765
|
+
<td>—</td>
|
|
2766
|
+
<td>ButtonDef[]</td>
|
|
2767
|
+
<td>Custom button definitions</td>
|
|
2768
|
+
</tr>
|
|
2769
|
+
<tr>
|
|
2770
|
+
<td>width</td>
|
|
2771
|
+
<td>—</td>
|
|
2772
|
+
<td>'sm' | 'lg' | 'xl' | 'fl'</td>
|
|
2773
|
+
<td>Width mode</td>
|
|
2774
|
+
</tr>
|
|
2775
|
+
<tr>
|
|
2776
|
+
<td>layout</td>
|
|
2777
|
+
<td>'hbf'</td>
|
|
2778
|
+
<td>string</td>
|
|
2779
|
+
<td>Order of header/body/footer</td>
|
|
2780
|
+
</tr>
|
|
2781
|
+
<tr>
|
|
2782
|
+
<td>closeButton</td>
|
|
2783
|
+
<td>true</td>
|
|
2784
|
+
<td>boolean</td>
|
|
2785
|
+
<td>Show/hide X button</td>
|
|
2786
|
+
</tr>
|
|
2787
|
+
<tr>
|
|
2788
|
+
<td>showClose</td>
|
|
2789
|
+
<td>—</td>
|
|
2790
|
+
<td>boolean</td>
|
|
2791
|
+
<td>Alias for closeButton</td>
|
|
2792
|
+
</tr>
|
|
2793
|
+
<tr>
|
|
2794
|
+
<td>showMin</td>
|
|
2795
|
+
<td>false</td>
|
|
2796
|
+
<td>boolean</td>
|
|
2797
|
+
<td>Show minimize button</td>
|
|
2798
|
+
</tr>
|
|
2799
|
+
<tr>
|
|
2800
|
+
<td>showMaxMin</td>
|
|
2801
|
+
<td>false</td>
|
|
2802
|
+
<td>boolean</td>
|
|
2803
|
+
<td>Show maximize button</td>
|
|
2804
|
+
</tr>
|
|
2805
|
+
<tr>
|
|
2806
|
+
<td>delButtons</td>
|
|
2807
|
+
<td>false</td>
|
|
2808
|
+
<td>boolean</td>
|
|
2809
|
+
<td>Remove all footer buttons</td>
|
|
2810
|
+
</tr>
|
|
2811
|
+
<tr>
|
|
2812
|
+
<td>autoFocus</td>
|
|
2813
|
+
<td>false</td>
|
|
2814
|
+
<td>boolean</td>
|
|
2815
|
+
<td>Auto-focus first input</td>
|
|
2816
|
+
</tr>
|
|
2817
|
+
<tr>
|
|
2818
|
+
<td>fontFamily</td>
|
|
2819
|
+
<td>'Quicksand', sans-serif</td>
|
|
2820
|
+
<td>string</td>
|
|
2821
|
+
<td>CSS font-family</td>
|
|
2822
|
+
</tr>
|
|
2823
|
+
<tr>
|
|
2824
|
+
<td>animation</td>
|
|
2825
|
+
<td>'slide-top'</td>
|
|
2826
|
+
<td>string</td>
|
|
2827
|
+
<td>CSS animation class</td>
|
|
2828
|
+
</tr>
|
|
2829
|
+
<tr>
|
|
2830
|
+
<td>data</td>
|
|
2831
|
+
<td>—</td>
|
|
2832
|
+
<td>object</td>
|
|
2833
|
+
<td>Shared mutable data for all lifecycle hooks</td>
|
|
2834
|
+
</tr>
|
|
2835
|
+
<tr>
|
|
2836
|
+
<td>color</td>
|
|
2837
|
+
<td>'#2b2b2b'</td>
|
|
2838
|
+
<td>color</td>
|
|
2839
|
+
<td>Body text color</td>
|
|
2840
|
+
</tr>
|
|
2841
|
+
<tr>
|
|
2842
|
+
<td>background</td>
|
|
2843
|
+
<td>'rgba(0,0,0,0.4)'</td>
|
|
2844
|
+
<td>color</td>
|
|
2845
|
+
<td>Overlay background</td>
|
|
2846
|
+
</tr>
|
|
2847
|
+
<tr>
|
|
2848
|
+
<td>titleColor</td>
|
|
2849
|
+
<td>—</td>
|
|
2850
|
+
<td>color</td>
|
|
2851
|
+
<td>Title text color</td>
|
|
2852
|
+
</tr>
|
|
2853
|
+
<tr>
|
|
2854
|
+
<td>titleBackground</td>
|
|
2855
|
+
<td>—</td>
|
|
2856
|
+
<td>color</td>
|
|
2857
|
+
<td>Title bar background</td>
|
|
2858
|
+
</tr>
|
|
2859
|
+
<tr>
|
|
2860
|
+
<td>zIndex</td>
|
|
2861
|
+
<td>4000</td>
|
|
2862
|
+
<td>number</td>
|
|
2863
|
+
<td>Overlay z-index</td>
|
|
2864
|
+
</tr>
|
|
2865
|
+
<tr>
|
|
2866
|
+
<td>appendTarget</td>
|
|
2867
|
+
<td>'body'</td>
|
|
2868
|
+
<td>string | HTMLElement</td>
|
|
2869
|
+
<td>Mount container</td>
|
|
2870
|
+
</tr>
|
|
2871
|
+
<tr>
|
|
2872
|
+
<td>focusTrap</td>
|
|
2873
|
+
<td>true</td>
|
|
2874
|
+
<td>boolean</td>
|
|
2875
|
+
<td>Lock Tab focus inside the modal</td>
|
|
2876
|
+
</tr>
|
|
2877
|
+
<tr>
|
|
2878
|
+
<td>isDark</td>
|
|
2879
|
+
<td>—</td>
|
|
2880
|
+
<td>boolean | ()=>boolean</td>
|
|
2881
|
+
<td>Enable dark mode for body & footer</td>
|
|
2882
|
+
</tr>
|
|
2883
|
+
<tr>
|
|
2884
|
+
<td>darkBgColor</td>
|
|
2885
|
+
<td>'#1a202c'</td>
|
|
2886
|
+
<td>color</td>
|
|
2887
|
+
<td>Dark mode background color</td>
|
|
2888
|
+
</tr>
|
|
2889
|
+
<tr>
|
|
2890
|
+
<td>onInit</td>
|
|
2891
|
+
<td>—</td>
|
|
2892
|
+
<td>(el,data)=>void</td>
|
|
2893
|
+
<td>After element built</td>
|
|
2894
|
+
</tr>
|
|
2895
|
+
<tr>
|
|
2896
|
+
<td>beforeShow</td>
|
|
2897
|
+
<td>—</td>
|
|
2898
|
+
<td>(el,data)=>void</td>
|
|
2899
|
+
<td>Before DOM append</td>
|
|
2900
|
+
</tr>
|
|
2901
|
+
<tr>
|
|
2902
|
+
<td>afterShow</td>
|
|
2903
|
+
<td>—</td>
|
|
2904
|
+
<td>(el,data)=>void</td>
|
|
2905
|
+
<td>After DOM append</td>
|
|
2906
|
+
</tr>
|
|
2907
|
+
<tr>
|
|
2908
|
+
<td>onOpen</td>
|
|
2909
|
+
<td>—</td>
|
|
2910
|
+
<td>(el,data)=>void</td>
|
|
2911
|
+
<td>After modal opens</td>
|
|
2912
|
+
</tr>
|
|
2913
|
+
<tr>
|
|
2914
|
+
<td>onClosing</td>
|
|
2915
|
+
<td>—</td>
|
|
2916
|
+
<td>(el,data)=>void</td>
|
|
2917
|
+
<td>When modal starts closing</td>
|
|
2918
|
+
</tr>
|
|
2919
|
+
<tr>
|
|
2920
|
+
<td>onClose</td>
|
|
2921
|
+
<td>—</td>
|
|
2922
|
+
<td>(data)=>void</td>
|
|
2923
|
+
<td>During close animation</td>
|
|
2924
|
+
</tr>
|
|
2925
|
+
<tr>
|
|
2926
|
+
<td>onClosed</td>
|
|
2927
|
+
<td>—</td>
|
|
2928
|
+
<td>(data)=>void</td>
|
|
2929
|
+
<td>After modal fully removed</td>
|
|
2930
|
+
</tr>
|
|
2931
|
+
</table>
|
|
2932
|
+
</div>
|
|
2933
|
+
|
|
2934
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
2935
|
+
<strong>Async:</strong>
|
|
2936
|
+
<code
|
|
2937
|
+
>Fnon.Dialogue.Theme.Async(message, title?, okText?,
|
|
2938
|
+
cancelText?)</code
|
|
2939
|
+
>
|
|
2940
|
+
returns <code>Promise<boolean | null></code> —
|
|
2941
|
+
<code>true</code> on OK, <code>false</code> on Cancel,
|
|
2942
|
+
<code>null</code> on close/X.
|
|
2943
|
+
</p>
|
|
2944
|
+
|
|
2945
|
+
<div class="sandbox">
|
|
2946
|
+
<h3>Sandbox — Dialogue</h3>
|
|
2947
|
+
<p>Configure a modal with the most common options.</p>
|
|
2948
|
+
<div class="sandbox-grid">
|
|
2949
|
+
<div class="sandbox-row">
|
|
2950
|
+
<label>Message</label>
|
|
2951
|
+
<input type="text" id="dlg-msg" value="Custom dialogue message" />
|
|
2952
|
+
</div>
|
|
2953
|
+
<div class="sandbox-row">
|
|
2954
|
+
<label>Title</label>
|
|
2955
|
+
<input type="text" id="dlg-title" value="Dialogue Sandbox" />
|
|
2956
|
+
</div>
|
|
2957
|
+
<div class="sandbox-row">
|
|
2958
|
+
<label>Theme</label>
|
|
2959
|
+
<select id="dlg-theme">
|
|
2960
|
+
<option>Primary</option>
|
|
2961
|
+
<option>Success</option>
|
|
2962
|
+
<option>Warning</option>
|
|
2963
|
+
<option>Danger</option>
|
|
2964
|
+
<option>Info</option>
|
|
2965
|
+
<option>Light</option>
|
|
2966
|
+
<option>Dark</option>
|
|
2967
|
+
</select>
|
|
2968
|
+
</div>
|
|
2969
|
+
<div class="sandbox-row">
|
|
2970
|
+
<label>Width</label>
|
|
2971
|
+
<select id="dlg-width">
|
|
2972
|
+
<option value="">Normal</option>
|
|
2973
|
+
<option>sm</option>
|
|
2974
|
+
<option>lg</option>
|
|
2975
|
+
<option>xl</option>
|
|
2976
|
+
<option>fl</option>
|
|
2977
|
+
</select>
|
|
2978
|
+
</div>
|
|
2979
|
+
<div class="sandbox-row">
|
|
2980
|
+
<label>Layout</label>
|
|
2981
|
+
<input type="text" id="dlg-layout" value="hbf" />
|
|
2982
|
+
</div>
|
|
2983
|
+
<div class="sandbox-row">
|
|
2984
|
+
<label>Font family</label>
|
|
2985
|
+
<input
|
|
2986
|
+
type="text"
|
|
2987
|
+
id="dlg-fontfamily"
|
|
2988
|
+
value="'Quicksand', sans-serif"
|
|
2989
|
+
/>
|
|
2990
|
+
</div>
|
|
2991
|
+
<div class="sandbox-row">
|
|
2992
|
+
<div class="chk-row">
|
|
2993
|
+
<input type="checkbox" id="dlg-showclose" checked /><label
|
|
2994
|
+
for="dlg-showclose"
|
|
2995
|
+
>Show close button</label
|
|
2996
|
+
>
|
|
2997
|
+
</div>
|
|
2998
|
+
</div>
|
|
2999
|
+
<div class="sandbox-row">
|
|
3000
|
+
<div class="chk-row">
|
|
3001
|
+
<input type="checkbox" id="dlg-showmin" /><label
|
|
3002
|
+
for="dlg-showmin"
|
|
3003
|
+
>Show minimize button</label
|
|
3004
|
+
>
|
|
3005
|
+
</div>
|
|
3006
|
+
</div>
|
|
3007
|
+
<div class="sandbox-row">
|
|
3008
|
+
<div class="chk-row">
|
|
3009
|
+
<input type="checkbox" id="dlg-showmaxmin" /><label
|
|
3010
|
+
for="dlg-showmaxmin"
|
|
3011
|
+
>Show maximize button</label
|
|
3012
|
+
>
|
|
3013
|
+
</div>
|
|
3014
|
+
</div>
|
|
3015
|
+
<div class="sandbox-row">
|
|
3016
|
+
<div class="chk-row">
|
|
3017
|
+
<input type="checkbox" id="dlg-autofocus" /><label
|
|
3018
|
+
for="dlg-autofocus"
|
|
3019
|
+
>Auto-focus</label
|
|
3020
|
+
>
|
|
3021
|
+
</div>
|
|
3022
|
+
</div>
|
|
3023
|
+
</div>
|
|
3024
|
+
<div class="sandbox-actions">
|
|
3025
|
+
<button class="pri" onclick="runDialogueSandbox()">
|
|
3026
|
+
Run Dialogue
|
|
3027
|
+
</button>
|
|
3028
|
+
</div>
|
|
3029
|
+
</div>
|
|
3030
|
+
</section>
|
|
3031
|
+
|
|
3032
|
+
<!-- ══════════════════════════ BREAKING ══════════════════════════ -->
|
|
3033
|
+
<section id="breaking">
|
|
3034
|
+
<h2>
|
|
3035
|
+
7. Breaking
|
|
3036
|
+
<span class="badge"
|
|
3037
|
+
>Fnon.Breaking(opts) · Fnon.Breaking.Theme(headline?)</span
|
|
3038
|
+
>
|
|
3039
|
+
</h2>
|
|
3040
|
+
<p class="section-desc">
|
|
3041
|
+
Full-width notification bar anchored to top or bottom. Auto-dismisses
|
|
3042
|
+
after 5 seconds. Supports custom buttons and headlines.
|
|
3043
|
+
</p>
|
|
3044
|
+
|
|
3045
|
+
<div class="demo-grid">
|
|
3046
|
+
<div class="demo-card">
|
|
3047
|
+
<div class="card-body">
|
|
3048
|
+
<h3>Themed shortcuts</h3>
|
|
3049
|
+
<p class="desc">
|
|
3050
|
+
One arg: <code>Fnon.Breaking.Theme(headline)</code>.
|
|
3051
|
+
Auto-dismisses after 5s.
|
|
3052
|
+
</p>
|
|
3053
|
+
<div class="card-actions">
|
|
3054
|
+
<button
|
|
3055
|
+
class="dan"
|
|
3056
|
+
onclick="Fnon.Breaking.Danger('Breaking news')"
|
|
3057
|
+
>
|
|
3058
|
+
Danger
|
|
3059
|
+
</button>
|
|
3060
|
+
<button
|
|
3061
|
+
class="suc"
|
|
3062
|
+
onclick="Fnon.Breaking.Success('Good news!')"
|
|
3063
|
+
>
|
|
3064
|
+
Success
|
|
3065
|
+
</button>
|
|
3066
|
+
<button class="war" onclick="Fnon.Breaking.Warning('Heads up')">
|
|
3067
|
+
Warning
|
|
3068
|
+
</button>
|
|
3069
|
+
<button class="pri" onclick="Fnon.Breaking.Primary('Notice')">
|
|
3070
|
+
Primary
|
|
3071
|
+
</button>
|
|
3072
|
+
</div>
|
|
3073
|
+
</div>
|
|
3074
|
+
<div class="code">
|
|
3075
|
+
<span class="kw">Fnon</span>.Breaking.Danger(<span class="str"
|
|
3076
|
+
>'Breaking news'</span
|
|
3077
|
+
>)
|
|
3078
|
+
</div>
|
|
3079
|
+
</div>
|
|
3080
|
+
|
|
3081
|
+
<div class="demo-card">
|
|
3082
|
+
<div class="card-body">
|
|
3083
|
+
<h3>Full options + bottom anchor</h3>
|
|
3084
|
+
<p class="desc">
|
|
3085
|
+
headline, message, theme, anchor, buttons, timeout, closable,
|
|
3086
|
+
onClose.
|
|
3087
|
+
</p>
|
|
3088
|
+
<div class="card-actions">
|
|
3089
|
+
<button
|
|
3090
|
+
onclick="
|
|
3091
|
+
Fnon.Breaking({
|
|
3092
|
+
headline: 'BOTTOM',
|
|
3093
|
+
message: 'Bottom anchored!',
|
|
3094
|
+
anchor: 'bottom',
|
|
3095
|
+
theme: 'Success',
|
|
3096
|
+
timeout: 4000,
|
|
3097
|
+
})
|
|
3098
|
+
"
|
|
3099
|
+
>
|
|
3100
|
+
Bottom (4s)
|
|
3101
|
+
</button>
|
|
3102
|
+
<button
|
|
3103
|
+
onclick="
|
|
3104
|
+
Fnon.Breaking({
|
|
3105
|
+
headline: 'ACTIONS',
|
|
3106
|
+
message: 'With buttons',
|
|
3107
|
+
buttons: [
|
|
3108
|
+
{
|
|
3109
|
+
text: 'Click',
|
|
3110
|
+
style: 'Danger',
|
|
3111
|
+
callback: (c) => {
|
|
3112
|
+
Fnon.Hint.Info('Clicked!');
|
|
3113
|
+
},
|
|
3114
|
+
},
|
|
3115
|
+
],
|
|
3116
|
+
timeout: 6000,
|
|
3117
|
+
})
|
|
3118
|
+
"
|
|
3119
|
+
>
|
|
3120
|
+
+ Buttons (6s)
|
|
3121
|
+
</button>
|
|
3122
|
+
</div>
|
|
3123
|
+
</div>
|
|
3124
|
+
<div class="code">
|
|
3125
|
+
<span class="kw">Fnon</span>.Breaking({
|
|
3126
|
+
<span class="str">headline</span>:
|
|
3127
|
+
<span class="str">'BOTTOM'</span>,
|
|
3128
|
+
<span class="str">anchor</span>:
|
|
3129
|
+
<span class="str">'bottom'</span> })
|
|
3130
|
+
</div>
|
|
3131
|
+
</div>
|
|
3132
|
+
|
|
3133
|
+
<div class="demo-card">
|
|
3134
|
+
<div class="card-body">
|
|
3135
|
+
<h3>.Async + .Init</h3>
|
|
3136
|
+
<p class="desc">
|
|
3137
|
+
<code>.Async</code> resolves when bar closes.
|
|
3138
|
+
<code>.Init</code> changes global defaults.
|
|
3139
|
+
</p>
|
|
3140
|
+
<div class="card-actions">
|
|
3141
|
+
<button
|
|
3142
|
+
class="pri"
|
|
3143
|
+
onclick="
|
|
3144
|
+
(async () => {
|
|
3145
|
+
await Fnon.Breaking.Danger.Async('Resolved!');
|
|
3146
|
+
Fnon.Hint.Success('Closed!');
|
|
3147
|
+
})()
|
|
3148
|
+
"
|
|
3149
|
+
>
|
|
3150
|
+
Breaking.Async
|
|
3151
|
+
</button>
|
|
3152
|
+
<button
|
|
3153
|
+
onclick="
|
|
3154
|
+
Fnon.Breaking.Init({
|
|
3155
|
+
headline: 'ALERT',
|
|
3156
|
+
theme: 'Warning',
|
|
3157
|
+
timeout: 3000,
|
|
3158
|
+
});
|
|
3159
|
+
Fnon.Breaking('Defaults changed!');
|
|
3160
|
+
"
|
|
3161
|
+
>
|
|
3162
|
+
Apply .Init
|
|
3163
|
+
</button>
|
|
3164
|
+
<button
|
|
3165
|
+
onclick="
|
|
3166
|
+
Fnon.Breaking.Init({
|
|
3167
|
+
headline: 'BREAKING',
|
|
3168
|
+
theme: 'Danger',
|
|
3169
|
+
timeout: 5000,
|
|
3170
|
+
});
|
|
3171
|
+
Fnon.Hint.Info('Reset');
|
|
3172
|
+
"
|
|
3173
|
+
>
|
|
3174
|
+
Reset
|
|
3175
|
+
</button>
|
|
3176
|
+
</div>
|
|
3177
|
+
</div>
|
|
3178
|
+
<div class="code">
|
|
3179
|
+
<span class="kw">Fnon</span>.Breaking.<span class="fn">Init</span
|
|
3180
|
+
>({ <span class="str">headline</span>:
|
|
3181
|
+
<span class="str">'ALERT'</span> })
|
|
3182
|
+
</div>
|
|
3183
|
+
</div>
|
|
3184
|
+
</div>
|
|
3185
|
+
|
|
3186
|
+
<div class="ref-section">
|
|
3187
|
+
<h3>BreakingOptions</h3>
|
|
3188
|
+
<table class="ref-table">
|
|
3189
|
+
<tr>
|
|
3190
|
+
<th>Option</th>
|
|
3191
|
+
<th>Default</th>
|
|
3192
|
+
<th>Type</th>
|
|
3193
|
+
<th>Description</th>
|
|
3194
|
+
</tr>
|
|
3195
|
+
<tr>
|
|
3196
|
+
<td>headline</td>
|
|
3197
|
+
<td>'BREAKING'</td>
|
|
3198
|
+
<td>string</td>
|
|
3199
|
+
<td>Bold label text</td>
|
|
3200
|
+
</tr>
|
|
3201
|
+
<tr>
|
|
3202
|
+
<td>message</td>
|
|
3203
|
+
<td>—</td>
|
|
3204
|
+
<td>string | HTMLElement</td>
|
|
3205
|
+
<td>Body content</td>
|
|
3206
|
+
</tr>
|
|
3207
|
+
<tr>
|
|
3208
|
+
<td>theme</td>
|
|
3209
|
+
<td>'Danger'</td>
|
|
3210
|
+
<td>ThemeName</td>
|
|
3211
|
+
<td>Color scheme</td>
|
|
3212
|
+
</tr>
|
|
3213
|
+
<tr>
|
|
3214
|
+
<td>anchor</td>
|
|
3215
|
+
<td>'top'</td>
|
|
3216
|
+
<td>'top' | 'bottom'</td>
|
|
3217
|
+
<td>Where the bar attaches</td>
|
|
3218
|
+
</tr>
|
|
3219
|
+
<tr>
|
|
3220
|
+
<td>timeout</td>
|
|
3221
|
+
<td>5000</td>
|
|
3222
|
+
<td>number (ms)</td>
|
|
3223
|
+
<td>Auto-dismiss after N ms</td>
|
|
3224
|
+
</tr>
|
|
3225
|
+
<tr>
|
|
3226
|
+
<td>closable</td>
|
|
3227
|
+
<td>true</td>
|
|
3228
|
+
<td>boolean</td>
|
|
3229
|
+
<td>Show/hide the X button</td>
|
|
3230
|
+
</tr>
|
|
3231
|
+
<tr>
|
|
3232
|
+
<td>buttons</td>
|
|
3233
|
+
<td>—</td>
|
|
3234
|
+
<td>ButtonDef[]</td>
|
|
3235
|
+
<td>Action buttons in the bar</td>
|
|
3236
|
+
</tr>
|
|
3237
|
+
<tr>
|
|
3238
|
+
<td>fontFamily</td>
|
|
3239
|
+
<td>'Quicksand', sans-serif</td>
|
|
3240
|
+
<td>string</td>
|
|
3241
|
+
<td>Font family</td>
|
|
3242
|
+
</tr>
|
|
3243
|
+
<tr>
|
|
3244
|
+
<td>appendTarget</td>
|
|
3245
|
+
<td>'body'</td>
|
|
3246
|
+
<td>string | HTMLElement</td>
|
|
3247
|
+
<td>Mount container</td>
|
|
3248
|
+
</tr>
|
|
3249
|
+
<tr>
|
|
3250
|
+
<td>onClose</td>
|
|
3251
|
+
<td>—</td>
|
|
3252
|
+
<td>() => void</td>
|
|
3253
|
+
<td>Called when bar closes</td>
|
|
3254
|
+
</tr>
|
|
3255
|
+
</table>
|
|
3256
|
+
</div>
|
|
3257
|
+
|
|
3258
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
3259
|
+
<strong>Async:</strong>
|
|
3260
|
+
<code>Fnon.Breaking.Theme.Async(message?, headline?)</code> returns
|
|
3261
|
+
<code>Promise<void></code> that resolves when the bar is closed
|
|
3262
|
+
(auto-dismiss or manual).
|
|
3263
|
+
</p>
|
|
3264
|
+
|
|
3265
|
+
<div class="sandbox">
|
|
3266
|
+
<h3>Sandbox — Breaking</h3>
|
|
3267
|
+
<p>Configure a breaking notification bar.</p>
|
|
3268
|
+
<div class="sandbox-grid">
|
|
3269
|
+
<div class="sandbox-row">
|
|
3270
|
+
<label>Headline</label>
|
|
3271
|
+
<input type="text" id="breaking-headline" value="BREAKING" />
|
|
3272
|
+
</div>
|
|
3273
|
+
<div class="sandbox-row">
|
|
3274
|
+
<label>Message</label>
|
|
3275
|
+
<input
|
|
3276
|
+
type="text"
|
|
3277
|
+
id="breaking-msg"
|
|
3278
|
+
value="This is a breaking notification!"
|
|
3279
|
+
/>
|
|
3280
|
+
</div>
|
|
3281
|
+
<div class="sandbox-row">
|
|
3282
|
+
<label>Theme</label>
|
|
3283
|
+
<select id="breaking-theme">
|
|
3284
|
+
<option>Danger</option>
|
|
3285
|
+
<option>Primary</option>
|
|
3286
|
+
<option>Success</option>
|
|
3287
|
+
<option>Warning</option>
|
|
3288
|
+
<option>Info</option>
|
|
3289
|
+
<option>Light</option>
|
|
3290
|
+
<option>Dark</option>
|
|
3291
|
+
</select>
|
|
3292
|
+
</div>
|
|
3293
|
+
<div class="sandbox-row">
|
|
3294
|
+
<label>Anchor</label>
|
|
3295
|
+
<select id="breaking-anchor">
|
|
3296
|
+
<option>top</option>
|
|
3297
|
+
<option>bottom</option>
|
|
3298
|
+
</select>
|
|
3299
|
+
</div>
|
|
3300
|
+
<div class="sandbox-row">
|
|
3301
|
+
<label>Timeout (ms)</label>
|
|
3302
|
+
<input type="number" id="breaking-timeout" value="5000" />
|
|
3303
|
+
</div>
|
|
3304
|
+
<div class="sandbox-row">
|
|
3305
|
+
<div class="chk-row">
|
|
3306
|
+
<input type="checkbox" id="breaking-closable" checked /><label
|
|
3307
|
+
for="breaking-closable"
|
|
3308
|
+
>Closable (show X button)</label
|
|
3309
|
+
>
|
|
3310
|
+
</div>
|
|
3311
|
+
</div>
|
|
3312
|
+
</div>
|
|
3313
|
+
<div class="sandbox-actions">
|
|
3314
|
+
<button class="pri" onclick="runBreakingSandbox()">
|
|
3315
|
+
Run Breaking
|
|
3316
|
+
</button>
|
|
3317
|
+
</div>
|
|
3318
|
+
</div>
|
|
3319
|
+
</section>
|
|
3320
|
+
|
|
3321
|
+
<!-- ══════════════════════════ DATEPICKER ══════════════════════════ -->
|
|
3322
|
+
<section id="datepicker">
|
|
3323
|
+
<h2>
|
|
3324
|
+
8. DatePicker
|
|
3325
|
+
<span class="badge">Fnon.DatePicker(opts) · Fnon.DP(opts)</span>
|
|
3326
|
+
</h2>
|
|
3327
|
+
<p class="section-desc">
|
|
3328
|
+
A modal date picker with month/year selector, range mode, optional
|
|
3329
|
+
time picker, and min/max constraints. Returns a Promise.
|
|
3330
|
+
</p>
|
|
3331
|
+
|
|
3332
|
+
<div class="demo-grid">
|
|
3333
|
+
<div class="demo-card">
|
|
3334
|
+
<div class="card-body">
|
|
3335
|
+
<h3>Single Date</h3>
|
|
3336
|
+
<p class="desc">
|
|
3337
|
+
Click a date → resolves immediately. Toggle dark mode first
|
|
3338
|
+
to test dark theme support.
|
|
3339
|
+
</p>
|
|
3340
|
+
<div class="card-actions">
|
|
3341
|
+
<button
|
|
3342
|
+
class="pri"
|
|
3343
|
+
onclick="
|
|
3344
|
+
Fnon.DatePicker({ title: 'Pick a date' })
|
|
3345
|
+
.then((d) => Fnon.Hint.Success(d.toLocaleDateString()))
|
|
3346
|
+
.catch(() => Fnon.Hint.Info('Cancelled'))
|
|
3347
|
+
"
|
|
3348
|
+
>
|
|
3349
|
+
Pick Date
|
|
3350
|
+
</button>
|
|
3351
|
+
<button
|
|
3352
|
+
onclick="
|
|
3353
|
+
Fnon.DatePicker({
|
|
3354
|
+
withTime: true,
|
|
3355
|
+
title: 'Select Date & Time',
|
|
3356
|
+
})
|
|
3357
|
+
.then((d) => Fnon.Hint.Success(d.toLocaleString()))
|
|
3358
|
+
.catch(() => Fnon.Hint.Info('Cancelled'))
|
|
3359
|
+
"
|
|
3360
|
+
>
|
|
3361
|
+
Date + Time
|
|
3362
|
+
</button>
|
|
3363
|
+
</div>
|
|
3364
|
+
</div>
|
|
3365
|
+
<div class="code">
|
|
3366
|
+
<span class="kw">Fnon</span>.<span class="fn">DatePicker</span>({
|
|
3367
|
+
<span class="str">title</span>:
|
|
3368
|
+
<span class="str">'Pick a date'</span> }) .<span class="fn"
|
|
3369
|
+
>then</span
|
|
3370
|
+
>(<span class="pr">d</span> <span class="kw">=></span>
|
|
3371
|
+
<span class="fn">console</span>.<span class="fn">log</span>(<span
|
|
3372
|
+
class="pr"
|
|
3373
|
+
>d</span
|
|
3374
|
+
>)) .<span class="fn">catch</span>(()
|
|
3375
|
+
<span class="kw">=></span>
|
|
3376
|
+
<span class="fn">console</span>.<span class="fn">log</span>(<span
|
|
3377
|
+
class="str"
|
|
3378
|
+
>'cancelled'</span
|
|
3379
|
+
>))
|
|
3380
|
+
</div>
|
|
3381
|
+
</div>
|
|
3382
|
+
|
|
3383
|
+
<div class="demo-card">
|
|
3384
|
+
<div class="card-body">
|
|
3385
|
+
<h3>Date Range</h3>
|
|
3386
|
+
<p class="desc">
|
|
3387
|
+
Click start date, then end date. Promise resolves with
|
|
3388
|
+
<code>{ start, end }</code>.
|
|
3389
|
+
</p>
|
|
3390
|
+
<div class="card-actions">
|
|
3391
|
+
<button
|
|
3392
|
+
class="pri"
|
|
3393
|
+
onclick="
|
|
3394
|
+
Fnon.DatePicker({ dateRange: true, title: 'Select Range' })
|
|
3395
|
+
.then((r) =>
|
|
3396
|
+
Fnon.Hint.Success(
|
|
3397
|
+
r.start.toLocaleDateString() +
|
|
3398
|
+
' — ' +
|
|
3399
|
+
r.end.toLocaleDateString(),
|
|
3400
|
+
),
|
|
3401
|
+
)
|
|
3402
|
+
.catch(() => Fnon.Hint.Info('Cancelled'))
|
|
3403
|
+
"
|
|
3404
|
+
>
|
|
3405
|
+
Pick Range
|
|
3406
|
+
</button>
|
|
3407
|
+
</div>
|
|
3408
|
+
</div>
|
|
3409
|
+
<div class="code">
|
|
3410
|
+
<span class="kw">Fnon</span>.<span class="fn">DatePicker</span>({
|
|
3411
|
+
<span class="str">dateRange</span>:
|
|
3412
|
+
<span class="num">true</span> }) .<span class="fn">then</span
|
|
3413
|
+
>(<span class="pr">r</span> <span class="kw">=></span>
|
|
3414
|
+
<span class="fn">console</span>.<span class="fn">log</span>(<span
|
|
3415
|
+
class="pr"
|
|
3416
|
+
>r</span
|
|
3417
|
+
>.<span class="pr">start</span>, <span class="pr">r</span>.<span
|
|
3418
|
+
class="pr"
|
|
3419
|
+
>end</span
|
|
3420
|
+
>))
|
|
3421
|
+
</div>
|
|
3422
|
+
</div>
|
|
3423
|
+
|
|
3424
|
+
<div class="demo-card">
|
|
3425
|
+
<div class="card-body">
|
|
3426
|
+
<h3>Constrained</h3>
|
|
3427
|
+
<p class="desc">
|
|
3428
|
+
Only dates within a range are selectable (<code>minDate</code> /
|
|
3429
|
+
<code>maxDate</code>).
|
|
3430
|
+
</p>
|
|
3431
|
+
<div class="card-actions">
|
|
3432
|
+
<button
|
|
3433
|
+
onclick="
|
|
3434
|
+
var n = new Date();
|
|
3435
|
+
Fnon.DatePicker({
|
|
3436
|
+
initDate: n,
|
|
3437
|
+
minDate: new Date(n.getFullYear(), n.getMonth(), 1),
|
|
3438
|
+
maxDate: new Date(n.getFullYear(), n.getMonth() + 1, 0),
|
|
3439
|
+
title: 'This month only',
|
|
3440
|
+
})
|
|
3441
|
+
.then((d) => Fnon.Hint.Success(d.toLocaleDateString()))
|
|
3442
|
+
.catch(() => Fnon.Hint.Info('Cancelled'));
|
|
3443
|
+
"
|
|
3444
|
+
>
|
|
3445
|
+
This Month Only
|
|
3446
|
+
</button>
|
|
3447
|
+
</div>
|
|
3448
|
+
</div>
|
|
3449
|
+
<div class="code">
|
|
3450
|
+
<span class="kw">Fnon</span>.<span class="fn">DatePicker</span>({
|
|
3451
|
+
<span class="str">minDate</span>: <span class="kw">new</span>
|
|
3452
|
+
<span class="fn">Date</span>(<span class="str">'2026-01-01'</span
|
|
3453
|
+
>), <span class="str">maxDate</span>: <span class="kw">new</span>
|
|
3454
|
+
<span class="fn">Date</span>(<span class="str">'2026-12-31'</span
|
|
3455
|
+
>) })
|
|
3456
|
+
</div>
|
|
3457
|
+
</div>
|
|
3458
|
+
</div>
|
|
3459
|
+
|
|
3460
|
+
<div class="ref-section">
|
|
3461
|
+
<h3>DatePickerOptions</h3>
|
|
3462
|
+
<pre>
|
|
3463
|
+
{
|
|
3464
|
+
<span style="color:#63b3ed">initDate</span>: <span style="color:#9ae6b4">Date</span> <span style="color:#6b7280">// Initial month to show (default: today)</span>
|
|
3465
|
+
<span style="color:#63b3ed">dateRange</span>: <span style="color:#9ae6b4">boolean</span> <span style="color:#6b7280">// Enable range mode (default: false)</span>
|
|
3466
|
+
<span style="color:#63b3ed">withTime</span>: <span style="color:#9ae6b4">boolean</span> <span style="color:#6b7280">// Show time picker after date selection (default: false)</span>
|
|
3467
|
+
<span style="color:#63b3ed">minDate</span>: <span style="color:#9ae6b4">Date</span> <span style="color:#6b7280">// Earliest selectable date</span>
|
|
3468
|
+
<span style="color:#63b3ed">maxDate</span>: <span style="color:#9ae6b4">Date</span> <span style="color:#6b7280">// Latest selectable date</span>
|
|
3469
|
+
<span style="color:#63b3ed">title</span>: <span style="color:#9ae6b4">string</span> <span style="color:#6b7280">// Modal title</span>
|
|
3470
|
+
<span style="color:#63b3ed">isDark</span>: <span style="color:#9ae6b4">boolean|()=>boolean</span> <span style="color:#6b7280">// Enable dark mode for this instance</span>
|
|
3471
|
+
}
|
|
3472
|
+
</pre>
|
|
3473
|
+
</div>
|
|
3474
|
+
|
|
3475
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
3476
|
+
<strong>Async:</strong> Always async — returns
|
|
3477
|
+
<code>Promise<Date | { start: Date; end: Date }></code>. Rejects
|
|
3478
|
+
when the modal is closed without selecting. Also available as
|
|
3479
|
+
<code>Fnon.DP(opts)</code>.
|
|
3480
|
+
</p>
|
|
3481
|
+
|
|
3482
|
+
<div class="sandbox">
|
|
3483
|
+
<h3>Sandbox — DatePicker</h3>
|
|
3484
|
+
<p>Configure and run a DatePicker instance.</p>
|
|
3485
|
+
<div class="sandbox-grid">
|
|
3486
|
+
<div class="sandbox-row">
|
|
3487
|
+
<label for="dp-title">Title</label>
|
|
3488
|
+
<input type="text" id="dp-title" value="Select a Date" />
|
|
3489
|
+
</div>
|
|
3490
|
+
<div class="sandbox-row">
|
|
3491
|
+
<div class="chk-row">
|
|
3492
|
+
<input type="checkbox" id="dp-range" /><label for="dp-range"
|
|
3493
|
+
>Date range mode</label
|
|
3494
|
+
>
|
|
3495
|
+
</div>
|
|
3496
|
+
</div>
|
|
3497
|
+
<div class="sandbox-row">
|
|
3498
|
+
<div class="chk-row">
|
|
3499
|
+
<input type="checkbox" id="dp-time" /><label for="dp-time"
|
|
3500
|
+
>With time picker</label
|
|
3501
|
+
>
|
|
3502
|
+
</div>
|
|
3503
|
+
</div>
|
|
3504
|
+
<div class="sandbox-row">
|
|
3505
|
+
<label for="dp-min">Min date (YYYY-MM-DD, optional)</label>
|
|
3506
|
+
<input type="date" id="dp-min" />
|
|
3507
|
+
</div>
|
|
3508
|
+
<div class="sandbox-row">
|
|
3509
|
+
<label for="dp-max">Max date (YYYY-MM-DD, optional)</label>
|
|
3510
|
+
<input type="date" id="dp-max" />
|
|
3511
|
+
</div>
|
|
3512
|
+
</div>
|
|
3513
|
+
<div class="sandbox-actions">
|
|
3514
|
+
<button class="pri" onclick="runDpSandbox()">
|
|
3515
|
+
Open DatePicker
|
|
3516
|
+
</button>
|
|
3517
|
+
</div>
|
|
3518
|
+
</div>
|
|
3519
|
+
</section>
|
|
3520
|
+
|
|
3521
|
+
<!-- ══════════════════════════ CONTEXT MENU ══════════════════════════ -->
|
|
3522
|
+
<section id="contextmenu">
|
|
3523
|
+
<h2>
|
|
3524
|
+
9. ContextMenu
|
|
3525
|
+
<span class="badge">Fnon.ContextMenu(event, items[], globalOnClick?)</span>
|
|
3526
|
+
</h2>
|
|
3527
|
+
<p class="section-desc">
|
|
3528
|
+
Right-click or programmatic context menu with nested submenus,
|
|
3529
|
+
keyboard navigation, viewport-aware positioning, and dark mode support.
|
|
3530
|
+
</p>
|
|
3531
|
+
|
|
3532
|
+
<div class="demo-grid">
|
|
3533
|
+
<div class="demo-card">
|
|
3534
|
+
<div class="card-body" style="text-align: center;">
|
|
3535
|
+
<h3>Right-click anywhere</h3>
|
|
3536
|
+
<p class="desc">
|
|
3537
|
+
Right-click (or Ctrl+click) on this card to open the context menu.
|
|
3538
|
+
Try submenus and keyboard navigation (Arrow keys, Enter, Escape).
|
|
3539
|
+
</p>
|
|
3540
|
+
<div class="card-actions" style="justify-content: center;">
|
|
3541
|
+
<button class="pri" onclick="openContextMenu(event)">
|
|
3542
|
+
Open Context Menu
|
|
3543
|
+
</button>
|
|
3544
|
+
<button onclick="openContextMenuDark(event)">
|
|
3545
|
+
Dark menu
|
|
3546
|
+
</button>
|
|
3547
|
+
</div>
|
|
3548
|
+
</div>
|
|
3549
|
+
<div class="code">
|
|
3550
|
+
<span class="kw">Fnon</span>.<span class="fn">ContextMenu</span>(event, [
|
|
3551
|
+
<br /> { <span class="str">text</span>: <span class="str">'Edit'</span>, <span class="fn">onClick</span>: () => {} },
|
|
3552
|
+
<br /> { <span class="str">text</span>: <span class="str">'Share'</span>,
|
|
3553
|
+
<br /> <span class="str">items</span>: [
|
|
3554
|
+
<br /> { <span class="str">text</span>: <span class="str">'Twitter'</span> },
|
|
3555
|
+
<br /> { <span class="str">text</span>: <span class="str">'Facebook'</span> },
|
|
3556
|
+
<br /> ] },
|
|
3557
|
+
<br /> { <span class="str">text</span>: <span class="str">'Delete'</span>, <span class="str">disabled</span>: <span class="pr">true</span> },
|
|
3558
|
+
<br />])
|
|
3559
|
+
</div>
|
|
3560
|
+
</div>
|
|
3561
|
+
</div>
|
|
3562
|
+
|
|
3563
|
+
<div class="ref-section">
|
|
3564
|
+
<h3>ContextMenuItem</h3>
|
|
3565
|
+
<table class="ref-table">
|
|
3566
|
+
<tr>
|
|
3567
|
+
<th>Prop</th>
|
|
3568
|
+
<th>Type</th>
|
|
3569
|
+
<th>Default</th>
|
|
3570
|
+
<th>Description</th>
|
|
3571
|
+
</tr>
|
|
3572
|
+
<tr>
|
|
3573
|
+
<td>label</td>
|
|
3574
|
+
<td>string</td>
|
|
3575
|
+
<td>—</td>
|
|
3576
|
+
<td>Menu item text</td>
|
|
3577
|
+
</tr>
|
|
3578
|
+
<tr>
|
|
3579
|
+
<td>onClick</td>
|
|
3580
|
+
<td>() => void</td>
|
|
3581
|
+
<td>—</td>
|
|
3582
|
+
<td>Called when item is chosen. Ignored if <code>items</code> is set.</td>
|
|
3583
|
+
</tr>
|
|
3584
|
+
<tr>
|
|
3585
|
+
<td>items</td>
|
|
3586
|
+
<td>ContextMenuItem[]</td>
|
|
3587
|
+
<td>—</td>
|
|
3588
|
+
<td>Nested submenu (takes priority over onClick)</td>
|
|
3589
|
+
</tr>
|
|
3590
|
+
<tr>
|
|
3591
|
+
<td>disabled</td>
|
|
3592
|
+
<td>boolean</td>
|
|
3593
|
+
<td>false</td>
|
|
3594
|
+
<td>Gray out and prevent interaction</td>
|
|
3595
|
+
</tr>
|
|
3596
|
+
<tr>
|
|
3597
|
+
<td>divider</td>
|
|
3598
|
+
<td>boolean</td>
|
|
3599
|
+
<td>false</td>
|
|
3600
|
+
<td>Render as a visual separator</td>
|
|
3601
|
+
</tr>
|
|
3602
|
+
<tr>
|
|
3603
|
+
<td>icon</td>
|
|
3604
|
+
<td>string</td>
|
|
3605
|
+
<td>—</td>
|
|
3606
|
+
<td>Optional icon HTML (e.g. SVG) prepended to label</td>
|
|
3607
|
+
</tr>
|
|
3608
|
+
</table>
|
|
3609
|
+
</div>
|
|
3610
|
+
|
|
3611
|
+
<p style="font-size: 0.82rem; color: #718096; margin: 0.5rem 0">
|
|
3612
|
+
<strong>Keyboard:</strong> Arrow keys to navigate, Enter/Space to select,
|
|
3613
|
+
Escape to close, ArrowRight to open submenu, ArrowLeft to close submenu.
|
|
3614
|
+
<strong>Alias:</strong> <code>Fnon.CM(event, items, globalOnClick?)</code>
|
|
3615
|
+
</p>
|
|
3616
|
+
</section>
|
|
3617
|
+
|
|
3618
|
+
<hr />
|
|
3619
|
+
<footer>
|
|
3620
|
+
Fnon.js v2.0.0 — Interactive Playground · MIT License
|
|
3621
|
+
·
|
|
3622
|
+
<a
|
|
3623
|
+
href="https://github.com/anomalyco/fnon"
|
|
3624
|
+
target="_blank"
|
|
3625
|
+
style="color: #029eff"
|
|
3626
|
+
>GitHub</a
|
|
3627
|
+
>
|
|
3628
|
+
</footer>
|
|
3629
|
+
</div>
|
|
3630
|
+
|
|
3631
|
+
<script src="fnon.es.js"></script>
|
|
3632
|
+
<script src="fnon.min.js"></script>
|
|
3633
|
+
<script>
|
|
3634
|
+
// ── Helper: get value or undefined ──
|
|
3635
|
+
function val(id) {
|
|
3636
|
+
var e = document.getElementById(id);
|
|
3637
|
+
return e ? e.value : undefined;
|
|
3638
|
+
}
|
|
3639
|
+
function num(id) {
|
|
3640
|
+
var v = parseFloat(val(id));
|
|
3641
|
+
return isNaN(v) ? undefined : v;
|
|
3642
|
+
}
|
|
3643
|
+
function chk(id) {
|
|
3644
|
+
var e = document.getElementById(id);
|
|
3645
|
+
return e ? e.checked : false;
|
|
3646
|
+
}
|
|
3647
|
+
function themeFn(theme) {
|
|
3648
|
+
return Fnon.Hint[theme] || Fnon.Hint.Primary;
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
// ── Hint sandbox ──
|
|
3652
|
+
function runHintSandbox() {
|
|
3653
|
+
var theme = val("hint-theme") || "Primary";
|
|
3654
|
+
var msg = val("hint-msg") || "Hello!";
|
|
3655
|
+
var opts = {};
|
|
3656
|
+
var title = val("hint-title");
|
|
3657
|
+
if (title) opts.title = title;
|
|
3658
|
+
var pos = val("hint-position");
|
|
3659
|
+
if (pos) opts.position = pos;
|
|
3660
|
+
var to = num("hint-timeout");
|
|
3661
|
+
if (to !== undefined) opts.timeOut = to;
|
|
3662
|
+
opts.closable = chk("hint-closable");
|
|
3663
|
+
var w = val("hint-width");
|
|
3664
|
+
if (w) opts.width = w;
|
|
3665
|
+
var fs = val("hint-fontsize");
|
|
3666
|
+
if (fs) opts.fontSize = fs;
|
|
3667
|
+
var pc = val("hint-progresscolor");
|
|
3668
|
+
if (pc) opts.progressColor = pc;
|
|
3669
|
+
Fnon.Hint[theme](msg, opts);
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3672
|
+
// ── Wait sandbox ──
|
|
3673
|
+
function runWaitSandbox() {
|
|
3674
|
+
var type = val("wait-type") || "Orbit";
|
|
3675
|
+
var text = val("wait-text") || "";
|
|
3676
|
+
var opts = {};
|
|
3677
|
+
var sc = val("wait-svgcolor");
|
|
3678
|
+
if (sc) opts.svgColor = sc;
|
|
3679
|
+
var cs = val("wait-containersize");
|
|
3680
|
+
if (cs) opts.containerSize = cs;
|
|
3681
|
+
var ff = val("wait-fontfamily");
|
|
3682
|
+
if (ff) opts.fontFamily = ff;
|
|
3683
|
+
opts.clickToClose = chk("wait-clicktoclose");
|
|
3684
|
+
Fnon.Wait[type](text, opts);
|
|
3685
|
+
}
|
|
3686
|
+
|
|
3687
|
+
// ── Box sandbox ──
|
|
3688
|
+
function runBoxSandbox() {
|
|
3689
|
+
var type = val("box-type") || "Orbit";
|
|
3690
|
+
var sel = val("box-selector") || "#box-target";
|
|
3691
|
+
var text = val("box-text") || "";
|
|
3692
|
+
var opts = {};
|
|
3693
|
+
var sc = val("box-svgcolor");
|
|
3694
|
+
if (sc) opts.svgColor = sc;
|
|
3695
|
+
var sw = num("box-svgw");
|
|
3696
|
+
var sh = num("box-svgh");
|
|
3697
|
+
if (sw !== undefined || sh !== undefined)
|
|
3698
|
+
opts.svgSize = { w: sw || 40, h: sh || 40 };
|
|
3699
|
+
Fnon.Box[type](sel, text, Object.keys(opts).length ? opts : undefined);
|
|
3700
|
+
}
|
|
3701
|
+
|
|
3702
|
+
// ── Alert sandbox ──
|
|
3703
|
+
function runAlertSandbox() {
|
|
3704
|
+
var theme = val("alert-theme") || "Primary";
|
|
3705
|
+
var msg = val("alert-msg") || "Hello!";
|
|
3706
|
+
var opts = { message: msg };
|
|
3707
|
+
var title = val("alert-title");
|
|
3708
|
+
if (title) opts.title = title;
|
|
3709
|
+
var btn = val("alert-btnok");
|
|
3710
|
+
if (btn) opts.btnOkText = btn;
|
|
3711
|
+
var w = val("alert-width");
|
|
3712
|
+
if (w) opts.width = w;
|
|
3713
|
+
var ff = val("alert-fontfamily");
|
|
3714
|
+
if (ff) opts.fontFamily = ff;
|
|
3715
|
+
opts.closeButton = chk("alert-showclose");
|
|
3716
|
+
opts.autoFocus = chk("alert-autofocus");
|
|
3717
|
+
Fnon.Alert[theme](opts);
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3720
|
+
// ── Ask sandbox ──
|
|
3721
|
+
function runAskSandbox() {
|
|
3722
|
+
var theme = val("ask-theme") || "Primary";
|
|
3723
|
+
var msg = val("ask-msg") || "Proceed?";
|
|
3724
|
+
var opts = { message: msg };
|
|
3725
|
+
var title = val("ask-title");
|
|
3726
|
+
if (title) opts.title = title;
|
|
3727
|
+
var ok = val("ask-btnok");
|
|
3728
|
+
if (ok) opts.btnOkText = ok;
|
|
3729
|
+
var cancel = val("ask-btncancel");
|
|
3730
|
+
if (cancel) opts.btnCancelText = cancel;
|
|
3731
|
+
var w = val("ask-width");
|
|
3732
|
+
if (w) opts.width = w;
|
|
3733
|
+
opts.closeButton = chk("ask-showclose");
|
|
3734
|
+
Fnon.Ask[theme](opts);
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3737
|
+
// ── Dialogue sandbox ──
|
|
3738
|
+
function runDialogueSandbox() {
|
|
3739
|
+
var msg = val("dlg-msg") || "Dialogue message";
|
|
3740
|
+
var opts = { message: msg };
|
|
3741
|
+
var title = val("dlg-title");
|
|
3742
|
+
if (title) opts.title = title;
|
|
3743
|
+
var w = val("dlg-width");
|
|
3744
|
+
if (w) opts.width = w;
|
|
3745
|
+
var lay = val("dlg-layout");
|
|
3746
|
+
if (lay) opts.layout = lay;
|
|
3747
|
+
var ff = val("dlg-fontfamily");
|
|
3748
|
+
if (ff) opts.fontFamily = ff;
|
|
3749
|
+
opts.closeButton = chk("dlg-showclose");
|
|
3750
|
+
opts.showMin = chk("dlg-showmin");
|
|
3751
|
+
opts.showMaxMin = chk("dlg-showmaxmin");
|
|
3752
|
+
opts.autoFocus = chk("dlg-autofocus");
|
|
3753
|
+
opts.buttons = [
|
|
3754
|
+
{
|
|
3755
|
+
text: "OK",
|
|
3756
|
+
style: val("dlg-theme") || "Primary",
|
|
3757
|
+
callback: function (c) {
|
|
3758
|
+
c();
|
|
3759
|
+
},
|
|
3760
|
+
},
|
|
3761
|
+
];
|
|
3762
|
+
Fnon.Dialogue(opts);
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
// ── Breaking sandbox ──
|
|
3766
|
+
function runBreakingSandbox() {
|
|
3767
|
+
var headline = val("breaking-headline") || "BREAKING";
|
|
3768
|
+
var msg = val("breaking-msg") || "Notification!";
|
|
3769
|
+
var opts = { headline: headline, message: msg };
|
|
3770
|
+
var th = val("breaking-theme");
|
|
3771
|
+
if (th) opts.theme = th;
|
|
3772
|
+
var anc = val("breaking-anchor");
|
|
3773
|
+
if (anc) opts.anchor = anc;
|
|
3774
|
+
var to = num("breaking-timeout");
|
|
3775
|
+
if (to !== undefined) opts.timeout = to;
|
|
3776
|
+
opts.closable = chk("breaking-closable");
|
|
3777
|
+
Fnon.Breaking(opts);
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3780
|
+
// ── DatePicker sandbox ──
|
|
3781
|
+
function runDpSandbox() {
|
|
3782
|
+
var title = val("dp-title") || "Select a Date";
|
|
3783
|
+
var opts = { title: title };
|
|
3784
|
+
if (chk("dp-range")) opts.dateRange = true;
|
|
3785
|
+
if (chk("dp-time")) opts.withTime = true;
|
|
3786
|
+
var min = val("dp-min");
|
|
3787
|
+
if (min) opts.minDate = new Date(min + "T00:00:00");
|
|
3788
|
+
var max = val("dp-max");
|
|
3789
|
+
if (max) opts.maxDate = new Date(max + "T00:00:00");
|
|
3790
|
+
var isDark = document.documentElement.dataset.theme === "dark";
|
|
3791
|
+
if (isDark) {
|
|
3792
|
+
opts.isDark = true;
|
|
3793
|
+
opts.darkBgColor = "#1e293b";
|
|
3794
|
+
}
|
|
3795
|
+
Fnon.DatePicker(opts)
|
|
3796
|
+
.then(function (r) {
|
|
3797
|
+
if (r && r.start) {
|
|
3798
|
+
Fnon.Hint.Success(
|
|
3799
|
+
r.start.toLocaleDateString() +
|
|
3800
|
+
" — " +
|
|
3801
|
+
r.end.toLocaleDateString(),
|
|
3802
|
+
);
|
|
3803
|
+
} else {
|
|
3804
|
+
Fnon.Hint.Success(r.toLocaleDateString());
|
|
3805
|
+
}
|
|
3806
|
+
})
|
|
3807
|
+
.catch(function () {
|
|
3808
|
+
Fnon.Hint.Info("Cancelled");
|
|
3809
|
+
});
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3812
|
+
// ── ContextMenu demo ──
|
|
3813
|
+
function openContextMenu(e) {
|
|
3814
|
+
e.preventDefault();
|
|
3815
|
+
Fnon.ContextMenu(e, [
|
|
3816
|
+
{ text: 'Rename', onClick: function() { Fnon.Hint.Success('Renamed!'); } },
|
|
3817
|
+
{ text: 'Duplicate', onClick: function() { Fnon.Hint.Primary('Duplicated'); } },
|
|
3818
|
+
{ text: 'Share', items: [
|
|
3819
|
+
{ text: 'Twitter', onClick: function() { Fnon.Hint.Info('Shared to Twitter'); } },
|
|
3820
|
+
{ text: 'Facebook', onClick: function() { Fnon.Hint.Info('Shared to Facebook'); } },
|
|
3821
|
+
{ text: 'Copy Link', onClick: function() { Fnon.Hint.Light('Link copied!'); } },
|
|
3822
|
+
]},
|
|
3823
|
+
{ text: 'Delete', disabled: true },
|
|
3824
|
+
]);
|
|
3825
|
+
}
|
|
3826
|
+
function openContextMenuDark(e) {
|
|
3827
|
+
e.preventDefault();
|
|
3828
|
+
Fnon.Init({ isDark: true, darkBgColor: '#1e293b' });
|
|
3829
|
+
Fnon.ContextMenu(e, [
|
|
3830
|
+
{ text: 'Edit', onClick: function() { Fnon.Hint.Primary('Edit'); } },
|
|
3831
|
+
{ text: 'Delete', onClick: function() { Fnon.Hint.Danger('Deleted!'); } },
|
|
3832
|
+
], function(item) {
|
|
3833
|
+
Fnon.Hint.Warning('Global: ' + item.text);
|
|
3834
|
+
});
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3837
|
+
// ── Dark/light theme toggle ──
|
|
3838
|
+
function getPreferredTheme() {
|
|
3839
|
+
const saved = localStorage.getItem("fnon-demo-theme");
|
|
3840
|
+
if (saved) return saved;
|
|
3841
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
3842
|
+
? "dark"
|
|
3843
|
+
: "light";
|
|
3844
|
+
}
|
|
3845
|
+
function syncFnonTheme(isDark) {
|
|
3846
|
+
if (typeof Fnon !== "undefined") {
|
|
3847
|
+
Fnon.Init({ isDark, darkBgColor: "#1e293b" });
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
function applyTheme(theme) {
|
|
3851
|
+
document.documentElement.dataset.theme = theme;
|
|
3852
|
+
document.getElementById("theme-toggle").textContent =
|
|
3853
|
+
theme === "dark" ? "☀️" : "🌙";
|
|
3854
|
+
localStorage.setItem("fnon-demo-theme", theme);
|
|
3855
|
+
syncFnonTheme(theme === "dark");
|
|
3856
|
+
}
|
|
3857
|
+
function toggleTheme() {
|
|
3858
|
+
const next =
|
|
3859
|
+
document.documentElement.dataset.theme === "dark" ? "light" : "dark";
|
|
3860
|
+
applyTheme(next);
|
|
3861
|
+
}
|
|
3862
|
+
applyTheme(getPreferredTheme());
|
|
3863
|
+
|
|
3864
|
+
// ── RTL/LTR direction toggle ──
|
|
3865
|
+
function syncFnonDir(dir) {
|
|
3866
|
+
if (typeof Fnon !== "undefined") {
|
|
3867
|
+
Fnon.Init({ dir });
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
function toggleRtl() {
|
|
3871
|
+
const next = document.documentElement.dir === "rtl" ? "ltr" : "rtl";
|
|
3872
|
+
document.documentElement.dir = next;
|
|
3873
|
+
document.getElementById("rtl-toggle").textContent =
|
|
3874
|
+
next === "rtl" ? "←" : "→";
|
|
3875
|
+
localStorage.setItem("fnon-demo-dir", next);
|
|
3876
|
+
syncFnonDir(next);
|
|
3877
|
+
}
|
|
3878
|
+
(function initRtl() {
|
|
3879
|
+
const saved = localStorage.getItem("fnon-demo-dir");
|
|
3880
|
+
const dir = saved || "ltr";
|
|
3881
|
+
document.documentElement.dir = dir;
|
|
3882
|
+
document.getElementById("rtl-toggle").textContent =
|
|
3883
|
+
dir === "rtl" ? "←" : "→";
|
|
3884
|
+
if (dir === "rtl") syncFnonDir("rtl");
|
|
3885
|
+
})();
|
|
3886
|
+
</script>
|
|
3887
|
+
</body>
|
|
3888
|
+
</html>
|