@jsenv/navi 0.0.1 → 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.
Files changed (138) hide show
  1. package/dist/jsenv_navi.js +22954 -0
  2. package/index.js +66 -16
  3. package/package.json +22 -11
  4. package/src/actions.js +50 -26
  5. package/src/browser_integration/browser_integration.js +31 -6
  6. package/src/browser_integration/via_history.js +42 -9
  7. package/src/components/action_execution/render_actionable_component.jsx +6 -4
  8. package/src/components/action_execution/use_action.js +51 -282
  9. package/src/components/action_execution/use_execute_action.js +106 -92
  10. package/src/components/action_execution/use_run_on_mount.js +9 -0
  11. package/src/components/action_renderer.jsx +21 -32
  12. package/src/components/demos/0_button_demo.html +574 -103
  13. package/src/components/demos/10_column_reordering_debug.html +277 -0
  14. package/src/components/demos/11_table_selection_debug.html +432 -0
  15. package/src/components/demos/1_checkbox_demo.html +579 -202
  16. package/src/components/demos/2_input_textual_demo.html +81 -138
  17. package/src/components/demos/3_radio_demo.html +0 -2
  18. package/src/components/demos/4_select_demo.html +19 -23
  19. package/src/components/demos/6_tablist_demo.html +77 -0
  20. package/src/components/demos/7_table_selection_demo.html +176 -0
  21. package/src/components/demos/8_table_fixed_headers_demo.html +584 -0
  22. package/src/components/demos/9_table_column_drag_demo.html +325 -0
  23. package/src/components/demos/action/0_button_demo.html +2 -4
  24. package/src/components/demos/action/1_input_text_demo.html +643 -222
  25. package/src/components/demos/action/3_details_demo.html +146 -115
  26. package/src/components/demos/action/4_input_checkbox_demo.html +442 -322
  27. package/src/components/demos/action/5_input_checkbox_state_demo.html +270 -0
  28. package/src/components/demos/action/6_checkbox_list_demo.html +304 -72
  29. package/src/components/demos/action/7_radio_list_demo.html +310 -170
  30. package/src/components/demos/action/{8_editable_text_demo.html → 8_editable_demo.html} +65 -76
  31. package/src/components/demos/action/9_link_demo.html +84 -62
  32. package/src/components/demos/ui_transition/0_action_renderer_ui_transition_demo.html +695 -0
  33. package/src/components/demos/ui_transition/1_nested_ui_transition_demo.html +429 -0
  34. package/src/components/demos/ui_transition/2_height_transition_test.html +295 -0
  35. package/src/components/details/details.jsx +62 -64
  36. package/src/components/edition/editable.jsx +186 -0
  37. package/src/components/field/README.md +247 -0
  38. package/src/components/{input → field}/button.jsx +151 -130
  39. package/src/components/field/checkbox_list.jsx +184 -0
  40. package/src/components/{collect_form_element_values.js → field/collect_form_element_values.js} +7 -4
  41. package/src/components/{input → field}/field_css.js +4 -1
  42. package/src/components/field/form.jsx +211 -0
  43. package/src/components/{input → field}/input.jsx +1 -0
  44. package/src/components/{input → field}/input_checkbox.jsx +132 -155
  45. package/src/components/{input → field}/input_radio.jsx +135 -46
  46. package/src/components/{input → field}/input_textual.jsx +247 -173
  47. package/src/components/field/label.jsx +32 -0
  48. package/src/components/field/radio_list.jsx +182 -0
  49. package/src/components/{input → field}/select.jsx +17 -32
  50. package/src/components/field/use_action_events.js +132 -0
  51. package/src/components/field/use_form_events.js +55 -0
  52. package/src/components/field/use_ui_state_controller.js +506 -0
  53. package/src/components/item_tracker/README.md +461 -0
  54. package/src/components/item_tracker/use_isolated_item_tracker.jsx +209 -0
  55. package/src/components/item_tracker/use_isolated_item_tracker_demo.html +148 -0
  56. package/src/components/item_tracker/use_isolated_item_tracker_demo.jsx +460 -0
  57. package/src/components/item_tracker/use_item_tracker.jsx +143 -0
  58. package/src/components/item_tracker/use_item_tracker_demo.html +207 -0
  59. package/src/components/item_tracker/use_item_tracker_demo.jsx +216 -0
  60. package/src/components/keyboard_shortcuts/active_keyboard_shortcuts.jsx +87 -0
  61. package/src/components/keyboard_shortcuts/aria_key_shortcuts.js +61 -0
  62. package/src/components/keyboard_shortcuts/keyboard_key_meta.js +17 -0
  63. package/src/components/keyboard_shortcuts/keyboard_shortcuts.js +371 -0
  64. package/src/components/link/link.jsx +65 -102
  65. package/src/components/link/link_with_icon.jsx +52 -0
  66. package/src/components/loader/loader_background.jsx +85 -64
  67. package/src/components/loader/rectangle_loading.jsx +38 -19
  68. package/src/components/route.jsx +8 -4
  69. package/src/components/selection/selection.jsx +1583 -0
  70. package/src/components/svg/font_sized_svg.jsx +45 -0
  71. package/src/components/svg/icon_and_text.jsx +21 -0
  72. package/src/components/svg/svg_mask_overlay.jsx +105 -0
  73. package/src/components/table/drag/table_drag.jsx +506 -0
  74. package/src/components/table/resize/table_resize.jsx +650 -0
  75. package/src/components/table/resize/table_size.js +43 -0
  76. package/src/components/table/selection/table_selection.js +106 -0
  77. package/src/components/table/selection/table_selection.jsx +203 -0
  78. package/src/components/table/sticky/sticky_group.js +354 -0
  79. package/src/components/table/sticky/table_sticky.js +25 -0
  80. package/src/components/table/sticky/table_sticky.jsx +501 -0
  81. package/src/components/table/table.jsx +721 -0
  82. package/src/components/table/table_css.js +211 -0
  83. package/src/components/table/table_ui.jsx +49 -0
  84. package/src/components/table/use_cells_and_columns.js +90 -0
  85. package/src/components/table/use_object_array_to_cells.js +46 -0
  86. package/src/components/table/z_indexes.js +23 -0
  87. package/src/components/tablist/tablist.jsx +99 -0
  88. package/src/components/text/overflow.jsx +15 -0
  89. package/src/components/text/text_and_count.jsx +28 -0
  90. package/src/components/ui_transition.jsx +128 -0
  91. package/src/components/use_auto_focus.js +58 -7
  92. package/src/components/use_batch_during_render.js +33 -0
  93. package/src/components/use_debounce_true.js +7 -7
  94. package/src/components/use_dependencies_diff.js +35 -0
  95. package/src/components/use_focus_group.js +4 -3
  96. package/src/components/use_initial_value.js +8 -34
  97. package/src/components/use_signal_sync.js +1 -1
  98. package/src/components/use_stable_callback.js +68 -0
  99. package/src/components/use_state_array.js +16 -9
  100. package/src/docs/actions.md +22 -0
  101. package/src/notes.md +33 -12
  102. package/src/route/route.js +97 -47
  103. package/src/store/resource_graph.js +2 -1
  104. package/src/store/tests/{resource_graph_dependencies.test.js → resource_graph_dependencies.test_manual.js} +13 -13
  105. package/src/utils/is_signal.js +20 -0
  106. package/src/utils/stringify_for_display.js +4 -23
  107. package/src/validation/constraints/confirm_constraint.js +14 -0
  108. package/src/validation/constraints/create_unique_value_constraint.js +27 -0
  109. package/src/validation/constraints/native_constraints.js +313 -0
  110. package/src/validation/constraints/readonly_constraint.js +36 -0
  111. package/src/validation/constraints/single_space_constraint.js +13 -0
  112. package/src/validation/custom_constraint_validation.js +599 -0
  113. package/src/validation/custom_message.js +18 -0
  114. package/src/validation/demos/browser_style.png +0 -0
  115. package/src/validation/demos/form_validation_demo.html +142 -0
  116. package/src/validation/demos/form_validation_demo_preact.html +87 -0
  117. package/src/validation/demos/form_validation_native_popover_demo.html +168 -0
  118. package/src/validation/demos/form_validation_vs_native_demo.html +172 -0
  119. package/src/validation/demos/validation_message_demo.html +203 -0
  120. package/src/validation/hooks/use_constraints.js +23 -0
  121. package/src/validation/hooks/use_custom_validation_ref.js +73 -0
  122. package/src/validation/hooks/use_validation_message.js +19 -0
  123. package/src/validation/validation_message.js +741 -0
  124. package/src/components/editable_text/editable_text.jsx +0 -96
  125. package/src/components/form.jsx +0 -144
  126. package/src/components/input/checkbox_list.jsx +0 -294
  127. package/src/components/input/field.jsx +0 -61
  128. package/src/components/input/radio_list.jsx +0 -283
  129. package/src/components/input/use_form_event.js +0 -20
  130. package/src/components/input/use_on_change.js +0 -12
  131. package/src/components/selection/selection.js +0 -5
  132. package/src/components/selection/selection_context.jsx +0 -262
  133. package/src/components/shortcut/shortcut_context.jsx +0 -390
  134. package/src/components/use_action_events.js +0 -37
  135. package/src/utils/iterable_weak_set.js +0 -62
  136. /package/src/components/demos/action/{11_nested_shortcuts_demo.html → 11_nested_shortcuts_demo.xhtml} +0 -0
  137. /package/src/components/{shortcut → keyboard_shortcuts}/os.js +0 -0
  138. /package/src/route/{route.test.html → route.xtest.html} +0 -0
