@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,304 +0,0 @@
|
|
|
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>Tree Focus Group</title>
|
|
7
|
-
<style>
|
|
8
|
-
body {
|
|
9
|
-
font-family: Arial, sans-serif;
|
|
10
|
-
max-width: 800px;
|
|
11
|
-
margin: 20px auto;
|
|
12
|
-
padding: 20px;
|
|
13
|
-
line-height: 1.6;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.tree-container {
|
|
17
|
-
border: 2px solid #333;
|
|
18
|
-
padding: 20px;
|
|
19
|
-
margin: 20px 0;
|
|
20
|
-
background: #f9f9f9;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
details {
|
|
24
|
-
margin: 8px 0;
|
|
25
|
-
border: 1px solid #ddd;
|
|
26
|
-
border-radius: 4px;
|
|
27
|
-
background: white;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
summary {
|
|
31
|
-
padding: 12px;
|
|
32
|
-
background: #e8e8e8;
|
|
33
|
-
cursor: pointer;
|
|
34
|
-
border-radius: 4px 4px 0 0;
|
|
35
|
-
font-weight: bold;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
summary:hover {
|
|
39
|
-
background: #d8d8d8;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
summary:focus {
|
|
43
|
-
outline: 2px solid #0066cc;
|
|
44
|
-
outline-offset: 2px;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.content {
|
|
48
|
-
padding-left: 16px;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.focusable-item {
|
|
52
|
-
display: block;
|
|
53
|
-
padding: 8px 12px;
|
|
54
|
-
margin: 4px 0;
|
|
55
|
-
background: #fff;
|
|
56
|
-
border: 1px solid #ccc;
|
|
57
|
-
border-radius: 3px;
|
|
58
|
-
text-decoration: none;
|
|
59
|
-
color: #333;
|
|
60
|
-
cursor: pointer;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.focusable-item:hover {
|
|
64
|
-
background: #f0f8ff;
|
|
65
|
-
border-color: #0066cc;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.focusable-item:focus {
|
|
69
|
-
outline: 2px solid #0066cc;
|
|
70
|
-
outline-offset: 1px;
|
|
71
|
-
background: #e6f3ff;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.debug {
|
|
75
|
-
position: fixed;
|
|
76
|
-
top: 10px;
|
|
77
|
-
right: 10px;
|
|
78
|
-
width: 300px;
|
|
79
|
-
background: #222;
|
|
80
|
-
color: #fff;
|
|
81
|
-
padding: 10px;
|
|
82
|
-
border-radius: 4px;
|
|
83
|
-
font-size: 12px;
|
|
84
|
-
max-height: 300px;
|
|
85
|
-
overflow-y: auto;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.debug h3 {
|
|
89
|
-
margin: 0 0 10px 0;
|
|
90
|
-
font-size: 14px;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.status-line {
|
|
94
|
-
margin: 2px 0;
|
|
95
|
-
padding: 2px 4px;
|
|
96
|
-
background: #333;
|
|
97
|
-
border-radius: 2px;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/* Visual indicators for focus group hierarchy */
|
|
101
|
-
[data-focus-group="root"] {
|
|
102
|
-
border-left: 4px solid #0066cc;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
[data-focus-group="level-1"] {
|
|
106
|
-
border-left: 4px solid #00cc66;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
[data-focus-group="level-2"] {
|
|
110
|
-
border-left: 4px solid #cc6600;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
[data-focus-group="level-3"] {
|
|
114
|
-
border-left: 4px solid #cc0066;
|
|
115
|
-
}
|
|
116
|
-
</style>
|
|
117
|
-
</head>
|
|
118
|
-
<body>
|
|
119
|
-
<h1>Tree Focus Group Test</h1>
|
|
120
|
-
|
|
121
|
-
<p>
|
|
122
|
-
This demonstrates a tree-like structure using nested
|
|
123
|
-
<code><details></code> elements with focus groups. Each details
|
|
124
|
-
contains a focus group for vertical arrow navigation within its content.
|
|
125
|
-
</p>
|
|
126
|
-
|
|
127
|
-
<div class="debug">
|
|
128
|
-
<h3>Debug Info</h3>
|
|
129
|
-
<div id="debug-output"></div>
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
<!-- Test element before the tree -->
|
|
133
|
-
<div
|
|
134
|
-
style="
|
|
135
|
-
margin: 20px 0;
|
|
136
|
-
padding: 10px;
|
|
137
|
-
border: 2px solid #0066cc;
|
|
138
|
-
background: #f0f8ff;
|
|
139
|
-
"
|
|
140
|
-
>
|
|
141
|
-
<label for="before-input">Input before tree (Tab test):</label>
|
|
142
|
-
<input
|
|
143
|
-
id="before-input"
|
|
144
|
-
type="text"
|
|
145
|
-
placeholder="Focus me, then press Tab"
|
|
146
|
-
style="margin-left: 10px; padding: 5px"
|
|
147
|
-
/>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<div class="tree-container">
|
|
151
|
-
<h2>File System Tree</h2>
|
|
152
|
-
|
|
153
|
-
<!-- Root level details -->
|
|
154
|
-
<details open data-focus-group="root">
|
|
155
|
-
<summary tabindex="0">📁 Projects</summary>
|
|
156
|
-
|
|
157
|
-
<div class="content" id="projects-group">
|
|
158
|
-
<!-- Nested details level 1 -->
|
|
159
|
-
<details data-focus-group="level-1">
|
|
160
|
-
<summary tabindex="-1">📁 src</summary>
|
|
161
|
-
<div class="content" id="src-group">
|
|
162
|
-
<!-- Nested details level 2 -->
|
|
163
|
-
<details data-focus-group="level-2">
|
|
164
|
-
<summary tabindex="-1">📁 components</summary>
|
|
165
|
-
<div class="content" id="components-group">
|
|
166
|
-
<div tabindex="-1" class="focusable-item">📄 Button.jsx</div>
|
|
167
|
-
<div tabindex="-1" class="focusable-item">📄 Modal.jsx</div>
|
|
168
|
-
</div>
|
|
169
|
-
</details>
|
|
170
|
-
</div>
|
|
171
|
-
</details>
|
|
172
|
-
<details data-focus-group="level-2">
|
|
173
|
-
<summary tabindex="-1">📁 utils</summary>
|
|
174
|
-
<div class="content" id="utils-group">
|
|
175
|
-
<div tabindex="-1" class="focusable-item">📄 helpers.js</div>
|
|
176
|
-
<div tabindex="-1" class="focusable-item">📄 config.js</div>
|
|
177
|
-
</div>
|
|
178
|
-
</details>
|
|
179
|
-
<div tabindex="0" class="focusable-item">📄 README.md</div>
|
|
180
|
-
<div tabindex="0" class="focusable-item">📄 package.json</div>
|
|
181
|
-
<div tabindex="0" class="focusable-item">� .gitignore</div>
|
|
182
|
-
</div>
|
|
183
|
-
</details>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
<!-- Test element after the tree -->
|
|
187
|
-
<div
|
|
188
|
-
style="
|
|
189
|
-
margin: 20px 0;
|
|
190
|
-
padding: 10px;
|
|
191
|
-
border: 2px solid #cc6600;
|
|
192
|
-
background: #fff8f0;
|
|
193
|
-
"
|
|
194
|
-
>
|
|
195
|
-
<label for="after-input">Input after tree (Tab test):</label>
|
|
196
|
-
<input
|
|
197
|
-
id="after-input"
|
|
198
|
-
type="text"
|
|
199
|
-
placeholder="Should receive focus after tree"
|
|
200
|
-
style="margin-left: 10px; padding: 5px"
|
|
201
|
-
/>
|
|
202
|
-
<button style="margin-left: 10px; padding: 5px 10px">
|
|
203
|
-
Button after tree
|
|
204
|
-
</button>
|
|
205
|
-
</div>
|
|
206
|
-
|
|
207
|
-
<div class="tree-container">
|
|
208
|
-
<h2>Expected Focus Group Behavior</h2>
|
|
209
|
-
<ul>
|
|
210
|
-
<li>
|
|
211
|
-
<strong>Tab Navigation:</strong> Should skip over focus groups
|
|
212
|
-
entirely - from "Input before tree" directly to "Input after tree"
|
|
213
|
-
</li>
|
|
214
|
-
<li>
|
|
215
|
-
<strong>Arrow Up/Down:</strong> Navigates within the current focus
|
|
216
|
-
group (vertical)
|
|
217
|
-
</li>
|
|
218
|
-
<li>
|
|
219
|
-
<strong>Future Implementation:</strong> Arrow Left/Right to
|
|
220
|
-
collapse/expand or move between sibling groups
|
|
221
|
-
</li>
|
|
222
|
-
</ul>
|
|
223
|
-
|
|
224
|
-
<h3>Tab Navigation Test</h3>
|
|
225
|
-
<ol>
|
|
226
|
-
<li>Click on "Input before tree" field above</li>
|
|
227
|
-
<li>
|
|
228
|
-
Press Tab - should jump directly to "Input after tree" (skipping all
|
|
229
|
-
focus groups)
|
|
230
|
-
</li>
|
|
231
|
-
<li>Press Shift+Tab - should jump back to "Input before tree"</li>
|
|
232
|
-
<li>
|
|
233
|
-
To enter a focus group: click on any file/folder item, then use arrows
|
|
234
|
-
</li>
|
|
235
|
-
</ol>
|
|
236
|
-
|
|
237
|
-
<h3>Focus Group Configuration</h3>
|
|
238
|
-
<p>Each <code>details</code> element would be initialized as:</p>
|
|
239
|
-
<pre><code>initFocusGroup(element, {
|
|
240
|
-
direction: "vertical", // Only up/down arrows
|
|
241
|
-
loop: false, // Stay at boundaries
|
|
242
|
-
skipTab: true // Tab exits the group
|
|
243
|
-
});</code></pre>
|
|
244
|
-
</div>
|
|
245
|
-
|
|
246
|
-
<script type="module">
|
|
247
|
-
import { initFocusGroup } from "../focus_group.js";
|
|
248
|
-
|
|
249
|
-
// Initialize focus groups on details elements
|
|
250
|
-
const focusGroups = document.querySelectorAll("details");
|
|
251
|
-
focusGroups.forEach((group) => {
|
|
252
|
-
initFocusGroup(group, {
|
|
253
|
-
direction: "vertical", // Only allow up/down navigation within each group
|
|
254
|
-
loop: false, // Don't wrap around at boundaries
|
|
255
|
-
skipTab: true, // Tab key exits the group
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
// Debug logging
|
|
260
|
-
const debugOutput = document.getElementById("debug-output");
|
|
261
|
-
|
|
262
|
-
function log(message) {
|
|
263
|
-
const line = document.createElement("div");
|
|
264
|
-
line.className = "status-line";
|
|
265
|
-
line.textContent = `${new Date().toLocaleTimeString()}: ${message}`;
|
|
266
|
-
debugOutput.insertBefore(line, debugOutput.firstChild);
|
|
267
|
-
|
|
268
|
-
// Keep only last 10 messages
|
|
269
|
-
while (debugOutput.children.length > 10) {
|
|
270
|
-
debugOutput.removeChild(debugOutput.lastChild);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Track focus changes
|
|
275
|
-
document.addEventListener("focusin", (event) => {
|
|
276
|
-
const element = event.target;
|
|
277
|
-
const groupId =
|
|
278
|
-
element.closest("details")?.getAttribute("data-focus-group") ||
|
|
279
|
-
"none";
|
|
280
|
-
const elementType = element.tagName.toLowerCase();
|
|
281
|
-
const elementText = element.textContent.trim().substring(0, 20);
|
|
282
|
-
|
|
283
|
-
log(`Focus: ${elementType} "${elementText}" in ${groupId}`);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
// Track key presses for debugging
|
|
287
|
-
document.addEventListener("keydown", (event) => {
|
|
288
|
-
if (
|
|
289
|
-
["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Tab"].includes(
|
|
290
|
-
event.key,
|
|
291
|
-
)
|
|
292
|
-
) {
|
|
293
|
-
const activeGroup =
|
|
294
|
-
document.activeElement
|
|
295
|
-
?.closest("details")
|
|
296
|
-
?.getAttribute("data-focus-group") || "none";
|
|
297
|
-
log(`Key: ${event.key} in ${activeGroup}`);
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
log("Tree focus group test initialized");
|
|
302
|
-
</script>
|
|
303
|
-
</body>
|
|
304
|
-
</html>
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { Details } from "@jsenv/navi";
|
|
2
|
-
import { render } from "preact";
|
|
3
|
-
|
|
4
|
-
// Add CSS styles
|
|
5
|
-
import.meta.css = /* css */ `
|
|
6
|
-
body {
|
|
7
|
-
font-family: Arial, sans-serif;
|
|
8
|
-
max-width: 800px;
|
|
9
|
-
margin: 20px auto;
|
|
10
|
-
padding: 20px;
|
|
11
|
-
line-height: 1.6;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.tree-container {
|
|
15
|
-
border: 2px solid #333;
|
|
16
|
-
padding: 20px;
|
|
17
|
-
margin: 20px 0;
|
|
18
|
-
background: #f9f9f9;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
details {
|
|
22
|
-
margin: 8px 0;
|
|
23
|
-
border: 1px solid #ddd;
|
|
24
|
-
border-radius: 4px;
|
|
25
|
-
background: white;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
summary {
|
|
29
|
-
padding: 12px;
|
|
30
|
-
background: #e8e8e8;
|
|
31
|
-
cursor: pointer;
|
|
32
|
-
border-radius: 4px 4px 0 0;
|
|
33
|
-
font-weight: bold;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
summary:hover {
|
|
37
|
-
background: #d8d8d8;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.content {
|
|
41
|
-
padding-left: 16px;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.focusable-item {
|
|
45
|
-
display: block;
|
|
46
|
-
padding: 8px 12px;
|
|
47
|
-
margin: 4px 0;
|
|
48
|
-
background: #fff;
|
|
49
|
-
border: 1px solid #ccc;
|
|
50
|
-
border-radius: 3px;
|
|
51
|
-
text-decoration: none;
|
|
52
|
-
color: #333;
|
|
53
|
-
cursor: pointer;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.focusable-item:hover {
|
|
57
|
-
background: #f0f8ff;
|
|
58
|
-
border-color: #0066cc;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.focusable-item:focus {
|
|
62
|
-
outline: 2px solid #0066cc;
|
|
63
|
-
outline-offset: 1px;
|
|
64
|
-
background: #e6f3ff;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.debug {
|
|
68
|
-
position: fixed;
|
|
69
|
-
top: 10px;
|
|
70
|
-
right: 10px;
|
|
71
|
-
width: 300px;
|
|
72
|
-
background: #222;
|
|
73
|
-
color: #fff;
|
|
74
|
-
padding: 10px;
|
|
75
|
-
border-radius: 4px;
|
|
76
|
-
font-size: 12px;
|
|
77
|
-
max-height: 300px;
|
|
78
|
-
overflow-y: auto;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.debug h3 {
|
|
82
|
-
margin: 0 0 10px 0;
|
|
83
|
-
font-size: 14px;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.status-line {
|
|
87
|
-
margin: 2px 0;
|
|
88
|
-
padding: 2px 4px;
|
|
89
|
-
background: #333;
|
|
90
|
-
border-radius: 2px;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.test-input-container {
|
|
94
|
-
margin: 20px 0;
|
|
95
|
-
padding: 10px;
|
|
96
|
-
border-radius: 4px;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.before-tree {
|
|
100
|
-
border: 2px solid #0066cc;
|
|
101
|
-
background: #f0f8ff;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.after-tree {
|
|
105
|
-
border: 2px solid #cc6600;
|
|
106
|
-
background: #fff8f0;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
input,
|
|
110
|
-
button {
|
|
111
|
-
margin-left: 10px;
|
|
112
|
-
padding: 5px;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
button {
|
|
116
|
-
padding: 5px 10px;
|
|
117
|
-
}
|
|
118
|
-
`;
|
|
119
|
-
|
|
120
|
-
const TreeFocusTest = () => {
|
|
121
|
-
return (
|
|
122
|
-
<div>
|
|
123
|
-
<h1>Tree Focus Group Test - Preact</h1>
|
|
124
|
-
|
|
125
|
-
<p>
|
|
126
|
-
This demonstrates a tree-like structure using @jsenv/navi's{" "}
|
|
127
|
-
<code><Details></code> component with focus groups.
|
|
128
|
-
</p>
|
|
129
|
-
|
|
130
|
-
{/* Test element before the tree */}
|
|
131
|
-
<div className="test-input-container before-tree">
|
|
132
|
-
<label htmlFor="before-input">Input before tree (Tab test):</label>
|
|
133
|
-
<input
|
|
134
|
-
id="before-input"
|
|
135
|
-
type="text"
|
|
136
|
-
placeholder="Focus me, then press Tab"
|
|
137
|
-
/>
|
|
138
|
-
</div>
|
|
139
|
-
|
|
140
|
-
<div className="tree-container">
|
|
141
|
-
<h2>File System Tree</h2>
|
|
142
|
-
|
|
143
|
-
{/* Root level details */}
|
|
144
|
-
<Details
|
|
145
|
-
focusGroup
|
|
146
|
-
focusGroupDirection="vertical"
|
|
147
|
-
open
|
|
148
|
-
label={"📁 Projects"}
|
|
149
|
-
>
|
|
150
|
-
<div className="content">
|
|
151
|
-
{/* Nested details level 1 */}
|
|
152
|
-
<Details focusGroup focusGroupDirection="vertical" label="📁 src">
|
|
153
|
-
<div className="content">
|
|
154
|
-
{/* Nested details level 2 */}
|
|
155
|
-
<Details
|
|
156
|
-
focusGroup
|
|
157
|
-
focusGroupDirection="vertical"
|
|
158
|
-
label="📁 components"
|
|
159
|
-
>
|
|
160
|
-
<div className="content">
|
|
161
|
-
<div tabIndex="-1" className="focusable-item">
|
|
162
|
-
📄 Button.jsx
|
|
163
|
-
</div>
|
|
164
|
-
<div tabIndex="-1" className="focusable-item">
|
|
165
|
-
📄 Modal.jsx
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
</Details>
|
|
169
|
-
</div>
|
|
170
|
-
</Details>
|
|
171
|
-
|
|
172
|
-
<Details focusGroup focusGroupDirection="vertical" label="📁 utils">
|
|
173
|
-
<div className="content">
|
|
174
|
-
<div tabIndex="-1" className="focusable-item">
|
|
175
|
-
📄 helpers.js
|
|
176
|
-
</div>
|
|
177
|
-
<div tabIndex="-1" className="focusable-item">
|
|
178
|
-
📄 config.js
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
|
-
</Details>
|
|
182
|
-
|
|
183
|
-
<div tabIndex="0" className="focusable-item">
|
|
184
|
-
📄 README.md
|
|
185
|
-
</div>
|
|
186
|
-
<div tabIndex="0" className="focusable-item">
|
|
187
|
-
📄 package.json
|
|
188
|
-
</div>
|
|
189
|
-
<div tabIndex="0" className="focusable-item">
|
|
190
|
-
📄 .gitignore
|
|
191
|
-
</div>
|
|
192
|
-
</div>
|
|
193
|
-
</Details>
|
|
194
|
-
</div>
|
|
195
|
-
|
|
196
|
-
{/* Test element after the tree */}
|
|
197
|
-
<div className="test-input-container after-tree">
|
|
198
|
-
<label htmlFor="after-input">Input after tree (Tab test):</label>
|
|
199
|
-
<input
|
|
200
|
-
id="after-input"
|
|
201
|
-
type="text"
|
|
202
|
-
placeholder="Should receive focus after tree"
|
|
203
|
-
/>
|
|
204
|
-
<button>Button after tree</button>
|
|
205
|
-
</div>
|
|
206
|
-
|
|
207
|
-
<div className="tree-container">
|
|
208
|
-
<h2>Expected Focus Group Behavior</h2>
|
|
209
|
-
<ul>
|
|
210
|
-
<li>
|
|
211
|
-
<strong>Tab Navigation:</strong> Should skip over focus groups
|
|
212
|
-
entirely - from "Input before tree" directly to
|
|
213
|
-
"Input after tree"
|
|
214
|
-
</li>
|
|
215
|
-
<li>
|
|
216
|
-
<strong>Arrow Up/Down:</strong> Navigates within the current focus
|
|
217
|
-
group (vertical)
|
|
218
|
-
</li>
|
|
219
|
-
<li>
|
|
220
|
-
<strong>Future Implementation:</strong> Arrow Left/Right to
|
|
221
|
-
collapse/expand or move between sibling groups
|
|
222
|
-
</li>
|
|
223
|
-
</ul>
|
|
224
|
-
|
|
225
|
-
<h3>Tab Navigation Test</h3>
|
|
226
|
-
<ol>
|
|
227
|
-
<li>Click on "Input before tree" field above</li>
|
|
228
|
-
<li>
|
|
229
|
-
Press Tab - should jump directly to "Input after tree"
|
|
230
|
-
(skipping all focus groups)
|
|
231
|
-
</li>
|
|
232
|
-
<li>
|
|
233
|
-
Press Shift+Tab - should jump back to "Input before tree"
|
|
234
|
-
</li>
|
|
235
|
-
<li>
|
|
236
|
-
To enter a focus group: click on any file/folder item, then use
|
|
237
|
-
arrows
|
|
238
|
-
</li>
|
|
239
|
-
</ol>
|
|
240
|
-
|
|
241
|
-
<h3>Focus Group Configuration</h3>
|
|
242
|
-
<p>
|
|
243
|
-
Each <code><Details></code> component is configured as:
|
|
244
|
-
</p>
|
|
245
|
-
<pre>
|
|
246
|
-
<code>{`<Details
|
|
247
|
-
focusGroup
|
|
248
|
-
label="📁 Folder"
|
|
249
|
-
>
|
|
250
|
-
<div className="content">
|
|
251
|
-
{/* Content */}
|
|
252
|
-
</div>
|
|
253
|
-
</Details>`}</code>
|
|
254
|
-
</pre>
|
|
255
|
-
</div>
|
|
256
|
-
</div>
|
|
257
|
-
);
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
// Mount the component
|
|
261
|
-
render(<TreeFocusTest />, document.body);
|
|
@@ -1,13 +0,0 @@
|
|
|
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>Tree Focus Group Test - Preact</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<div id="root"></div>
|
|
10
|
-
|
|
11
|
-
<script type="module" src="./tree_focus_test.jsx"></script>
|
|
12
|
-
</body>
|
|
13
|
-
</html>
|