@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
@@ -1,96 +0,0 @@
1
- import { forwardRef } from "preact/compat";
2
- import {
3
- useCallback,
4
- useImperativeHandle,
5
- useRef,
6
- useState,
7
- } from "preact/hooks";
8
- import { Input } from "../input/input.jsx";
9
-
10
- export const useEditableController = () => {
11
- const [editable, editableSetter] = useState(null);
12
- const startEditing = useCallback(({ focusVisible } = {}) => {
13
- editableSetter({
14
- focusVisible,
15
- });
16
- }, []);
17
- const stopEditing = useCallback(() => {
18
- editableSetter(null);
19
- }, []);
20
-
21
- const prevEditableRef = useRef(editable);
22
- const editableJustEnded = prevEditableRef.current && !editable;
23
- prevEditableRef.current = editable;
24
-
25
- return { editable, startEditing, stopEditing, editableJustEnded };
26
- };
27
-
28
- export const EditableText = forwardRef((props, ref) => {
29
- let { children, action, editable, value, valueSignal, onEditEnd, ...rest } =
30
- props;
31
- if (import.meta.DEV && !action) {
32
- console.warn(`EditableText requires an action prop`);
33
- }
34
-
35
- const innerRef = useRef();
36
- useImperativeHandle(ref, () => innerRef.current);
37
-
38
- if (valueSignal) {
39
- value = valueSignal.value;
40
- }
41
-
42
- const editablePreviousRef = useRef(editable);
43
- const valueWhenEditStartRef = useRef(editable ? value : undefined);
44
- if (editablePreviousRef.current !== editable) {
45
- if (editable) {
46
- valueWhenEditStartRef.current = value;
47
- }
48
- editablePreviousRef.current = editable;
49
- }
50
-
51
- return (
52
- <>
53
- <div style={{ display: editable ? "none" : "inline-flex", flexGrow: 1 }}>
54
- {children || <span>{value}</span>}
55
- </div>
56
- {editable && (
57
- <Input
58
- autoFocus
59
- autoFocusVisible
60
- autoSelect
61
- required
62
- cancelOnEscape
63
- cancelOnBlurInvalid
64
- onCancel={(e) => {
65
- if (valueSignal) {
66
- valueSignal.value = valueWhenEditStartRef.current;
67
- }
68
- onEditEnd({
69
- cancelled: true,
70
- event: e,
71
- });
72
- }}
73
- onBlur={(e) => {
74
- if (e.target.value === valueWhenEditStartRef.current) {
75
- onEditEnd({
76
- cancelled: true,
77
- event: e,
78
- });
79
- }
80
- }}
81
- action={action}
82
- onActionEnd={(e) => {
83
- onEditEnd({
84
- success: true,
85
- event: e,
86
- });
87
- }}
88
- ref={innerRef}
89
- value={value}
90
- valueSignal={valueSignal}
91
- {...rest}
92
- />
93
- )}
94
- </>
95
- );
96
- });
@@ -1,144 +0,0 @@
1
- /**
2
- *
3
- * Here we want the same behaviour as web standards:
4
- *
5
- * 1. When submitting the form URL does not change
6
- * 2. When form submission id done user is redirected (by default the current one)
7
- * (we can configure this using target)
8
- * So for example user might be reidrect to a page with the resource he just created
9
- * I could create an example where we would put a link on the page to let user see what he created
10
- * but by default user stays on the form allowing to create multiple resources at once
11
- * And an other where he is redirected to the resource he created
12
- * 3. If form submission fails ideally we should display this somewhere on the UI
13
- * right now it's just logged to the console I need to see how we can achieve this
14
- */
15
-
16
- import { requestAction, useConstraints } from "@jsenv/validation";
17
- import { forwardRef } from "preact/compat";
18
- import { useImperativeHandle, useRef, useState } from "preact/hooks";
19
- import { FormContext } from "./action_execution/form_context.js";
20
- import { renderActionableComponent } from "./action_execution/render_actionable_component.jsx";
21
- import { useFormActionBoundToFormParams } from "./action_execution/use_action.js";
22
- import { useExecuteAction } from "./action_execution/use_execute_action.js";
23
- import { collectFormElementValues } from "./collect_form_element_values.js";
24
- import { useActionEvents } from "./use_action_events.js";
25
-
26
- export const Form = forwardRef((props, ref) => {
27
- return renderActionableComponent(props, ref, {
28
- Basic: FormBasic,
29
- WithAction: FormWithAction,
30
- });
31
- });
32
-
33
- const FormBasic = forwardRef((props, ref) => {
34
- return <form ref={ref} {...props} />;
35
- });
36
-
37
- const FormWithAction = forwardRef((props, ref) => {
38
- let {
39
- action,
40
- method,
41
- readOnly = false,
42
- allowConcurrentActions: formAllowConcurrentActions = false,
43
- actionErrorEffect = "show_validation_message", // "show_validation_message" or "throw"
44
- onActionPrevented,
45
- onActionStart,
46
- onActionAbort,
47
- onActionError,
48
- onActionEnd,
49
- children,
50
- ...rest
51
- } = props;
52
-
53
- const innerRef = useRef();
54
- useImperativeHandle(ref, () => innerRef.current);
55
- // instantiation validation to:
56
- // - receive "requestsubmit" custom event ensure submit is prevented
57
- // (and also execute action without validation if form.submit() is ever called)
58
- useConstraints(innerRef, []);
59
-
60
- const [boundAction, formParamsSignal, setFormParams] =
61
- useFormActionBoundToFormParams(action);
62
- const [formActionRequester, setFormActionRequester] = useState(null);
63
- const [formIsBusy, setFormIsBusy] = useState(false);
64
- const [formActionError, setFormActionError] = useState(null);
65
- const [formActionAborted, setFormActionAborted] = useState(false);
66
- const executeAction = useExecuteAction(innerRef, {
67
- errorEffect: actionErrorEffect,
68
- });
69
- const formIsReadOnly =
70
- readOnly || (formIsBusy && !formAllowConcurrentActions);
71
-
72
- useActionEvents(innerRef, {
73
- onPrevented: onActionPrevented,
74
- onAction: (actionEvent) => {
75
- const form = innerRef.current;
76
- const formElementValues = collectFormElementValues(form);
77
- setFormParams(formElementValues);
78
-
79
- setFormActionRequester(actionEvent.detail.requester);
80
- executeAction(actionEvent);
81
- },
82
- onStart: (e) => {
83
- setFormIsBusy(true);
84
- setFormActionError(null);
85
- setFormActionAborted(false);
86
- onActionStart?.(e);
87
- },
88
- onAbort: (e) => {
89
- setFormIsBusy(false);
90
- setFormActionAborted(true);
91
- onActionAbort?.(e);
92
- },
93
- onError: (e) => {
94
- setFormIsBusy(false);
95
- setFormActionError(e);
96
- onActionError?.(e);
97
- },
98
- onEnd: (e) => {
99
- setFormIsBusy(false);
100
- onActionEnd?.(e);
101
- },
102
- });
103
-
104
- return (
105
- <form
106
- {...rest}
107
- data-action={boundAction.name}
108
- data-method={action.meta?.httpVerb || method || "GET"}
109
- ref={innerRef}
110
- // eslint-disable-next-line react/no-unknown-property
111
- onrequestsubmit={(e) => {
112
- // prevent "submit" event that would be dispatched by the browser after form.requestSubmit()
113
- // (not super important because our <form> listen the "action" and do does preventDefault on "submit")
114
- e.preventDefault();
115
- requestAction(boundAction, { event: e });
116
- }}
117
- >
118
- <FormContext.Provider
119
- value={{
120
- formAllowConcurrentActions,
121
- formAction: boundAction,
122
- formParamsSignal,
123
- formActionRequester,
124
- formIsReadOnly,
125
- formIsBusy,
126
- formActionAborted,
127
- formActionError,
128
- }}
129
- >
130
- {children}
131
- </FormContext.Provider>
132
- </form>
133
- );
134
- });
135
-
136
- // const dispatchCustomEventOnFormAndFormElements = (type, options) => {
137
- // const form = innerRef.current;
138
- // const customEvent = new CustomEvent(type, options);
139
- // // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
140
- // for (const element of form.elements) {
141
- // element.dispatchEvent(customEvent);
142
- // }
143
- // form.dispatchEvent(customEvent);
144
- // };
@@ -1,294 +0,0 @@
1
- import { requestAction } from "@jsenv/validation";
2
- import { forwardRef } from "preact/compat";
3
- import { useEffect, useImperativeHandle, useRef } from "preact/hooks";
4
- import { useNavState } from "../../browser_integration/browser_integration.js";
5
- import { useActionStatus } from "../../use_action_status.js";
6
- import { renderActionableComponent } from "../action_execution/render_actionable_component.jsx";
7
- import {
8
- useActionBoundToOneArrayParam,
9
- useOneFormArrayParam,
10
- } from "../action_execution/use_action.js";
11
- import { useExecuteAction } from "../action_execution/use_execute_action.js";
12
- import { useActionEvents } from "../use_action_events.js";
13
- import { useRefArray } from "../use_ref_array.js";
14
- import { useStateArray } from "../use_state_array.js";
15
- import { Field } from "./field.jsx";
16
- import { InputCheckbox } from "./input_checkbox.jsx";
17
- import { useFormEvents } from "./use_form_event.js";
18
-
19
- import.meta.css = /* css */ `
20
- .checkbox_list {
21
- display: flex;
22
- flex-direction: column;
23
- }
24
- `;
25
-
26
- export const CheckboxList = forwardRef((props, ref) => {
27
- return renderActionableComponent(props, ref, {
28
- Basic: CheckboxListBasic,
29
- WithAction: CheckboxListWithAction,
30
- InsideForm: CheckboxListInsideForm,
31
- });
32
- });
33
-
34
- const CheckboxListControlled = forwardRef((props, ref) => {
35
- const {
36
- name,
37
- value,
38
- label,
39
- loading,
40
- disabled,
41
- readOnly,
42
- children,
43
- onChange,
44
- ...rest
45
- } = props;
46
-
47
- const innerRef = useRef();
48
- useImperativeHandle(ref, () => innerRef.current);
49
-
50
- return (
51
- <fieldset
52
- {...rest}
53
- className="checkbox_list"
54
- ref={innerRef}
55
- data-checkbox-list
56
- >
57
- {label ? <legend>{label}</legend> : null}
58
- {children.map((child) => {
59
- const {
60
- label: childLabel,
61
- readOnly: childReadOnly,
62
- disabled: childDisabled,
63
- loading: childLoading,
64
- onChange: childOnChange,
65
- value: childValue,
66
- ...childRest
67
- } = child;
68
-
69
- const checkbox = (
70
- <InputCheckbox
71
- {...childRest}
72
- // ignoreForm: each input is controller by this list
73
- // we don't want the input to try to update the form because it's already done here
74
- ignoreForm
75
- name={name}
76
- value={childValue}
77
- checked={value.includes(childValue)}
78
- readOnly={readOnly || childReadOnly}
79
- disabled={disabled || childDisabled}
80
- loading={loading || childLoading}
81
- onChange={(event) => {
82
- onChange(event, child);
83
- childOnChange?.(event);
84
- }}
85
- />
86
- );
87
-
88
- return <Field key={childValue} input={checkbox} label={childLabel} />;
89
- })}
90
- </fieldset>
91
- );
92
- });
93
-
94
- const CheckboxListBasic = forwardRef((props, ref) => {
95
- const { value: externalValue, id, children, ...rest } = props;
96
-
97
- const innerRef = useRef();
98
- useImperativeHandle(ref, () => innerRef.current);
99
-
100
- const [navState, setNavState] = useNavState(id);
101
- const [valueArray, addValue, removeValue] = useStateArray(
102
- externalValue,
103
- navState,
104
- [],
105
- );
106
- useEffect(() => {
107
- setNavState(valueArray);
108
- }, [valueArray]);
109
-
110
- return (
111
- <CheckboxListControlled
112
- ref={innerRef}
113
- value={valueArray}
114
- onChange={(event) => {
115
- const checkbox = event.target;
116
- const checkboxIsChecked = checkbox.checked;
117
- const checkboxValue = checkbox.value;
118
- if (checkboxIsChecked) {
119
- addValue(checkboxValue);
120
- } else {
121
- removeValue(checkboxValue);
122
- }
123
- }}
124
- {...rest}
125
- >
126
- {children}
127
- </CheckboxListControlled>
128
- );
129
- });
130
-
131
- const CheckboxListWithAction = forwardRef((props, ref) => {
132
- const {
133
- id,
134
- name,
135
- value: externalValue,
136
- valueSignal,
137
- action,
138
- children,
139
- actionErrorEffect,
140
- onCancel,
141
- onActionPrevented,
142
- onActionStart,
143
- onActionAbort,
144
- onActionError,
145
- onActionEnd,
146
- ...rest
147
- } = props;
148
-
149
- const innerRef = useRef();
150
- useImperativeHandle(ref, () => innerRef.current);
151
-
152
- const [navState, setNavState, resetNavState] = useNavState(id);
153
- const [boundAction, valueArray, addValue, removeValue, resetValueArray] =
154
- useActionBoundToOneArrayParam(
155
- action,
156
- name,
157
- valueSignal ? valueSignal : externalValue,
158
- navState,
159
- [],
160
- );
161
- const { loading: actionLoading } = useActionStatus(boundAction);
162
- const executeAction = useExecuteAction(innerRef, {
163
- errorEffect: actionErrorEffect,
164
- });
165
- useEffect(() => {
166
- setNavState(valueArray);
167
- }, [valueArray]);
168
-
169
- const actionRequesterRef = useRef(null);
170
- useActionEvents(innerRef, {
171
- onCancel: (e, reason) => {
172
- resetNavState();
173
- resetValueArray();
174
- onCancel?.(e, reason);
175
- },
176
- onPrevented: onActionPrevented,
177
- onAction: (actionEvent) => {
178
- actionRequesterRef.current = actionEvent.detail.requester;
179
- executeAction(actionEvent);
180
- },
181
- onStart: onActionStart,
182
- onAbort: (e) => {
183
- resetValueArray();
184
- onActionAbort?.(e);
185
- },
186
- onError: (e) => {
187
- resetValueArray();
188
- onActionError?.(e);
189
- },
190
- onEnd: (e) => {
191
- resetNavState();
192
- onActionEnd?.(e);
193
- },
194
- });
195
-
196
- const childRefArray = useRefArray(children, (child) => child.value);
197
-
198
- return (
199
- <CheckboxListControlled
200
- {...rest}
201
- name={name}
202
- value={valueArray}
203
- data-action={boundAction}
204
- ref={innerRef}
205
- onChange={(event) => {
206
- const checkbox = event.target;
207
- const checkboxIsChecked = checkbox.checked;
208
- const checkboxValue = checkbox.value;
209
- if (checkboxIsChecked) {
210
- addValue(checkboxValue, valueArray);
211
- } else {
212
- removeValue(checkboxValue, valueArray);
213
- }
214
- const checkboxListContainer = innerRef.current;
215
- requestAction(boundAction, {
216
- event,
217
- target: checkboxListContainer,
218
- requester: checkbox,
219
- });
220
- }}
221
- >
222
- {children.map((child, i) => {
223
- const childRef = childRefArray[i];
224
- const loading =
225
- child.loading ||
226
- (actionLoading && actionRequesterRef.current === childRef.current);
227
-
228
- return {
229
- ...child,
230
- ref: childRef,
231
- loading,
232
- readOnly: child.readOnly || actionLoading,
233
- };
234
- })}
235
- </CheckboxListControlled>
236
- );
237
- });
238
-
239
- const CheckboxListInsideForm = forwardRef((props, ref) => {
240
- const {
241
- formContext,
242
- id,
243
- name,
244
- readOnly,
245
- value: initialValue,
246
- children,
247
- ...rest
248
- } = props;
249
- const { formIsReadOnly } = formContext;
250
-
251
- const innerRef = useRef();
252
- useImperativeHandle(ref, () => innerRef.current);
253
-
254
- const [navState, setNavState] = useNavState(id);
255
- const [valueArray, addValue, removeValue, resetValueArray] =
256
- useOneFormArrayParam(name, initialValue, navState, []);
257
- useEffect(() => {
258
- setNavState(valueArray);
259
- }, [valueArray]);
260
-
261
- useFormEvents(innerRef, {
262
- onFormReset: () => {
263
- resetValueArray();
264
- },
265
- onFormActionAbort: () => {
266
- resetValueArray();
267
- },
268
- onFormActionError: () => {
269
- resetValueArray();
270
- },
271
- });
272
-
273
- return (
274
- <CheckboxListControlled
275
- ref={innerRef}
276
- name={name}
277
- value={valueArray}
278
- readOnly={readOnly || formIsReadOnly}
279
- onChange={(event) => {
280
- const checkbox = event.target;
281
- const checkboxIsChecked = checkbox.checked;
282
- const checkboxValue = checkbox.value;
283
- if (checkboxIsChecked) {
284
- addValue(checkboxValue, valueArray);
285
- } else {
286
- removeValue(checkboxValue, valueArray);
287
- }
288
- }}
289
- {...rest}
290
- >
291
- {children}
292
- </CheckboxListControlled>
293
- );
294
- });
@@ -1,61 +0,0 @@
1
- import { useLayoutEffect, useRef, useState } from "preact/hooks";
2
-
3
- import.meta.css = /* css */ `
4
- .label_wrapper_for_opacity {
5
- display: inline-flex;
6
- }
7
-
8
- label[data-readonly] .label_wrapper_for_opacity {
9
- opacity: 0.5;
10
- }
11
- `;
12
-
13
- export const Field = (props) => {
14
- const { label, input, readOnly, ...rest } = props;
15
-
16
- const keys = Object.keys(props);
17
- const labelIndex = keys.indexOf("label");
18
- const inputIndex = keys.indexOf("input");
19
- const labelBeforeInput = labelIndex < inputIndex;
20
-
21
- const labelWrapped = <div className="label_wrapper_for_opacity">{label}</div>;
22
-
23
- const children = labelBeforeInput
24
- ? [labelWrapped, input]
25
- : [input, labelWrapped];
26
-
27
- const [inputReadOnly, setInputReadOnly] = useState(false);
28
- const innerReadOnly = readOnly || inputReadOnly;
29
- const labelRef = useRef();
30
- useLayoutEffect(() => {
31
- if (readOnly) {
32
- return null;
33
- }
34
- let animationFrame;
35
- const updateInputDisabled = () => {
36
- const label = labelRef.current;
37
- const input = label.querySelector("input");
38
- if (!input) {
39
- setInputReadOnly(false);
40
- } else {
41
- setInputReadOnly(input.readonly || input.hasAttribute("data-readonly"));
42
- }
43
- animationFrame = requestAnimationFrame(updateInputDisabled);
44
- };
45
- updateInputDisabled();
46
-
47
- return () => {
48
- cancelAnimationFrame(animationFrame);
49
- };
50
- }, [readOnly]);
51
-
52
- return (
53
- <label
54
- ref={labelRef}
55
- data-readonly={innerReadOnly ? "" : undefined}
56
- {...rest}
57
- >
58
- {children}
59
- </label>
60
- );
61
- };