@jsenv/navi 0.0.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 (123) hide show
  1. package/index.js +51 -0
  2. package/package.json +38 -0
  3. package/src/action_private_properties.js +11 -0
  4. package/src/action_proxy_test.html +353 -0
  5. package/src/action_run_states.js +5 -0
  6. package/src/actions.js +1377 -0
  7. package/src/browser_integration/browser_integration.js +191 -0
  8. package/src/browser_integration/document_back_and_forward.js +17 -0
  9. package/src/browser_integration/document_loading_signal.js +100 -0
  10. package/src/browser_integration/document_state_signal.js +9 -0
  11. package/src/browser_integration/document_url_signal.js +9 -0
  12. package/src/browser_integration/use_is_visited.js +19 -0
  13. package/src/browser_integration/via_history.js +199 -0
  14. package/src/browser_integration/via_navigation.js +168 -0
  15. package/src/components/action_execution/form_context.js +8 -0
  16. package/src/components/action_execution/render_actionable_component.jsx +27 -0
  17. package/src/components/action_execution/use_action.js +330 -0
  18. package/src/components/action_execution/use_execute_action.js +161 -0
  19. package/src/components/action_renderer.jsx +136 -0
  20. package/src/components/collect_form_element_values.js +79 -0
  21. package/src/components/demos/0_button_demo.html +155 -0
  22. package/src/components/demos/1_checkbox_demo.html +257 -0
  23. package/src/components/demos/2_input_textual_demo.html +354 -0
  24. package/src/components/demos/3_radio_demo.html +222 -0
  25. package/src/components/demos/4_select_demo.html +104 -0
  26. package/src/components/demos/5_list_scrollable_demo.html +153 -0
  27. package/src/components/demos/action/0_button_demo.html +204 -0
  28. package/src/components/demos/action/10_shortcuts_demo.html +189 -0
  29. package/src/components/demos/action/11_nested_shortcuts_demo.html +401 -0
  30. package/src/components/demos/action/1_input_text_demo.html +461 -0
  31. package/src/components/demos/action/2_form_multiple.html +303 -0
  32. package/src/components/demos/action/3_details_demo.html +172 -0
  33. package/src/components/demos/action/4_input_checkbox_demo.html +611 -0
  34. package/src/components/demos/action/6_checkbox_list_demo.html +109 -0
  35. package/src/components/demos/action/7_radio_list_demo.html +217 -0
  36. package/src/components/demos/action/8_editable_text_demo.html +442 -0
  37. package/src/components/demos/action/9_link_demo.html +172 -0
  38. package/src/components/demos/demo.md +0 -0
  39. package/src/components/demos/route/basic/basic.html +14 -0
  40. package/src/components/demos/route/basic/basic_route_demo.jsx +224 -0
  41. package/src/components/demos/route/multi/multi.html +14 -0
  42. package/src/components/demos/route/multi/multi_route_demo.jsx +277 -0
  43. package/src/components/details/details.jsx +248 -0
  44. package/src/components/details/summary_marker.jsx +141 -0
  45. package/src/components/editable_text/editable_text.jsx +96 -0
  46. package/src/components/error_boundary_context.js +9 -0
  47. package/src/components/form.jsx +144 -0
  48. package/src/components/input/button.jsx +333 -0
  49. package/src/components/input/checkbox_list.jsx +294 -0
  50. package/src/components/input/field.jsx +61 -0
  51. package/src/components/input/field_css.js +118 -0
  52. package/src/components/input/input.jsx +15 -0
  53. package/src/components/input/input_checkbox.jsx +370 -0
  54. package/src/components/input/input_radio.jsx +299 -0
  55. package/src/components/input/input_textual.jsx +338 -0
  56. package/src/components/input/radio_list.jsx +283 -0
  57. package/src/components/input/select.jsx +273 -0
  58. package/src/components/input/use_form_event.js +20 -0
  59. package/src/components/input/use_on_change.js +12 -0
  60. package/src/components/link/link.jsx +291 -0
  61. package/src/components/loader/loader_background.jsx +324 -0
  62. package/src/components/loader/loading_spinner.jsx +68 -0
  63. package/src/components/loader/network_speed.js +83 -0
  64. package/src/components/loader/rectangle_loading.jsx +225 -0
  65. package/src/components/route.jsx +15 -0
  66. package/src/components/selection/selection.js +5 -0
  67. package/src/components/selection/selection_context.jsx +262 -0
  68. package/src/components/shortcut/os.js +9 -0
  69. package/src/components/shortcut/shortcut_context.jsx +390 -0
  70. package/src/components/use_action_events.js +37 -0
  71. package/src/components/use_auto_focus.js +43 -0
  72. package/src/components/use_debounce_true.js +31 -0
  73. package/src/components/use_focus_group.js +19 -0
  74. package/src/components/use_initial_value.js +104 -0
  75. package/src/components/use_is_visited.js +19 -0
  76. package/src/components/use_ref_array.js +38 -0
  77. package/src/components/use_signal_sync.js +50 -0
  78. package/src/components/use_state_array.js +40 -0
  79. package/src/docs/actions.md +228 -0
  80. package/src/docs/demos/resource/action_status.jsx +42 -0
  81. package/src/docs/demos/resource/demo.md +1 -0
  82. package/src/docs/demos/resource/resource_demo_0.html +84 -0
  83. package/src/docs/demos/resource/resource_demo_10_post_gc.html +364 -0
  84. package/src/docs/demos/resource/resource_demo_11_describe_many.html +362 -0
  85. package/src/docs/demos/resource/resource_demo_2.html +173 -0
  86. package/src/docs/demos/resource/resource_demo_3_filtered_users.html +415 -0
  87. package/src/docs/demos/resource/resource_demo_4_details.html +284 -0
  88. package/src/docs/demos/resource/resource_demo_5_renderer_lazy.html +115 -0
  89. package/src/docs/demos/resource/resource_demo_6_gc.html +217 -0
  90. package/src/docs/demos/resource/resource_demo_7_child_gc.html +240 -0
  91. package/src/docs/demos/resource/resource_demo_8_proxy_gc.html +319 -0
  92. package/src/docs/demos/resource/resource_demo_9_describe_one.html +472 -0
  93. package/src/docs/demos/resource/tata.jsx +3 -0
  94. package/src/docs/demos/resource/toto.jsx +3 -0
  95. package/src/docs/demos/user_nav/user_nav.html +12 -0
  96. package/src/docs/demos/user_nav/user_nav.jsx +330 -0
  97. package/src/docs/resource_dependencies.md +103 -0
  98. package/src/docs/resource_with_params.md +80 -0
  99. package/src/notes.md +13 -0
  100. package/src/route/route.js +518 -0
  101. package/src/route/route.test.html +228 -0
  102. package/src/store/array_signal_store.js +537 -0
  103. package/src/store/local_storage_signal.js +17 -0
  104. package/src/store/resource_graph.js +1303 -0
  105. package/src/store/tests/resource_graph_autoreload_demo.html +12 -0
  106. package/src/store/tests/resource_graph_autoreload_demo.jsx +964 -0
  107. package/src/store/tests/resource_graph_dependencies.test.js +95 -0
  108. package/src/store/value_in_local_storage.js +187 -0
  109. package/src/symbol_object_signal.js +1 -0
  110. package/src/use_action_data.js +10 -0
  111. package/src/use_action_status.js +47 -0
  112. package/src/utils/add_many_event_listeners.js +15 -0
  113. package/src/utils/array_add_remove.js +61 -0
  114. package/src/utils/array_signal.js +15 -0
  115. package/src/utils/compare_two_js_values.js +172 -0
  116. package/src/utils/execute_with_cleanup.js +21 -0
  117. package/src/utils/get_caller_info.js +85 -0
  118. package/src/utils/iterable_weak_set.js +62 -0
  119. package/src/utils/js_value_weak_map.js +162 -0
  120. package/src/utils/js_value_weak_map_demo.html +690 -0
  121. package/src/utils/merge_two_js_values.js +53 -0
  122. package/src/utils/stringify_for_display.js +150 -0
  123. package/src/utils/weak_effect.js +48 -0
