@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.
- package/dist/jsenv_navi.js +8349 -3784
- package/package.json +3 -4
- package/src/components/action_execution/form_context.js +1 -4
- package/src/components/action_execution/use_action.js +2 -2
- package/src/components/demos/0_button_demo.html +149 -68
- package/src/components/demos/1_checkbox_demo.html +122 -2
- package/src/components/demos/2_input_textual_demo.html +44 -55
- package/src/components/demos/3_radio_demo.html +811 -157
- package/src/components/demos/action/0_button_demo.html +6 -4
- package/src/components/demos/action/1_input_text_demo.html +19 -25
- package/src/components/field/button.jsx +193 -84
- package/src/components/field/checkbox_list.jsx +5 -3
- package/src/components/field/custom_field.js +106 -0
- package/src/components/field/form.jsx +9 -4
- package/src/components/field/input_checkbox.jsx +206 -125
- package/src/components/field/input_radio.jsx +224 -188
- package/src/components/field/input_textual.jsx +98 -6
- package/src/components/field/label.jsx +18 -4
- package/src/components/field/navi_css_vars.js +10 -0
- package/src/components/field/radio_list.jsx +5 -3
- package/src/components/loader/loader_background.jsx +41 -14
- package/src/validation/constraints/readonly_constraint.js +5 -0
- package/src/validation/validation_message.js +159 -147
- package/src/components/field/field_css.js +0 -121
|
@@ -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 {
|
|
11
|
+
import {
|
|
12
|
+
LoadableInlineElement,
|
|
13
|
+
LoaderBackground,
|
|
14
|
+
} from "../loader/loader_background.jsx";
|
|
12
15
|
import { useAutoFocus } from "../use_auto_focus.js";
|
|
13
|
-
import {
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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 = "
|
|
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
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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="
|
|
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="
|
|
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="
|
|
411
|
+
<circle className="navi_radio_marker" cx="6" cy="6" r="3.5" />
|
|
376
412
|
</svg>
|
|
377
|
-
</
|
|
378
|
-
</
|
|
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 "./
|
|
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 = "
|
|
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
|
-
|
|
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>
|