@lyeve-labs/ui-kit 0.19.0 → 0.20.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.
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { safeHref } from '../internal/href.js';
3
+ import { formatCount } from '../internal/number.js';
3
4
 
4
5
  interface Base {
5
6
  page: number;
@@ -21,6 +22,19 @@
21
22
  * back.
22
23
  */
23
24
  hasNext?: boolean;
25
+ /**
26
+ * What the list holds, in the plural: 'files', 'jobs', 'webhooks'.
27
+ *
28
+ * The summary names it, because a console that stacks three lists under one
29
+ * page title prints '51 to 100' three times and says of what nowhere. Left
30
+ * out, the summary reads exactly as it did before this existed.
31
+ *
32
+ * Plural at every size, including a list of one. The noun labels the
33
+ * collection here rather than agreeing with a figure in the sentence, the
34
+ * same way the column header above it does, and a singular form would have
35
+ * to pick which of the three figures governs it.
36
+ */
37
+ noun?: string;
24
38
  class?: string;
25
39
  }
26
40
 
@@ -47,6 +61,7 @@
47
61
  total = undefined,
48
62
  perPage = 20,
49
63
  hasNext = false,
64
+ noun = '',
50
65
  class: cls = '',
51
66
  onchange,
52
67
  href,
@@ -102,20 +117,35 @@
102
117
 
103
118
  let nums = $derived(counted ? pageNumbers(safePage, totalPages) : []);
104
119
 
120
+ /**
121
+ * The noun as it will be read.
122
+ *
123
+ * Trimmed, and empty means absent: a caller composing the word from data can
124
+ * hand over ' ' as easily as 'files', and a summary that opens with a stray
125
+ * space is worse than one that names nothing.
126
+ */
127
+ let label = $derived(noun.trim());
128
+
105
129
  /**
106
130
  * The count, when there is one to state.
107
131
  *
108
132
  * An uncounted list says which page it is on and nothing else. It cannot say
109
133
  * "1 to 20 of 400" without the total, and it cannot say "1 to 20" either: the
110
- * last page is short and this component is never told how short.
134
+ * last page is short and this component is never told how short. It still
135
+ * groups the page number: `href` mode puts that number in the URL, so a link
136
+ * or a reader can land on page 5,000 without stepping there.
137
+ *
138
+ * Every figure is grouped, because a pager sits under a table that groups its
139
+ * own figures and the pager is where the largest number on the screen is.
111
140
  */
112
- let summary = $derived(
113
- counted
114
- ? safeTotal === 0
115
- ? 'No results'
116
- : `${from} to ${to} of ${safeTotal}`
117
- : `Page ${safePage}`,
118
- );
141
+ let summary = $derived.by(() => {
142
+ if (!counted) {
143
+ return label ? `${label}, page ${formatCount(safePage)}` : `Page ${formatCount(safePage)}`;
144
+ }
145
+ if (safeTotal === 0) return label ? `No ${label}` : 'No results';
146
+ const range = `${formatCount(from)} to ${formatCount(to)} of ${formatCount(safeTotal)}`;
147
+ return label ? `${label} ${range}` : range;
148
+ });
119
149
 
120
150
  /** The target of a control, sanitized, or nothing when the step is unavailable. */
