@poodle64/ui 2026.10.2 → 2026.10.4
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/README.md +5 -3
- package/dist/components/feedback/report-widget.svelte +12 -0
- package/dist/components/ui/app-shell/app-shell.svelte +7 -2
- package/dist/components/ui/app-shell/padding.d.ts +7 -1
- package/dist/components/ui/app-shell/padding.js +7 -1
- package/dist/components/ui/ledger/ledger.svelte +8 -7
- package/package.json +1 -1
- package/registry/component-map.json +1 -1
- package/registry/component-map.md +1 -1
package/README.md
CHANGED
|
@@ -911,9 +911,11 @@ Settled here, the same in every module, and not props:
|
|
|
911
911
|
above its card; figures in the body face with tabular numerals, money out
|
|
912
912
|
bracketed and money in green (`formatCurrency(v, { negative: 'brackets' })`).
|
|
913
913
|
- **Sorting and the groups' one control.** Click a column head to sort by it,
|
|
914
|
-
largest or newest first; click again to reverse
|
|
915
|
-
|
|
916
|
-
|
|
914
|
+
largest or newest first; click again to reverse; a third click returns to the
|
|
915
|
+
default order. A sort orders rows inside the grouping the viewer chose (the
|
|
916
|
+
groups stay newest first); grouped by none, the list is one flat run. The
|
|
917
|
+
head shows its state: a down chevron descending, an up chevron ascending,
|
|
918
|
+
none at rest. Until the viewer sorts, rows sit newest first. A chevron in the head's
|
|
917
919
|
gutter opens or closes every group at once; where rows tick, the gutter
|
|
918
920
|
widens to hold it beside the select-all checkbox.
|
|
919
921
|
- **The Columns menu** holds every column as a tick, the three fixed ones
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
// not sit in the situation→component registry either.
|
|
27
27
|
// A page control that shares its corner sets `--ds-report-clearance` on the
|
|
28
28
|
// document to lift the trigger clear of it (the librarian composer does).
|
|
29
|
+
// Every other page gets the trigger's footprint, net of that lift, as
|
|
30
|
+
// `--ds-report-reserve`: the shell ends its padded content with that much
|
|
31
|
+
// room, so a control under the corner can always scroll clear.
|
|
29
32
|
|
|
30
33
|
let {
|
|
31
34
|
/** Where the report POSTs. The app's own route, defaulting to the one every household app serves. */
|
|
@@ -50,6 +53,15 @@
|
|
|
50
53
|
const messageId = `feedback-message-${uid}`;
|
|
51
54
|
const screenshotId = `feedback-screenshot-${uid}`;
|
|
52
55
|
|
|
56
|
+
// The trigger's top edge sits 3.75rem up (1rem offset, 2.75rem disc); 4.5rem
|
|
57
|
+
// leaves a gap above it. Resolved on the document, so a lift set or cleared
|
|
58
|
+
// later moves it too.
|
|
59
|
+
$effect(() => {
|
|
60
|
+
const root = document.documentElement;
|
|
61
|
+
root.style.setProperty('--ds-report-reserve', 'calc(4.5rem - var(--ds-report-clearance, 0px))');
|
|
62
|
+
return () => root.style.removeProperty('--ds-report-reserve');
|
|
63
|
+
});
|
|
64
|
+
|
|
53
65
|
async function submit() {
|
|
54
66
|
phase = 'submitting';
|
|
55
67
|
|
|
@@ -720,8 +720,13 @@
|
|
|
720
720
|
{/if}
|
|
721
721
|
|
|
722
722
|
<div class="flex min-h-0 min-w-0 flex-1 flex-col">
|
|
723
|
+
<!-- The bar wraps when crowded, at every width, and pads top and bottom
|
|
724
|
+
alike so a second row clears both edges. Kept to one row, it shrank
|
|
725
|
+
`context` below its own content and the next item painted over it, so
|
|
726
|
+
the app's own control under the overlap could not be clicked
|
|
727
|
+
(mission-command's workspace menu, 04/10/2026). -->
|
|
723
728
|
<header
|
|
724
|
-
class="ds-shell-bar bg-shell/80 text-shell-foreground border-border sticky top-0 z-20 flex min-h-14 flex-none flex-wrap items-center gap-2 border-b px-3 pt-[env(safe-area-inset-top)] backdrop-blur sm:gap-3 sm:px-5
|
|
729
|
+
class="ds-shell-bar bg-shell/80 text-shell-foreground border-border sticky top-0 z-20 flex min-h-14 flex-none flex-wrap items-center gap-2 border-b px-3 pt-[calc(0.5rem+env(safe-area-inset-top))] pb-2 backdrop-blur sm:gap-3 sm:px-5"
|
|
725
730
|
>
|
|
726
731
|
{#if hasNav}
|
|
727
732
|
<!-- `aria-controls` names the region this toggle opens. It is present
|
|
@@ -773,7 +778,7 @@
|
|
|
773
778
|
class={cn(
|
|
774
779
|
'flex min-w-0 items-center gap-2 sm:gap-3',
|
|
775
780
|
controls.content
|
|
776
|
-
? 'order-last basis-full
|
|
781
|
+
? 'order-last basis-full xl:order-none xl:basis-auto'
|
|
777
782
|
: 'hidden md:flex'
|
|
778
783
|
)}
|
|
779
784
|
data-testid="ds-shell-location"
|
|
@@ -16,5 +16,11 @@
|
|
|
16
16
|
*
|
|
17
17
|
* The bottom pad carries `env(safe-area-inset-bottom)` so the last row of a page
|
|
18
18
|
* clears a home-indicator gesture bar.
|
|
19
|
+
*
|
|
20
|
+
* The trailing `::after` is `--ds-report-reserve`, the footprint the mounted
|
|
21
|
+
* report widget declares, so a page's last row can scroll clear of the button
|
|
22
|
+
* floating over its corner. An element rather than padding: a page taller than
|
|
23
|
+
* the content area overflows this box, which leaves its padding behind at the
|
|
24
|
+
* area's foot, while a last flex item follows the overflow to its end.
|
|
19
25
|
*/
|
|
20
|
-
export declare const CONTENT_PADDING = "px-4 pt-5 pb-[calc(1.25rem+env(safe-area-inset-bottom))] sm:px-6 md:px-8 md:pt-7 md:pb-[calc(1.75rem+env(safe-area-inset-bottom))] 2xl:px-12";
|
|
26
|
+
export declare const CONTENT_PADDING = "px-4 pt-5 pb-[calc(1.25rem+env(safe-area-inset-bottom))] sm:px-6 md:px-8 md:pt-7 md:pb-[calc(1.75rem+env(safe-area-inset-bottom))] 2xl:px-12 after:block after:flex-none after:h-[var(--ds-report-reserve,0px)]";
|
|
@@ -16,5 +16,11 @@
|
|
|
16
16
|
*
|
|
17
17
|
* The bottom pad carries `env(safe-area-inset-bottom)` so the last row of a page
|
|
18
18
|
* clears a home-indicator gesture bar.
|
|
19
|
+
*
|
|
20
|
+
* The trailing `::after` is `--ds-report-reserve`, the footprint the mounted
|
|
21
|
+
* report widget declares, so a page's last row can scroll clear of the button
|
|
22
|
+
* floating over its corner. An element rather than padding: a page taller than
|
|
23
|
+
* the content area overflows this box, which leaves its padding behind at the
|
|
24
|
+
* area's foot, while a last flex item follows the overflow to its end.
|
|
19
25
|
*/
|
|
20
|
-
export const CONTENT_PADDING = 'px-4 pt-5 pb-[calc(1.25rem+env(safe-area-inset-bottom))] sm:px-6 md:px-8 md:pt-7 md:pb-[calc(1.75rem+env(safe-area-inset-bottom))] 2xl:px-12';
|
|
26
|
+
export const CONTENT_PADDING = 'px-4 pt-5 pb-[calc(1.25rem+env(safe-area-inset-bottom))] sm:px-6 md:px-8 md:pt-7 md:pb-[calc(1.75rem+env(safe-area-inset-bottom))] 2xl:px-12 after:block after:flex-none after:h-[var(--ds-report-reserve,0px)]';
|
|
@@ -220,9 +220,9 @@
|
|
|
220
220
|
/** What a column sorts by; the running balance depends on the order, so never it. */
|
|
221
221
|
const sorter = (c: { key: string; sort?: LedgerColumn<R>['sort']; text?: LedgerColumn<R>['text'] }) =>
|
|
222
222
|
c.key === 'balance' ? undefined : (c.sort ?? c.text);
|
|
223
|
-
/** Click a head to sort by it, largest or newest first; again to reverse. */
|
|
223
|
+
/** Click a head to sort by it, largest or newest first; again to reverse; a third time back to the default order. */
|
|
224
224
|
function sortBy(key: string) {
|
|
225
|
-
sort = sort?.key
|
|
225
|
+
sort = sort?.key !== key ? { key, dir: -1 } : sort.dir === -1 ? { key, dir: 1 } : null;
|
|
226
226
|
}
|
|
227
227
|
/** The sort in force: a column the viewer has since unticked no longer sorts. */
|
|
228
228
|
const activeSort = $derived.by(() => {
|
|
@@ -231,8 +231,8 @@
|
|
|
231
231
|
? sort
|
|
232
232
|
: null;
|
|
233
233
|
});
|
|
234
|
-
/**
|
|
235
|
-
const grouped = $derived(prefs.period !== 'none'
|
|
234
|
+
/** A sort orders rows inside their period's groups; only `none` is the flat list. */
|
|
235
|
+
const grouped = $derived(prefs.period !== 'none');
|
|
236
236
|
const BY_DAY = $derived(grouped && prefs.period === 'day');
|
|
237
237
|
|
|
238
238
|
const shown = $derived(
|
|
@@ -262,8 +262,9 @@
|
|
|
262
262
|
});
|
|
263
263
|
const groups = $derived.by(() => {
|
|
264
264
|
const by = activeSort && sorter(resolved.find((c) => c.key === activeSort.key)!);
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
const base = groupRows(rows, prefs.period, fy);
|
|
266
|
+
if (!activeSort || !by) return base;
|
|
267
|
+
return base.map((g) => ({ key: g.key, rows: sortRows(g.rows, by, activeSort.dir) }));
|
|
267
268
|
});
|
|
268
269
|
/** Closed groups, keyed with their period so a new period starts open. */
|
|
269
270
|
const closed = new SvelteSet<string>();
|
|
@@ -923,7 +924,7 @@
|
|
|
923
924
|
mine && 'text-foreground'
|
|
924
925
|
)}
|
|
925
926
|
aria-label={mine
|
|
926
|
-
? `Sorted by ${c.label}, ${mine.dir === -1 ? 'descending' : 'ascending'}. Click to reverse`
|
|
927
|
+
? `Sorted by ${c.label}, ${mine.dir === -1 ? 'descending' : 'ascending'}. Click ${mine.dir === -1 ? 'to reverse' : 'for the default order'}`
|
|
927
928
|
: `Sort by ${c.label}`}
|
|
928
929
|
onclick={() => sortBy(c.key)}
|
|
929
930
|
data-slot="ledger-sort"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poodle64/ui",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.4",
|
|
4
4
|
"description": "Household shared component layer: shadcn-svelte primitives (bits-ui) plus the composed page chrome every app builds its routes from, restyled by each app's @poodle64/design-tokens alias layer. One fix reaches every app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @poodle64/ui — situation → component map
|
|
2
2
|
|
|
3
3
|
<!-- GENERATED by scripts/generate-registry.mjs from scripts/situations.json + package source. DO NOT EDIT. -->
|
|
4
|
-
Generated from `@poodle64/ui@2026.10.
|
|
4
|
+
Generated from `@poodle64/ui@2026.10.4`. 62 components, 18 situations.
|
|
5
5
|
|
|
6
6
|
**Read this before writing a `<div>`.** Find the SITUATION you are in below, then compose the component named for it — do not hand-build it from raw `Card` or utility classes. Import is `import { Name } from '<import path>'`. Props marked `?` are optional. This map is the retrieval step the [`frontend-design` skill] makes mandatory; the [CHI 2026 study] measured composing-from-a-registry at 95% design-system compliance against 71% for writing the CSS from a prose style guide.
|
|
7
7
|
|