@muten/shadcn 0.2.10 → 0.2.11
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/kit.css +13 -1
- package/package.json +1 -1
- package/registry/kit/table.js +5 -3
package/kit.css
CHANGED
|
@@ -780,7 +780,7 @@ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webki
|
|
|
780
780
|
.cx-dt td.cx-dt-act { display: none; }
|
|
781
781
|
.cx-dt-who small { display: none; }
|
|
782
782
|
.cx-dt td.cx-dt-svc[data-when]:not([data-when=""])::after { content: " · " attr(data-when); }
|
|
783
|
-
.cx-dt td.cx-dt-svc ~ td.cx-dt-svc::after { content: none; }
|
|
783
|
+
.cx-dt td.cx-dt-svc ~ td.cx-dt-svc[data-when]::after { content: none; }
|
|
784
784
|
}
|
|
785
785
|
|
|
786
786
|
/* ── Board ── */
|
|
@@ -5548,3 +5548,15 @@ a.cx-bc-item:hover { color: var(--foreground); }
|
|
|
5548
5548
|
|
|
5549
5549
|
/* ── Field: a field that must be filled says so at its label ── */
|
|
5550
5550
|
.cn-label.cx-required::after { content: " *"; color: var(--destructive); }
|
|
5551
|
+
|
|
5552
|
+
/* ── Alert with an action: the action takes its own column (Nova's absolute corner reserves 72 px, and a wider button
|
|
5553
|
+
covered the title); on a phone it goes under the text ── */
|
|
5554
|
+
.style-nova .cn-alert:has(> .cn-alert-action) { padding-right: 10px; grid-template-columns: 1fr auto; }
|
|
5555
|
+
.style-nova .cn-alert:has(> :is(svg, .mu-icon)):has(> .cn-alert-action) { grid-template-columns: auto 1fr auto; }
|
|
5556
|
+
.style-nova .cn-alert > .cn-alert-action { position: static; grid-column: -2; grid-row: 1 / span 9; align-self: center; margin-left: 8px; }
|
|
5557
|
+
@media (max-width: 560px) {
|
|
5558
|
+
.style-nova .cn-alert:has(> .cn-alert-action) { grid-template-columns: 1fr; }
|
|
5559
|
+
.style-nova .cn-alert:has(> :is(svg, .mu-icon)):has(> .cn-alert-action) { grid-template-columns: auto 1fr; }
|
|
5560
|
+
.style-nova .cn-alert > .cn-alert-action { grid-column: 1 / -1; grid-row: auto; justify-self: start; margin: 8px 0 0; }
|
|
5561
|
+
.style-nova .cn-alert:has(> :is(svg, .mu-icon)) > .cn-alert-action { grid-column: 2; }
|
|
5562
|
+
}
|
package/package.json
CHANGED
package/registry/kit/table.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// and bulk actions are data. Everything else is the artifact's: filters from their type (search · facet · date ·
|
|
3
3
|
// range) with counts, chips that leave with a fade, rows that fade out / slide / enter, the height easing, sort by
|
|
4
4
|
// header, selection with its own bulk bar, the phone's “search + Filters” sheet, and a narrow box becoming Items.
|
|
5
|
-
// columns [{key, label, type: person|text|date|status|money, sub (person: the key under the name), sortable}]
|
|
5
|
+
// columns [{key, label, type: person|text|date|status|money, sub (person: the key under the name), sortable, sort: "desc" (opens newest first)}]
|
|
6
6
|
// rows [{id, …keys}] (a date is "yyyy-mm-ddTHH:MM"; a row's date may be "+N" days from today too)
|
|
7
7
|
// filters [{id, type: search|facet|date|range, label, key | keys (search)}]
|
|
8
8
|
// statuses [{id, label, tone: ok|wait|info|bad}] · noun ["appointment", "appointments"] · bulk [{id, label, variant}]
|
|
@@ -37,14 +37,16 @@ export function dataTable(root, cfg, core, on) {
|
|
|
37
37
|
};
|
|
38
38
|
const SORTERS = Object.fromEntries(COLS.map((c) => [c.key, c.type === 'status' ? (r) => ST_ORDER.indexOf(r[c.key]) : c.type === 'date' ? (r) => +asDate(r[c.key]) : (r) => r[c.key]]));
|
|
39
39
|
const cbHtml = (label, on) => `<button data-slot="checkbox" role="checkbox" data-state="${on ? 'checked' : 'unchecked'}" aria-checked="${on}" class="cn-checkbox" aria-label="${label}"><span data-slot="checkbox-indicator" class="cn-checkbox-indicator"><svg class="cb-mark" viewBox="0 0 24 24">${CB_CHECK}</svg></span></button>`;
|
|
40
|
-
|
|
40
|
+
// the table opens sorted by its date column (else the first); a column with sort: "desc" opens newest first (a log)
|
|
41
|
+
const opening = dateCol ?? COLS[0];
|
|
42
|
+
const firstSort = { key: opening?.key, dir: opening?.sort === 'desc' ? -1 : 1 };
|
|
41
43
|
const bulk = list(cfg.bulk);
|
|
42
44
|
// rows are selectable only when there is something to do with them: without bulk actions, no checkbox column
|
|
43
45
|
const picks = bulk.length > 0;
|
|
44
46
|
// the phone's «Filters» sheet only when there is a filter besides the search
|
|
45
47
|
const sheetFilters = () => FILTERS.some((f) => f.type !== 'search');
|
|
46
48
|
const CELL_CLASS = { person: 'cx-dt-who', text: 'cx-dt-svc', date: 'cx-dt-when', status: 'cx-dt-st', money: 'cx-dt-num' };
|
|
47
|
-
root.innerHTML = `<div class="cx-dt-host"><div class="cx-dt-toolbar"><div class="cx-hstack cx-dt-tools" role="toolbar" aria-label="${T('Filters')}"></div><span class="cx-text" data-variant="caption" data-dt-shown aria-live="polite"></span></div><div class="cx-hstack cx-dt-chips" hidden></div><div class="cx-dt-bulk" aria-live="polite"><div><span data-dt-count></span><div class="cx-hstack" style="gap:6px">${bulk.map((b) => ui.button({ label: b.label, variant: b.variant || 'outline', size: 'xs', attrs: `data-dt-bulk="${b.id}"` })).join('')}${ui.button({ label: T('Clear selection'), variant: 'ghost', size: 'xs', attrs: 'data-dt-unselect' })}</div></div></div><div class="cx-dt-scroll cx-scroll"><table class="cx-dt"><thead><tr>${picks ? `<th class="cx-dt-check">${cbHtml(T('Select all'), false).replace('class="cn-checkbox"', 'class="cn-checkbox" data-dt-all')}</th>` : ''}${COLS.map((c) => `<th aria-sort="${c.key === firstSort.key ? 'ascending' : 'none'}" ${c.type === 'money' ? 'class="cx-dt-num"' : ''}>${c.sortable === false ? ui.text(c.label, 'label') : `<button class="cn-button cn-button-variant-ghost cn-button-size-xs cx-th" data-sort="${c.key}">${c.label}<svg><use href="#${c.key === firstSort.key ? 'arrowup' : 'sort'}"/></svg></button>`}</th>`).join('')}</tr></thead><tbody></tbody></table></div></div>`;
|
|
49
|
+
root.innerHTML = `<div class="cx-dt-host"><div class="cx-dt-toolbar"><div class="cx-hstack cx-dt-tools" role="toolbar" aria-label="${T('Filters')}"></div><span class="cx-text" data-variant="caption" data-dt-shown aria-live="polite"></span></div><div class="cx-hstack cx-dt-chips" hidden></div><div class="cx-dt-bulk" aria-live="polite"><div><span data-dt-count></span><div class="cx-hstack" style="gap:6px">${bulk.map((b) => ui.button({ label: b.label, variant: b.variant || 'outline', size: 'xs', attrs: `data-dt-bulk="${b.id}"` })).join('')}${ui.button({ label: T('Clear selection'), variant: 'ghost', size: 'xs', attrs: 'data-dt-unselect' })}</div></div></div><div class="cx-dt-scroll cx-scroll"><table class="cx-dt"><thead><tr>${picks ? `<th class="cx-dt-check">${cbHtml(T('Select all'), false).replace('class="cn-checkbox"', 'class="cn-checkbox" data-dt-all')}</th>` : ''}${COLS.map((c) => `<th aria-sort="${c.key === firstSort.key ? (firstSort.dir === 1 ? 'ascending' : 'descending') : 'none'}" ${c.type === 'money' ? 'class="cx-dt-num"' : ''}>${c.sortable === false ? ui.text(c.label, 'label') : `<button class="cn-button cn-button-variant-ghost cn-button-size-xs cx-th" data-sort="${c.key}">${c.label}<svg><use href="#${c.key === firstSort.key ? (firstSort.dir === 1 ? 'arrowup' : 'arrowdown') : 'sort'}"/></svg></button>`}</th>`).join('')}</tr></thead><tbody></tbody></table></div></div>`;
|
|
48
50
|
const host = $('.cx-dt-host', root), dtTools = $('.cx-dt-tools', root), dtChips = $('.cx-dt-chips', root), dtCountEl = $('[data-dt-shown]', root), dtBody = $('tbody', root), dtAll = $('[data-dt-all]', root), dtBulk = $('.cx-dt-bulk', root);
|
|
49
51
|
const dtSel = new Set(); let dtSort = firstSort;
|
|
50
52
|
const passes = (r, except) => FILTERS.every((f) => f.id === except || PASS[f.type](f, fState[f.id], r));
|