@jsenv/navi 0.0.1 → 0.1.1

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 (139) hide show
  1. package/dist/jsenv_navi.js +22959 -0
  2. package/index.js +66 -16
  3. package/package.json +23 -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/field/input_textual.jsx +418 -0
  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/input_textual.jsx +0 -338
  129. package/src/components/input/radio_list.jsx +0 -283
  130. package/src/components/input/use_form_event.js +0 -20
  131. package/src/components/input/use_on_change.js +0 -12
  132. package/src/components/selection/selection.js +0 -5
  133. package/src/components/selection/selection_context.jsx +0 -262
  134. package/src/components/shortcut/shortcut_context.jsx +0 -390
  135. package/src/components/use_action_events.js +0 -37
  136. package/src/utils/iterable_weak_set.js +0 -62
  137. /package/src/components/demos/action/{11_nested_shortcuts_demo.html → 11_nested_shortcuts_demo.xhtml} +0 -0
  138. /package/src/components/{shortcut → keyboard_shortcuts}/os.js +0 -0
  139. /package/src/route/{route.test.html → route.xtest.html} +0 -0
@@ -1,18 +1,16 @@
1
- import { requestAction } from "@jsenv/validation";
2
1
  import { forwardRef } from "preact/compat";
3
2
  import { useEffect, useImperativeHandle, useRef, useState } from "preact/hooks";
3
+
4
4
  import { useNavState } from "../../browser_integration/browser_integration.js";
5
5
  import { useActionStatus } from "../../use_action_status.js";
6
+ import { requestAction } from "../../validation/custom_constraint_validation.js";
6
7
  import { renderActionableComponent } from "../action_execution/render_actionable_component.jsx";
7
- import {
8
- useActionBoundToOneParam,
9
- useOneFormParam,
10
- } from "../action_execution/use_action.js";
8
+ import { useActionBoundToOneParam } from "../action_execution/use_action.js";
11
9
  import { useExecuteAction } from "../action_execution/use_execute_action.js";
12
10
  import { LoaderBackground } from "../loader/loader_background.jsx";
13
- import { useActionEvents } from "../use_action_events.js";
14
11
  import { useRefArray } from "../use_ref_array.js";
15
- import { useFormEvents } from "./use_form_event.js";
12
+ import { useActionEvents } from "./use_action_events.js";
13
+ import { useFormEvents } from "./use_form_events.js";
16
14
 
