@jsenv/dom 0.1.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 +9653 -0
- package/index.js +101 -0
- package/package.json +47 -0
- package/src/attr/add_attribute_effect.js +93 -0
- package/src/attr/attributes.js +32 -0
- package/src/demos/3_columns_resize_demo.html +84 -0
- package/src/demos/3_rows_resize_demo.html +89 -0
- package/src/demos/aside_and_main_demo.html +93 -0
- package/src/demos/coordinates_demo.html +450 -0
- package/src/demos/document_autoscroll_demo.html +517 -0
- package/src/demos/drag_gesture_constraints_demo.html +701 -0
- package/src/demos/drag_gesture_demo.html +1047 -0
- package/src/demos/drag_gesture_element_to_impact_demo.html +445 -0
- package/src/demos/drag_reference_element_demo.html +480 -0
- package/src/demos/flex_details_set_demo.html +302 -0
- package/src/demos/flex_details_set_demo_2.html +315 -0
- package/src/demos/visible_rect_demo.html +525 -0
- package/src/interaction/drag/constraint_feedback_line.js +92 -0
- package/src/interaction/drag/drag_constraint.js +659 -0
- package/src/interaction/drag/drag_debug_markers.js +635 -0
- package/src/interaction/drag/drag_element_positioner.js +382 -0
- package/src/interaction/drag/drag_gesture.js +566 -0
- package/src/interaction/drag/drag_resize_demo.html +571 -0
- package/src/interaction/drag/drag_to_move.js +301 -0
- package/src/interaction/drag/drag_to_resize_gesture.js +68 -0
- package/src/interaction/drag/drop_target_detection.js +148 -0
- package/src/interaction/drag/sticky_frontiers.js +160 -0
- package/src/interaction/element_log.js +8 -0
- package/src/interaction/event_marker.js +14 -0
- package/src/interaction/focus/active_element.js +33 -0
- package/src/interaction/focus/arrow_navigation.js +599 -0
- package/src/interaction/focus/element_is_focusable.js +57 -0
- package/src/interaction/focus/element_is_visible.js +36 -0
- package/src/interaction/focus/find_focusable.js +21 -0
- package/src/interaction/focus/focus_group.js +91 -0
- package/src/interaction/focus/focus_group_registry.js +12 -0
- package/src/interaction/focus/focus_nav.js +12 -0
- package/src/interaction/focus/focus_nav_event_marker.js +14 -0
- package/src/interaction/focus/focus_trap.js +105 -0
- package/src/interaction/focus/tab_navigation.js +128 -0
- package/src/interaction/focus/tests/focus_group_skip_tab_test.html +206 -0
- package/src/interaction/focus/tests/tree_focus_test.html +304 -0
- package/src/interaction/focus/tests/tree_focus_test.jsx +261 -0
- package/src/interaction/focus/tests/tree_focus_test_preact.html +13 -0
- package/src/interaction/isolate_interactions.js +161 -0
- package/src/interaction/keyboard.js +26 -0
- package/src/interaction/scroll/capture_scroll.js +47 -0
- package/src/interaction/scroll/is_scrollable.js +159 -0
- package/src/interaction/scroll/scroll_container.js +110 -0
- package/src/interaction/scroll/scroll_trap.js +44 -0
- package/src/interaction/scroll/scrollbar_size.js +20 -0
- package/src/interaction/scroll/wheel_through.js +138 -0
- package/src/iterable_weak_set.js +66 -0
- package/src/position/dom_coords.js +340 -0
- package/src/position/offset_parent.js +15 -0
- package/src/position/position_fixed.js +15 -0
- package/src/position/position_sticky.js +213 -0
- package/src/position/sticky_rect.js +79 -0
- package/src/position/visible_rect.js +482 -0
- package/src/pub_sub.js +28 -0
- package/src/size/can_take_size.js +11 -0
- package/src/size/details_content_full_height.js +63 -0
- package/src/size/flex_details_set.js +974 -0
- package/src/size/get_available_height.js +22 -0
- package/src/size/get_available_width.js +22 -0
- package/src/size/get_border_sizes.js +14 -0
- package/src/size/get_height.js +4 -0
- package/src/size/get_inner_height.js +15 -0
- package/src/size/get_inner_width.js +15 -0
- package/src/size/get_margin_sizes.js +10 -0
- package/src/size/get_max_height.js +57 -0
- package/src/size/get_max_width.js +47 -0
- package/src/size/get_min_height.js +14 -0
- package/src/size/get_min_width.js +14 -0
- package/src/size/get_padding_sizes.js +10 -0
- package/src/size/get_width.js +4 -0
- package/src/size/hooks/use_available_height.js +27 -0
- package/src/size/hooks/use_available_width.js +27 -0
- package/src/size/hooks/use_max_height.js +10 -0
- package/src/size/hooks/use_max_width.js +10 -0
- package/src/size/hooks/use_resize_status.js +62 -0
- package/src/size/resize.js +695 -0
- package/src/size/resolve_css_size.js +32 -0
- package/src/style/dom_styles.js +97 -0
- package/src/style/style_composition.js +78 -0
- package/src/style/style_controller.js +345 -0
- package/src/style/style_parsing.js +317 -0
- package/src/transition/demos/animation_resumption_test.xhtml +500 -0
- package/src/transition/demos/height_toggle_test.xhtml +515 -0
- package/src/transition/dom_transition.js +254 -0
- package/src/transition/easing.js +48 -0
- package/src/transition/group_transition.js +261 -0
- package/src/transition/transform_style_parser.js +32 -0
- package/src/transition/transition_playback.js +366 -0
- package/src/transition/transition_timeline.js +79 -0
- package/src/traversal.js +247 -0
- package/src/ui_transition/demos/content_states_transition_demo.html +628 -0
- package/src/ui_transition/demos/smooth_height_transition_demo.html +149 -0
- package/src/ui_transition/demos/transition_testing.html +354 -0
- package/src/ui_transition/ui_transition.js +1492 -0
- package/src/utils.js +69 -0
package/index.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// state management
|
|
2
|
+
export { createIterableWeakSet } from "./src/iterable_weak_set.js";
|
|
3
|
+
export { createPubSub } from "./src/pub_sub.js";
|
|
4
|
+
|
|
5
|
+
// style
|
|
6
|
+
export { addWillChange, getStyle, setStyles } from "./src/style/dom_styles.js";
|
|
7
|
+
export { createStyleController } from "./src/style/style_controller.js";
|
|
8
|
+
|
|
9
|
+
// attributes
|
|
10
|
+
export { addAttributeEffect } from "./src/attr/add_attribute_effect.js";
|
|
11
|
+
export { setAttribute, setAttributes } from "./src/attr/attributes.js";
|
|
12
|
+
|
|
13
|
+
// traversal
|
|
14
|
+
export {
|
|
15
|
+
findAfter,
|
|
16
|
+
findAncestor,
|
|
17
|
+
findBefore,
|
|
18
|
+
findDescendant,
|
|
19
|
+
} from "./src/traversal.js";
|
|
20
|
+
|
|
21
|
+
// interaction/focus
|
|
22
|
+
export {
|
|
23
|
+
activeElementSignal,
|
|
24
|
+
addActiveElementEffect,
|
|
25
|
+
useActiveElement,
|
|
26
|
+
} from "./src/interaction/focus/active_element.js";
|
|
27
|
+
export { elementIsFocusable } from "./src/interaction/focus/element_is_focusable.js";
|
|
28
|
+
export { elementIsVisible } from "./src/interaction/focus/element_is_visible.js";
|
|
29
|
+
export { findFocusable } from "./src/interaction/focus/find_focusable.js";
|
|
30
|
+
export { initFocusGroup } from "./src/interaction/focus/focus_group.js";
|
|
31
|
+
export { preventFocusNavViaKeyboard } from "./src/interaction/focus/focus_nav.js";
|
|
32
|
+
export { preventFocusNav } from "./src/interaction/focus/focus_nav_event_marker.js";
|
|
33
|
+
export { trapFocusInside } from "./src/interaction/focus/focus_trap.js";
|
|
34
|
+
// interaction/keyboard
|
|
35
|
+
export { canInterceptKeys } from "./src/interaction/keyboard.js";
|
|
36
|
+
// interaction/scroll
|
|
37
|
+
export { captureScrollState } from "./src/interaction/scroll/capture_scroll.js";
|
|
38
|
+
export { isScrollable } from "./src/interaction/scroll/is_scrollable.js";
|
|
39
|
+
export {
|
|
40
|
+
getScrollContainer,
|
|
41
|
+
getScrollContainerSet,
|
|
42
|
+
getSelfAndAncestorScrolls,
|
|
43
|
+
} from "./src/interaction/scroll/scroll_container.js";
|
|
44
|
+
export { trapScrollInside } from "./src/interaction/scroll/scroll_trap.js";
|
|
45
|
+
export { allowWheelThrough } from "./src/interaction/scroll/wheel_through.js";
|
|
46
|
+
// interaction/drag
|
|
47
|
+
export { getDragCoordinates } from "./src/interaction/drag/drag_element_positioner.js";
|
|
48
|
+
export {
|
|
49
|
+
createDragGestureController,
|
|
50
|
+
dragAfterThreshold,
|
|
51
|
+
} from "./src/interaction/drag/drag_gesture.js";
|
|
52
|
+
export { createDragToMoveGestureController } from "./src/interaction/drag/drag_to_move.js";
|
|
53
|
+
export { startDragToResizeGesture } from "./src/interaction/drag/drag_to_resize_gesture.js";
|
|
54
|
+
export { getDropTargetInfo } from "./src/interaction/drag/drop_target_detection.js";
|
|
55
|
+
|
|
56
|
+
// position
|
|
57
|
+
export { getScrollRelativeRect } from "./src/position/dom_coords.js";
|
|
58
|
+
export { getPositionedParent } from "./src/position/offset_parent.js";
|
|
59
|
+
export { initPositionSticky } from "./src/position/position_sticky.js";
|
|
60
|
+
export { stickyAsRelativeCoords } from "./src/position/sticky_rect.js";
|
|
61
|
+
export {
|
|
62
|
+
pickPositionRelativeTo,
|
|
63
|
+
visibleRectEffect,
|
|
64
|
+
} from "./src/position/visible_rect.js";
|
|
65
|
+
|
|
66
|
+
// size
|
|
67
|
+
export { initFlexDetailsSet } from "./src/size/flex_details_set.js";
|
|
68
|
+
export { getAvailableHeight } from "./src/size/get_available_height.js";
|
|
69
|
+
export { getAvailableWidth } from "./src/size/get_available_width.js";
|
|
70
|
+
export { getBorderSizes } from "./src/size/get_border_sizes.js";
|
|
71
|
+
export { getHeight } from "./src/size/get_height.js";
|
|
72
|
+
export { getInnerHeight } from "./src/size/get_inner_height.js";
|
|
73
|
+
export { getInnerWidth } from "./src/size/get_inner_width.js";
|
|
74
|
+
export { getMarginSizes } from "./src/size/get_margin_sizes.js";
|
|
75
|
+
export { getMaxHeight } from "./src/size/get_max_height.js";
|
|
76
|
+
export { getMaxWidth } from "./src/size/get_max_width.js";
|
|
77
|
+
export { getMinHeight } from "./src/size/get_min_height.js";
|
|
78
|
+
export { getMinWidth } from "./src/size/get_min_width.js";
|
|
79
|
+
export { getPaddingSizes } from "./src/size/get_padding_sizes.js";
|
|
80
|
+
export { getWidth } from "./src/size/get_width.js";
|
|
81
|
+
export { resolveCSSSize } from "./src/size/resolve_css_size.js";
|
|
82
|
+
// size hooks
|
|
83
|
+
export { useAvailableHeight } from "./src/size/hooks/use_available_height.js";
|
|
84
|
+
export { useAvailableWidth } from "./src/size/hooks/use_available_width.js";
|
|
85
|
+
export { useMaxHeight } from "./src/size/hooks/use_max_height.js";
|
|
86
|
+
export { useMaxWidth } from "./src/size/hooks/use_max_width.js";
|
|
87
|
+
export { useResizeStatus } from "./src/size/hooks/use_resize_status.js";
|
|
88
|
+
|
|
89
|
+
// transition
|
|
90
|
+
export {
|
|
91
|
+
createHeightTransition,
|
|
92
|
+
createOpacityTransition,
|
|
93
|
+
createTranslateXTransition,
|
|
94
|
+
createWidthTransition,
|
|
95
|
+
} from "./src/transition/dom_transition.js";
|
|
96
|
+
export { EASING, cubicBezier } from "./src/transition/easing.js";
|
|
97
|
+
export {
|
|
98
|
+
createTimelineTransition,
|
|
99
|
+
createTransition,
|
|
100
|
+
} from "./src/transition/transition_playback.js";
|
|
101
|
+
export { initUITransition } from "./src/ui_transition/ui_transition.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jsenv/dom",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DOM utilities for writing frontend code",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/jsenv/core",
|
|
8
|
+
"directory": "packages/frontend/dom"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "dmail",
|
|
13
|
+
"email": "dmaillard06@gmail.com"
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": [
|
|
16
|
+
"./dist/jsenv_dom.js"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"dev:jsenv": "./index.js",
|
|
22
|
+
"default": "./dist/jsenv_dom.js"
|
|
23
|
+
},
|
|
24
|
+
"./details_content_full_height": "./src/size/details_content_full_height.js",
|
|
25
|
+
"./details_toggle_animation": "./src/details_toggle_animation.js",
|
|
26
|
+
"./resize": "./src/size/resize.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"/dist/",
|
|
30
|
+
"/src/",
|
|
31
|
+
"/index.js"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "node ./scripts/build.mjs",
|
|
35
|
+
"prepublishOnly": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@jsenv/core": "../../../",
|
|
40
|
+
"@jsenv/navi": "../navi",
|
|
41
|
+
"@preact/signals": "^2.3.2",
|
|
42
|
+
"preact": "^10.27.2"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export const addAttributeEffect = (attributeName, effect) => {
|
|
2
|
+
const cleanupWeakMap = new WeakMap();
|
|
3
|
+
const applyEffect = (element) => {
|
|
4
|
+
const cleanup = effect(element);
|
|
5
|
+
cleanupWeakMap.set(
|
|
6
|
+
element,
|
|
7
|
+
typeof cleanup === "function" ? cleanup : () => {},
|
|
8
|
+
);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const cleanupEffect = (element) => {
|
|
12
|
+
const cleanup = cleanupWeakMap.get(element);
|
|
13
|
+
if (cleanup) {
|
|
14
|
+
cleanup();
|
|
15
|
+
cleanupWeakMap.delete(element);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const checkElement = (element) => {
|
|
20
|
+
if (element.hasAttribute(attributeName)) {
|
|
21
|
+
applyEffect(element);
|
|
22
|
+
}
|
|
23
|
+
const elementWithAttributeCollection = element.querySelectorAll(
|
|
24
|
+
`[${attributeName}]`,
|
|
25
|
+
);
|
|
26
|
+
for (const elementWithAttribute of elementWithAttributeCollection) {
|
|
27
|
+
applyEffect(elementWithAttribute);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
checkElement(document.body);
|
|
32
|
+
const mutationObserver = new MutationObserver((mutations) => {
|
|
33
|
+
for (const mutation of mutations) {
|
|
34
|
+
if (mutation.type === "childList") {
|
|
35
|
+
for (const addedNode of mutation.addedNodes) {
|
|
36
|
+
if (addedNode.nodeType !== Node.ELEMENT_NODE) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
checkElement(addedNode);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const removedNode of mutation.removedNodes) {
|
|
43
|
+
if (removedNode.nodeType !== Node.ELEMENT_NODE) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Clean up the removed node itself if it had the attribute
|
|
48
|
+
if (
|
|
49
|
+
removedNode.hasAttribute &&
|
|
50
|
+
removedNode.hasAttribute(attributeName)
|
|
51
|
+
) {
|
|
52
|
+
cleanupEffect(removedNode);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Clean up any children of the removed node that had the attribute
|
|
56
|
+
if (removedNode.querySelectorAll) {
|
|
57
|
+
const elementsWithAttribute = removedNode.querySelectorAll(
|
|
58
|
+
`[${attributeName}]`,
|
|
59
|
+
);
|
|
60
|
+
for (const element of elementsWithAttribute) {
|
|
61
|
+
cleanupEffect(element);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (
|
|
67
|
+
mutation.type === "attributes" &&
|
|
68
|
+
mutation.attributeName === attributeName
|
|
69
|
+
) {
|
|
70
|
+
const element = mutation.target;
|
|
71
|
+
if (element.hasAttribute(attributeName)) {
|
|
72
|
+
applyEffect(element);
|
|
73
|
+
} else {
|
|
74
|
+
cleanupEffect(element);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
mutationObserver.observe(document.body, {
|
|
80
|
+
childList: true,
|
|
81
|
+
subtree: true,
|
|
82
|
+
attributes: true,
|
|
83
|
+
attributeFilter: [attributeName],
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return () => {
|
|
87
|
+
mutationObserver.disconnect();
|
|
88
|
+
for (const cleanup of cleanupWeakMap.values()) {
|
|
89
|
+
cleanup();
|
|
90
|
+
}
|
|
91
|
+
cleanupWeakMap.clear();
|
|
92
|
+
};
|
|
93
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const setAttribute = (element, name, value) => {
|
|
2
|
+
if (element.hasAttribute(name)) {
|
|
3
|
+
const prevValue = element.getAttribute(name);
|
|
4
|
+
element.setAttribute(name, value);
|
|
5
|
+
return () => {
|
|
6
|
+
element.setAttribute(name, prevValue);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
element.setAttribute(name, value);
|
|
10
|
+
return () => {
|
|
11
|
+
element.removeAttribute(name);
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const createSetMany = (setter) => {
|
|
16
|
+
return (element, description) => {
|
|
17
|
+
const cleanupCallbackSet = new Set();
|
|
18
|
+
for (const name of Object.keys(description)) {
|
|
19
|
+
const value = description[name];
|
|
20
|
+
const restoreStyle = setter(element, name, value);
|
|
21
|
+
cleanupCallbackSet.add(restoreStyle);
|
|
22
|
+
}
|
|
23
|
+
return () => {
|
|
24
|
+
for (const cleanupCallback of cleanupCallbackSet) {
|
|
25
|
+
cleanupCallback();
|
|
26
|
+
}
|
|
27
|
+
cleanupCallbackSet.clear();
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const setAttributes = createSetMany(setAttribute);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>3 columns resize x demo</title>
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta charset="utf-8" />
|
|
7
|
+
<link rel="icon" href="data:," />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
* {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#app {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: row;
|
|
22
|
+
width: 600px;
|
|
23
|
+
border: 1px solid black;
|
|
24
|
+
box-sizing: content-box;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
[data-resize-handle] {
|
|
28
|
+
flex-grow: 1;
|
|
29
|
+
min-width: 50px;
|
|
30
|
+
}
|
|
31
|
+
</style>
|
|
32
|
+
|
|
33
|
+
<div id="app">
|
|
34
|
+
<div
|
|
35
|
+
id="a"
|
|
36
|
+
data-resize="horizontal"
|
|
37
|
+
data-resize-handle
|
|
38
|
+
style="background: blue; height: 100px"
|
|
39
|
+
></div>
|
|
40
|
+
<div
|
|
41
|
+
id="b"
|
|
42
|
+
data-resize="horizontal"
|
|
43
|
+
data-resize-handle
|
|
44
|
+
style="background: red; height: 200px"
|
|
45
|
+
></div>
|
|
46
|
+
<div
|
|
47
|
+
id="c"
|
|
48
|
+
data-resize="horizontal"
|
|
49
|
+
data-resize-handle
|
|
50
|
+
style="background: green; height: 100px"
|
|
51
|
+
></div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<label>
|
|
55
|
+
width:
|
|
56
|
+
<input type="number" id="container_width" />
|
|
57
|
+
</label>
|
|
58
|
+
|
|
59
|
+
<script type="module">
|
|
60
|
+
import "@jsenv/dom/resize";
|
|
61
|
+
|
|
62
|
+
const resizeCollection = document.querySelectorAll("[data-resize]");
|
|
63
|
+
for (const resize of resizeCollection) {
|
|
64
|
+
const sizeInLocalStorage = localStorage.getItem(`${resize.id}_width`);
|
|
65
|
+
if (sizeInLocalStorage) {
|
|
66
|
+
resize.style.width = `${sizeInLocalStorage}px`;
|
|
67
|
+
}
|
|
68
|
+
resize.addEventListener("resize", (event) => {
|
|
69
|
+
console.log("resize event", event.target.id, resize.id);
|
|
70
|
+
localStorage.setItem(`${resize.id}_width`, event.detail.width);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const input = document.querySelector("input");
|
|
75
|
+
input.oninput = () => {
|
|
76
|
+
const width = input.value;
|
|
77
|
+
document.querySelector("#app").style.width = `${width}px`;
|
|
78
|
+
};
|
|
79
|
+
input.value = document
|
|
80
|
+
.querySelector("#app")
|
|
81
|
+
.getBoundingClientRect().width;
|
|
82
|
+
</script>
|
|
83
|
+
</body>
|
|
84
|
+
</html>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>3 rows resize x demo</title>
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta charset="utf-8" />
|
|
7
|
+
<link rel="icon" href="data:," />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
* {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#app {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
height: 600px;
|
|
23
|
+
border: 1px solid black;
|
|
24
|
+
box-sizing: content-box;
|
|
25
|
+
width: 300px;
|
|
26
|
+
margin-left: 200px;
|
|
27
|
+
margin-top: 50px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
[data-resize-handle] {
|
|
31
|
+
flex-grow: 1;
|
|
32
|
+
min-height: 50px;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
35
|
+
|
|
36
|
+
<div id="app">
|
|
37
|
+
<div
|
|
38
|
+
id="a"
|
|
39
|
+
data-resize="vertical"
|
|
40
|
+
data-resize-handle
|
|
41
|
+
data-resize-absolute
|
|
42
|
+
style="background: blue; width: 100px"
|
|
43
|
+
></div>
|
|
44
|
+
<div
|
|
45
|
+
id="b"
|
|
46
|
+
data-resize="vertical"
|
|
47
|
+
data-resize-handle
|
|
48
|
+
data-resize-absolute
|
|
49
|
+
style="background: red; width: 200px"
|
|
50
|
+
></div>
|
|
51
|
+
<div
|
|
52
|
+
id="c"
|
|
53
|
+
data-resize="vertical"
|
|
54
|
+
data-resize-handle
|
|
55
|
+
data-resize-absolute
|
|
56
|
+
style="background: green; width: 100px"
|
|
57
|
+
></div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<label>
|
|
61
|
+
height:
|
|
62
|
+
<input type="number" id="container_size" />
|
|
63
|
+
</label>
|
|
64
|
+
|
|
65
|
+
<script type="module">
|
|
66
|
+
import "@jsenv/dom/resize";
|
|
67
|
+
|
|
68
|
+
const resizeCollection = document.querySelectorAll("[data-resize]");
|
|
69
|
+
for (const resize of resizeCollection) {
|
|
70
|
+
const sizeInLocalStorage = localStorage.getItem(`${resize.id}_height`);
|
|
71
|
+
if (sizeInLocalStorage) {
|
|
72
|
+
resize.style.height = `${sizeInLocalStorage}px`;
|
|
73
|
+
}
|
|
74
|
+
resize.addEventListener("resize", (event) => {
|
|
75
|
+
localStorage.setItem(`${resize.id}_height`, event.detail.height);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const input = document.querySelector("input");
|
|
80
|
+
input.oninput = () => {
|
|
81
|
+
const size = input.value;
|
|
82
|
+
document.querySelector("#app").style.height = `${size}px`;
|
|
83
|
+
};
|
|
84
|
+
input.value = document
|
|
85
|
+
.querySelector("#app")
|
|
86
|
+
.getBoundingClientRect().height;
|
|
87
|
+
</script>
|
|
88
|
+
</body>
|
|
89
|
+
</html>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Aside and main demo</title>
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta charset="utf-8" />
|
|
7
|
+
<link rel="icon" href="data:," />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
* {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#app {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: row;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
aside {
|
|
25
|
+
background: #f0f0f0;
|
|
26
|
+
border-right: 1px solid #ccc;
|
|
27
|
+
height: 100vh;
|
|
28
|
+
position: sticky;
|
|
29
|
+
top: 0;
|
|
30
|
+
width: 200px;
|
|
31
|
+
min-width: 100px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
main {
|
|
35
|
+
min-width: 200px;
|
|
36
|
+
padding-bottom: 0;
|
|
37
|
+
min-width: 200px; /* Prevents content area from becoming too narrow */
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
min-height: 100vh; /* Ensures content area is at least viewport height */
|
|
40
|
+
overflow-x: auto; /* Horizontal scrollbar appears when content is wider than available space */
|
|
41
|
+
scrollbar-gutter: stable; /* Reserves space for scrollbar to prevent layout shifts */
|
|
42
|
+
flex: 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.main_body {
|
|
46
|
+
width: fit-content;
|
|
47
|
+
padding: 20px; /* Consistent padding around main content */
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
aside > [data-resize-handle] {
|
|
51
|
+
position: absolute;
|
|
52
|
+
z-index: 1; /* Ensures resize handle appears above sidebar content */
|
|
53
|
+
width: 5px;
|
|
54
|
+
right: -2.5px; /* Centers the handle on the border */
|
|
55
|
+
top: 0;
|
|
56
|
+
bottom: 0;
|
|
57
|
+
cursor: ew-resize; /* Indicates horizontal resize capability */
|
|
58
|
+
}
|
|
59
|
+
aside > [data-resize-handle]:hover,
|
|
60
|
+
aside[data-resizing] > [data-resize-handle] {
|
|
61
|
+
background-color: blue;
|
|
62
|
+
opacity: 0.5;
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
65
|
+
|
|
66
|
+
<div id="app">
|
|
67
|
+
<aside data-resize="horizontal" data-resize-absolute>
|
|
68
|
+
<div data-resize-handle></div>
|
|
69
|
+
</aside>
|
|
70
|
+
<main>
|
|
71
|
+
<div class="main_body">
|
|
72
|
+
<h1 title="Explore and manager your database">Database Manager</h1>
|
|
73
|
+
|
|
74
|
+
<div style="background: blue; width: 600px; height: 600px"></div>
|
|
75
|
+
</div>
|
|
76
|
+
</main>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<script type="module">
|
|
80
|
+
import "@jsenv/dom/resize";
|
|
81
|
+
|
|
82
|
+
const aside = document.querySelector("aside");
|
|
83
|
+
const widthInLocalStorage = localStorage.getItem("sidebar_width");
|
|
84
|
+
if (widthInLocalStorage) {
|
|
85
|
+
aside.style.width = `${widthInLocalStorage}px`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
aside.addEventListener("resizeend", (event) => {
|
|
89
|
+
localStorage.setItem("sidebar_width", event.detail.width);
|
|
90
|
+
});
|
|
91
|
+
</script>
|
|
92
|
+
</body>
|
|
93
|
+
</html>
|