@xoong/ui 0.0.42 → 0.0.43

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": "@xoong/ui",
3
- "version": "0.0.42",
3
+ "version": "0.0.43",
4
4
  "description": "xoong admin set: xoong.css tokens, <xo-table>, <xo-form>, <xo-dialog>, toast, confirm and a declarative History-API router. Depends on @xoong/core, @xoong/data and @xoong/forms.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -10,6 +10,7 @@
10
10
  "default": "./src/index.js"
11
11
  },
12
12
  "./table": "./src/table.js",
13
+ "./pager": "./src/pager.js",
13
14
  "./form": "./src/form.js",
14
15
  "./dialog": "./src/dialog.js",
15
16
  "./toast": "./src/toast.js",
@@ -20,9 +21,9 @@
20
21
  "sideEffects": true,
21
22
  "license": "MIT",
22
23
  "dependencies": {
23
- "@xoong/core": "0.0.42",
24
- "@xoong/data": "0.0.42",
25
- "@xoong/forms": "0.0.42"
24
+ "@xoong/core": "0.0.43",
25
+ "@xoong/data": "0.0.43",
26
+ "@xoong/forms": "0.0.43"
26
27
  },
27
28
  "files": [
28
29
  "src"
package/src/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // Importing the package registers every element of the admin set.
2
2
  import '@xoong/forms'; // every <form xo-submit> (and <xo-form>) uses the schema-driven form model
3
3
  import './table.js';
4
+ import './pager.js';
4
5
  import './form.js';
5
6
  import './dialog.js';
6
7
  import './toast.js';
package/src/mist.css CHANGED
@@ -1468,6 +1468,30 @@
1468
1468
  .xo-file-list li { display: flex; align-items: center; gap: 12px; padding: 8px 12px; border: 1px solid var(--xo-color-border); border-radius: var(--xo-radius); background: var(--xo-color-surface); font-size: 14px; }
1469
1469
  .xo-file-list li img { width: 40px; height: 40px; border-radius: 6px; object-fit: cover; flex: none; }
1470
1470
  .xo-file-list li span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1471
+ .xo-kpi { display: grid; gap: 6px; }
1472
+ .xo-kpi__label { font-size: 13px; color: var(--xo-color-text-2); }
1473
+ .xo-kpi__value { font-size: 28px; font-weight: 600; line-height: 1.1; letter-spacing: -.01em; color: var(--xo-color-text); font-variant-numeric: tabular-nums; }
1474
+ .xo-kpi__delta { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 500; color: color-mix(in srgb, var(--xo-color-success) 55%, var(--xo-color-text)); }
1475
+ .xo-kpi__delta[data-good="false"], .xo-kpi__delta[data-trend="down"] { color: var(--xo-color-danger); }
1476
+ .xo-kpi__delta .ic, .xo-kpi__delta .icon { --xo-icon: 14px; width: 14px; height: 14px; }
1477
+ .xo-kpi__spark { display: block; width: 100%; height: 32px; margin-top: 4px; color: var(--xo-color-accent); }
1478
+ .xo-kpi__spark path { fill: none; stroke: currentcolor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
1479
+ .xo-spinner { display: inline-block; box-sizing: border-box; animation: xo-spinner .8s linear infinite; }
1480
+ @media (prefers-reduced-motion: reduce) {
1481
+ .xo-spinner { animation-duration: 2.4s; }
1482
+ }
1483
+ xo-progress[data-state="indeterminate"] .xo-progress > i, .xo-progress[data-state="indeterminate"] > i { animation: xo-progress-slide 1.4s ease-in-out infinite; }
1484
+ @keyframes xo-progress-slide {
1485
+ from { transform: translateX(-100%); }
1486
+ to { transform: translateX(250%); }
1487
+ }
1488
+ @media (prefers-reduced-motion: reduce) {
1489
+ xo-progress[data-state="indeterminate"] .xo-progress > i, .xo-progress[data-state="indeterminate"] > i { animation: none; opacity: .45; }
1490
+ }
1491
+ .xo-inline-edit__text { min-width: 0; overflow-wrap: anywhere; }
1492
+ .xo-inline-edit input { width: min(100%, 28ch); min-width: 12ch; height: 36px; min-height: 0; padding: 0 10px; font: inherit; color: var(--xo-color-text); background: var(--xo-color-surface); border: 1px solid var(--xo-color-accent); border-radius: var(--xo-radius); outline: var(--xo-focus); }
1493
+ .xo-inline-edit .xo-inline-edit__text + button { opacity: .7; }
1494
+ .xo-inline-edit:hover .xo-inline-edit__text + button, .xo-inline-edit .xo-inline-edit__text + button:focus-visible { opacity: 1; }
1471
1495
 
1472
1496
  /* ---- skin ---- */
1473
1497
  :root { --shadow-sm: 0 1px 2px color-mix(in srgb, var(--xo-color-text) 6%, transparent); --shadow-float: 0 12px 32px color-mix(in srgb, var(--xo-color-text) 14%, transparent), 0 2px 6px color-mix(in srgb, var(--xo-color-text) 8%, transparent); --xo-shadow-pop: var(--shadow-float); --xo-shadow-raised: none; --xo-focus: 2px solid var(--xo-color-accent); --xo-focus-thin: 2px solid var(--xo-color-accent); }
package/src/pager.js ADDED
@@ -0,0 +1,34 @@
1
+ // @ts-check
2
+ /**
3
+ * <xo-pager page-size="12" page-sizes="12,24,48"></xo-pager>: Previous and Next for any list in the enclosing <xo-view> (a tile grid, a thread
4
+ * list), the same pager <xo-table page-size> draws under its table.
5
+ *
6
+ * - page-size: rows per page; sets `limit`, and the buttons change `offset`. The operation must declare `limit` and `offset`, and the response
7
+ * needs a `total` field for the "1–12 of 48" text and for the end of the list.
8
+ * - page-sizes="12,24,48": a rows-per-page choice.
9
+ * - Draws `nav.xo-pager` (`span.xo-range`, `select.xo-page-size`, two buttons); Previous shows while `$hasPrev`, Next while `$hasNext`.
10
+ */
11
+ import { defineTemplate } from '@xoong/data/view';
12
+
13
+ const esc = (/** @type {string} */ s) => s.replace(/[&<>"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' })[c] ?? c);
14
+
15
+ /** The pager markup (also used by <xo-table>). @param {{ pageSize: number, sizes?: string[] }} options */
16
+ export function pagerMarkup({ pageSize, sizes = [] }) {
17
+ return `
18
+ <nav class="xo-pager" aria-label="Pagination" xo-t="aria-label:xoong.table.pagination">
19
+ <span class="xo-range" xo-if="total" xo-t="xoong.table.range">{$from}–{$to} of {total}</span>${sizes.length ? `
20
+ <select class="xo-page-size" xo-param="limit" aria-label="Rows per page" xo-t="aria-label:xoong.table.rowsPerPage">${sizes.map((s) => `<option value="${esc(s)}">${esc(s)}</option>`).join('')}</select>` : ''}
21
+ <button type="button" xo-if="$hasPrev" xo-param="offset-=${pageSize}" xo-t="xoong.table.previous">Previous</button>
22
+ <button type="button" xo-if="$hasNext" xo-param="offset+=${pageSize}" xo-t="xoong.table.next">Next</button>
23
+ </nav>`;
24
+ }
25
+
26
+ defineTemplate('xo-pager', (el, { host }) => {
27
+ const pageSize = Number(el.getAttribute('page-size')) || 25;
28
+ if (host.params.limit == null) host.params = { ...host.params, limit: pageSize }; // the view asks for one page
29
+ const sizes = (el.getAttribute('page-sizes') || '').split(',').map((s) => s.trim()).filter(Boolean);
30
+ const box = document.createElement('div');
31
+ box.style.display = 'contents'; // the pager sits where the element was, in the layout of its parent
32
+ box.innerHTML = pagerMarkup({ pageSize, sizes });
33
+ return box;
34
+ });
package/src/table.js CHANGED
@@ -23,6 +23,7 @@
23
23
  * The operation must declare those query parameters; `xoong check` reports it when it does not (XO250).
24
24
  */
25
25
  import { defineTemplate } from '@xoong/data/view';
26
+ import { pagerMarkup } from './pager.js';
26
27
 
27
28
  const esc = (s) => s.replace(/[&<>"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' })[c]);
28
29
 
@@ -68,12 +69,6 @@ defineTemplate('xo-table', (el, { host }) => {
68
69
  <thead><tr>${tickAll}${head}${actions ? '<th scope="col"><span class="xo-visually-hidden" xo-t="xoong.table.actions">Actions</span></th>' : ''}</tr></thead>
69
70
  <tbody><tr xo-each="${esc(of)}">${tickRow}${cells}${actions ?`<td class="xo-actions">${actions}</td>` : ''}</tr></tbody>
70
71
  </table>${empty ? `
71
- <div class="xo-empty" xo-if="!${esc(of)}"><div xo-if="!$loading"><div xo-if="!$error">${empty}</div></div></div>` : ''}${pageSize ? `
72
- <nav class="xo-pager" aria-label="Pagination" xo-t="aria-label:xoong.table.pagination">
73
- <span class="xo-range" xo-if="total" xo-t="xoong.table.range">{$from}–{$to} of {total}</span>${sizes.length ? `
74
- <select class="xo-page-size" xo-param="limit" aria-label="Rows per page" xo-t="aria-label:xoong.table.rowsPerPage">${sizes.map((s) => `<option value="${esc(s)}">${esc(s)}</option>`).join('')}</select>` : ''}
75
- <button type="button" xo-if="$hasPrev" xo-param="offset-=${pageSize}" xo-t="xoong.table.previous">Previous</button>
76
- <button type="button" xo-if="$hasNext" xo-param="offset+=${pageSize}" xo-t="xoong.table.next">Next</button>
77
- </nav>` : ''}`;
72
+ <div class="xo-empty" xo-if="!${esc(of)}"><div xo-if="!$loading"><div xo-if="!$error">${empty}</div></div></div>` : ''}${pageSize ? pagerMarkup({ pageSize, sizes }) : ''}`;
78
73
  return box;
79
74
  });