121
151
  function linkTo(target: number, enabled: boolean): string | undefined {
@@ -18,6 +18,19 @@ interface Base {
18
18
  * back.
19
19
  */
20
20
  hasNext?: boolean;
21
+ /**
22
+ * What the list holds, in the plural: 'files', 'jobs', 'webhooks'.
23
+ *
24
+ * The summary names it, because a console that stacks three lists under one
25
+ * page title prints '51 to 100' three times and says of what nowhere. Left
26
+ * out, the summary reads exactly as it did before this existed.
27
+ *
28
+ * Plural at every size, including a list of one. The noun labels the
29
+ * collection here rather than agreeing with a figure in the sentence, the
30
+ * same way the column header above it does, and a singular form would have
31
+ * to pick which of the three figures governs it.
32
+ */
33
+ noun?: string;
21
34
  class?: string;
22
35
  }
23
36
  /**
package/dist/index.d.ts CHANGED
@@ -89,4 +89,4 @@ export type { ConfirmOptions } from './components/dialog/dialog-manager.svelte.j
89
89
  export type { DialogOptions, DialogEntry, DialogSize } from './components/dialog/types.js';
90
90
  export { cn, type ClassValue } from './utils/cn.js';
91
91
  export { getTheme, getThemePreference, nextThemePreference, resolveTheme, setTheme, setThemePreference, systemTheme, themeBootScript, toggleTheme, watchSystemTheme, THEME_PREFERENCES, type Theme, type ThemePreference, } from './utils/theme.js';
92
- export declare const VERSION = "0.19.0";
92
+ export declare const VERSION = "0.20.0";
package/dist/index.js CHANGED
@@ -96,4 +96,4 @@ export { getTheme, getThemePreference, nextThemePreference, resolveTheme, setThe
96
96
  // ── Version ────────────────────────────────────────────────────────────────
97
97
  // Generated from package.json by `pnpm version:sync`. Bump package.json, never
98
98
  // this line; the build and the test suite fail when the two disagree.
99
- export const VERSION = '0.19.0';
99
+ export const VERSION = '0.20.0';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Digit grouping for a figure a reader is meant to take in at a glance.
3
+ *
4
+ * The locale is fixed rather than the runtime's. `toLocaleString()` with no
5
+ * argument formats by whatever locale the environment reports, and the server
6
+ * that renders a page and the browser that hydrates it do not have to report
7
+ * the same one: the same figure then arrives as `4,210` in the HTML and as
8
+ * `4.210` or `4210` after hydration, which is a mismatch the framework warns
9
+ * about and a number the reader watches change under them. A component library
10
+ * has no way to know which locale a host has configured either, so the
11
+ * separator has to be a decision the kit makes once.
12
+ *
13
+ * `en-US` because that is the language every string in the kit is written in,
14
+ * and an English sentence carrying a German separator is the worse of the two
15
+ * inconsistencies.
16
+ *
17
+ * Not exported from the package entry point - this is an implementation detail.
18
+ */
19
+ /**
20
+ * A count, grouped in threes.
21
+ *
22
+ * A value that is not a finite number reads as zero rather than reaching the
23
+ * formatter, which spells infinity as a glyph no summary line should carry and
24
+ * NaN as a word no reader can act on.
25
+ */
26
+ export declare function formatCount(n: number): string;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Digit grouping for a figure a reader is meant to take in at a glance.
3
+ *
4
+ * The locale is fixed rather than the runtime's. `toLocaleString()` with no
5
+ * argument formats by whatever locale the environment reports, and the server
6
+ * that renders a page and the browser that hydrates it do not have to report
7
+ * the same one: the same figure then arrives as `4,210` in the HTML and as
8
+ * `4.210` or `4210` after hydration, which is a mismatch the framework warns
9
+ * about and a number the reader watches change under them. A component library
10
+ * has no way to know which locale a host has configured either, so the
11
+ * separator has to be a decision the kit makes once.
12
+ *
13
+ * `en-US` because that is the language every string in the kit is written in,
14
+ * and an English sentence carrying a German separator is the worse of the two
15
+ * inconsistencies.
16
+ *
17
+ * Not exported from the package entry point - this is an implementation detail.
18
+ */
19
+ /**
20
+ * Built at module load, not per call.
21
+ *
22
+ * Constructing an `Intl` formatter is the expensive half of using one, and a
23
+ * pager re-renders on every keystroke that filters the list behind it.
24
+ */
25
+ const GROUPED = new Intl.NumberFormat('en-US');
26
+ /**
27
+ * A count, grouped in threes.
28
+ *
29
+ * A value that is not a finite number reads as zero rather than reaching the
30
+ * formatter, which spells infinity as a glyph no summary line should carry and
31
+ * NaN as a word no reader can act on.
32
+ */
33
+ export function formatCount(n) {
34
+ return Number.isFinite(n) ? GROUPED.format(n) : '0';
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyeve-labs/ui-kit",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "A clean, accessible, palette-aware Svelte 5 component library. The design system behind LyEve.",
5
5
  "license": "MIT",
6
6
  "author": "LyEve Labs <hello@lyeve.com>",