@@ -0,0 +1,136 @@
1
+ /**
2
+ * TODO: when switching from one state to another we should preserve the dimensions to prevent layout shift
3
+ * the exact way to do this is not yet clear but I suspect something as follow:
4
+ *
5
+ *
6
+ * While content is loading we don't know (except if we are given an size)
7
+ * When reloading the content will be gone, we should keep a placeholder taking the same space
8
+ * When there is an error the error should take the same space as the content
9
+ * but be displayed on top
10
+ * (If error is bigger it can take more space? I guess so, maybe an overflow would be better to prevent layout shit again)
11
+ *
12
+ * And once we know the new content size ideally we could have some sort of transition
13
+ * (like an height transition from current height to new height)
14
+ *
15
+ * consider https://motion.dev/docs/react-layout-animations
16
+ *
17
+ * but might be too complexe for what we want.
18
+ * we want ability to transit from anything to anything, it's not a layout change
19
+ * it's more view transition but with a very simple behavior
20
+ *
21
+ * And certainly this https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API#pseudo-elements
22
+ *
23
+ */
24
+
25
+ import { useErrorBoundary, useLayoutEffect } from "preact/hooks";
26
+ import { getActionPrivateProperties } from "../action_private_properties.js";
27
+ import { useActionStatus } from "../use_action_status.js";
28
+
29
+ import.meta.css = /* css */ `
30
+ .action_error {
31
+ padding: 20px;
32
+ background: #fdd;
33
+ border: 1px solid red;
34
+ margin-top: 0;
35
+ margin-bottom: 20px;
36
+ }
37
+ `;
38
+
39
+ const renderIdleDefault = () => null;
40
+ const renderLoadingDefault = () => null;
41
+ const renderAbortedDefault = () => null;
42
+ const renderErrorDefault = (error) => {
43
+ let routeErrorText = error && error.message ? error.message : error;
44
+ return <p className="action_error">An error occured: {routeErrorText}</p>;
45
+ };
46
+ const renderCompletedDefault = () => null;
47
+
48
+ export const ActionRenderer = ({ action, children }) => {
49
+ const {
50
+ idle: renderIdle = renderIdleDefault,
51
+ loading: renderLoading = renderLoadingDefault,
52
+ aborted: renderAborted = renderAbortedDefault,
53
+ error: renderError = renderErrorDefault,
54
+ completed: renderCompleted,
55
+ always: renderAlways,
56
+ } = typeof children === "function" ? { completed: children } : children || {};
57
+ if (!action) {
58
+ throw new Error(
59
+ "ActionRenderer requires an action to render, but none was provided.",
60
+ );
61
+ }
62
+ const { idle, loading, aborted, error, data } = useActionStatus(action);
63
+ const UIRenderedPromise = useUIRenderedPromise(action);
64
+ const [errorBoundary, resetErrorBoundary] = useErrorBoundary();
65
+
66
+ // Mark this action as bound to UI components (has renderers)
67
+ // This tells the action system that errors should be caught and stored
68
+ // in the action's error state rather than bubbling up
69
+ useLayoutEffect(() => {
70
+ const { ui } = getActionPrivateProperties(action);
71
+ ui.hasRenderers = true;
72
+ }, [action]);
73
+
74
+ useLayoutEffect(() => {
75
+ resetErrorBoundary();
76
+ }, [action, loading, idle, resetErrorBoundary]);
77
+
78
+ useLayoutEffect(() => {
79
+ UIRenderedPromise.resolve();
80
+ return () => {
81
+ actionUIRenderedPromiseWeakMap.delete(action);
82
+ };
83
+ }, []);
84
+
85
+ // If renderAlways is provided, it wins and handles all rendering
86
+ if (renderAlways) {
87
+ return renderAlways({ idle, loading, aborted, error, data });
88
+ }
89
+
90
+ if (idle) {
91
+ return renderIdle(action);
92
+ }
93
+ if (errorBoundary) {
94
+ return renderError(errorBoundary, "ui_error", action);
95
+ }
96
+ if (error) {
97
+ return renderError(error, "action_error", action);
98
+ }
99
+ if (aborted) {
100
+ return renderAborted(action);
101
+ }
102
+ let renderCompletedSafe;
103
+ if (renderCompleted) {
104
+ renderCompletedSafe = renderCompleted;
105
+ } else {
106
+ const { ui } = getActionPrivateProperties(action);
107
+ if (ui.renderCompleted) {
108
+ renderCompletedSafe = ui.renderCompleted;
109
+ } else {
110
+ renderCompletedSafe = renderCompletedDefault;
111
+ }
112
+ }
113
+ if (loading) {
114
+ if (action.canDisplayOldData && data !== undefined) {
115
+ return renderCompletedSafe(data, action);
116
+ }
117
+ return renderLoading(action);
118
+ }
119
+
120
+ return renderCompletedSafe(data, action);
121
+ };
122
+
123
+ const actionUIRenderedPromiseWeakMap = new WeakMap();
124
+ const useUIRenderedPromise = (route) => {
125
+ const actionUIRenderedPromise = actionUIRenderedPromiseWeakMap.get(route);
126
+ if (actionUIRenderedPromise) {
127
+ return actionUIRenderedPromise;
128
+ }
129
+ let resolve;
130
+ const promise = new Promise((res) => {
131
+ resolve = res;
132
+ });
133
+ promise.resolve = resolve;
134
+ actionUIRenderedPromiseWeakMap.set(route, promise);
135
+ return promise;
136
+ };
@@ -0,0 +1,79 @@
1
+ export const collectFormElementValues = (element) => {
2
+ let formElements;
3
+ if (element.tagName === "FORM") {
4
+ formElements = element.elements;
5
+ } else {
6
+ // fieldset or anything else
7
+ formElements = element.querySelectorAll(
8
+ "input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button[name]:not([disabled])",
9
+ );
10
+ }
11
+
12
+ const values = {};
13
+ const checkboxArrayNameSet = new Set();
14
+ for (const formElement of formElements) {
15
+ if (formElement.type === "checkbox" && formElement.name) {
16
+ const name = formElement.name;
17
+ const endsWithBrackets = name.endsWith("[]");
18
+ if (endsWithBrackets) {
19
+ checkboxArrayNameSet.add(name);
20
+ values[name] = [];
21
+ continue;
22
+ }
23
+ const closestDataCheckboxList = formElement.closest(
24
+ "[data-checkbox-list]",
25
+ );
26
+ if (closestDataCheckboxList) {
27
+ checkboxArrayNameSet.add(name);
28
+ values[name] = [];
29
+ }
30
+ }
31
+ }
32
+
33
+ for (const formElement of formElements) {
34
+ const name = formElement.name;
35
+ if (!name) {
36
+ continue;
37
+ }
38
+ const value = getFormElementValue(formElement);
39
+ if (value === undefined) {
40
+ continue; // Skip unchecked checkboxes/radios
41
+ }
42
+ if (formElement.type === "checkbox" && checkboxArrayNameSet.has(name)) {
43
+ values[name].push(value);
44
+ } else {
45
+ values[name] = value;
46
+ }
47
+ }
48
+ return values;
49
+ };
50
+
51
+ const getFormElementValue = (formElement) => {
52
+ const { type, tagName } = formElement;
53
+
54
+ if (tagName === "SELECT") {
55
+ if (formElement.multiple) {
56
+ return Array.from(formElement.selectedOptions, (option) =>
57
+ getValue(option),
58
+ );
59
+ }
60
+ return formElement.value;
61
+ }
62
+
63
+ if (type === "checkbox" || type === "radio") {
64
+ return formElement.checked ? getValue(formElement) : undefined;
65
+ }
66
+
67
+ if (type === "file") {
68
+ return formElement.files; // Return FileList for special handling
69
+ }
70
+
71
+ return getValue(formElement);
72
+ };
73
+
74
+ const getValue = (formElement) => {
75
+ const hasDataFormValueAttribute = formElement.hasAttribute("data-form-value");
76
+ return hasDataFormValueAttribute
77
+ ? formElement.getAttribute("data-form-value")
78
+ : formElement.value;
79
+ };
@@ -0,0 +1,155 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" href="data:," />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Button loading demo</title>
8
+ </head>
9
+ <body>
10
+ <div id="root" style="position: relative"></div>
11
+
12
+ <script type="module" jsenv-type="module/jsx">
13
+ import { render } from "preact";
14
+ import { useState } from "preact/hooks";
15
+ import {
16
+ // eslint-disable-next-line no-unused-vars
17
+ Button,
18
+ // eslint-disable-next-line no-unused-vars
19
+ Field,
20
+ } from "@jsenv/navi";
21
+
22
+ // eslint-disable-next-line no-unused-vars
23
+ const App = () => {
24
+ const [loading, setLoading] = useState(false);
25
+ const [loadingB, setLoadingB] = useState(false);
26
+ const [loadingC, setLoadingC] = useState(false);
27
+ const [loadingD, setLoadingD] = useState(false);
28
+
29
+ return (
30
+ <div>
31
+ <div style="display: flex; flex-direction: row; gap: 30px">
32
+ <div>
33
+ <p>
34
+ <strong>Loading</strong>
35
+ </p>
36
+ <Button loading={loading}>Toggle</Button>
37
+ <br />
38
+ <button
39
+ onClick={() => {
40
+ setLoading(!loading);
41
+ }}
42
+ >
43
+ Toggle
44
+ </button>
45
+ </div>
46
+
47
+ <div>
48
+ <p>
49
+ <strong>Loading (action)</strong>
50
+ </p>
51
+ <Button loading={loadingB} action={() => {}}>
52
+ B
53
+ </Button>
54
+ <br /> <br />
55
+ <button
56
+ onClick={() => {
57
+ setLoadingB(!loadingB);
58
+ }}
59
+ >
60
+ Toggle
61
+ </button>
62
+ </div>
63
+
64
+ <div>
65
+ <p>
66
+ <strong>Readonly</strong>
67
+ </p>
68
+ <Button loading={loadingC} readOnly>
69
+ C
70
+ </Button>
71
+ <br />
72
+ <button data-readonly>C</button>
73
+ <br />
74
+ <br />
75
+ <button>
76
+ <span
77
+ onClick={() => {
78
+ setLoadingC(!loadingC);
79
+ }}
80
+ >
81
+ Toggle
82
+ </span>
83
+ </button>
84
+ </div>
85
+
86
+ <div>
87
+ <p>
88
+ <strong>Disabled</strong>
89
+ </p>
90
+ <Button loading={loadingD} disabled>
91
+ D
92
+ </Button>
93
+ <br />
94
+ <button disabled>D</button>
95
+ <br /> <br />
96
+ <button>
97
+ <span
98
+ onClick={() => {
99
+ setLoadingD(!loadingD);
100
+ }}
101
+ >
102
+ Toggle
103
+ </span>
104
+ </button>
105
+ </div>
106
+ </div>
107
+
108
+ <div style="display: flex; flex-direction: row; gap: 30px">
109
+ <div>
110
+ <p>
111
+ <strong>Large button (anim speed shoud be consistent)</strong>
112
+ </p>
113
+ <Button loading={loading}>
114
+ This button is quite large but loader speed should be same as
115
+ small buttons
116
+ </Button>
117
+ <br />
118
+ <button
119
+ onClick={() => {
120
+ setLoading(!loading);
121
+ }}
122
+ >
123
+ Toggle
124
+ </button>
125
+ </div>
126
+ </div>
127
+
128
+ <div>
129
+ <div>
130
+ <p>
131
+ <strong>Big borders</strong>
132
+ </p>
133
+ <Button loading={loadingC} borderWidth={10}>
134
+ C
135
+ </Button>
136
+ <br /> <br />
137
+ <button>
138
+ <span
139
+ onClick={() => {
140
+ setLoadingC(!loadingC);
141
+ }}
142
+ >
143
+ Toggle
144
+ </span>
145
+ </button>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ );
150
+ };
151
+
152
+ render(<App />, document.querySelector("#root"));
153
+ </script>
154
+ </body>
155
+ </html>
@@ -0,0 +1,257 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" href="data:," />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Checkbox demo</title>
8
+ </head>
9
+ <body>
10
+ <div id="root" style="position: relative"></div>
11
+
12
+ <script type="module" jsenv-type="module/jsx">
13
+ import { render } from "preact";
14
+ import { useState } from "preact/hooks";
15
+ import {
16
+ // eslint-disable-next-line no-unused-vars
17
+ Input,
18
+ // eslint-disable-next-line no-unused-vars
19
+ Field,
20
+ } from "@jsenv/navi";
21
+
22
+ // eslint-disable-next-line no-unused-vars
23
+ const App = () => {
24
+ const [loading, setLoading] = useState(false);
25
+ const [loadingB, setLoadingB] = useState(false);
26
+ const [loadingC, setLoadingC] = useState(false);
27
+ const [loadingD, setLoadingD] = useState(false);
28
+ const [loadingE, setLoadingE] = useState(false);
29
+ const [loadingF, setLoadingF] = useState(false);
30
+
31
+ return (
32
+ <div>
33
+ <div style="display: flex; flex-direction: row; gap: 30px">
34
+ <div>
35
+ <p>
36
+ <strong>Loading</strong>
37
+ </p>
38
+
39
+ <Field
40
+ input={
41
+ <Input
42
+ id="test"
43
+ type="checkbox"
44
+ name="colors"
45
+ loading={loading}
46
+ />
47
+ }
48
+ label="Coucou"
49
+ ></Field>
50
+
51
+ <button>
52
+ <span
53
+ onClick={() => {
54
+ setLoading(!loading);
55
+ }}
56
+ >
57
+ Toggle
58
+ </span>
59
+ </button>
60
+
61
+ <div>
62
+ <label>
63
+ <input type="checkbox" name="colors" checked />
64
+ Coucou
65
+ </label>
66
+ </div>
67
+ </div>
68
+ </div>
69
+
70
+ <div>
71
+ <div>
72
+ <p>
73
+ <strong>Loading with action</strong>
74
+ </p>
75
+
76
+ <Field
77
+ input={
78
+ <Input
79
+ id="test"
80
+ action={() => {}}
81
+ type="checkbox"
82
+ name="colors"
83
+ loading={loadingB}
84
+ />
85
+ }
86
+ label="Coucou"
87
+ ></Field>
88
+
89
+ <button>
90
+ <span
91
+ onClick={() => {
92
+ setLoadingB(!loadingB);
93
+ }}
94
+ >
95
+ Toggle
96
+ </span>
97
+ </button>
98
+ </div>
99
+ </div>
100
+
101
+ <div>
102
+ <div>
103
+ <p>
104
+ <strong>Read Only</strong>
105
+ </p>
106
+
107
+ <Field
108
+ input={
109
+ <Input
110
+ id="test"
111
+ readOnly
112
+ type="checkbox"
113
+ name="colors"
114
+ loading={loadingC}
115
+ />
116
+ }
117
+ label="C"
118
+ />
119
+
120
+ <button>
121
+ <span
122
+ onClick={() => {
123
+ setLoadingC(!loadingC);
124
+ }}
125
+ >
126
+ Toggle
127
+ </span>
128
+ </button>
129
+
130
+ <div>
131
+ <label>
132
+ <input type="checkbox" name="colors" readonly />C
133
+ </label>
134
+ </div>
135
+ </div>
136
+ </div>
137
+
138
+ <div>
139
+ <div>
140
+ <p>
141
+ <strong>Read Only + checked</strong>
142
+ </p>
143
+
144
+ <Field
145
+ input={
146
+ <Input
147
+ id="test"
148
+ readOnly
149
+ checked
150
+ type="checkbox"
151
+ name="colors"
152
+ loading={loadingD}
153
+ />
154
+ }
155
+ label="D"
156
+ />
157
+
158
+ <button>
159
+ <span
160
+ onClick={() => {
161
+ setLoadingD(!loadingD);
162
+ }}
163
+ >
164
+ Toggle
165
+ </span>
166
+ </button>
167
+
168
+ <div>
169
+ <label>
170
+ <input type="checkbox" name="colors" readonly />D
171
+ </label>
172
+ </div>
173
+ </div>
174
+ </div>
175
+
176
+ <div>
177
+ <div>
178
+ <p>
179
+ <strong>Disabled</strong>
180
+ </p>
181
+
182
+ <Field
183
+ input={
184
+ <Input
185
+ id="test"
186
+ disabled
187
+ type="checkbox"
188
+ name="colors"
189
+ loading={loadingE}
190
+ />
191
+ }
192
+ label="E"
193
+ />
194
+
195
+ <button>
196
+ <span
197
+ onClick={() => {
198
+ setLoadingE(!loadingE);
199
+ }}
200
+ >
201
+ Toggle
202
+ </span>
203
+ </button>
204
+
205
+ <div>
206
+ <label>
207
+ <input type="checkbox" name="colors" disabled />E
208
+ </label>
209
+ </div>
210
+ </div>
211
+ </div>
212
+
213
+ <div>
214
+ <div>
215
+ <p>
216
+ <strong>Disabled + checked</strong>
217
+ </p>
218
+
219
+ <Field
220
+ input={
221
+ <Input
222
+ id="test"
223
+ disabled
224
+ checked
225
+ type="checkbox"
226
+ name="colors"
227
+ loading={loadingF}
228
+ />
229
+ }
230
+ label="Coucou"
231
+ />
232
+
233
+ <button>
234
+ <span
235
+ onClick={() => {
236
+ setLoadingF(!loadingF);
237
+ }}
238
+ >
239
+ Toggle
240
+ </span>
241
+ </button>
242
+
243
+ <div>
244
+ <label>
245
+ <input type="checkbox" name="colors" disabled checked />F
246
+ </label>
247
+ </div>
248
+ </div>
249
+ </div>
250
+ </div>
251
+ );
252
+ };
253
+
254
+ render(<App />, document.querySelector("#root"));
255
+ </script>
256
+ </body>
257
+ </html>