@jsenv/navi 0.1.1 → 0.2.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.
@@ -8,9 +8,16 @@ import {
8
8
 
9
9
  import { useConstraints } from "../../validation/hooks/use_constraints.js";
10
10
  import { renderActionableComponent } from "../action_execution/render_actionable_component.jsx";
11
- import { LoadableInlineElement } from "../loader/loader_background.jsx";
11
+ import {
12
+ LoadableInlineElement,
13
+ LoaderBackground,
14
+ } from "../loader/loader_background.jsx";
12
15
  import { useAutoFocus } from "../use_auto_focus.js";
13
- import { ReportReadOnlyOnLabelContext } from "./label.jsx";
16
+ import { initCustomField } from "./custom_field.js";
17
+ import {
18
+ ReportDisabledOnLabelContext,
19
+ ReportReadOnlyOnLabelContext,
20
+ } from "./label.jsx";
14
21
  import {
15
22
  DisabledContext,
16
23
  FieldNameContext,
@@ -25,169 +32,162 @@ import {
25
32
  } from "./use_ui_state_controller.js";
26
33
 
27
34
  import.meta.css = /* css */ `
28
- .custom_radio_wrapper {
29
- position: relative;
30
- display: inline-flex;
31
- box-sizing: content-box;
32
-
33
- --checked-color: #3b82f6;
34
- --checked-disabled-color: var(--field-disabled-border-color);
35
-
36
- --checkmark-color: var(--checked-color);
37
- --checkmark-disabled-color: var(--field-disabled-text-color);
38
- }
39
-
40
- .custom_radio_wrapper input {
41
- position: absolute;
42
- opacity: 0;
43
- inset: 0;
44
- margin: 0;
45
- padding: 0;
46
- border: none;
47
- }
48
-
49
- .custom_radio {
50
- width: 13px;
51
- height: 13px;
52
- background: transparent;
53
- border-radius: 50%;
54
- display: inline-flex;
55
- align-items: center;
56
- justify-content: center;
57
- margin-left: 5px;
58
- margin-top: 3px;
59
- margin-right: 3px;
60
- }
61
-
62
- .custom_radio svg {
63
- width: 100%;
64
- height: 100%;
65
- pointer-events: none;
66
- }
67
-
68
- .custom_radio svg .custom_radio_dashed_border {
69
- display: none;
70
- }
71
-
72
- .custom_radio svg .custom_radio_marker {
73
- fill: var(--checkmark-color);
74
- opacity: 0;
75
- transform-origin: center;
76
- transform: scale(0.3);
77
- }
78
-
79
- .custom_radio[data-transition] svg {
80
- transition: all 0.15s ease;
81
- }
82
- .custom_radio[data-transition] svg .custom_radio_dashed_border {
83
- transition: all 0.15s ease;
84
- }
85
- .custom_radio[data-transition] svg .custom_radio_border {
86
- transition: all 0.15s ease;
87
- }
35
+ @layer navi {
36
+ :root {
37
+ --navi-radiomark-color: light-dark(#4476ff, #3b82f6);
38
+ }
88
39
 
89
- /* États hover */
90
- .custom_radio_wrapper:hover .custom_radio svg .custom_radio_border {
91
- stroke: var(--field-hover-border-color);
92
- }
93
- .custom_radio_wrapper:hover .custom_radio svg .custom_radio_marker {
94
- fill: var(--field-strong-color);
95
- }
40
+ .navi_radio {
41
+ position: relative;
42
+ display: inline-flex;
43
+ box-sizing: content-box;
96
44
 
97
- .custom_radio_wrapper:hover
98
- input:checked
99
- + .custom_radio
100
- svg
101
- .custom_radio_border {
102
- stroke: var(--field-strong-color);
103
- }
45
+ --outline-offset: 1px;
46
+ --outline-width: 2px;
47
+ --width: 13px;
48
+ --height: 13px;
104
49
 
105
- /* État checked */
106
- .custom_radio_wrapper input:checked + .custom_radio svg .custom_radio_border {
107
- stroke: var(--field-strong-color);
108
- }
50
+ --outline-color: light-dark(#4476ff, #3b82f6);
51
+ --border-color: light-dark(#767676, #8e8e93);
52
+ --background-color: white;
53
+ --accent-color: var(--navi-radiomark-color);
54
+ --mark-color: var(--accent-color);
109
55
 
110
- .custom_radio_wrapper input:checked + .custom_radio svg .custom_radio_marker {
111
- opacity: 1;
112
- transform: scale(1);
113
- }
56
+ /* light-dark(rgba(239, 239, 239, 0.3), rgba(59, 59, 59, 0.3)); */
57
+ --accent-color-checked: color-mix(
58
+ in srgb,
59
+ var(--accent-color) 70%,
60
+ black
61
+ );
114
62
 
115
- /* États disabled */
116
- .custom_radio_wrapper
117
- input[disabled]
118
- + .custom_radio
119
- svg
120
- .custom_radio_border {
121
- fill: light-dark(rgba(239, 239, 239, 0.3), rgba(59, 59, 59, 0.3));
122
- stroke: var(--field-disabled-border-color);
123
- }
63
+ --border-color-readonly: color-mix(
64
+ in srgb,
65
+ var(--border-color) 30%,
66
+ white
67
+ );
68
+ --border-color-disabled: var(--border-color-readonly);
69
+ --border-color-hover: color-mix(in srgb, var(--border-color) 70%, black);
70
+ --border-color-checked: var(--accent-color);
71
+ --border-color-checked-hover: var(--accent-color-checked);
72
+ --border-color-checked-readonly: #d3d3d3;
73
+ --border-color-checked-disabled: #d3d3d3;
74
+ --background-color-readonly: var(--background-color);
75
+ --background-color-disabled: var(--background-color);
76
+ --background-color-checked-readonly: #d3d3d3;
77
+ --background-color-checked-disabled: var(--background-color);
78
+ --mark-color-hover: var(--accent-color-checked);
79
+ --mark-color-readonly: grey;
80
+ --mark-color-disabled: #eeeeee;
81
+ }
82
+ .navi_radio input {
83
+ position: absolute;
84
+ inset: 0;
85
+ margin: 0;
86
+ padding: 0;
87
+ opacity: 0;
88
+ cursor: inherit;
89
+ }
90
+ .navi_radio_field {
91
+ display: inline-flex;
92
+ width: var(--width);
93
+ height: var(--height);
94
+ margin-top: 3px;
95
+ margin-right: 3px;
96
+ margin-left: 5px;
97
+ align-items: center;
98
+ justify-content: center;
99
+ border-radius: 50%;
100
+ outline-width: var(--outline-width);
124
101
 
125
- .custom_radio_wrapper
126
- input[disabled]:checked
127
- + .custom_radio
128
- svg
129
- .custom_radio_border {
130
- stroke: var(--checked-disabled-color);
131
- }
102
+ outline-style: none;
132
103
 
133
- .custom_radio_wrapper
134
- input[disabled]:checked
135
- + .custom_radio
136
- svg
137
- .custom_radio_marker {
138
- fill: var(--checkmark-disabled-color);
139
- }
104
+ outline-color: var(--outline-color);
140
105
 
141
- .custom_radio_wrapper
142
- input[data-readonly]
143
- + .custom_radio
144
- svg
145
- .custom_radio_border {
146
- fill: light-dark(rgba(239, 239, 239, 0.3), rgba(59, 59, 59, 0.3));
147
- stroke: var(--field-disabled-border-color);
148
- }
149
- .custom_radio_wrapper
150
- input[data-readonly]
151
- + .custom_radio
152
- svg
153
- .custom_radio_dashed_border {
154
- display: none;
155
- }
156
- .custom_radio_wrapper
157
- input[data-readonly]:checked
158
- + .custom_radio
159
- svg
160
- .custom_radio_border {
161
- stroke: var(--checked-disabled-color);
162
- }
163
- .custom_radio_wrapper
164
- input[data-readonly]:checked
165
- + .custom_radio
166
- svg
167
- .custom_radio_marker {
168
- fill: var(--checkmark-disabled-color);
169
- }
170
- .custom_radio_wrapper:hover
171
- input[data-readonly]
172
- + .custom_radio
173
- svg
174
- .custom_radio_border {
175
- fill: light-dark(rgba(239, 239, 239, 0.3), rgba(59, 59, 59, 0.3));
176
- stroke: var(--field-disabled-border-color);
177
- }
178
- .custom_radio_wrapper:hover
179
- input[data-readonly]:checked
180
- + .custom_radio
181
- svg
182
- .custom_radio_border {
183
- stroke: var(--checked-disabled-color);
184
- }
106
+ outline-offset: var(--outline-offset);
107
+ }
108
+ .navi_radio_field svg {
109
+ overflow: visible;
110
+ }
111
+ .navi_radio_border {
112
+ fill: var(--background-color);
113
+ stroke: var(--border-color);
114
+ }
115
+ .navi_radio_marker {
116
+ width: 100%;
117
+ height: 100%;
118
+ opacity: 0;
119
+ fill: var(--mark-color);
120
+ transform: scale(0.3);
121
+ transform-origin: center;
122
+ pointer-events: none;
123
+ }
124
+ .navi_radio_dashed_border {
125
+ display: none;
126
+ }
127
+ .navi_radio[data-transition] .navi_radio_marker {
128
+ transition: all 0.15s ease;
129
+ }
130
+ .navi_radio[data-transition] .navi_radio_dashed_border {
131
+ transition: all 0.15s ease;
132
+ }
133
+ .navi_radio[data-transition] .navi_radio_border {
134
+ transition: all 0.15s ease;
135
+ }
185
136
 
186
- /* Focus state avec outline */
187
- .custom_radio_wrapper input:focus-visible + .custom_radio {
188
- outline: 2px solid var(--field-outline-color);
189
- outline-offset: 1px;
190
- border-radius: 50%;
137
+ /* Focus */
138
+ .navi_radio[data-focus-visible] .navi_radio_field {
139
+ outline-style: solid;
140
+ }
141
+ /* Hover */
142
+ .navi_radio[data-hover] .navi_radio_border {
143
+ stroke: var(--border-color-hover);
144
+ }
145
+ .navi_radio[data-hover] .navi_radio_marker {
146
+ fill: var(--mark-color-hover);
147
+ }
148
+ /* Checked */
149
+ .navi_radio[data-checked] .navi_radio_border {
150
+ stroke: var(--border-color-checked);
151
+ }
152
+ .navi_radio[data-checked] .navi_radio_marker {
153
+ opacity: 1;
154
+ transform: scale(1);
155
+ }
156
+ .navi_radio[data-hover][data-checked] .navi_radio_border {
157
+ stroke: var(--border-color-checked-hover);
158
+ }
159
+ /* Readonly */
160
+ .navi_radio[data-readonly] .navi_radio_border {
161
+ fill: var(--background-color-readonly);
162
+ stroke: var(--border-color-readonly);
163
+ }
164
+ .navi_radio[data-readonly] .navi_radio_marker {
165
+ fill: var(--mark-color-readonly);
166
+ }
167
+ .navi_radio[data-readonly] .navi_radio_dashed_border {
168
+ display: none;
169
+ }
170
+ .navi_radio[data-checked][data-readonly] .navi_radio_border {
171
+ fill: var(--background-color-checked-readonly);
172
+ stroke: var(--border-color-checked-readonly);
173
+ }
174
+ .navi_radio[data-checked][data-readonly] .navi_radio_marker {
175
+ fill: var(--mark-color-readonly);
176
+ }
177
+ /* Disabled */
178
+ .navi_radio[data-disabled] .navi_radio_border {
179
+ fill: var(--background-color-disabled);
180
+ stroke: var(--border-color-disabled);
181
+ }
182
+ .navi_radio[data-disabled] .navi_radio_marker {
183
+ fill: var(--mark-color-disabled);
184
+ }
185
+ .navi_radio[data-hover][data-checked][data-disabled] .navi_radio_border {
186
+ stroke: var(--border-color-disabled);
187
+ }
188
+ .navi_radio[data-checked][data-disabled] .navi_radio_marker {
189
+ fill: var(--mark-color-disabled);
190
+ }
191
191
  }
192
192
  `;
193
193
 
@@ -223,6 +223,7 @@ const InputRadioBasic = forwardRef((props, ref) => {
223
223
  const uiStateController = useContext(UIStateControllerContext);
224
224
  const uiState = useContext(UIStateContext);
225
225
  const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
226
+ const reportDisabledOnLabel = useContext(ReportDisabledOnLabelContext);
226
227
  const {
227
228
  name,
228
229
  readOnly,
@@ -233,10 +234,11 @@ const InputRadioBasic = forwardRef((props, ref) => {
233
234
  autoFocus,
234
235
  constraints = [],
235
236
 
236
- appeareance = "custom", // "custom" or "default"
237
+ appeareance = "navi", // "navi" or "default"
237
238
  accentColor,
238
239
  onClick,
239
240
  onInput,
241
+ style,
240
242
  ...rest
241
243
  } = props;
242
244
  const innerRef = useRef(null);
@@ -251,14 +253,10 @@ const InputRadioBasic = forwardRef((props, ref) => {
251
253
  readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
252
254
 
253
255
  reportReadOnlyOnLabel?.(innerReadOnly);
256
+ reportDisabledOnLabel?.(innerDisabled);
254
257
  useAutoFocus(innerRef, autoFocus);
255
258
  useConstraints(innerRef, constraints);
256
259
  const checked = Boolean(uiState);
257
- const actionName = rest["data-action"];
258
- if (actionName) {
259
- delete rest["data-action"];
260
- }
261
-
262
260
  // we must first dispatch an event to inform all other radios they where unchecked
263
261
  // this way each other radio uiStateController knows thery are unchecked
264
262
  // we do this on "input"
@@ -266,6 +264,9 @@ const InputRadioBasic = forwardRef((props, ref) => {
266
264
  const updateOtherRadiosInGroup = () => {
267
265
  const thisRadio = innerRef.current;
268
266
  const radioList = thisRadio.closest("[data-radio-list]");
267
+ if (!radioList) {
268
+ return;
269
+ }
269
270
  const radioInputs = radioList.querySelectorAll(
270
271
  `input[type="radio"][name="${thisRadio.name}"]`,
271
272
  );
@@ -284,14 +285,18 @@ const InputRadioBasic = forwardRef((props, ref) => {
284
285
  }
285
286
  }, [checked]);
286
287
 
288
+ const actionName = rest["data-action"];
289
+ if (actionName) {
290
+ delete rest["data-action"];
291
+ }
287
292
  const inputRadio = (
288
293
  <input
289
294
  {...rest}
290
295
  ref={innerRef}
291
296
  type="radio"
297
+ style={appeareance === "default" ? style : undefined}
292
298
  name={innerName}
293
299
  checked={checked}
294
- data-readonly={innerReadOnly ? "" : undefined}
295
300
  disabled={innerDisabled}
296
301
  required={innerRequired}
297
302
  data-validation-message-arrow-x="center"
@@ -320,30 +325,65 @@ const InputRadioBasic = forwardRef((props, ref) => {
320
325
  }}
321
326
  />
322
327
  );
323
- const inputRadioDisplayed =
324
- appeareance === "custom" ? (
325
- <CustomRadio accentColor={accentColor}>{inputRadio}</CustomRadio>
326
- ) : (
327
- inputRadio
328
+ const loaderProps = {
329
+ loading: innerLoading,
330
+ inset: -1,
331
+ style: {
332
+ "--accent-color": accentColor || "light-dark(#355fcc, #4476ff)",
333
+ },
334
+ color: "var(--accent-color)",
335
+ };
336
+ if (appeareance === "navi") {
337
+ return (
338
+ <NaviRadio
339
+ data-action={actionName}
340
+ inputRef={innerRef}
341
+ accentColor={accentColor}
342
+ readOnly={innerReadOnly}
343
+ disabled={innerDisabled}
344
+ style={style}
345
+ >
346
+ <LoaderBackground {...loaderProps} targetSelector=".navi_radio_field">
347
+ {inputRadio}
348
+ </LoaderBackground>
349
+ </NaviRadio>
328
350
  );
351
+ }
329
352
 
330
353
  return (
331
- <LoadableInlineElement
332
- data-action={actionName}
333
- loading={innerLoading}
334
- targetSelector={appeareance === "custom" ? ".custom_radio" : ""}
335
- inset={-1}
336
- color="light-dark(#355fcc, #3b82f6)"
337
- >
338
- {inputRadioDisplayed}
354
+ <LoadableInlineElement {...loaderProps} data-action={actionName}>
355
+ {inputRadio}
339
356
  </LoadableInlineElement>
340
357
  );
341
358
  });
342
- const CustomRadio = ({ children }) => {
359
+ const NaviRadio = ({
360
+ inputRef,
361
+ accentColor,
362
+ readOnly,
363
+ disabled,
364
+ style,
365
+ children,
366
+ ...rest
367
+ }) => {
368
+ const ref = useRef();
369
+ useLayoutEffect(() => {
370
+ return initCustomField(ref.current, inputRef.current);
371
+ }, []);
372
+
343
373
  return (
344
- <div className="custom_radio_wrapper" data-field-wrapper="">
374
+ <span
375
+ {...rest}
376
+ ref={ref}
377
+ className="navi_radio"
378
+ style={{
379
+ ...(accentColor ? { "--accent-color": accentColor } : {}),
380
+ ...style,
381
+ }}
382
+ data-readonly={readOnly ? "" : undefined}
383
+ data-disabled={disabled ? "" : undefined}
384
+ >
345
385
  {children}
346
- <div className="custom_radio">
386
+ <span className="navi_radio_field">
347
387
  <svg
348
388
  viewBox="0 0 12 12"
349
389
  aria-hidden="true"
@@ -351,31 +391,27 @@ const CustomRadio = ({ children }) => {
351
391
  >
352
392
  {/* Border circle - always visible */}
353
393
  <circle
354
- className="custom_radio_border"
394
+ className="navi_radio_border"
355
395
  cx="6"
356
396
  cy="6"
357
397
  r="5.5"
358
- fill="white"
359
- stroke="var(--field-border-color)"
360
398
  strokeWidth="1"
361
399
  />
362
400
  {/* Dashed border for readonly - calculated for even distribution */}
363
401
  <circle
364
- className="custom_radio_dashed_border"
402
+ className="navi_radio_dashed_border"
365
403
  cx="6"
366
404
  cy="6"
367
405
  r="5.5"
368
- fill="var(--field-readonly-background-color)"
369
- stroke="var(--field-border-color)"
370
406
  strokeWidth="1"
371
407
  strokeDasharray="2.16 2.16"
372
408
  strokeDashoffset="0"
373
409
  />
374
410
  {/* Inner fill circle - only visible when checked */}
375
- <circle className="custom_radio_marker" cx="6" cy="6" r="3.5" />
411
+ <circle className="navi_radio_marker" cx="6" cy="6" r="3.5" />
376
412
  </svg>
377
- </div>
378
- </div>
413
+ </span>
414
+ </span>
379
415
  );
380
416
  };
381
417
 
@@ -33,7 +33,7 @@ import { useActionBoundToOneParam } from "../action_execution/use_action.js";
33
33
  import { useExecuteAction } from "../action_execution/use_execute_action.js";
34
34
  import { LoadableInlineElement } from "../loader/loader_background.jsx";
35
35
  import { useAutoFocus } from "../use_auto_focus.js";
36
- import "./field_css.js";
36
+ import { initCustomField } from "./custom_field.js";
37
37
  import { ReportReadOnlyOnLabelContext } from "./label.jsx";
38
38
  import { useActionEvents } from "./use_action_events.js";
39
39
  import {
@@ -47,6 +47,86 @@ import {
47
47
  useUIStateController,
48
48
  } from "./use_ui_state_controller.js";
49
49
 
50
+ import.meta.css = /* css */ `
51
+ @layer navi {
52
+ .navi_input {
53
+ --border-width: 1px;
54
+ --outline-width: 1px;
55
+ --outer-width: calc(var(--border-width) + var(--outline-width));
56
+ --padding-x: 6px;
57
+ --padding-y: 1px;
58
+
59
+ --outline-color: light-dark(#4476ff, #3b82f6);
60
+
61
+ --border-radius: 2px;
62
+ --border-color: light-dark(#767676, #8e8e93);
63
+ --border-color-hover: color-mix(in srgb, var(--border-color) 70%, black);
64
+ --border-color-active: color-mix(in srgb, var(--border-color) 90%, black);
65
+ --border-color-readonly: color-mix(
66
+ in srgb,
67
+ var(--border-color) 45%,
68
+ transparent
69
+ );
70
+ --border-color-disabled: var(--border-color-readonly);
71
+
72
+ --background-color: white;
73
+ --background-color-hover: color-mix(
74
+ in srgb,
75
+ var(--background-color) 95%,
76
+ black
77
+ );
78
+ --background-color-readonly: var(--background-color);
79
+ --background-color-disabled: color-mix(
80
+ in srgb,
81
+ var(--background-color) 60%,
82
+ transparent
83
+ );
84
+
85
+ --color: currentColor;
86
+ --color-readonly: color-mix(in srgb, currentColor 60%, transparent);
87
+ --color-disabled: var(--color-readonly);
88
+ color: var(--color);
89
+
90
+ background-color: var(--background-color);
91
+ border-width: var(--outer-width);
92
+ border-width: var(--outer-width);
93
+ border-style: solid;
94
+ border-color: transparent;
95
+ border-radius: var(--border-radius);
96
+ outline-width: var(--border-width);
97
+ outline-style: solid;
98
+ outline-color: var(--border-color);
99
+ outline-offset: calc(-1 * (var(--border-width)));
100
+ }
101
+ /* Focus */
102
+ .navi_input[data-focus] {
103
+ border-color: var(--outline-color);
104
+ outline-width: var(--outer-width);
105
+ outline-color: var(--outline-color);
106
+ outline-offset: calc(-1 * var(--outer-width));
107
+ }
108
+ /* Readonly */
109
+ .navi_input[data-readonly] {
110
+ color: var(--color-readonly);
111
+ background-color: var(--background-color-readonly);
112
+ outline-color: var(--border-color-readonly);
113
+ }
114
+ .navi_input[data-readonly]::placeholder {
115
+ color: var(--color-readonly);
116
+ }
117
+ /* Disabled */
118
+ .navi_input[data-disabled] {
119
+ color: var(--color-disabled);
120
+ background-color: var(--background-color-disabled);
121
+ outline-color: var(--border-color-disabled);
122
+ }
123
+ /* Invalid */
124
+ .navi_input[aria-invalid="true"] {
125
+ border-color: var(--invalid-color);
126
+ }
127
+ }
128
+ `;
129
+
50
130
  export const InputTextual = forwardRef((props, ref) => {
51
131
  const uiStateController = useUIStateController(props, "input");
52
132
  const uiState = useUIState(uiStateController);
@@ -83,7 +163,8 @@ const InputTextualBasic = forwardRef((props, ref) => {
83
163
  autoFocus,
84
164
  autoFocusVisible,
85
165
  autoSelect,
86
- appearance = "custom",
166
+ appearance = "navi",
167
+ accentColor,
87
168
  width,
88
169
  height,
89
170
  ...rest
@@ -110,14 +191,14 @@ const InputTextualBasic = forwardRef((props, ref) => {
110
191
  <input
111
192
  {...rest}
112
193
  ref={innerRef}
194
+ className={appearance === "navi" ? "navi_input" : undefined}
113
195
  type={type}
114
196
  data-value={uiState}
115
197
  value={innerValue}
116
- data-field=""
117
- data-field-with-border=""
118
- data-custom={appearance === "custom" ? "" : undefined}
119
198
  readOnly={innerReadOnly}
120
199
  disabled={innerDisabled}
200
+ data-readOnly={innerReadOnly ? "" : undefined}
201
+ data-disabled={innerDisabled ? "" : undefined}
121
202
  onInput={(e) => {
122
203
  let inputValue;
123
204
  if (type === "number") {
@@ -141,12 +222,23 @@ const InputTextualBasic = forwardRef((props, ref) => {
141
222
  />
142
223
  );
143
224
 
225
+ useLayoutEffect(() => {
226
+ return initCustomField(innerRef.current, innerRef.current);
227
+ }, []);
228
+
229
+ if (type === "hidden") {
230
+ return inputTextual;
231
+ }
144
232
  return (
145
233
  <LoadableInlineElement
146
234
  loading={innerLoading}
147
- color="light-dark(#355fcc, #3b82f6)"
235
+ style={{
236
+ "--accent-color": accentColor || "light-dark(#355fcc, #4476ff)",
237
+ }}
238
+ color="var(--accent-color)"
148
239
  width={width}
149
240
  height={height}
241
+ inset={-1}
150
242
  >
151
243
  {inputTextual}
152
244
  </LoadableInlineElement>