@yuneta/gobj-ui 7.23.56 → 7.23.58
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/gobj-ui.cjs.js +44 -8
- package/dist/gobj-ui.es.js +44 -8
- package/package.json +1 -1
- package/src/c_yui_form.css +15 -0
- package/src/c_yui_form.js +49 -1
- package/src/form_toolbar_plan.js +18 -6
- package/src/form_toolbar_plan.test.js +19 -10
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -5900,18 +5900,18 @@ function refresh_clear($input) {
|
|
|
5900
5900
|
* Copyright (c) 2026, ArtGins.
|
|
5901
5901
|
* All Rights Reserved.
|
|
5902
5902
|
***********************************************************************/
|
|
5903
|
-
var LEFT_BUTTONS = [
|
|
5904
|
-
|
|
5903
|
+
var LEFT_BUTTONS = ["copy", "paste"];
|
|
5904
|
+
var RIGHT_BUTTONS = [
|
|
5905
5905
|
"undo",
|
|
5906
|
-
"clear"
|
|
5906
|
+
"clear",
|
|
5907
|
+
"save"
|
|
5907
5908
|
];
|
|
5908
|
-
var RIGHT_BUTTONS = ["copy", "paste"];
|
|
5909
5909
|
var DEFAULT_TOOLBAR = [
|
|
5910
|
-
"
|
|
5910
|
+
"copy",
|
|
5911
|
+
"paste",
|
|
5911
5912
|
"undo",
|
|
5912
5913
|
"clear",
|
|
5913
|
-
"
|
|
5914
|
-
"paste"
|
|
5914
|
+
"save"
|
|
5915
5915
|
];
|
|
5916
5916
|
/***************************************************************
|
|
5917
5917
|
* plan_toolbar(wanted) -> {left, right, unknown}
|
|
@@ -7064,7 +7064,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
7064
7064
|
"div",
|
|
7065
7065
|
{
|
|
7066
7066
|
class: "xcontrol control",
|
|
7067
|
-
style: "max-width:
|
|
7067
|
+
style: "max-width:220px;"
|
|
7068
7068
|
},
|
|
7069
7069
|
[]
|
|
7070
7070
|
]]
|
|
@@ -7322,6 +7322,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
7322
7322
|
]);
|
|
7323
7323
|
$control.appendChild($extend);
|
|
7324
7324
|
if (inputType !== "color" && inputType !== "datetime-local" && (!readonly || is_pkey)) attach_clear($control, $extend);
|
|
7325
|
+
if (inputType === "color") attach_color_value($control, $extend);
|
|
7325
7326
|
break;
|
|
7326
7327
|
}
|
|
7327
7328
|
case "textarea": {
|
|
@@ -7520,6 +7521,37 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
7520
7521
|
return $element;
|
|
7521
7522
|
}
|
|
7522
7523
|
/******************************************************************
|
|
7524
|
+
* A colour swatch beside its own value.
|
|
7525
|
+
*
|
|
7526
|
+
* The swatch says WHICH colour and nothing else -- and the value is
|
|
7527
|
+
* the half a person needs: to read it, to write it down, to paste it
|
|
7528
|
+
* into the next record. Read-only it was unreachable altogether;
|
|
7529
|
+
* editable it was a colour you could only pick, never copy.
|
|
7530
|
+
*
|
|
7531
|
+
* A `<span>`, not a second input: the record is collected from the
|
|
7532
|
+
* controls marked `yui-form-data-input`, and one field with two of
|
|
7533
|
+
* them is a field read twice. It carries `user-select: all`, so one
|
|
7534
|
+
* click takes the whole value and not the half a double-click would
|
|
7535
|
+
* stop at (`#e0a800` is three words to a browser).
|
|
7536
|
+
******************************************************************/
|
|
7537
|
+
function attach_color_value($control, $input) {
|
|
7538
|
+
let $value = (0, _yuneta_gobj_js.createElement2)([
|
|
7539
|
+
"span",
|
|
7540
|
+
{ class: "yui-color-value is-family-monospace is-size-7" },
|
|
7541
|
+
""
|
|
7542
|
+
]);
|
|
7543
|
+
function refresh() {
|
|
7544
|
+
let v = $input.value || "";
|
|
7545
|
+
$value.textContent = v;
|
|
7546
|
+
$value.title = v;
|
|
7547
|
+
}
|
|
7548
|
+
refresh();
|
|
7549
|
+
$input.addEventListener("input", refresh);
|
|
7550
|
+
$input.addEventListener("change", refresh);
|
|
7551
|
+
$input.yui_color_value = $value;
|
|
7552
|
+
$control.appendChild($value);
|
|
7553
|
+
}
|
|
7554
|
+
/******************************************************************
|
|
7523
7555
|
* `readonly` is an attribute of a TEXT control and of nothing else.
|
|
7524
7556
|
*
|
|
7525
7557
|
* A `<select>` ignores it. So does a checkbox, and so does a radio:
|
|
@@ -8099,6 +8131,10 @@ function set_form_values(gobj, template, $form, record) {
|
|
|
8099
8131
|
break;
|
|
8100
8132
|
case "color":
|
|
8101
8133
|
$input.value = convertColor(value);
|
|
8134
|
+
if ($input.yui_color_value) {
|
|
8135
|
+
$input.yui_color_value.textContent = $input.value;
|
|
8136
|
+
$input.yui_color_value.title = $input.value;
|
|
8137
|
+
}
|
|
8102
8138
|
break;
|
|
8103
8139
|
default: $input.value = value;
|
|
8104
8140
|
}
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -5895,18 +5895,18 @@ function refresh_clear($input) {
|
|
|
5895
5895
|
* Copyright (c) 2026, ArtGins.
|
|
5896
5896
|
* All Rights Reserved.
|
|
5897
5897
|
***********************************************************************/
|
|
5898
|
-
var LEFT_BUTTONS = [
|
|
5899
|
-
|
|
5898
|
+
var LEFT_BUTTONS = ["copy", "paste"];
|
|
5899
|
+
var RIGHT_BUTTONS = [
|
|
5900
5900
|
"undo",
|
|
5901
|
-
"clear"
|
|
5901
|
+
"clear",
|
|
5902
|
+
"save"
|
|
5902
5903
|
];
|
|
5903
|
-
var RIGHT_BUTTONS = ["copy", "paste"];
|
|
5904
5904
|
var DEFAULT_TOOLBAR = [
|
|
5905
|
-
"
|
|
5905
|
+
"copy",
|
|
5906
|
+
"paste",
|
|
5906
5907
|
"undo",
|
|
5907
5908
|
"clear",
|
|
5908
|
-
"
|
|
5909
|
-
"paste"
|
|
5909
|
+
"save"
|
|
5910
5910
|
];
|
|
5911
5911
|
/***************************************************************
|
|
5912
5912
|
* plan_toolbar(wanted) -> {left, right, unknown}
|
|
@@ -7059,7 +7059,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
7059
7059
|
"div",
|
|
7060
7060
|
{
|
|
7061
7061
|
class: "xcontrol control",
|
|
7062
|
-
style: "max-width:
|
|
7062
|
+
style: "max-width:220px;"
|
|
7063
7063
|
},
|
|
7064
7064
|
[]
|
|
7065
7065
|
]]
|
|
@@ -7317,6 +7317,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
7317
7317
|
]);
|
|
7318
7318
|
$control.appendChild($extend);
|
|
7319
7319
|
if (inputType !== "color" && inputType !== "datetime-local" && (!readonly || is_pkey)) attach_clear($control, $extend);
|
|
7320
|
+
if (inputType === "color") attach_color_value($control, $extend);
|
|
7320
7321
|
break;
|
|
7321
7322
|
}
|
|
7322
7323
|
case "textarea": {
|
|
@@ -7515,6 +7516,37 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
7515
7516
|
return $element;
|
|
7516
7517
|
}
|
|
7517
7518
|
/******************************************************************
|
|
7519
|
+
* A colour swatch beside its own value.
|
|
7520
|
+
*
|
|
7521
|
+
* The swatch says WHICH colour and nothing else -- and the value is
|
|
7522
|
+
* the half a person needs: to read it, to write it down, to paste it
|
|
7523
|
+
* into the next record. Read-only it was unreachable altogether;
|
|
7524
|
+
* editable it was a colour you could only pick, never copy.
|
|
7525
|
+
*
|
|
7526
|
+
* A `<span>`, not a second input: the record is collected from the
|
|
7527
|
+
* controls marked `yui-form-data-input`, and one field with two of
|
|
7528
|
+
* them is a field read twice. It carries `user-select: all`, so one
|
|
7529
|
+
* click takes the whole value and not the half a double-click would
|
|
7530
|
+
* stop at (`#e0a800` is three words to a browser).
|
|
7531
|
+
******************************************************************/
|
|
7532
|
+
function attach_color_value($control, $input) {
|
|
7533
|
+
let $value = createElement2([
|
|
7534
|
+
"span",
|
|
7535
|
+
{ class: "yui-color-value is-family-monospace is-size-7" },
|
|
7536
|
+
""
|
|
7537
|
+
]);
|
|
7538
|
+
function refresh() {
|
|
7539
|
+
let v = $input.value || "";
|
|
7540
|
+
$value.textContent = v;
|
|
7541
|
+
$value.title = v;
|
|
7542
|
+
}
|
|
7543
|
+
refresh();
|
|
7544
|
+
$input.addEventListener("input", refresh);
|
|
7545
|
+
$input.addEventListener("change", refresh);
|
|
7546
|
+
$input.yui_color_value = $value;
|
|
7547
|
+
$control.appendChild($value);
|
|
7548
|
+
}
|
|
7549
|
+
/******************************************************************
|
|
7518
7550
|
* `readonly` is an attribute of a TEXT control and of nothing else.
|
|
7519
7551
|
*
|
|
7520
7552
|
* A `<select>` ignores it. So does a checkbox, and so does a radio:
|
|
@@ -8094,6 +8126,10 @@ function set_form_values(gobj, template, $form, record) {
|
|
|
8094
8126
|
break;
|
|
8095
8127
|
case "color":
|
|
8096
8128
|
$input.value = convertColor(value);
|
|
8129
|
+
if ($input.yui_color_value) {
|
|
8130
|
+
$input.yui_color_value.textContent = $input.value;
|
|
8131
|
+
$input.yui_color_value.title = $input.value;
|
|
8132
|
+
}
|
|
8097
8133
|
break;
|
|
8098
8134
|
default: $input.value = value;
|
|
8099
8135
|
}
|
package/package.json
CHANGED
package/src/c_yui_form.css
CHANGED
|
@@ -79,3 +79,18 @@
|
|
|
79
79
|
.C_YUI_FORM .yui-jse-readonly {
|
|
80
80
|
background-color: var(--bulma-background, #f5f5f5);
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
/* The value of a colour, beside its swatch: what the swatch cannot say.
|
|
84
|
+
* `user-select: all` so one click takes the whole `#e0a800` -- to a
|
|
85
|
+
* browser that is three words, and a double-click stops at one of them. */
|
|
86
|
+
.C_YUI_FORM .yui-color-value {
|
|
87
|
+
margin-left: 0.5rem;
|
|
88
|
+
vertical-align: middle;
|
|
89
|
+
color: var(--bulma-text-weak, #7a7a7a);
|
|
90
|
+
user-select: all;
|
|
91
|
+
-webkit-user-select: all;
|
|
92
|
+
cursor: text;
|
|
93
|
+
}
|
|
94
|
+
.C_YUI_FORM input[type="color"] {
|
|
95
|
+
vertical-align: middle;
|
|
96
|
+
}
|
package/src/c_yui_form.js
CHANGED
|
@@ -1024,7 +1024,9 @@ function create_form_field(
|
|
|
1024
1024
|
|
|
1025
1025
|
['div', {class: 'field-body'}, [
|
|
1026
1026
|
['div', {class: 'field'}, [
|
|
1027
|
-
|
|
1027
|
+
/* Room for the swatch AND its value
|
|
1028
|
+
* beside it (attach_color_value). */
|
|
1029
|
+
['div', {class: 'xcontrol control', style: 'max-width:220px;'}, []]
|
|
1028
1030
|
]]
|
|
1029
1031
|
]]
|
|
1030
1032
|
]]
|
|
@@ -1201,6 +1203,9 @@ function create_form_field(
|
|
|
1201
1203
|
(!readonly || is_pkey)) {
|
|
1202
1204
|
attach_clear($control, $extend);
|
|
1203
1205
|
}
|
|
1206
|
+
if(inputType === 'color') {
|
|
1207
|
+
attach_color_value($control, $extend);
|
|
1208
|
+
}
|
|
1204
1209
|
break;
|
|
1205
1210
|
}
|
|
1206
1211
|
|
|
@@ -1456,6 +1461,43 @@ function create_form_field(
|
|
|
1456
1461
|
return $element;
|
|
1457
1462
|
}
|
|
1458
1463
|
|
|
1464
|
+
/******************************************************************
|
|
1465
|
+
* A colour swatch beside its own value.
|
|
1466
|
+
*
|
|
1467
|
+
* The swatch says WHICH colour and nothing else -- and the value is
|
|
1468
|
+
* the half a person needs: to read it, to write it down, to paste it
|
|
1469
|
+
* into the next record. Read-only it was unreachable altogether;
|
|
1470
|
+
* editable it was a colour you could only pick, never copy.
|
|
1471
|
+
*
|
|
1472
|
+
* A `<span>`, not a second input: the record is collected from the
|
|
1473
|
+
* controls marked `yui-form-data-input`, and one field with two of
|
|
1474
|
+
* them is a field read twice. It carries `user-select: all`, so one
|
|
1475
|
+
* click takes the whole value and not the half a double-click would
|
|
1476
|
+
* stop at (`#e0a800` is three words to a browser).
|
|
1477
|
+
******************************************************************/
|
|
1478
|
+
function attach_color_value($control, $input)
|
|
1479
|
+
{
|
|
1480
|
+
let $value = createElement2(
|
|
1481
|
+
['span', {class: 'yui-color-value is-family-monospace is-size-7'}, '']
|
|
1482
|
+
);
|
|
1483
|
+
|
|
1484
|
+
function refresh() {
|
|
1485
|
+
let v = $input.value || "";
|
|
1486
|
+
$value.textContent = v;
|
|
1487
|
+
$value.title = v;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
refresh();
|
|
1491
|
+
$input.addEventListener('input', refresh);
|
|
1492
|
+
/* The swatch's value is also written from outside (loading a record
|
|
1493
|
+
* into the form), and that fires nothing. `set_field_value()` ends
|
|
1494
|
+
* in a synthetic `change`, which is why this listens to both. */
|
|
1495
|
+
$input.addEventListener('change', refresh);
|
|
1496
|
+
$input.yui_color_value = $value;
|
|
1497
|
+
|
|
1498
|
+
$control.appendChild($value);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1459
1501
|
/******************************************************************
|
|
1460
1502
|
* `readonly` is an attribute of a TEXT control and of nothing else.
|
|
1461
1503
|
*
|
|
@@ -2398,6 +2440,12 @@ function set_form_values(gobj, template, $form, record)
|
|
|
2398
2440
|
break;
|
|
2399
2441
|
case "color":
|
|
2400
2442
|
$input.value = convertColor(value);
|
|
2443
|
+
/* Writing `.value` fires nothing, so the readout
|
|
2444
|
+
* beside the swatch has to be told. */
|
|
2445
|
+
if($input.yui_color_value) {
|
|
2446
|
+
$input.yui_color_value.textContent = $input.value;
|
|
2447
|
+
$input.yui_color_value.title = $input.value;
|
|
2448
|
+
}
|
|
2401
2449
|
break;
|
|
2402
2450
|
default:
|
|
2403
2451
|
$input.value = value;
|
package/src/form_toolbar_plan.js
CHANGED
|
@@ -10,13 +10,25 @@
|
|
|
10
10
|
* All Rights Reserved.
|
|
11
11
|
***********************************************************************/
|
|
12
12
|
|
|
13
|
-
/*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
/* Two groups, and the split is a real one: `undo`, `clear` and `save`
|
|
14
|
+
* act on the RECORD being edited, `copy` and `paste` move it in and out
|
|
15
|
+
* of the clipboard. Keeping them apart means a caller who drops one
|
|
16
|
+
* group does not leave a hole in the middle.
|
|
17
|
+
*
|
|
18
|
+
* WHICH SIDE EACH ONE TAKES CHANGED (2026-09-04), and the reason is that
|
|
19
|
+
* the form changed shape: it was an embedded panel and it opens as a
|
|
20
|
+
* MODAL DIALOG now. In a dialog the primary action goes bottom-RIGHT --
|
|
21
|
+
* every platform puts it there, and it is where the eye ends after
|
|
22
|
+
* reading the fields. `save` sat hard against the left edge, which is
|
|
23
|
+
* where a person looks last.
|
|
24
|
+
*
|
|
25
|
+
* So: clipboard on the left, record actions on the right, and `save`
|
|
26
|
+
* LAST of all. The order inside a group is the order asked for, which
|
|
27
|
+
* is why DEFAULT_TOOLBAR is written in the order it is drawn. */
|
|
28
|
+
const LEFT_BUTTONS = ["copy", "paste"];
|
|
29
|
+
const RIGHT_BUTTONS = ["undo", "clear", "save"];
|
|
18
30
|
|
|
19
|
-
const DEFAULT_TOOLBAR = ["
|
|
31
|
+
const DEFAULT_TOOLBAR = ["copy", "paste", "undo", "clear", "save"];
|
|
20
32
|
|
|
21
33
|
|
|
22
34
|
/***************************************************************
|
|
@@ -5,17 +5,26 @@ describe("plan_toolbar", () => {
|
|
|
5
5
|
|
|
6
6
|
it("says nothing -> the five buttons this gclass always had", () => {
|
|
7
7
|
const p = plan_toolbar(undefined);
|
|
8
|
-
expect(p.left).toEqual(["
|
|
9
|
-
expect(p.right).toEqual(["
|
|
8
|
+
expect(p.left).toEqual(["copy", "paste"]);
|
|
9
|
+
expect(p.right).toEqual(["undo", "clear", "save"]);
|
|
10
10
|
expect(p.unknown).toEqual([]);
|
|
11
11
|
expect(DEFAULT_TOOLBAR.length).toBe(5);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
+
it("save is the LAST button of the bar", () => {
|
|
15
|
+
/* The form opens as a modal dialog and a dialog's primary action
|
|
16
|
+
* goes bottom-right. Asserted on the plan and not on the CSS,
|
|
17
|
+
* because the plan is what decides the two groups. */
|
|
18
|
+
const p = plan_toolbar(undefined);
|
|
19
|
+
expect(p.right[p.right.length - 1]).toBe("save");
|
|
20
|
+
expect(p.left).not.toContain("save");
|
|
21
|
+
});
|
|
22
|
+
|
|
14
23
|
it("a non-array is not an empty toolbar: it is the default", () => {
|
|
15
24
|
/* Reading a JSON attr that was never set must not silently
|
|
16
25
|
* leave a form with no save button. */
|
|
17
26
|
for(const v of [null, "save", 0, {}]) {
|
|
18
|
-
expect(plan_toolbar(v).
|
|
27
|
+
expect(plan_toolbar(v).right).toContain("save");
|
|
19
28
|
}
|
|
20
29
|
});
|
|
21
30
|
|
|
@@ -28,21 +37,21 @@ describe("plan_toolbar", () => {
|
|
|
28
37
|
|
|
29
38
|
it("one action: a dialog asks for save only", () => {
|
|
30
39
|
const p = plan_toolbar(["save"]);
|
|
31
|
-
expect(p.
|
|
32
|
-
expect(p.
|
|
40
|
+
expect(p.right).toEqual(["save"]);
|
|
41
|
+
expect(p.left).toEqual([]);
|
|
33
42
|
});
|
|
34
43
|
|
|
35
44
|
it("keeps the order asked for inside each side", () => {
|
|
36
45
|
const p = plan_toolbar(["clear", "save", "paste", "copy"]);
|
|
37
|
-
expect(p.
|
|
38
|
-
expect(p.
|
|
46
|
+
expect(p.right).toEqual(["clear", "save"]);
|
|
47
|
+
expect(p.left).toEqual(["paste", "copy"]);
|
|
39
48
|
});
|
|
40
49
|
|
|
41
50
|
it("an unknown name is REPORTED, never silently dropped", () => {
|
|
42
51
|
/* A typo here would otherwise remove a button and leave no
|
|
43
52
|
* trace of why it is missing. */
|
|
44
53
|
const p = plan_toolbar(["save", "sav", "undo"]);
|
|
45
|
-
expect(p.
|
|
54
|
+
expect(p.right).toEqual(["save", "undo"]);
|
|
46
55
|
expect(p.unknown).toEqual(["sav"]);
|
|
47
56
|
});
|
|
48
57
|
|
|
@@ -59,7 +68,7 @@ describe("plan_toolbar", () => {
|
|
|
59
68
|
|
|
60
69
|
it("drops one whole side without disturbing the other", () => {
|
|
61
70
|
const p = plan_toolbar(["save", "undo", "clear"]);
|
|
62
|
-
expect(p.
|
|
63
|
-
expect(p.
|
|
71
|
+
expect(p.right).toEqual(["save", "undo", "clear"]);
|
|
72
|
+
expect(p.left).toEqual([]);
|
|
64
73
|
});
|
|
65
74
|
});
|