@jsenv/dom 0.6.0 → 0.7.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.
Files changed (109) hide show
  1. package/dist/jsenv_dom.js +262 -330
  2. package/package.json +2 -4
  3. package/index.js +0 -124
  4. package/src/attr/add_attribute_effect.js +0 -93
  5. package/src/attr/attributes.js +0 -32
  6. package/src/color/color_constrast.js +0 -69
  7. package/src/color/color_parsing.js +0 -319
  8. package/src/color/color_scheme.js +0 -28
  9. package/src/color/pick_light_or_dark.js +0 -34
  10. package/src/color/resolve_css_color.js +0 -60
  11. package/src/demos/3_columns_resize_demo.html +0 -84
  12. package/src/demos/3_rows_resize_demo.html +0 -89
  13. package/src/demos/aside_and_main_demo.html +0 -93
  14. package/src/demos/coordinates_demo.html +0 -450
  15. package/src/demos/document_autoscroll_demo.html +0 -517
  16. package/src/demos/drag_gesture_constraints_demo.html +0 -701
  17. package/src/demos/drag_gesture_demo.html +0 -1047
  18. package/src/demos/drag_gesture_element_to_impact_demo.html +0 -445
  19. package/src/demos/drag_reference_element_demo.html +0 -480
  20. package/src/demos/flex_details_set_demo.html +0 -302
  21. package/src/demos/flex_details_set_demo_2.html +0 -315
  22. package/src/demos/visible_rect_demo.html +0 -525
  23. package/src/element_signature.js +0 -100
  24. package/src/interaction/drag/constraint_feedback_line.js +0 -92
  25. package/src/interaction/drag/drag_constraint.js +0 -659
  26. package/src/interaction/drag/drag_debug_markers.js +0 -635
  27. package/src/interaction/drag/drag_element_positioner.js +0 -382
  28. package/src/interaction/drag/drag_gesture.js +0 -566
  29. package/src/interaction/drag/drag_resize_demo.html +0 -571
  30. package/src/interaction/drag/drag_to_move.js +0 -301
  31. package/src/interaction/drag/drag_to_resize_gesture.js +0 -68
  32. package/src/interaction/drag/drop_target_detection.js +0 -148
  33. package/src/interaction/drag/sticky_frontiers.js +0 -160
  34. package/src/interaction/event_marker.js +0 -14
  35. package/src/interaction/focus/active_element.js +0 -33
  36. package/src/interaction/focus/arrow_navigation.js +0 -599
  37. package/src/interaction/focus/element_is_focusable.js +0 -57
  38. package/src/interaction/focus/element_visibility.js +0 -111
  39. package/src/interaction/focus/find_focusable.js +0 -21
  40. package/src/interaction/focus/focus_group.js +0 -91
  41. package/src/interaction/focus/focus_group_registry.js +0 -12
  42. package/src/interaction/focus/focus_nav.js +0 -12
  43. package/src/interaction/focus/focus_nav_event_marker.js +0 -14
  44. package/src/interaction/focus/focus_trap.js +0 -105
  45. package/src/interaction/focus/tab_navigation.js +0 -128
  46. package/src/interaction/focus/tests/focus_group_skip_tab_test.html +0 -206
  47. package/src/interaction/focus/tests/tree_focus_test.html +0 -304
  48. package/src/interaction/focus/tests/tree_focus_test.jsx +0 -261
  49. package/src/interaction/focus/tests/tree_focus_test_preact.html +0 -13
  50. package/src/interaction/isolate_interactions.js +0 -161
  51. package/src/interaction/keyboard.js +0 -26
  52. package/src/interaction/scroll/capture_scroll.js +0 -47
  53. package/src/interaction/scroll/is_scrollable.js +0 -159
  54. package/src/interaction/scroll/scroll_container.js +0 -110
  55. package/src/interaction/scroll/scroll_trap.js +0 -44
  56. package/src/interaction/scroll/scrollbar_size.js +0 -20
  57. package/src/interaction/scroll/wheel_through.js +0 -138
  58. package/src/iterable_weak_set.js +0 -66
  59. package/src/position/dom_coords.js +0 -340
  60. package/src/position/offset_parent.js +0 -15
  61. package/src/position/position_fixed.js +0 -15
  62. package/src/position/position_sticky.js +0 -213
  63. package/src/position/sticky_rect.js +0 -79
  64. package/src/position/visible_rect.js +0 -486
  65. package/src/pub_sub.js +0 -31
  66. package/src/size/can_take_size.js +0 -11
  67. package/src/size/details_content_full_height.js +0 -63
  68. package/src/size/flex_details_set.js +0 -974
  69. package/src/size/get_available_height.js +0 -22
  70. package/src/size/get_available_width.js +0 -22
  71. package/src/size/get_border_sizes.js +0 -14
  72. package/src/size/get_height.js +0 -4
  73. package/src/size/get_inner_height.js +0 -15
  74. package/src/size/get_inner_width.js +0 -15
  75. package/src/size/get_margin_sizes.js +0 -10
  76. package/src/size/get_max_height.js +0 -57
  77. package/src/size/get_max_width.js +0 -47
  78. package/src/size/get_min_height.js +0 -14
  79. package/src/size/get_min_width.js +0 -14
  80. package/src/size/get_padding_sizes.js +0 -10
  81. package/src/size/get_width.js +0 -4
  82. package/src/size/hooks/use_available_height.js +0 -27
  83. package/src/size/hooks/use_available_width.js +0 -27
  84. package/src/size/hooks/use_max_height.js +0 -10
  85. package/src/size/hooks/use_max_width.js +0 -10
  86. package/src/size/hooks/use_resize_status.js +0 -62
  87. package/src/size/resize.js +0 -695
  88. package/src/size/resolve_css_size.js +0 -32
  89. package/src/style/dom_styles.js +0 -97
  90. package/src/style/style_composition.js +0 -121
  91. package/src/style/style_controller.js +0 -345
  92. package/src/style/style_default.js +0 -153
  93. package/src/style/style_default_demo.html +0 -128
  94. package/src/style/style_parsing.js +0 -375
  95. package/src/transition/demos/animation_resumption_test.xhtml +0 -500
  96. package/src/transition/demos/height_toggle_test.xhtml +0 -515
  97. package/src/transition/dom_transition.js +0 -254
  98. package/src/transition/easing.js +0 -48
  99. package/src/transition/group_transition.js +0 -261
  100. package/src/transition/transform_style_parser.js +0 -32
  101. package/src/transition/transition_playback.js +0 -366
  102. package/src/transition/transition_timeline.js +0 -79
  103. package/src/traversal.js +0 -247
  104. package/src/ui_transition/demos/content_states_transition_demo.html +0 -628
  105. package/src/ui_transition/demos/smooth_height_transition_demo.html +0 -149
  106. package/src/ui_transition/demos/transition_testing.html +0 -354
  107. package/src/ui_transition/ui_transition.js +0 -1491
  108. package/src/utils.js +0 -69
  109. package/src/value_effect.js +0 -35