17
15
  import.meta.css = /* css */ `
18
16
  .navi_select[data-readonly] {
@@ -21,11 +19,12 @@ import.meta.css = /* css */ `
21
19
  `;
22
20
 
23
21
  export const Select = forwardRef((props, ref) => {
24
- return renderActionableComponent(props, ref, {
22
+ const select = renderActionableComponent(props, ref, {
25
23
  Basic: SelectBasic,
26
24
  WithAction: SelectWithAction,
27
25
  InsideForm: SelectInsideForm,
28
26
  });
27
+ return select;
29
28
  });
30
29
 
31
30
  const SelectControlled = forwardRef((props, ref) => {
@@ -137,7 +136,7 @@ const SelectWithAction = forwardRef((props, ref) => {
137
136
  useImperativeHandle(ref, () => innerRef.current);
138
137
 
139
138
  const [navState, setNavState, resetNavState] = useNavState(id);
140
- const [boundAction, value, setValue, resetValue] = useActionBoundToOneParam(
139
+ const [boundAction, value, setValue, initialValue] = useActionBoundToOneParam(
141
140
  action,
142
141
  name,
143
142
  valueSignal ? valueSignal : externalValue,
@@ -155,7 +154,7 @@ const SelectWithAction = forwardRef((props, ref) => {
155
154
  useActionEvents(innerRef, {
156
155
  onCancel: (e, reason) => {
157
156
  resetNavState();
158
- resetValue();
157
+ setValue(initialValue);
159
158
  onCancel?.(e, reason);
160
159
  },
161
160
  onPrevented: onActionPrevented,
@@ -165,11 +164,11 @@ const SelectWithAction = forwardRef((props, ref) => {
165
164
  },
166
165
  onStart: onActionStart,
167
166
  onAbort: (e) => {
168
- resetValue();
167
+ setValue(initialValue);
169
168
  onActionAbort?.(e);
170
169
  },
171
170
  onError: (error) => {
172
- resetValue();
171
+ setValue(initialValue);
173
172
  onActionError?.(error);
174
173
  },
175
174
  onEnd: () => {
@@ -194,10 +193,10 @@ const SelectWithAction = forwardRef((props, ref) => {
194
193
  const optionSelected = select.querySelector(
195
194
  `option[value="${selectedValue}"]`,
196
195
  );
197
- requestAction(boundAction, {
196
+ requestAction(radioListContainer, boundAction, {
198
197
  event,
199
- target: radioListContainer,
200
198
  requester: optionSelected,
199
+ actionOrigin: "action_prop",
201
200
  });
202
201
  }}
203
202
  {...rest}
@@ -218,26 +217,13 @@ const SelectWithAction = forwardRef((props, ref) => {
218
217
  });
219
218
 
220
219
  const SelectInsideForm = forwardRef((props, ref) => {
221
- const {
222
- formContext,
223
- id,
224
- name,
225
- readOnly,
226
- value: externalValue,
227
- children,
228
- ...rest
229
- } = props;
230
- const { formIsReadOnly } = formContext;
220
+ const { id, name, value: externalValue, children, ...rest } = props;
231
221
 
232
222
  const innerRef = useRef();
233
223
  useImperativeHandle(ref, () => innerRef.current);
234
224
 
235
225
  const [navState, setNavState] = useNavState(id);
236
- const [value, setValue, resetValue] = useOneFormParam(
237
- name,
238
- externalValue,
239
- navState,
240
- );
226
+ const [value, setValue, initialValue] = [name, externalValue, navState];
241
227
  useEffect(() => {
242
228
  setNavState(value);
243
229
  }, [value]);
@@ -247,10 +233,10 @@ const SelectInsideForm = forwardRef((props, ref) => {
247
233
  setValue(undefined);
248
234
  },
249
235
  onFormActionAbort: () => {
250
- resetValue();
236
+ setValue(initialValue);
251
237
  },
252
238
  onFormActionError: () => {
253
- resetValue();
239
+ setValue(initialValue);
254
240
  },
255
241
  });
256
242
 
@@ -259,7 +245,6 @@ const SelectInsideForm = forwardRef((props, ref) => {
259
245
  ref={innerRef}
260
246
  name={name}
261
247
  value={value}
262
- readOnly={readOnly || formIsReadOnly}
263
248
  onChange={(event) => {
264
249
  const select = event.target;
265
250
  const selectedValue = select.checked;
@@ -0,0 +1,132 @@
1
+ import { useLayoutEffect, useState } from "preact/hooks";
2
+
3
+ import { addManyEventListeners } from "../../utils/add_many_event_listeners.js";
4
+ import { useStableCallback } from "../use_stable_callback.js";
5
+
6
+ export const useActionEvents = (
7
+ elementRef,
8
+ {
9
+ actionOrigin = "action_prop",
10
+ /**
11
+ * @param {Event} e - L'événement original
12
+ * @param {"form_reset" | "blur_invalid" | "escape_key"} reason - Raison du cancel
13
+ */
14
+ onCancel,
15
+ onRequested,
16
+ onPrevented,
17
+ onAction,
18
+ onStart,
19
+ onAbort,
20
+ onError,
21
+ onEnd,
22
+ },
23
+ ) => {
24
+ onCancel = useStableCallback(onCancel);
25
+ onRequested = useStableCallback(onRequested);
26
+ onPrevented = useStableCallback(onPrevented);
27
+ onAction = useStableCallback(onAction);
28
+ onStart = useStableCallback(onStart);
29
+ onAbort = useStableCallback(onAbort);
30
+ onError = useStableCallback(onError);
31
+ onEnd = useStableCallback(onEnd);
32
+
33
+ useLayoutEffect(() => {
34
+ const element = elementRef.current;
35
+ if (!element) {
36
+ return null;
37
+ }
38
+
39
+ return addManyEventListeners(element, {
40
+ cancel: (e) => {
41
+ // cancel don't need to check for actionOrigin because
42
+ // it's actually unrelated to a specific actions
43
+ // in that sense it should likely be moved elsewhere as it's related to
44
+ // interaction and constraint validation, not to a specific action
45
+ onCancel?.(e, e.detail.reason);
46
+ },
47
+ actionrequested: (e) => {
48
+ if (e.detail.actionOrigin !== actionOrigin) {
49
+ return;
50
+ }
51
+ onRequested?.(e);
52
+ },
53
+ actionprevented: (e) => {
54
+ if (e.detail.actionOrigin !== actionOrigin) {
55
+ return;
56
+ }
57
+ onPrevented?.(e);
58
+ },
59
+ action: (e) => {
60
+ if (e.detail.actionOrigin !== actionOrigin) {
61
+ return;
62
+ }
63
+ onAction?.(e);
64
+ },
65
+ actionstart: (e) => {
66
+ if (e.detail.actionOrigin !== actionOrigin) {
67
+ return;
68
+ }
69
+ onStart?.(e);
70
+ },
71
+ actionabort: (e) => {
72
+ if (e.detail.actionOrigin !== actionOrigin) {
73
+ return;
74
+ }
75
+ onAbort?.(e);
76
+ },
77
+ actionerror: (e) => {
78
+ if (e.detail.actionOrigin !== actionOrigin) {
79
+ return;
80
+ }
81
+ onError?.(e.detail.error, e);
82
+ },
83
+ actionend: onEnd,
84
+ });
85
+ }, [
86
+ actionOrigin,
87
+ onCancel,
88
+ onRequested,
89
+ onPrevented,
90
+ onAction,
91
+ onStart,
92
+ onAbort,
93
+ onError,
94
+ onEnd,
95
+ ]);
96
+ };
97
+
98
+ export const useRequestedActionStatus = (elementRef) => {
99
+ const [actionRequester, setActionRequester] = useState(null);
100
+ const [actionPending, setActionPending] = useState(false);
101
+ const [actionAborted, setActionAborted] = useState(false);
102
+ const [actionError, setActionError] = useState(null);
103
+
104
+ useActionEvents(elementRef, {
105
+ onAction: (actionEvent) => {
106
+ setActionRequester(actionEvent.detail.requester);
107
+ },
108
+ onStart: () => {
109
+ setActionPending(true);
110
+ setActionAborted(false);
111
+ setActionError(null);
112
+ },
113
+ onAbort: () => {
114
+ setActionPending(false);
115
+ setActionAborted(true);
116
+ },
117
+ onError: (error) => {
118
+ setActionPending(false);
119
+ setActionError(error);
120
+ },
121
+ onEnd: () => {
122
+ setActionPending(false);
123
+ },
124
+ });
125
+
126
+ return {
127
+ actionRequester,
128
+ actionPending,
129
+ actionAborted,
130
+ actionError,
131
+ };
132
+ };
@@ -0,0 +1,55 @@
1
+ import { useLayoutEffect } from "preact/hooks";
2
+
3
+ import { addManyEventListeners } from "../../utils/add_many_event_listeners.js";
4
+ import { useStableCallback } from "../use_stable_callback.js";
5
+
6
+ export const useFormEvents = (
7
+ elementRef,
8
+ {
9
+ onFormReset,
10
+ onFormActionPrevented,
11
+ onFormActionStart,
12
+ onFormActionAbort,
13
+ onFormActionError,
14
+ onFormActionEnd,
15
+ },
16
+ ) => {
17
+ onFormReset = useStableCallback(onFormReset);
18
+ onFormActionPrevented = useStableCallback(onFormActionPrevented);
19
+ onFormActionStart = useStableCallback(onFormActionStart);
20
+ onFormActionAbort = useStableCallback(onFormActionAbort);
21
+ onFormActionError = useStableCallback(onFormActionError);
22
+ onFormActionEnd = useStableCallback(onFormActionEnd);
23
+
24
+ useLayoutEffect(() => {
25
+ const element = elementRef.current;
26
+ if (!element) {
27
+ return null;
28
+ }
29
+
30
+ let form = element.form;
31
+ if (!form) {
32
+ // some non input elements may want to listen form events (<RadioList> is a <div>)
33
+ form = element.closest("form");
34
+ if (!form) {
35
+ console.warn("No form found for element", element);
36
+ return null;
37
+ }
38
+ }
39
+ return addManyEventListeners(form, {
40
+ reset: onFormReset,
41
+ actionprevented: onFormActionPrevented,
42
+ actionstart: onFormActionStart,
43
+ actionabort: onFormActionAbort,
44
+ actionerror: onFormActionError,
45
+ actionend: onFormActionEnd,
46
+ });
47
+ }, [
48
+ onFormReset,
49
+ onFormActionPrevented,
50
+ onFormActionStart,
51
+ onFormActionAbort,
52
+ onFormActionError,
53
+ onFormActionEnd,
54
+ ]);
55
+ };