@rathnasgala2/template 3.2.0 → 4.0.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.
@@ -253,9 +253,10 @@
253
253
  };
254
254
  const composers = new Set();
255
255
  let rootComposer = /** @type {Composer | null} */ (null);
256
- let inline = /** @type {{composer: Composer, item: CommentItem} | null} */ (
257
- null
258
- );
256
+ let inline =
257
+ /** @type {{composer: Composer, item: CommentItem, trigger: HTMLElement | null} | null} */ (
258
+ null
259
+ );
259
260
  let loadToken = 0;
260
261
 
261
262
  // ------------------------------------------------------------------- helpers
@@ -295,6 +296,47 @@
295
296
  return node;
296
297
  }
297
298
 
299
+ /**
300
+ * One place for the disabled state: the native attribute (which blocks
301
+ * activation and focus) and `aria-disabled` together, so the base layer's
302
+ * `:disabled` / `[aria-disabled="true"]` rule and assistive technology agree.
303
+ *
304
+ * @param {HTMLElement} node
305
+ * @param {boolean} on
306
+ */
307
+ function setDisabled(node, on) {
308
+ /** @type {HTMLButtonElement} */ (node).disabled = on;
309
+ if (on) node.setAttribute('aria-disabled', 'true');
310
+ else node.removeAttribute('aria-disabled');
311
+ }
312
+
313
+ /**
314
+ * The working (pending) state: disabled for activation, but marked
315
+ * `aria-busy` so the base layer draws a spinner instead of the muted
316
+ * disabled look.
317
+ *
318
+ * @param {HTMLElement} node
319
+ * @param {boolean} on
320
+ */
321
+ function setBusy(node, on) {
322
+ setDisabled(node, on);
323
+ if (on) node.setAttribute('aria-busy', 'true');
324
+ else node.removeAttribute('aria-busy');
325
+ }
326
+
327
+ /**
328
+ * A trigger whose action is already in progress (its inline composer is
329
+ * open) stays focusable, so it is `aria-disabled` only, and ignores clicks.
330
+ *
331
+ * @param {HTMLElement | null} trigger
332
+ * @param {boolean} on
333
+ */
334
+ function holdTrigger(trigger, on) {
335
+ if (!trigger) return;
336
+ if (on) trigger.setAttribute('aria-disabled', 'true');
337
+ else trigger.removeAttribute('aria-disabled');
338
+ }
339
+
298
340
  let idCounter = 0;
299
341
  /**
300
342
  * @param {string} prefix
@@ -867,7 +909,7 @@
867
909
  continue;
868
910
  }
869
911
  node.hidden = false;
870
- node.disabled = false;
912
+ setDisabled(node, false);
871
913
  setPressed(node, !!item.viewerActive);
872
914
  setCount(node, item.count, 'reactions');
873
915
  }
@@ -1267,7 +1309,7 @@
1267
1309
  let cursor = /** @type {string | null} */ (null);
1268
1310
  let first = true;
1269
1311
  more.addEventListener('click', async () => {
1270
- more.disabled = true;
1312
+ setBusy(more, true);
1271
1313
  try {
1272
1314
  const query = new URLSearchParams({ parentId: comment.id });
1273
1315
  if (cursor) query.set('cursor', cursor);
@@ -1284,9 +1326,9 @@
1284
1326
  list.appendChild(renderComment(reply));
1285
1327
  cursor = page.nextCursor || null;
1286
1328
  if (!cursor) more.remove();
1287
- else more.disabled = false;
1329
+ else setBusy(more, false);
1288
1330
  } catch (error) {
1289
- more.disabled = false;
1331
+ setBusy(more, false);
1290
1332
  announce(failureMessage(error));
1291
1333
  }
1292
1334
  });
@@ -1307,9 +1349,10 @@
1307
1349
  MESSAGES.reply,
1308
1350
  MESSAGES.reply + ' to ' + name,
1309
1351
  );
1310
- reply.addEventListener('click', () =>
1311
- openInlineComposer(item, 'reply', reply),
1312
- );
1352
+ reply.addEventListener('click', () => {
1353
+ if (reply.getAttribute('aria-disabled') === 'true') return;
1354
+ openInlineComposer(item, 'reply', reply);
1355
+ });
1313
1356
  actions.appendChild(reply);
1314
1357
  }
1315
1358
  if (comment.viewer && comment.viewer.canEdit) {
@@ -1318,9 +1361,10 @@
1318
1361
  MESSAGES.edit,
1319
1362
  MESSAGES.edit + ' your comment',
1320
1363
  );
1321
- edit.addEventListener('click', () =>
1322
- openInlineComposer(item, 'edit', edit),
1323
- );
1364
+ edit.addEventListener('click', () => {
1365
+ if (edit.getAttribute('aria-disabled') === 'true') return;
1366
+ openInlineComposer(item, 'edit', edit);
1367
+ });
1324
1368
  actions.appendChild(edit);
1325
1369
  }
1326
1370
  if (comment.viewer && comment.viewer.canDelete) {
@@ -1376,8 +1420,8 @@
1376
1420
  }