@@ -1,628 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <title>Content States Transition Demo</title>
6
- <style>
7
- body {
8
- margin: 0;
9
- font-family: system-ui;
10
- }
11
-
12
- .page-layout {
13
- display: flex;
14
- min-height: 100vh;
15
- }
16
-
17
- .controls {
18
- padding: 20px;
19
- background: #f5f5f5;
20
- border-right: 1px solid #ccc;
21
- width: 400px;
22
- flex-shrink: 0;
23
- }
24
-
25
- .demo-container {
26
- flex-grow: 1;
27
- padding: 20px;
28
- }
29
-
30
- .demo-container h2 {
31
- margin-top: 0;
32
- color: #666;
33
- font-weight: 500;
34
- }
35
-
36
- #content-box {
37
- background: white;
38
- border: 2px solid #666;
39
- padding: 16px;
40
- margin: 20px 0;
41
- width: 300px;
42
- }
43
-
44
- /* Nested wrapper structure:
45
- - outer wrapper: manages size constraints during animations
46
- - measure wrapper: allows measuring natural content size without animation constraints
47
- - content: actual content that can change height */
48
- .ui-transition-outer-wrapper {
49
- position: relative;
50
- }
51
- .ui-transition-measure-wrapper {
52
- /* prevent margins from collapsing which would affect measurements */
53
- padding: 0.1px 0;
54
- }
55
-
56
- /* State-specific styles */
57
- .loading-state {
58
- color: #666;
59
- text-align: center;
60
- }
61
-
62
- .loading-state.tall {
63
- padding: 140px 0;
64
- }
65
-
66
- .content-state {
67
- color: #000;
68
- }
69
-
70
- .content-state[data-animate-height] {
71
- height: 0;
72
- overflow: hidden;
73
- transition: height 0.5s ease-out;
74
- }
75
-
76
- .content-state[data-animate-height].visible {
77
- height: auto;
78
- }
79
-
80
- .content-state[data-animate-height] .content-block {
81
- opacity: 0;
82
- transition: opacity 0.5s ease-out;
83
- }
84
-
85
- .content-state[data-animate-height].visible .content-block {
86
- opacity: 1;
87
- }
88
-
89
- .error-state {
90
- color: #d32f2f;
91
- text-align: center;
92
- }
93
-
94
- .error-state.tall {
95
- padding: 140px 0;
96
- }
97
-
98
- /* Shared styles */
99
- .content-block {
100
- background: #f0f0f0;
101
- margin: 8px 0;
102
- padding: 12px;
103
- transition: padding 0.3s;
104
- }
105
-
106
- .content-block[data-expanded] {
107
- padding: 32px 12px;
108
- }
109
-
110
- button {
111
- margin: 0 8px 8px 0;
112
- padding: 8px 16px;
113
- }
114
-
115
- button.active {
116
- background: #4caf50;
117
- color: white;
118
- border-color: #388e3c;
119
- }
120
-
121
- .description {
122
- color: #666;
123
- font-size: 0.9em;
124
- margin: 8px 0 16px;
125
- }
126
-
127
- .separator {
128
- height: 1px;
129
- background: #ccc;
130
- margin: 20px 0;
131
- }
132
-
133
- .speed-control {
134
- background: #fff;
135
- padding: 12px 15px;
136
- border-radius: 4px;
137
- }
138
-
139
- details.manual-control {
140
- margin-top: 20px;
141
- }
142
-
143
- details.manual-control summary {
144
- cursor: pointer;
145
- font-size: 1.17em;
146
- font-weight: bold;
147
- margin-top: 1em;
148
- }
149
-
150
- .radio-group {
151
- display: flex;
152
- gap: 20px;
153
- }
154
-
155
- .radio-group label {
156
- display: flex;
157
- align-items: center;
158
- gap: 6px;
159
- cursor: pointer;
160
- }
161
-
162
- .spinner {
163
- display: inline-block;
164
- width: 24px;
165
- height: 24px;
166
- border: 3px solid #f3f3f3;
167
- border-top: 3px solid #666;
168
- border-radius: 50%;
169
- animation: spin 1s linear infinite;
170
- margin-bottom: 8px;
171
- }
172
-
173
- @keyframes spin {
174
- 0% {
175
- transform: rotate(0deg);
176
- }
177
- 100% {
178
- transform: rotate(360deg);
179
- }
180
- }
181
- </style>
182
- </head>
183
- <body>
184
- <div class="page-layout">
185
- <div class="controls">
186
- <h3>Content Lifecycle (Same UI Key)</h3>
187
- <p class="description">
188
- Simulates loading states and errors for the same content (like a page
189
- refresh)
190
- </p>
191
- <div>
192
- <button id="demo-content-loading">Load Content</button>
193
- <button id="demo-loading-error">Loading → Error</button>
194
- <button id="demo-error-retry">Error → Loading → Content</button>
195
- <button id="demo-content-update">Update Active Content</button>
196
- <button id="demo-content-add-block">Add Content Block</button>
197
- </div>
198
-
199
- <h3 style="margin-top: 20px">Content Navigation (Different UI Keys)</h3>
200
- <p class="description">
201
- Simulates navigating between different contents
202
- </p>
203
- <div>
204
- <button id="demo-navigate-simple">Navigate: A → B</button>
205
- <button id="demo-navigate-size-change">
206
- Navigate: Small → Big Content
207
- </button>
208
- </div>
209
-
210
- <div style="margin-top: 30px">
211
- <div style="margin-bottom: 20px">
212
- <label style="display: block; margin-bottom: 8px; font-weight: 500"
213
- >Content Animation:</label
214
- >
215
- <label style="display: block">
216
- <input type="checkbox" id="animate-content-height" />
217
- Animate content height after insert
218
- </label>
219
- <p class="description" style="margin-top: 4px">
220
- When checked, content blocks will animate their height after being
221
- inserted. This helps demonstrate how height animations in content
222
- can affect transitions.
223
- </p>
224
- </div>
225
-
226
- <div style="margin-bottom: 20px">
227
- <label style="display: block; margin-bottom: 8px; font-weight: 500"
228
- >Sequence Behavior:</label
229
- >
230
- <label style="display: block">
231
- <input type="checkbox" id="preserve-between-sequences" />
232
- Preserve content between sequences
233
- </label>
234
- <p class="description" style="margin-top: 4px">
235
- When checked, the content box will maintain its state between
236
- sequence runs. When unchecked, it will reset to empty before each
237
- sequence.
238
- </p>
239
- </div>
240
-
241
- <div class="speed-control">
242
- <label style="display: block; margin-bottom: 8px; font-weight: 500"
243
- >Loading State Duration:</label
244
- >
245
- <div class="radio-group">
246
- <label>
247
- <input type="radio" name="speed" value="fast" checked />
248
- Fast (100ms)
249
- </label>
250
- <label>
251
- <input type="radio" name="speed" value="medium" /> Medium
252
- (300ms)
253
- </label>
254
- <label>
255
- <input type="radio" name="speed" value="slow" /> Slow (1s)
256
- </label>
257
- </div>
258
- </div>
259
- </div>
260
-
261
- <div class="separator"></div>
262
-
263
- <details class="manual-control">
264
- <summary>Manual Control</summary>
265
- <div style="padding-top: 10px">
266
- <div>
267
- <button id="show-loading">Loading</button>
268
- <button id="show-content">Content A</button>
269
- <button id="show-content-alt">Content B</button>
270
- <button id="show-error">Error</button>
271
- </div>
272
- <div>
273
- <button id="toggle-size">Toggle Large State Size</button>
274
- <button id="reset-content">Reset Content</button>
275
- </div>
276
- </div>
277
- </details>
278
- </div>
279
-
280
- <div class="demo-container">
281
- <h2>Content Display Area</h2>
282
- <p class="description">
283
- This area shows how the UI handles different content states and
284
- transitions. Use the controls on the left to trigger various content
285
- lifecycle and navigation scenarios.
286
- </p>
287
- <div id="content-box" class="ui_transition_container">
288
- <div class="ui_transition_outer_wrapper">
289
- <div class="ui_transition_measure_wrapper">
290
- <div class="ui_transition_slot"></div>
291
- </div>
292
- </div>
293
- <div class="ui_transition_overlay"></div>
294
- </div>
295
- </div>
296
- </div>
297
-
298
- <style>
299
- .ui-transition-container {
300
- position: relative;
301
- }
302
- .ui-transition-wrapper {
303
- position: relative;
304
- overflow: hidden;
305
- }
306
- .ui-transition-content {
307
- position: relative;
308
- width: 100%;
309
- }
310
- .ui-transition-content > * {
311
- width: 100%;
312
- }
313
- </style>
314
-
315
- <script type="module">
316
- import { initUITransition } from "../ui_transition.js";
317
-
318
- const contentBox = document.getElementById("content-box");
319
- let uiTransition = initUITransition(contentBox);
320
-
321
- const createState = (type, options = {}) => {
322
- const {
323
- tall = false,
324
- bigContent = false,
325
- contentVariant = "A",
326
- } = options;
327
-
328
- const states = {
329
- loading: (uiKey) => `
330
- <div class="loading-state ${tall ? "tall" : ""}" data-content-key="${uiKey}" data-content-phase data-ui-name="loading">
331
- <div class="spinner"></div>
332
- <div>Loading...</div>
333
- </div>
334
- `,
335
- content: (uiKey) => {
336
- const shouldAnimate = document.getElementById(
337
- "animate-content-height",
338
- )?.checked;
339
- return `
340
- <div class="content-state" data-content-key="${uiKey}" ${shouldAnimate ? "data-animate-height" : ""} data-ui-name="${uiKey}">
341
- ${
342
- contentVariant === "B"
343
- ? `
344
- <div class="content-block">Alternative content block</div>
345
- <div class="content-block">With different structure</div>
346
- ${bigContent ? `<div class="content-block">And extra content when big</div>` : ""}
347
- `
348
- : bigContent
349
- ? Array.from({ length: 6 })
350
- .map(
351
- (_, i) => `
352
- <div class="content-block">Content block ${i + 1}</div>
353
- `,
354
- )
355
- .join("")
356
- : `
357
- <div class="content-block">Content block one</div>
358
- <div class="content-block">Content block two</div>
359
- <div class="content-block">Content block three</div>
360
- `
361
- }
362
- </div>
363
- `;
364
- },
365
- error: (uiKey) => `
366
- <div class="error-state ${tall ? "tall" : ""}" data-content-key="${uiKey}" data-content-phase data-ui-name="error">
367
- <div>⚠️</div>
368
- <div>An error occurred</div>
369
- </div>
370
- `,
371
- };
372
-
373
- return states[type](options.uiKey);
374
- };
375
-
376
- // For manual control
377
- let isLargeState = false;
378
- let activeButton = document.getElementById("show-content");
379
- activeButton.classList.add("active");
380
-
381
- const resetContent = () => {
382
- // Properly cleanup the current maintainSize functionality
383
- if (uiTransition) {
384
- uiTransition.cleanup();
385
- }
386
-
387
- // Reset content without any animation
388
- const contentContainer = contentBox.querySelector(
389
- ".ui-transition-content",
390
- );
391
- if (contentContainer) {
392
- contentContainer.innerHTML = "";
393
- }
394
-
395
- // Reinstall the maintainSize functionality
396
- uiTransition = initUITransition(contentBox);
397
-
398
- // Reset active button state
399
- activeButton.classList.remove("active");
400
- activeButton = document.getElementById("show-content");
401
- activeButton.classList.add("active");
402
- };
403
-
404
- const setState = (type, options = {}) => {
405
- if (
406
- !options.skipButtonUpdate &&
407
- type in { loading: 1, content: 1, error: 1 }
408
- ) {
409
- const buttonId =
410
- type === "content" && options.contentVariant === "B"
411
- ? "show-content-alt"
412
- : `show-${type}`;
413
- activeButton.classList.remove("active");
414
- activeButton = document.getElementById(buttonId);
415
- activeButton.classList.add("active");
416
- }
417
-
418
- // Generate UI key based on the content we're displaying
419
- // For content A and B, they get different keys
420
- // For loading/error states of the same content, they share the key
421
- const uiKey =
422
- options.contentVariant === "B" ? "content-b" : "content-a";
423
- const content = createState(type, { ...options, uiKey });
424
-
425
- uiTransition.slot.innerHTML = content;
426
-
427
- // If it's content with height animation, add visible class in next frame
428
- // This ensures height=0 is measured first by ui_transition.js
429
- const contentState = uiTransition.slot.querySelector(
430
- ".content-state[data-animate-height]",
431
- );
432
- if (contentState) {
433
- requestAnimationFrame(() => {
434
- contentState.classList.add("visible");
435
- });
436
- }
437
- };
438
-
439
- // Sequence runner
440
- const runSequence = async (sequence) => {
441
- for (const [type, delay, options] of sequence) {
442
- setState(type, { skipButtonUpdate: true, ...options });
443
- await new Promise((resolve) => setTimeout(resolve, delay));
444
- }
445
- };
446
-
447
- // Restore UI state from localStorage
448
- const restoreUIState = () => {
449
- // Restore animation checkbox
450
- const shouldAnimate =
451
- localStorage.getItem("animate-content-height") === "true";
452
- document.getElementById("animate-content-height").checked =
453
- shouldAnimate;
454
-
455
- // Restore sequence preservation checkbox
456
- const shouldPreserve =
457
- localStorage.getItem("preserve-between-sequences") === "true";
458
- document.getElementById("preserve-between-sequences").checked =
459
- shouldPreserve;
460
-
461
- // Restore speed selection
462
- const savedSpeed = localStorage.getItem("loading-speed") || "fast";
463
- document.querySelector(
464
- `input[name="speed"][value="${savedSpeed}"]`,
465
- ).checked = true;
466
- };
467
-
468
- // Save UI state to localStorage
469
- const saveUIState = () => {
470
- // Save animation checkbox
471
- localStorage.setItem(
472
- "animate-content-height",
473
- document.getElementById("animate-content-height").checked,
474
- );
475
-
476
- // Save sequence preservation checkbox
477
- localStorage.setItem(
478
- "preserve-between-sequences",
479
- document.getElementById("preserve-between-sequences").checked,
480
- );
481
-
482
- // Save speed selection
483
- const selectedSpeed = document.querySelector(
484
- 'input[name="speed"]:checked',
485
- ).value;
486
- localStorage.setItem("loading-speed", selectedSpeed);
487
- };
488
-
489
- // Restore state on page load
490
- restoreUIState();
491
-
492
- // Setup persistence listeners
493
- document
494
- .getElementById("animate-content-height")
495
- .addEventListener("change", saveUIState);
496
- document
497
- .getElementById("preserve-between-sequences")
498
- .addEventListener("change", saveUIState);
499
- document.querySelectorAll('input[name="speed"]').forEach((radio) => {
500
- radio.addEventListener("change", saveUIState);
501
- });
502
-
503
- // Loading speed control
504
- const LOADING_SPEEDS = {
505
- fast: 100,
506
- medium: 300,
507
- slow: 1000,
508
- };
509
-
510
- const getLoadingSpeed = () => {
511
- const selectedSpeed = document.querySelector(
512
- 'input[name="speed"]:checked',
513
- ).value;
514
- return LOADING_SPEEDS[selectedSpeed];
515
- };
516
-
517
- // Predefined sequences
518
- const sequences = {
519
- // Content Lifecycle (Same UI Key)
520
- "content-loading": () => [
521
- ["loading", getLoadingSpeed()],
522
- ["content", 0],
523
- ],
524
- "loading-error": () => [
525
- ["loading", getLoadingSpeed()],
526
- ["error", 0],
527
- ],
528
- "error-retry": () => [
529
- ["error", 500],
530
- ["loading", getLoadingSpeed()],
531
- ["content", 0],
532
- ],
533
-
534
- // Content Navigation (Different UI Keys)
535
- "navigate-simple": () => [
536
- ["content", 600], // Show initial content
537
- ["loading", getLoadingSpeed()],
538
- ["content", 0, { contentVariant: "B" }],
539
- ],
540
- "navigate-size-change": () => [
541
- ["content", 500], // Show initial content
542
- ["loading", getLoadingSpeed()],
543
- ["content", 0, { bigContent: true }],
544
- ],
545
- };
546
-
547
- // Setup sequence listeners
548
- Object.keys(sequences).forEach((key) => {
549
- document.getElementById(`demo-${key}`).addEventListener("click", () => {
550
- const shouldPreserve = document.getElementById(
551
- "preserve-between-sequences",
552
- ).checked;
553
- if (!shouldPreserve) {
554
- resetContent();
555
- }
556
- runSequence(sequences[key]());
557
- });
558
- });
559
-
560
- // Manual control listeners
561
- document
562
- .getElementById("show-loading")
563
- .addEventListener("click", () =>
564
- setState("loading", { tall: isLargeState }),
565
- );
566
- document
567
- .getElementById("show-content")
568
- .addEventListener("click", () => setState("content"));
569
- document
570
- .getElementById("show-content-alt")
571
- .addEventListener("click", () =>
572
- setState("content", { contentVariant: "B" }),
573
- );
574
- document
575
- .getElementById("show-error")
576
- .addEventListener("click", () =>
577
- setState("error", { tall: isLargeState }),
578
- );
579
- document
580
- .getElementById("reset-content")
581
- .addEventListener("click", resetContent);
582
-
583
- // Update Active Content button logic
584
- document
585
- .getElementById("demo-content-update")
586
- .addEventListener("click", () => {
587
- const slot = uiTransition.slot;
588
- const contentState = slot.querySelector(".content-state");
589
- if (!contentState) return;
590
-
591
- // Toggle data-expanded attribute on content blocks
592
- const blocks = contentState.querySelectorAll(".content-block");
593
- blocks.forEach((block) => {
594
- if (block.hasAttribute("data-expanded")) {
595
- block.removeAttribute("data-expanded");
596
- // Convert text back to normal case
597
- block.textContent = block.textContent.toLowerCase();
598
- } else {
599
- block.setAttribute("data-expanded", "");
600
- // Convert text to uppercase
601
- block.textContent = block.textContent.toUpperCase();
602
- }
603
- });
604
- });
605
-
606
- document.getElementById("toggle-size").addEventListener("click", () => {
607
- isLargeState = !isLargeState;
608
- const currentState = activeButton.id.replace("show-", "");
609
- setState(currentState, { tall: isLargeState });
610
- });
611
-
612
- // Add Content Block button logic
613
- document
614
- .getElementById("demo-content-add-block")
615
- .addEventListener("click", () => {
616
- // Only works if current state is content (A or B)
617
- const slot = uiTransition.slot;
618
- if (!slot) return;
619
-
620
- // Add a new content block
621
- const newBlock = document.createElement("div");
622
- newBlock.className = "content-block";
623
- newBlock.textContent = `Dynamically added block ${slot.children.length + 1}`;
624
- slot.appendChild(newBlock);
625
- });
626
- </script>
627
- </body>
628
- </html>