@@ -0,0 +1,142 @@
1
+ <!--
2
+
3
+ TOFIX:
4
+
5
+ resize observer pas content lorsqu'on a un contenu vachement large
6
+
7
+ lorsqu'on zoom le comportement semble étrange
8
+
9
+
10
+ -->
11
+
12
+ <!doctype html>
13
+ <html>
14
+ <head>
15
+ <title>From validation demo</title>
16
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
17
+ <meta charset="utf-8" />
18
+ <link rel="icon" href="data:," />
19
+ <style>
20
+ body {
21
+ background: yellow;
22
+ }
23
+
24
+ input {
25
+ border-width: 5px;
26
+ }
27
+ </style>
28
+ </head>
29
+ <body>
30
+ <div id="app">
31
+ <div style="display: flex; gap: 30px">
32
+ <div>
33
+ <h3>Required</h3>
34
+ <div style="border: 1px solid black">
35
+ <form action="javascript:void(0)">
36
+ <input
37
+ type="text"
38
+ required
39
+ value=""
40
+ title="Coucou"
41
+ oninput="this.reportValidity()"
42
+ />
43
+ <button>button</button>
44
+ <button type="submit">button type submit</button>
45
+ <input preserve type="submit" value="submit" />
46
+
47
+ <a onclick="this.parentNode.requestSubmit()"
48
+ >form.requestSubmit()</a
49
+ >
50
+ </form>
51
+ </div>
52
+ </div>
53
+
54
+ <div>
55
+ <h3>Native email</h3>
56
+ <div style="border: 1px solid black">
57
+ <form action="javascript:void(0)">
58
+ <input
59
+ type="email"
60
+ preserve
61
+ value=""
62
+ oninput="this.reportValidity()"
63
+ />
64
+ <button>button</button>
65
+ <button type="submit">button type submit</button>
66
+ <input preserve type="submit" value="submit" />
67
+ </form>
68
+ </div>
69
+ </div>
70
+
71
+ <div>
72
+ <h3>Pattern</h3>
73
+ <div style="border: 1px solid black">
74
+ <form action="javascript:void(0)">
75
+ <input
76
+ type="text"
77
+ pattern="^[a-z]{4,8}$"
78
+ title="4 to 8 lowercase letters"
79
+ value="10"
80
+ oninput="this.reportValidity()"
81
+ />
82
+ </form>
83
+ </div>
84
+ </div>
85
+ </div>
86
+
87
+ <div>
88
+ <h3>No "a" constraint</h3>
89
+ <div style="border: 1px solid black">
90
+ <form action="javascript:void(0)">
91
+ <input
92
+ id="no_a_constraint"
93
+ type="text"
94
+ value="10"
95
+ oninput="this.reportValidity()"
96
+ />
97
+ </form>
98
+
99
+ <button id="add_custom">Add custom message</button>
100
+ <button id="remove_custom">Remove custom message</button>
101
+ </div>
102
+ </div>
103
+ </div>
104
+ <script type="module">
105
+ // eslint-disable-next-line import-x/no-unresolved
106
+ import { installInputValidation } from "./input_validity.js";
107
+
108
+ const noAConstraint = {
109
+ check: (input) => {
110
+ const value = input.value;
111
+ if (value.includes("a")) {
112
+ return `Ce champ ne doit pas contenir la lettre "a".`;
113
+ }
114
+ return null;
115
+ },
116
+ };
117
+ for (const input of document.querySelectorAll("input")) {
118
+ if (input.hasAttribute("preserve")) {
119
+ continue;
120
+ }
121
+
122
+ installInputValidation(input, {
123
+ customConstraints:
124
+ input.id === "no_a_constraint" ? [noAConstraint] : [],
125
+ });
126
+ }
127
+
128
+ const addCustomButton = document.querySelector("#add_custom");
129
+ document.querySelector("#add_custom").addEventListener("click", () => {
130
+ const input = addCustomButton.parentNode.querySelector("input");
131
+ input.validationInterface.addCustomMessage("test", "Hey oh", {
132
+ level: "error",
133
+ });
134
+ });
135
+ const removeCustomButton = document.querySelector("#remove_custom");
136
+ removeCustomButton.addEventListener("click", () => {
137
+ const input = removeCustomButton.parentNode.querySelector("input");
138
+ input.validationInterface.removeCustomMessage("test");
139
+ });
140
+ </script>
141
+ </body>
142
+ </html>
@@ -0,0 +1,87 @@
1
+ <!--
2
+
3
+ TOFIX:
4
+
5
+ resize observer pas content lorsqu'on a un contenu vachement large
6
+
7
+ lorsqu'on zoom le comportement semble étrange
8
+
9
+
10
+ -->
11
+
12
+ <!doctype html>
13
+ <html>
14
+ <head>
15
+ <title>From validation demo</title>
16
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
17
+ <meta charset="utf-8" />
18
+ <link rel="icon" href="data:," />
19
+ <style>
20
+ body {
21
+ background: yellow;
22
+ }
23
+
24
+ input {
25
+ border-width: 5px;
26
+ }
27
+ </style>
28
+ </head>
29
+ <body>
30
+ <div id="app"></div>
31
+ <script type="module" jsenv-type="module/jsx">
32
+ import { render } from "preact";
33
+ import { useRef } from "preact/hooks";
34
+ import { useConstraints } from "../hooks/use_constraints.js";
35
+ import { useValidationMessage } from "../hooks/use_validation_message.js";
36
+
37
+ // eslint-disable-next-line no-unused-vars
38
+ const App = () => {
39
+ const inputRef = useRef();
40
+
41
+ useConstraints(inputRef, (input) => {
42
+ const value = input.value;
43
+ if (value.includes("a")) {
44
+ return `Ce champ ne doit pas contenir la lettre "a".`;
45
+ }
46
+ return null;
47
+ });
48
+
49
+ const [addInputError, removeInputError] = useValidationMessage(
50
+ inputRef,
51
+ "error",
52
+ );
53
+
54
+ return (
55
+ <div>
56
+ <input
57
+ required
58
+ ref={inputRef}
59
+ type="text"
60
+ placeholder="Type something"
61
+ onCancel={() => {
62
+ console.log("cancel");
63
+ }}
64
+ />
65
+
66
+ <button
67
+ onClick={() => {
68
+ addInputError("hey");
69
+ }}
70
+ >
71
+ Set error
72
+ </button>
73
+ <button
74
+ onClick={() => {
75
+ removeInputError();
76
+ }}
77
+ >
78
+ Reset error
79
+ </button>
80
+ </div>
81
+ );
82
+ };
83
+
84
+ render(<App />, document.querySelector("#app"));
85
+ </script>
86
+ </body>
87
+ </html>
@@ -0,0 +1,168 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>Form validation native popover</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta charset="utf-8" />
7
+ <link rel="icon" href="data:," />
8
+ <style>
9
+ body {
10
+ background: yellow;
11
+ }
12
+ </style>
13
+ </head>
14
+ <body>
15
+ <div id="app">
16
+ <h1>Form validation popover</h1>
17
+
18
+ <div>
19
+ <p>This demo shows how native popover behaves on form validation</p>
20
+ </div>
21
+
22
+ <div style="display: flex; gap: 30px">
23
+ <div style="border: 1px solid black">
24
+ <h3>Basic</h3>
25
+ <form action="javascript:void(0)">
26
+ <input
27
+ type="text"
28
+ pattern="^[a-z]{4,8}$"
29
+ title="4 to 8 lowercase letters"
30
+ autocomplete="off"
31
+ value="10"
32
+ oninput="this.reportValidity()"
33
+ />
34
+ </form>
35
+ </div>
36
+
37
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
38
+ <h3>Top of scrollable content</h3>
39
+ <form action="javascript:void(0)">
40
+ <input
41
+ type="text"
42
+ pattern="^[a-z]{4,8}$"
43
+ title="4 to 8 lowercase letters"
44
+ autocomplete="off"
45
+ value="10"
46
+ oninput="this.reportValidity()"
47
+ />
48
+ </form>
49
+ <div style="height: 300px; background: blue"></div>
50
+ </div>
51
+
52
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
53
+ <h3>Bottom of scrollable content</h3>
54
+ <div style="height: 300px; background: blue"></div>
55
+ <form action="javascript:void(0)">
56
+ <input
57
+ type="text"
58
+ pattern="^[a-z]{4,8}$"
59
+ title="4 to 8 lowercase letters"
60
+ autocomplete="off"
61
+ value="10"
62
+ oninput="this.reportValidity()"
63
+ />
64
+ </form>
65
+ </div>
66
+ </div>
67
+
68
+ <br />
69
+
70
+ <div style="display: flex; gap: 30px">
71
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
72
+ <h3>minLength</h3>
73
+ <form action="javascript:void(0)">
74
+ <input type="text" minlength="5" oninput="this.reportValidity()" />
75
+ </form>
76
+ </div>
77
+
78
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
79
+ <h3>maxLength</h3>
80
+ <form action="javascript:void(0)">
81
+ <input
82
+ type="text"
83
+ id="max_length"
84
+ maxlength="5"
85
+ oninput="this.reportValidity()"
86
+ />
87
+ </form>
88
+ </div>
89
+
90
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
91
+ <h3>min on number</h3>
92
+ <form action="javascript:void(0)">
93
+ <input
94
+ type="number"
95
+ min="5"
96
+ value="4"
97
+ oninput="this.reportValidity()"
98
+ />
99
+ </form>
100
+ </div>
101
+
102
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
103
+ <h3>min on range</h3>
104
+ <form action="javascript:void(0)">
105
+ <input
106
+ type="range"
107
+ id="min_range"
108
+ min="10"
109
+ max="100"
110
+ value="5"
111
+ oninput="this.reportValidity()"
112
+ onchange="this.reportValidity()"
113
+ />
114
+ </form>
115
+ </div>
116
+ </div>
117
+
118
+ <br />
119
+
120
+ <div style="display: flex; gap: 30px">
121
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
122
+ <h3>min on week</h3>
123
+ <form action="javascript:void(0)">
124
+ <input
125
+ type="week"
126
+ min="2017-W3"
127
+ max="2017-W8"
128
+ value="2017-W5"
129
+ oninput="this.reportValidity()"
130
+ onchange="this.reportValidity()"
131
+ />
132
+ </form>
133
+ </div>
134
+
135
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
136
+ <h3>min on date</h3>
137
+ <form action="javascript:void(0)">
138
+ <input
139
+ type="date"
140
+ id="date_min"
141
+ min="2018-01-01"
142
+ max="2018-05-05"
143
+ value="2019-12-31"
144
+ oninput="this.reportValidity()"
145
+ />
146
+ </form>
147
+ </div>
148
+
149
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
150
+ <h3>min on time</h3>
151
+ <form action="javascript:void(0)">
152
+ <input
153
+ type="time"
154
+ id="time_min"
155
+ min="09:10"
156
+ max="18:00"
157
+ value="06:00"
158
+ oninput="this.reportValidity()"
159
+ />
160
+ </form>
161
+ </div>
162
+ </div>
163
+
164
+ <!-- <div style="background: blue; height: 400px"></div> -->
165
+ </div>
166
+ <script type="module"></script>
167
+ </body>
168
+ </html>
@@ -0,0 +1,172 @@
1
+ <!--
2
+
3
+ TOFIX:
4
+
5
+ resize observer pas content lorsqu'on a un contenu vachement large
6
+
7
+ lorsqu'on zoom le comportement semble étrange
8
+
9
+
10
+ -->
11
+
12
+ <!doctype html>
13
+ <html>
14
+ <head>
15
+ <title>From validation demo</title>
16
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
17
+ <meta charset="utf-8" />
18
+ <link rel="icon" href="data:," />
19
+ <style>
20
+ body {
21
+ background: yellow;
22
+ }
23
+
24
+ input {
25
+ border-width: 5px;
26
+ }
27
+ </style>
28
+ </head>
29
+ <body>
30
+ <div id="app">
31
+ <div style="display: flex; gap: 30px">
32
+ <div>
33
+ <h3>Basic</h3>
34
+ <div style="border: 1px solid black; width: 300px">
35
+ <form action="javascript:void(0)">
36
+ <input
37
+ type="text"
38
+ pattern="^[a-z]{4,8}$"
39
+ title="4 to 8 lowercase letters"
40
+ autocomplete="off"
41
+ value="10"
42
+ oninput="this.reportValidity()"
43
+ />
44
+ </form>
45
+ </div>
46
+ </div>
47
+
48
+ <div>
49
+ <h3>Basic right</h3>
50
+ <div style="border: 1px solid black; width: 600px">
51
+ <form action="javascript:void(0)">
52
+ <input
53
+ type="text"
54
+ pattern="^[a-z]{4,8}$"
55
+ title="4 to 8 lowercase letters"
56
+ autocomplete="off"
57
+ value="10"
58
+ style="width: 500px"
59
+ oninput="this.reportValidity()"
60
+ />
61
+ </form>
62
+
63
+ <button id="report">reportValidity()</button>
64
+ </div>
65
+ </div>
66
+
67
+ <div>
68
+ <h3>Message smaller than input</h3>
69
+ <form action="javascript:void(0)">
70
+ <input
71
+ type="text"
72
+ pattern="^[a-z]{4,8}$"
73
+ title="4 to 8 lowercase letters"
74
+ autocomplete="off"
75
+ value="10"
76
+ oninput="this.reportValidity()"
77
+ style="width: 300px"
78
+ />
79
+ </form>
80
+ </div>
81
+
82
+ <div>
83
+ <h3>Message bigger than input</h3>
84
+ <form action="javascript:void(0)">
85
+ <input
86
+ type="text"
87
+ pattern="^[a-z]{4,8}$"
88
+ title="4 to 8 lowercase letters"
89
+ autocomplete="off"
90
+ value="10"
91
+ oninput="this.reportValidity()"
92
+ style="width: 20px"
93
+ />
94
+ </form>
95
+ </div>
96
+ </div>
97
+
98
+ <div>
99
+ <h3>Top of scrollable content</h3>
100
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
101
+ <form action="javascript:void(0)">
102
+ <input
103
+ type="text"
104
+ pattern="^[a-z]{4,8}$"
105
+ title="4 to 8 lowercase letters"
106
+ autocomplete="off"
107
+ value="10"
108
+ oninput="this.reportValidity()"
109
+ />
110
+ </form>
111
+ <div style="height: 300px; background: blue"></div>
112
+ </div>
113
+ </div>
114
+
115
+ <div>
116
+ <h3>Bottom of scrollable content</h3>
117
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
118
+ <div style="height: 300px; background: blue"></div>
119
+ <form action="javascript:void(0)">
120
+ <input
121
+ type="text"
122
+ pattern="^[a-z]{4,8}$"
123
+ title="4 to 8 lowercase letters"
124
+ autocomplete="off"
125
+ value="10"
126
+ oninput="this.reportValidity()"
127
+ />
128
+ </form>
129
+ </div>
130
+ </div>
131
+
132
+ <div>
133
+ <h3>Middle of scrollable content</h3>
134
+ <div style="border: 1px solid black; overflow: auto; height: 150px">
135
+ <div style="height: 250px; background: blue"></div>
136
+ <form action="javascript:void(0)">
137
+ <input
138
+ type="text"
139
+ pattern="^[a-z]{4,8}$"
140
+ title="4 to 8 lowercase letters"
141
+ autocomplete="off"
142
+ value="10"
143
+ oninput="this.reportValidity()"
144
+ />
145
+ </form>
146
+ <div style="height: 250px; background: blue"></div>
147
+ </div>
148
+ </div>
149
+ </div>
150
+
151
+ <br />
152
+ <br />
153
+ <br />
154
+ <div style="background: red; width: 2000px; height: 1px"></div>
155
+ <div style="background: blue; height: 400px"></div>
156
+ <script type="module">
157
+ import { openValidationMessage } from "../validation_message.js";
158
+
159
+ const inputs = document.querySelectorAll("input");
160
+ for (const input of inputs) {
161
+ input.addEventListener("focus", () => {
162
+ openValidationMessage(input, "Veuillez respecter le format requis.");
163
+ });
164
+ }
165
+
166
+ const reportButton = document.querySelector("#report");
167
+ document.querySelector("#report").onclick = () => {
168
+ reportButton.parentNode.querySelector("input").reportValidity();
169
+ };
170
+ </script>
171
+ </body>
172
+ </html>