@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.
- package/dist/jsenv_dom.js +262 -330
- package/package.json +2 -4
- package/index.js +0 -124
- package/src/attr/add_attribute_effect.js +0 -93
- package/src/attr/attributes.js +0 -32
- package/src/color/color_constrast.js +0 -69
- package/src/color/color_parsing.js +0 -319
- package/src/color/color_scheme.js +0 -28
- package/src/color/pick_light_or_dark.js +0 -34
- package/src/color/resolve_css_color.js +0 -60
- package/src/demos/3_columns_resize_demo.html +0 -84
- package/src/demos/3_rows_resize_demo.html +0 -89
- package/src/demos/aside_and_main_demo.html +0 -93
- package/src/demos/coordinates_demo.html +0 -450
- package/src/demos/document_autoscroll_demo.html +0 -517
- package/src/demos/drag_gesture_constraints_demo.html +0 -701
- package/src/demos/drag_gesture_demo.html +0 -1047
- package/src/demos/drag_gesture_element_to_impact_demo.html +0 -445
- package/src/demos/drag_reference_element_demo.html +0 -480
- package/src/demos/flex_details_set_demo.html +0 -302
- package/src/demos/flex_details_set_demo_2.html +0 -315
- package/src/demos/visible_rect_demo.html +0 -525
- package/src/element_signature.js +0 -100
- package/src/interaction/drag/constraint_feedback_line.js +0 -92
- package/src/interaction/drag/drag_constraint.js +0 -659
- package/src/interaction/drag/drag_debug_markers.js +0 -635
- package/src/interaction/drag/drag_element_positioner.js +0 -382
- package/src/interaction/drag/drag_gesture.js +0 -566
- package/src/interaction/drag/drag_resize_demo.html +0 -571
- package/src/interaction/drag/drag_to_move.js +0 -301
- package/src/interaction/drag/drag_to_resize_gesture.js +0 -68
- package/src/interaction/drag/drop_target_detection.js +0 -148
- package/src/interaction/drag/sticky_frontiers.js +0 -160
- package/src/interaction/event_marker.js +0 -14
- package/src/interaction/focus/active_element.js +0 -33
- package/src/interaction/focus/arrow_navigation.js +0 -599
- package/src/interaction/focus/element_is_focusable.js +0 -57
- package/src/interaction/focus/element_visibility.js +0 -111
- package/src/interaction/focus/find_focusable.js +0 -21
- package/src/interaction/focus/focus_group.js +0 -91
- package/src/interaction/focus/focus_group_registry.js +0 -12
- package/src/interaction/focus/focus_nav.js +0 -12
- package/src/interaction/focus/focus_nav_event_marker.js +0 -14
- package/src/interaction/focus/focus_trap.js +0 -105
- package/src/interaction/focus/tab_navigation.js +0 -128
- package/src/interaction/focus/tests/focus_group_skip_tab_test.html +0 -206
- package/src/interaction/focus/tests/tree_focus_test.html +0 -304
- package/src/interaction/focus/tests/tree_focus_test.jsx +0 -261
- package/src/interaction/focus/tests/tree_focus_test_preact.html +0 -13
- package/src/interaction/isolate_interactions.js +0 -161
- package/src/interaction/keyboard.js +0 -26
- package/src/interaction/scroll/capture_scroll.js +0 -47
- package/src/interaction/scroll/is_scrollable.js +0 -159
- package/src/interaction/scroll/scroll_container.js +0 -110
- package/src/interaction/scroll/scroll_trap.js +0 -44
- package/src/interaction/scroll/scrollbar_size.js +0 -20
- package/src/interaction/scroll/wheel_through.js +0 -138
- package/src/iterable_weak_set.js +0 -66
- package/src/position/dom_coords.js +0 -340
- package/src/position/offset_parent.js +0 -15
- package/src/position/position_fixed.js +0 -15
- package/src/position/position_sticky.js +0 -213
- package/src/position/sticky_rect.js +0 -79
- package/src/position/visible_rect.js +0 -486
- package/src/pub_sub.js +0 -31
- package/src/size/can_take_size.js +0 -11
- package/src/size/details_content_full_height.js +0 -63
- package/src/size/flex_details_set.js +0 -974
- package/src/size/get_available_height.js +0 -22
- package/src/size/get_available_width.js +0 -22
- package/src/size/get_border_sizes.js +0 -14
- package/src/size/get_height.js +0 -4
- package/src/size/get_inner_height.js +0 -15
- package/src/size/get_inner_width.js +0 -15
- package/src/size/get_margin_sizes.js +0 -10
- package/src/size/get_max_height.js +0 -57
- package/src/size/get_max_width.js +0 -47
- package/src/size/get_min_height.js +0 -14
- package/src/size/get_min_width.js +0 -14
- package/src/size/get_padding_sizes.js +0 -10
- package/src/size/get_width.js +0 -4
- package/src/size/hooks/use_available_height.js +0 -27
- package/src/size/hooks/use_available_width.js +0 -27
- package/src/size/hooks/use_max_height.js +0 -10
- package/src/size/hooks/use_max_width.js +0 -10
- package/src/size/hooks/use_resize_status.js +0 -62
- package/src/size/resize.js +0 -695
- package/src/size/resolve_css_size.js +0 -32
- package/src/style/dom_styles.js +0 -97
- package/src/style/style_composition.js +0 -121
- package/src/style/style_controller.js +0 -345
- package/src/style/style_default.js +0 -153
- package/src/style/style_default_demo.html +0 -128
- package/src/style/style_parsing.js +0 -375
- package/src/transition/demos/animation_resumption_test.xhtml +0 -500
- package/src/transition/demos/height_toggle_test.xhtml +0 -515
- package/src/transition/dom_transition.js +0 -254
- package/src/transition/easing.js +0 -48
- package/src/transition/group_transition.js +0 -261
- package/src/transition/transform_style_parser.js +0 -32
- package/src/transition/transition_playback.js +0 -366
- package/src/transition/transition_timeline.js +0 -79
- package/src/traversal.js +0 -247
- package/src/ui_transition/demos/content_states_transition_demo.html +0 -628
- package/src/ui_transition/demos/smooth_height_transition_demo.html +0 -149
- package/src/ui_transition/demos/transition_testing.html +0 -354
- package/src/ui_transition/ui_transition.js +0 -1491
- package/src/utils.js +0 -69
- 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>
|