1377
1421
  });
1378
1422
  yes.addEventListener('click', async () => {
1379
- yes.disabled = true;
1380
- no.disabled = true;
1423
+ setBusy(yes, true);
1424
+ setDisabled(no, true);
1381
1425
  try {
1382
1426
  await api(
1383
1427
  'DELETE',
@@ -1386,8 +1430,8 @@
1386
1430
  applyDeleted(item);
1387
1431
  announce(MESSAGES.deleted);
1388
1432
  } catch (error) {
1389
- yes.disabled = false;
1390
- no.disabled = false;
1433
+ setBusy(yes, false);
1434
+ setDisabled(no, false);
1391
1435
  announce(failureMessage(error));
1392
1436
  }
1393
1437
  });
@@ -1599,7 +1643,7 @@
1599
1643
  return;
1600
1644
  }
1601
1645
  composer.busy = true;
1602
- submit.disabled = true;
1646
+ setDisabled(submit, true);
1603
1647
  submit.setAttribute('aria-busy', 'true');
1604
1648
  showError('');
1605
1649
  try {
@@ -1626,7 +1670,7 @@
1626
1670
  showError(failureMessage(failure));
1627
1671
  } finally {
1628
1672
  composer.busy = false;
1629
- submit.disabled = false;
1673
+ setDisabled(submit, false);
1630
1674
  submit.removeAttribute('aria-busy');
1631
1675
  }
1632
1676
  });
@@ -1682,6 +1726,7 @@
1682
1726
  function closeInline() {
1683
1727
  if (inline) {
1684
1728
  inline.composer.close();
1729
+ holdTrigger(inline.trigger, false);
1685
1730
  inline = null;
1686
1731
  }
1687
1732
  }
@@ -1697,6 +1742,7 @@
1697
1742
  const comment = item._comment;
1698
1743
  const done = (/** @type {any} */ result) => {
1699
1744
  /** @type {{composer: Composer}} */ (inline).composer.close();
1745
+ holdTrigger(trigger, false);
1700
1746
  inline = null;
1701
1747
  if (mode === 'edit') {
1702
1748
  fillComment(item, result);
@@ -1713,12 +1759,14 @@
1713
1759
  body: mode === 'edit' ? comment.body || '' : presetBody || '',
1714
1760
  onDone: done,
1715
1761
  onCancel: () => {
1762
+ holdTrigger(trigger, false);
1716
1763
  inline = null;
1717
1764
  if (trigger && trigger.isConnected) focusNode(trigger);
1718
1765
  else focusNode(item);
1719
1766
  },
1720
1767
  });
1721
- inline = { composer, item };
1768
+ holdTrigger(trigger, true);
1769
+ inline = { composer, item, trigger };
1722
1770
  const replies = item.querySelector(':scope > .g-comment__replies');
1723
1771
  if (replies) item.insertBefore(composer.element, replies);
1724
1772
  else item.appendChild(composer.element);
@@ -1805,7 +1853,7 @@
1805
1853
  });
1806
1854
  cancel.addEventListener('click', finish);
1807
1855
  send.addEventListener('click', async () => {
1808
- send.disabled = true;
1856
+ setBusy(send, true);
1809
1857
  error.hidden = true;
1810
1858
  /** @type {{reasonCode: string, note?: string}} */
1811
1859
  const payload = { reasonCode: select.value };
@@ -1822,7 +1870,7 @@
1822
1870
  finish();
1823
1871
  announce(MESSAGES.reported);
1824
1872
  } catch (failure) {
1825
- send.disabled = false;
1873
+ setBusy(send, false);
1826
1874
  error.textContent = failureMessage(failure);
1827
1875
  error.hidden = false;
1828
1876
  }
@@ -1959,7 +2007,7 @@
1959
2007
  showError(MESSAGES.appealTooLong);
1960
2008
  return;
1961
2009
  }
1962
- send.disabled = true;
2010
+ setDisabled(send, true);
1963
2011
  send.setAttribute('aria-busy', 'true');
1964
2012
  showError('');
1965
2013
  try {
@@ -1991,7 +2039,7 @@
1991
2039
  );
1992
2040
  announce(message);
1993
2041
  } else {
1994
- send.disabled = false;
2042
+ setDisabled(send, false);
1995
2043
  showError(message);
1996
2044
  }
1997
2045
  } finally {
@@ -2088,7 +2136,7 @@
2088
2136
 
2089
2137
  async function loadMore() {
2090
2138
  if (!live.nextCursor || !moreEl) return;
2091
- moreEl.disabled = true;
2139
+ setBusy(moreEl, true);
2092
2140
  try {
2093
2141
  const query = new URLSearchParams({ cursor: live.nextCursor });
2094
2142
  const page = await api(
@@ -2099,7 +2147,7 @@
2099
2147
  } catch (error) {
2100
2148
  announce(failureMessage(error));
2101
2149
  } finally {
2102
- moreEl.disabled = false;
2150
+ setBusy(moreEl, false);
2103
2151
  }
2104
2152
  }
2105
2153