@yuneta/gobj-ui 5.9.0 → 5.10.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "5.9.0",
3
+ "version": "5.10.0",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -140,4 +140,70 @@ function yui_copy_table_json(tabulator)
140
140
  });
141
141
  }
142
142
 
143
- export {yui_copy_text, yui_copy_json, yui_table_rows, yui_copy_table_json};
143
+ /***************************************************************
144
+ * Show a button as "done": swap its icon for a check and
145
+ * its label for the given text. Idempotent — calling it
146
+ * twice does not lose the original.
147
+ *
148
+ * The TIMING is not here on purpose. A view arms its own
149
+ * C_TIMER and calls yui_button_unmark() from the timeout
150
+ * action, so going back is an FSM transition and shows up
151
+ * in the machine trace, instead of a setTimeout nobody can
152
+ * see. gobj-ui owns the look; the view owns the when.
153
+ *
154
+ * Expects the Bulma button shape both views use:
155
+ * <button><span class="icon"><span class="yi-…">
156
+ * <span>label</span></button>
157
+ * The label is optional (icon-only buttons on a phone).
158
+ ***************************************************************/
159
+ function yui_button_mark_done($button, label)
160
+ {
161
+ if(!$button) {
162
+ log_error("yui_button_mark_done(): no button");
163
+ return;
164
+ }
165
+
166
+ let $icon = $button.querySelector("span.icon > span");
167
+ let $label = $button.querySelector("span.icon ~ span");
168
+
169
+ if($icon && $button.dataset.yuiIconWas === undefined) {
170
+ $button.dataset.yuiIconWas = $icon.className;
171
+ $icon.className = "yi-check";
172
+ }
173
+ if($label && $button.dataset.yuiLabelWas === undefined) {
174
+ $button.dataset.yuiLabelWas = $label.textContent;
175
+ $label.textContent = label;
176
+ }
177
+ }
178
+
179
+ /***************************************************************
180
+ * Put the button back the way it was. Safe to call when
181
+ * it was never marked.
182
+ ***************************************************************/
183
+ function yui_button_unmark($button)
184
+ {
185
+ if(!$button) {
186
+ return;
187
+ }
188
+
189
+ let $icon = $button.querySelector("span.icon > span");
190
+ let $label = $button.querySelector("span.icon ~ span");
191
+
192
+ if($icon && $button.dataset.yuiIconWas !== undefined) {
193
+ $icon.className = $button.dataset.yuiIconWas;
194
+ delete $button.dataset.yuiIconWas;
195
+ }
196
+ if($label && $button.dataset.yuiLabelWas !== undefined) {
197
+ $label.textContent = $button.dataset.yuiLabelWas;
198
+ delete $button.dataset.yuiLabelWas;
199
+ }
200
+ }
201
+
202
+ export {
203
+ yui_copy_text,
204
+ yui_copy_json,
205
+ yui_table_rows,
206
+ yui_copy_table_json,
207
+ yui_button_mark_done,
208
+ yui_button_unmark,
209
+ };
@@ -10,6 +10,8 @@ import {
10
10
  yui_copy_json,
11
11
  yui_table_rows,
12
12
  yui_copy_table_json,
13
+ yui_button_mark_done,
14
+ yui_button_unmark,
13
15
  } from "./yui_clipboard.js";
14
16
 
15
17
  let written;
@@ -110,3 +112,73 @@ test("copy_table_json: counts the SELECTION when there is one", async () => {
110
112
  let active = [{id: 1}, {id: 2}, {id: 3}];
111
113
  await expect(yui_copy_table_json(fake_table(active, [{id: 2}]))).resolves.toBe(1);
112
114
  });
115
+
116
+ /*============================================================
117
+ * yui_button_mark_done / yui_button_unmark
118
+ *
119
+ * Doubles instead of jsdom: the library has no DOM test
120
+ * environment and does not need one for this. What is worth
121
+ * testing here is the save/restore bookkeeping; that the
122
+ * selectors match the real markup is the app's job to prove.
123
+ *============================================================*/
124
+ function fake_button(with_label)
125
+ {
126
+ let $icon = {className: "yi-copy"};
127
+ let $label = with_label? {textContent: "Copy JSON"} : null;
128
+
129
+ return {
130
+ $icon: $icon,
131
+ $label: $label,
132
+ dataset: {},
133
+ querySelector: function(sel) {
134
+ if(sel === "span.icon > span") {
135
+ return $icon;
136
+ }
137
+ return $label;
138
+ }
139
+ };
140
+ }
141
+
142
+ test("mark_done: swaps the glyph for a check and the label", () => {
143
+ let $b = fake_button(true);
144
+ yui_button_mark_done($b, "Copied");
145
+ expect($b.$icon.className).toBe("yi-check");
146
+ expect($b.$label.textContent).toBe("Copied");
147
+ });
148
+
149
+ test("unmark: puts the original glyph and label back", () => {
150
+ let $b = fake_button(true);
151
+ yui_button_mark_done($b, "Copied");
152
+ yui_button_unmark($b);
153
+ expect($b.$icon.className).toBe("yi-copy");
154
+ expect($b.$label.textContent).toBe("Copy JSON");
155
+ });
156
+
157
+ test("mark_done twice does NOT lose the original", () => {
158
+ let $b = fake_button(true);
159
+ yui_button_mark_done($b, "Copied");
160
+ yui_button_mark_done($b, "Copied again");
161
+ yui_button_unmark($b);
162
+ expect($b.$icon.className).toBe("yi-copy");
163
+ expect($b.$label.textContent).toBe("Copy JSON");
164
+ });
165
+
166
+ test("an icon-only button (no label) round-trips too", () => {
167
+ let $b = fake_button(false);
168
+ yui_button_mark_done($b, "Copied");
169
+ expect($b.$icon.className).toBe("yi-check");
170
+ yui_button_unmark($b);
171
+ expect($b.$icon.className).toBe("yi-copy");
172
+ });
173
+
174
+ test("unmark on a button that was never marked is a no-op", () => {
175
+ let $b = fake_button(true);
176
+ yui_button_unmark($b);
177
+ expect($b.$icon.className).toBe("yi-copy");
178
+ expect($b.$label.textContent).toBe("Copy JSON");
179
+ });
180
+
181
+ test("mark_done without a button is reported, not thrown", () => {
182
+ expect(() => yui_button_mark_done(null, "Copied")).not.toThrow();
183
+ expect(() => yui_button_unmark(null)).not.toThrow();
184
+ });