@marianmeres/stuic 3.167.0 → 3.169.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.
- package/AGENTS.md +6 -6
- package/dist/README.md +1 -1
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/attachments/long-press.d.ts +43 -0
- package/dist/attachments/long-press.js +107 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.svelte +198 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.svelte.d.ts +60 -0
- package/dist/components/Breadcrumbs/README.md +174 -0
- package/dist/components/Breadcrumbs/i18n-sk.d.ts +17 -0
- package/dist/components/Breadcrumbs/i18n-sk.js +19 -0
- package/dist/components/Breadcrumbs/i18n.d.ts +31 -0
- package/dist/components/Breadcrumbs/i18n.js +40 -0
- package/dist/components/Breadcrumbs/index.css +84 -0
- package/dist/components/Breadcrumbs/index.d.ts +4 -0
- package/dist/components/Breadcrumbs/index.js +4 -0
- package/dist/components/Breadcrumbs/json-ld.d.ts +58 -0
- package/dist/components/Breadcrumbs/json-ld.js +56 -0
- package/dist/components/Collapsible/Collapsible.svelte +84 -15
- package/dist/components/Collapsible/Collapsible.svelte.d.ts +29 -2
- package/dist/components/Collapsible/README.md +82 -23
- package/dist/components/Collapsible/index.css +38 -0
- package/dist/components/Collapsible/index.d.ts +1 -1
- package/dist/components/ContextMenu/ContextMenu.svelte +302 -0
- package/dist/components/ContextMenu/ContextMenu.svelte.d.ts +94 -0
- package/dist/components/ContextMenu/README.md +159 -0
- package/dist/components/ContextMenu/i18n-sk.d.ts +17 -0
- package/dist/components/ContextMenu/i18n-sk.js +18 -0
- package/dist/components/ContextMenu/i18n.d.ts +30 -0
- package/dist/components/ContextMenu/i18n.js +38 -0
- package/dist/components/ContextMenu/index.css +26 -0
- package/dist/components/ContextMenu/index.d.ts +3 -0
- package/dist/components/ContextMenu/index.js +3 -0
- package/dist/components/CopyButton/CopyButton.svelte +278 -0
- package/dist/components/CopyButton/CopyButton.svelte.d.ts +76 -0
- package/dist/components/CopyButton/README.md +241 -0
- package/dist/components/CopyButton/i18n-sk.d.ts +17 -0
- package/dist/components/CopyButton/i18n-sk.js +20 -0
- package/dist/components/CopyButton/i18n.d.ts +35 -0
- package/dist/components/CopyButton/i18n.js +43 -0
- package/dist/components/CopyButton/index.css +67 -0
- package/dist/components/CopyButton/index.d.ts +3 -0
- package/dist/components/CopyButton/index.js +3 -0
- package/dist/components/DataTable/DataTable.svelte +41 -34
- package/dist/components/DataTable/README.md +45 -0
- package/dist/components/DataTable/i18n-sk.js +1 -0
- package/dist/components/DataTable/i18n.d.ts +1 -0
- package/dist/components/DataTable/i18n.js +3 -0
- package/dist/components/DataTable/index.css +41 -3
- package/dist/components/EmptyState/EmptyState.svelte +121 -0
- package/dist/components/EmptyState/EmptyState.svelte.d.ts +40 -0
- package/dist/components/EmptyState/README.md +188 -0
- package/dist/components/EmptyState/index.css +154 -0
- package/dist/components/EmptyState/index.d.ts +1 -0
- package/dist/components/EmptyState/index.js +1 -0
- package/dist/components/Input/FieldOptions.svelte +92 -2
- package/dist/components/Input/FieldOptions.svelte.d.ts +13 -0
- package/dist/components/Input/README.md +66 -31
- package/dist/components/Input/_internal/FieldLikeChips.svelte +286 -0
- package/dist/components/Input/_internal/FieldLikeChips.svelte.d.ts +65 -0
- package/dist/components/Input/index.css +58 -0
- package/dist/components/Pagination/Pagination.svelte +250 -0
- package/dist/components/Pagination/Pagination.svelte.d.ts +69 -0
- package/dist/components/Pagination/README.md +152 -0
- package/dist/components/Pagination/i18n-sk.d.ts +17 -0
- package/dist/components/Pagination/i18n-sk.js +24 -0
- package/dist/components/Pagination/i18n.d.ts +41 -0
- package/dist/components/Pagination/i18n.js +49 -0
- package/dist/components/Pagination/index.css +50 -0
- package/dist/components/Pagination/index.d.ts +4 -0
- package/dist/components/Pagination/index.js +4 -0
- package/dist/components/Pagination/pagination-range.d.ts +21 -0
- package/dist/components/Pagination/pagination-range.js +41 -0
- package/dist/components/Pill/Pill.svelte +8 -2
- package/dist/components/Pill/Pill.svelte.d.ts +2 -0
- package/dist/components/Pill/README.md +35 -22
- package/dist/components/Pill/index.css +57 -18
- package/dist/components/Stat/README.md +157 -0
- package/dist/components/Stat/Stat.svelte +226 -0
- package/dist/components/Stat/Stat.svelte.d.ts +54 -0
- package/dist/components/Stat/index.css +217 -0
- package/dist/components/Stat/index.d.ts +1 -0
- package/dist/components/Stat/index.js +1 -0
- package/dist/components/Stepper/README.md +181 -0
- package/dist/components/Stepper/Stepper.svelte +240 -0
- package/dist/components/Stepper/Stepper.svelte.d.ts +86 -0
- package/dist/components/Stepper/i18n-sk.d.ts +17 -0
- package/dist/components/Stepper/i18n-sk.js +21 -0
- package/dist/components/Stepper/i18n.d.ts +35 -0
- package/dist/components/Stepper/i18n.js +43 -0
- package/dist/components/Stepper/index.css +302 -0
- package/dist/components/Stepper/index.d.ts +3 -0
- package/dist/components/Stepper/index.js +3 -0
- package/dist/components/TrendChart/README.md +123 -0
- package/dist/components/TrendChart/TrendChart.svelte +114 -0
- package/dist/components/TrendChart/TrendChart.svelte.d.ts +36 -0
- package/dist/components/TrendChart/index.css +51 -0
- package/dist/components/TrendChart/index.d.ts +1 -0
- package/dist/components/TrendChart/index.js +1 -0
- package/dist/icons/index.d.ts +4 -0
- package/dist/icons/index.js +4 -0
- package/dist/index.css +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +12 -0
- package/dist/utils/copy-to-clipboard.d.ts +43 -0
- package/dist/utils/copy-to-clipboard.js +102 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/docs/architecture.md +1 -1
- package/docs/domains/attachments.md +41 -4
- package/docs/domains/components.md +280 -13
- package/docs/domains/utils.md +8 -6
- package/docs/maybe-todo.md +132 -0
- package/docs/upgrading.md +6 -0
- package/package.json +11 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { PagingCalcResult } from "@marianmeres/paging-store";
|
|
4
|
+
import type { TranslateFn } from "../../types.js";
|
|
5
|
+
import type { ButtonSize } from "../Button/Button.svelte";
|
|
6
|
+
export type PaginationVariant = "compact" | "numbers";
|
|
7
|
+
export interface Props extends Omit<HTMLAttributes<HTMLElement>, "children"> {
|
|
8
|
+
/**
|
|
9
|
+
* Paging calculation result from `@marianmeres/paging-store` — the exact shape
|
|
10
|
+
* `DataTable` consumes, so both can be fed from the same store or `calculatePaging`
|
|
11
|
+
* call. Takes precedence over the `total`/`limit`/`offset` convenience props.
|
|
12
|
+
*/
|
|
13
|
+
paging?: PagingCalcResult;
|
|
14
|
+
/** Convenience alternative to `paging`: total number of items in the dataset. */
|
|
15
|
+
total?: number;
|
|
16
|
+
/** Convenience alternative to `paging`: items per page (default 10). */
|
|
17
|
+
limit?: number;
|
|
18
|
+
/** Convenience alternative to `paging`: current offset (default 0). */
|
|
19
|
+
offset?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Callback when the user navigates to a different page. First argument is the new
|
|
22
|
+
* offset (`DataTable`'s `onPageChange` signature), second is the 1-based target page.
|
|
23
|
+
*/
|
|
24
|
+
onPageChange?: (offset: number, page: number) => void;
|
|
25
|
+
/**
|
|
26
|
+
* `"compact"` (default): prev / "Page X of Y" / next — the `DataTable` pager.
|
|
27
|
+
* `"numbers"`: windowed page-number buttons with ellipsis gaps.
|
|
28
|
+
*/
|
|
29
|
+
variant?: PaginationVariant;
|
|
30
|
+
/** Numbers variant: pages always shown around the current page (default 1). */
|
|
31
|
+
siblingCount?: number;
|
|
32
|
+
/** Numbers variant: pages always shown at the start and at the end (default 1). */
|
|
33
|
+
boundaryCount?: number;
|
|
34
|
+
/** Render first/last jump buttons (default false). */
|
|
35
|
+
showFirstLast?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Render the "Page X of Y" info. Defaults per variant: `true` for compact (between
|
|
38
|
+
* prev/next), `false` for numbers (after the buttons when enabled).
|
|
39
|
+
*/
|
|
40
|
+
showInfo?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Render nothing when there is at most one page (default true — the `DataTable`
|
|
43
|
+
* rule: one page of results needs no pager). Set `false` to keep it visible.
|
|
44
|
+
*/
|
|
45
|
+
hideSinglePage?: boolean;
|
|
46
|
+
/** Disable all controls (e.g. while a page of data is loading). */
|
|
47
|
+
disabled?: boolean;
|
|
48
|
+
/** Size preset passed to the inner Buttons (default "sm", as in `DataTable`). */
|
|
49
|
+
size?: ButtonSize;
|
|
50
|
+
/** i18n translate function (see `createPaginationT`). */
|
|
51
|
+
t?: TranslateFn;
|
|
52
|
+
/** Override the "Page X of Y" info content. */
|
|
53
|
+
renderInfo?: Snippet<[PagingCalcResult]>;
|
|
54
|
+
/** Skip all default styling (inner Buttons keep their own Button styling) */
|
|
55
|
+
unstyled?: boolean;
|
|
56
|
+
/** Additional CSS classes */
|
|
57
|
+
class?: string;
|
|
58
|
+
/** Class for every inner button */
|
|
59
|
+
classButton?: string;
|
|
60
|
+
/** Extra class for the current-page button (numbers variant) */
|
|
61
|
+
classButtonCurrent?: string;
|
|
62
|
+
/** Class for the "Page X of Y" info */
|
|
63
|
+
classInfo?: string;
|
|
64
|
+
/** Bindable element reference */
|
|
65
|
+
el?: HTMLElement;
|
|
66
|
+
}
|
|
67
|
+
declare const Pagination: import("svelte").Component<Props, {}, "el">;
|
|
68
|
+
type Pagination = ReturnType<typeof Pagination>;
|
|
69
|
+
export default Pagination;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Pagination
|
|
2
|
+
|
|
3
|
+
Standalone pagination control for lists, search results, and custom views. Two
|
|
4
|
+
variants: `compact` — prev / "Page X of Y" / next, which _is_ the pager `DataTable`
|
|
5
|
+
renders internally — and `numbers` — windowed page-number buttons with ellipsis gaps
|
|
6
|
+
(the classic `1 … 4 5 6 … 20`).
|
|
7
|
+
|
|
8
|
+
Consumes the same `PagingCalcResult` from
|
|
9
|
+
[`@marianmeres/paging-store`](https://github.com/marianmeres/paging-store) that
|
|
10
|
+
`DataTable` does, so one paging store (or one `calculatePaging` call) can feed both.
|
|
11
|
+
For quick standalone use, `total`/`limit`/`offset` props compute the paging
|
|
12
|
+
internally.
|
|
13
|
+
|
|
14
|
+
## Props
|
|
15
|
+
|
|
16
|
+
| Prop | Type | Default | Description |
|
|
17
|
+
| -------------------- | ------------------------ | ----------- | ------------------------------------------------------------------------------------- |
|
|
18
|
+
| `paging` | `PagingCalcResult` | - | Paging metadata (same shape `DataTable` consumes); wins over `total`/`limit`/`offset` |
|
|
19
|
+
| `total` | `number` | - | Convenience alternative to `paging`: total item count |
|
|
20
|
+
| `limit` | `number` | `10` | Convenience alternative to `paging`: page size |
|
|
21
|
+
| `offset` | `number` | `0` | Convenience alternative to `paging`: current offset |
|
|
22
|
+
| `onPageChange` | `(offset, page) => void` | - | Navigation callback: new offset (`DataTable`-compatible first arg) + 1-based page |
|
|
23
|
+
| `variant` | `"compact" \| "numbers"` | `"compact"` | Prev/info/next, or windowed page-number buttons |
|
|
24
|
+
| `siblingCount` | `number` | `1` | Numbers variant: pages always shown around the current page |
|
|
25
|
+
| `boundaryCount` | `number` | `1` | Numbers variant: pages always shown at the start and end |
|
|
26
|
+
| `showFirstLast` | `boolean` | `false` | Render first/last jump buttons (« ») |
|
|
27
|
+
| `showInfo` | `boolean` | per variant | "Page X of Y" info; defaults `true` for compact, `false` for numbers |
|
|
28
|
+
| `hideSinglePage` | `boolean` | `true` | Render nothing when there is at most one page (the `DataTable` rule) |
|
|
29
|
+
| `disabled` | `boolean` | `false` | Disable all controls (e.g. while loading) |
|
|
30
|
+
| `size` | `ButtonSize` | `"sm"` | Size preset of the inner Buttons |
|
|
31
|
+
| `t` | `TranslateFn` | English | i18n translate function (see below) |
|
|
32
|
+
| `unstyled` | `boolean` | `false` | Skip pagination styling (inner Buttons keep their own Button styling) |
|
|
33
|
+
| `class` | `string` | - | Additional CSS classes (merged via twMerge) |
|
|
34
|
+
| `classButton` | `string` | - | Class for every inner button |
|
|
35
|
+
| `classButtonCurrent` | `string` | - | Extra class for the current-page button (numbers variant) |
|
|
36
|
+
| `classInfo` | `string` | - | Class for the "Page X of Y" info |
|
|
37
|
+
| `el` | `HTMLElement` | - | Element reference (bindable) |
|
|
38
|
+
|
|
39
|
+
## Snippet Props
|
|
40
|
+
|
|
41
|
+
| Snippet | Description |
|
|
42
|
+
| ------------ | ------------------------------------------------------------------------ |
|
|
43
|
+
| `renderInfo` | Override the "Page X of Y" info content; receives the `PagingCalcResult` |
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Basic (compact)
|
|
48
|
+
|
|
49
|
+
```svelte
|
|
50
|
+
<script lang="ts">
|
|
51
|
+
import { Pagination } from "@marianmeres/stuic";
|
|
52
|
+
|
|
53
|
+
let offset = $state(0);
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<Pagination total={137} limit={10} {offset} onPageChange={(o) => (offset = o)} />
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### With a paging store (shared with DataTable)
|
|
60
|
+
|
|
61
|
+
The `paging` prop takes the exact object `DataTable` consumes — hide the table's
|
|
62
|
+
built-in pager and drive both from one store:
|
|
63
|
+
|
|
64
|
+
```svelte
|
|
65
|
+
<script lang="ts">
|
|
66
|
+
import { DataTable, Pagination } from "@marianmeres/stuic";
|
|
67
|
+
import { createPagingStore } from "@marianmeres/paging-store";
|
|
68
|
+
|
|
69
|
+
const paging = createPagingStore({ total: 137, limit: 10, offset: 0 });
|
|
70
|
+
const onPageChange = (offset: number) => paging.update({ offset });
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<DataTable {columns} {data} paging={$paging} showPager={false} />
|
|
74
|
+
<Pagination paging={$paging} {onPageChange} variant="numbers" />
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Numbers variant
|
|
78
|
+
|
|
79
|
+
```svelte
|
|
80
|
+
<Pagination variant="numbers" total={200} {offset} onPageChange={(o) => (offset = o)} />
|
|
81
|
+
|
|
82
|
+
<!-- wider window, first/last jumps -->
|
|
83
|
+
<Pagination
|
|
84
|
+
variant="numbers"
|
|
85
|
+
siblingCount={2}
|
|
86
|
+
boundaryCount={2}
|
|
87
|
+
showFirstLast
|
|
88
|
+
total={200}
|
|
89
|
+
{offset}
|
|
90
|
+
onPageChange={(o) => (offset = o)}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### i18n
|
|
95
|
+
|
|
96
|
+
Built-in English; bundled Slovak (`PAGINATION_MESSAGES_SK`) is opt-in. The
|
|
97
|
+
`previous_page`, `next_page` and `page_x_of_y` keys are identical to `DataTable`'s,
|
|
98
|
+
so one merged catalog (and one `t`) can serve both components.
|
|
99
|
+
|
|
100
|
+
```svelte
|
|
101
|
+
<script lang="ts">
|
|
102
|
+
import {
|
|
103
|
+
Pagination,
|
|
104
|
+
createPaginationT,
|
|
105
|
+
PAGINATION_MESSAGES_SK,
|
|
106
|
+
} from "@marianmeres/stuic";
|
|
107
|
+
const t = createPaginationT(PAGINATION_MESSAGES_SK);
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<Pagination {paging} {onPageChange} {t} />
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Custom info
|
|
114
|
+
|
|
115
|
+
```svelte
|
|
116
|
+
<Pagination {paging} {onPageChange}>
|
|
117
|
+
{#snippet renderInfo(p)}
|
|
118
|
+
{p.offset + 1}–{Math.min(p.offset + p.limit, p.total)} of {p.total}
|
|
119
|
+
{/snippet}
|
|
120
|
+
</Pagination>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Single page
|
|
124
|
+
|
|
125
|
+
By default nothing renders when there is at most one page (same rule as
|
|
126
|
+
`DataTable`'s internal pager). Keep it visible with `hideSinglePage={false}`.
|
|
127
|
+
|
|
128
|
+
## Accessibility
|
|
129
|
+
|
|
130
|
+
- Renders a `<nav aria-label="Pagination">` landmark (label localized via `t`).
|
|
131
|
+
- Every button carries a localized `aria-label`; the current page button (numbers
|
|
132
|
+
variant) is marked `aria-current="page"`.
|
|
133
|
+
|
|
134
|
+
## Exports
|
|
135
|
+
|
|
136
|
+
Besides the component: `paginationRange(currentPage, pageCount, { siblingCount, boundaryCount })`
|
|
137
|
+
— the pure windowing helper behind the numbers variant, usable for fully custom pagers.
|
|
138
|
+
|
|
139
|
+
## CSS Variables
|
|
140
|
+
|
|
141
|
+
| Variable | Default | Description |
|
|
142
|
+
| ------------------------------------- | -------------------------------- | -------------------------------------------------- |
|
|
143
|
+
| `--stuic-pagination-gap` | `0.5rem` | Gap between controls |
|
|
144
|
+
| `--stuic-pagination-button-min-width` | `--stuic-button-min-height-sm` | Min button width (keeps number buttons square-ish) |
|
|
145
|
+
| `--stuic-pagination-info-font-size` | `--text-sm` | Info font size |
|
|
146
|
+
| `--stuic-pagination-info-text` | `--stuic-color-muted-foreground` | Info color |
|
|
147
|
+
| `--stuic-pagination-ellipsis-text` | `--stuic-color-muted-foreground` | Ellipsis color |
|
|
148
|
+
|
|
149
|
+
## Data Attributes
|
|
150
|
+
|
|
151
|
+
- `data-variant` - `"compact" | "numbers"` (on the root `<nav>`)
|
|
152
|
+
- `data-current` - `"true"` on the current-page button (numbers variant)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PaginationMessages } from "./i18n.js";
|
|
2
|
+
/**
|
|
3
|
+
* Slovak message catalog for `Pagination`. Opt-in — English stays the built-in default,
|
|
4
|
+
* and this module is only pulled into a bundle when it is actually imported (the
|
|
5
|
+
* component itself never references it).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```svelte
|
|
9
|
+
* <script>
|
|
10
|
+
* import { Pagination, createPaginationT, PAGINATION_MESSAGES_SK } from "@marianmeres/stuic";
|
|
11
|
+
* const t = createPaginationT(PAGINATION_MESSAGES_SK);
|
|
12
|
+
* </script>
|
|
13
|
+
*
|
|
14
|
+
* <Pagination {paging} {onPageChange} {t} />
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const PAGINATION_MESSAGES_SK: PaginationMessages;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slovak message catalog for `Pagination`. Opt-in — English stays the built-in default,
|
|
3
|
+
* and this module is only pulled into a bundle when it is actually imported (the
|
|
4
|
+
* component itself never references it).
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```svelte
|
|
8
|
+
* <script>
|
|
9
|
+
* import { Pagination, createPaginationT, PAGINATION_MESSAGES_SK } from "@marianmeres/stuic";
|
|
10
|
+
* const t = createPaginationT(PAGINATION_MESSAGES_SK);
|
|
11
|
+
* </script>
|
|
12
|
+
*
|
|
13
|
+
* <Pagination {paging} {onPageChange} {t} />
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export const PAGINATION_MESSAGES_SK = {
|
|
17
|
+
previous_page: "Späť",
|
|
18
|
+
next_page: "Ďalej",
|
|
19
|
+
first_page: "Prvá strana",
|
|
20
|
+
last_page: "Posledná strana",
|
|
21
|
+
page_x_of_y: "Strana {page} z {pageCount}",
|
|
22
|
+
go_to_page_x: "Prejsť na stranu {page}",
|
|
23
|
+
pagination: "Stránkovanie",
|
|
24
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { TranslateFn } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The built-in (English) message catalog of `Pagination`. Also the fallback of every
|
|
4
|
+
* other bundled locale, so a locale missing a key still renders text.
|
|
5
|
+
*
|
|
6
|
+
* The `previous_page`, `next_page` and `page_x_of_y` keys are intentionally identical
|
|
7
|
+
* to `DataTable`'s, so one merged catalog (and one `t`) can serve both components.
|
|
8
|
+
*
|
|
9
|
+
* Placeholders are single-brace (`{page}`, `{pageCount}`, ...).
|
|
10
|
+
*/
|
|
11
|
+
export declare const PAGINATION_MESSAGES_EN: {
|
|
12
|
+
previous_page: string;
|
|
13
|
+
next_page: string;
|
|
14
|
+
first_page: string;
|
|
15
|
+
last_page: string;
|
|
16
|
+
page_x_of_y: string;
|
|
17
|
+
go_to_page_x: string;
|
|
18
|
+
pagination: string;
|
|
19
|
+
};
|
|
20
|
+
/** Every message key `Pagination` may look up. */
|
|
21
|
+
export type PaginationMessageKey = keyof typeof PAGINATION_MESSAGES_EN;
|
|
22
|
+
/** A (possibly partial) catalog for one locale. */
|
|
23
|
+
export type PaginationMessages = Record<PaginationMessageKey, string>;
|
|
24
|
+
/**
|
|
25
|
+
* Builds the `t` prop of `Pagination` from a message catalog. Unknown or untranslated
|
|
26
|
+
* keys fall back to `fallbackMessages` (English by default), so a catalog may safely be
|
|
27
|
+
* partial and never renders a raw key.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```svelte
|
|
31
|
+
* <script>
|
|
32
|
+
* import { Pagination, createPaginationT, PAGINATION_MESSAGES_SK } from "@marianmeres/stuic";
|
|
33
|
+
* const t = createPaginationT(PAGINATION_MESSAGES_SK);
|
|
34
|
+
* </script>
|
|
35
|
+
*
|
|
36
|
+
* <Pagination {paging} {onPageChange} {t} />
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function createPaginationT(messages: Partial<PaginationMessages> | Record<string, string>, fallbackMessages?: Partial<PaginationMessages> | Record<string, string>): TranslateFn;
|
|
40
|
+
/** The component's built-in English `t`. */
|
|
41
|
+
export declare const t_default: TranslateFn;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { isPlainObject } from "../../utils/is-plain-object.js";
|
|
2
|
+
import { replaceMap } from "../../utils/replace-map.js";
|
|
3
|
+
/**
|
|
4
|
+
* The built-in (English) message catalog of `Pagination`. Also the fallback of every
|
|
5
|
+
* other bundled locale, so a locale missing a key still renders text.
|
|
6
|
+
*
|
|
7
|
+
* The `previous_page`, `next_page` and `page_x_of_y` keys are intentionally identical
|
|
8
|
+
* to `DataTable`'s, so one merged catalog (and one `t`) can serve both components.
|
|
9
|
+
*
|
|
10
|
+
* Placeholders are single-brace (`{page}`, `{pageCount}`, ...).
|
|
11
|
+
*/
|
|
12
|
+
export const PAGINATION_MESSAGES_EN = {
|
|
13
|
+
previous_page: "Prev",
|
|
14
|
+
next_page: "Next",
|
|
15
|
+
first_page: "First page",
|
|
16
|
+
last_page: "Last page",
|
|
17
|
+
page_x_of_y: "Page {page} of {pageCount}",
|
|
18
|
+
go_to_page_x: "Go to page {page}",
|
|
19
|
+
pagination: "Pagination",
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Builds the `t` prop of `Pagination` from a message catalog. Unknown or untranslated
|
|
23
|
+
* keys fall back to `fallbackMessages` (English by default), so a catalog may safely be
|
|
24
|
+
* partial and never renders a raw key.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```svelte
|
|
28
|
+
* <script>
|
|
29
|
+
* import { Pagination, createPaginationT, PAGINATION_MESSAGES_SK } from "@marianmeres/stuic";
|
|
30
|
+
* const t = createPaginationT(PAGINATION_MESSAGES_SK);
|
|
31
|
+
* </script>
|
|
32
|
+
*
|
|
33
|
+
* <Pagination {paging} {onPageChange} {t} />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function createPaginationT(messages, fallbackMessages = PAGINATION_MESSAGES_EN) {
|
|
37
|
+
return (k, values = null, fallback = "") => {
|
|
38
|
+
const out = messages[k] ??
|
|
39
|
+
fallbackMessages[k] ??
|
|
40
|
+
(typeof fallback === "string" ? fallback : k);
|
|
41
|
+
return isPlainObject(values)
|
|
42
|
+
? replaceMap(out, values, {
|
|
43
|
+
preSearchKeyTransform: (k) => `{${k}}`,
|
|
44
|
+
})
|
|
45
|
+
: out;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** The component's built-in English `t`. */
|
|
49
|
+
export const t_default = createPaginationT(PAGINATION_MESSAGES_EN);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
PAGINATION COMPONENT TOKENS
|
|
3
|
+
Override globally: :root { --stuic-pagination-gap: 1rem; }
|
|
4
|
+
Override locally: <Pagination style="--stuic-pagination-button-min-width: 2rem;">
|
|
5
|
+
============================================================================ */
|
|
6
|
+
|
|
7
|
+
/* prettier-ignore */
|
|
8
|
+
:root {
|
|
9
|
+
--stuic-pagination-gap: 0.5rem;
|
|
10
|
+
|
|
11
|
+
/* Keeps single-character buttons («, ‹, page numbers) square-ish and aligned.
|
|
12
|
+
Sized to the `size="sm"` Button height. Text buttons (Prev/Next) simply exceed it. */
|
|
13
|
+
--stuic-pagination-button-min-width: var(--stuic-button-min-height-sm, 2.75rem);
|
|
14
|
+
|
|
15
|
+
/* "Page X of Y" info */
|
|
16
|
+
--stuic-pagination-info-font-size: var(--text-sm);
|
|
17
|
+
--stuic-pagination-info-text: var(--stuic-color-muted-foreground);
|
|
18
|
+
|
|
19
|
+
/* Ellipsis gap (numbers variant) */
|
|
20
|
+
--stuic-pagination-ellipsis-text: var(--stuic-color-muted-foreground);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@layer components {
|
|
24
|
+
.stuic-pagination {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
flex-wrap: wrap;
|
|
29
|
+
gap: var(--stuic-pagination-gap);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.stuic-pagination-button {
|
|
33
|
+
min-width: var(--stuic-pagination-button-min-width);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.stuic-pagination-info {
|
|
37
|
+
font-size: var(--stuic-pagination-info-font-size);
|
|
38
|
+
color: var(--stuic-pagination-info-text);
|
|
39
|
+
white-space: nowrap;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.stuic-pagination-ellipsis {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
min-width: var(--stuic-pagination-button-min-width);
|
|
47
|
+
color: var(--stuic-pagination-ellipsis-text);
|
|
48
|
+
user-select: none;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as Pagination, type Props as PaginationProps, type PaginationVariant, } from "./Pagination.svelte";
|
|
2
|
+
export { paginationRange, type PaginationRangeItem, type PaginationRangeOptions, } from "./pagination-range.js";
|
|
3
|
+
export { createPaginationT, PAGINATION_MESSAGES_EN, type PaginationMessageKey, type PaginationMessages, } from "./i18n.js";
|
|
4
|
+
export { PAGINATION_MESSAGES_SK } from "./i18n-sk.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** One rendered slot of the "numbers" variant: a page number or an ellipsis gap. */
|
|
2
|
+
export type PaginationRangeItem = number | "ellipsis";
|
|
3
|
+
export interface PaginationRangeOptions {
|
|
4
|
+
/** How many pages to always show around the current page (default 1). */
|
|
5
|
+
siblingCount?: number;
|
|
6
|
+
/** How many pages to always show at the start and at the end (default 1). */
|
|
7
|
+
boundaryCount?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Computes the windowed page list of the "numbers" variant: boundary pages at both
|
|
11
|
+
* ends, siblings around the current page, and `"ellipsis"` tokens for the collapsed
|
|
12
|
+
* gaps. The window is stable — for a given `pageCount` and options, every
|
|
13
|
+
* `currentPage` yields the same number of slots (no layout jumping while paging).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* paginationRange(5, 10); // [1, "ellipsis", 4, 5, 6, "ellipsis", 10]
|
|
18
|
+
* paginationRange(1, 5); // [1, 2, 3, 4, 5]
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function paginationRange(currentPage: number, pageCount: number, options?: PaginationRangeOptions): PaginationRangeItem[];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes the windowed page list of the "numbers" variant: boundary pages at both
|
|
3
|
+
* ends, siblings around the current page, and `"ellipsis"` tokens for the collapsed
|
|
4
|
+
* gaps. The window is stable — for a given `pageCount` and options, every
|
|
5
|
+
* `currentPage` yields the same number of slots (no layout jumping while paging).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* paginationRange(5, 10); // [1, "ellipsis", 4, 5, 6, "ellipsis", 10]
|
|
10
|
+
* paginationRange(1, 5); // [1, 2, 3, 4, 5]
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function paginationRange(currentPage, pageCount, options = {}) {
|
|
14
|
+
const siblingCount = Math.max(0, Math.floor(options.siblingCount ?? 1));
|
|
15
|
+
const boundaryCount = Math.max(0, Math.floor(options.boundaryCount ?? 1));
|
|
16
|
+
if (!Number.isFinite(pageCount) || pageCount <= 0)
|
|
17
|
+
return [];
|
|
18
|
+
const page = Math.min(Math.max(1, Math.floor(currentPage) || 1), pageCount);
|
|
19
|
+
const range = (start, end) => Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
20
|
+
const startPages = range(1, Math.min(boundaryCount, pageCount));
|
|
21
|
+
const endPages = range(Math.max(pageCount - boundaryCount + 1, boundaryCount + 1), pageCount);
|
|
22
|
+
const siblingsStart = Math.max(Math.min(page - siblingCount, pageCount - boundaryCount - siblingCount * 2 - 1), boundaryCount + 2);
|
|
23
|
+
const siblingsEnd = Math.min(Math.max(page + siblingCount, boundaryCount + siblingCount * 2 + 2), endPages.length > 0 ? endPages[0] - 2 : pageCount - 1);
|
|
24
|
+
return [
|
|
25
|
+
...startPages,
|
|
26
|
+
// start gap: ellipsis, the single page it would hide, or nothing
|
|
27
|
+
...(siblingsStart > boundaryCount + 2
|
|
28
|
+
? ["ellipsis"]
|
|
29
|
+
: boundaryCount + 1 < pageCount - boundaryCount
|
|
30
|
+
? [boundaryCount + 1]
|
|
31
|
+
: []),
|
|
32
|
+
...range(siblingsStart, siblingsEnd),
|
|
33
|
+
// end gap: ellipsis, the single page it would hide, or nothing
|
|
34
|
+
...(siblingsEnd < pageCount - boundaryCount - 1
|
|
35
|
+
? ["ellipsis"]
|
|
36
|
+
: pageCount - boundaryCount > boundaryCount
|
|
37
|
+
? [pageCount - boundaryCount]
|
|
38
|
+
: []),
|
|
39
|
+
...endPages,
|
|
40
|
+
];
|
|
41
|
+
}
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
dismissible?: boolean;
|
|
43
43
|
/** Called when X is clicked. Stops propagation so parent onclick is unaffected. */
|
|
44
44
|
ondismiss?: (e: MouseEvent) => void;
|
|
45
|
+
/** Accessible name of the built-in X dismiss button */
|
|
46
|
+
dismissLabel?: string;
|
|
45
47
|
/** Status dot rendered before content (uses current intent color) */
|
|
46
48
|
dot?: boolean;
|
|
47
49
|
/** Content rendered before children */
|
|
@@ -76,6 +78,7 @@
|
|
|
76
78
|
disabled,
|
|
77
79
|
dismissible = false,
|
|
78
80
|
ondismiss,
|
|
81
|
+
dismissLabel = "Dismiss",
|
|
79
82
|
dot = false,
|
|
80
83
|
contentBefore,
|
|
81
84
|
contentAfter,
|
|
@@ -109,11 +112,14 @@
|
|
|
109
112
|
<button
|
|
110
113
|
type="button"
|
|
111
114
|
class="stuic-pill-dismiss"
|
|
112
|
-
aria-label=
|
|
115
|
+
aria-label={dismissLabel}
|
|
113
116
|
onclick={handleDismiss}
|
|
114
117
|
{disabled}
|
|
115
118
|
>
|
|
116
|
-
|
|
119
|
+
<!-- The icon box is sized in CSS (tokens); the X itself just fills it. -->
|
|
120
|
+
<span class="stuic-pill-dismiss-icon" aria-hidden="true">
|
|
121
|
+
<X class="size-full" strokeWidth={2.5} />
|
|
122
|
+
</span>
|
|
117
123
|
</button>
|
|
118
124
|
{/snippet}
|
|
119
125
|
|
|
@@ -35,6 +35,8 @@ export interface Props extends Omit<HTMLAttributes<HTMLElement>, "children"> {
|
|
|
35
35
|
dismissible?: boolean;
|
|
36
36
|
/** Called when X is clicked. Stops propagation so parent onclick is unaffected. */
|
|
37
37
|
ondismiss?: (e: MouseEvent) => void;
|
|
38
|
+
/** Accessible name of the built-in X dismiss button */
|
|
39
|
+
dismissLabel?: string;
|
|
38
40
|
/** Status dot rendered before content (uses current intent color) */
|
|
39
41
|
dot?: boolean;
|
|
40
42
|
/** Content rendered before children */
|
|
@@ -4,27 +4,28 @@ A small rounded inline element for tags, badges, status indicators, and filter c
|
|
|
4
4
|
|
|
5
5
|
## Props
|
|
6
6
|
|
|
7
|
-
| Prop | Type | Default
|
|
8
|
-
| --------------- | ------------------------------------------------------------------ |
|
|
9
|
-
| `intent` | `"primary" \| "accent" \| "destructive" \| "warning" \| "success"` | -
|
|
10
|
-
| `variant` | `"solid" \| "outline" \| "ghost" \| "soft" \| "link"` | `"soft"`
|
|
11
|
-
| `size` | `"sm" \| "md" \| "lg"` | `"md"`
|
|
12
|
-
| `muted` | `boolean` | `false`
|
|
13
|
-
| `active` | `boolean` | `false`
|
|
14
|
-
| `roundedFull` | `boolean` | `true`
|
|
15
|
-
| `block` | `boolean` | `false`
|
|
16
|
-
| `unstyled` | `boolean` | `false`
|
|
17
|
-
| `href` | `string` | -
|
|
18
|
-
| `target` | `string` | -
|
|
19
|
-
| `onclick` | `(e: MouseEvent) => void` | -
|
|
20
|
-
| `disabled` | `boolean` | -
|
|
21
|
-
| `dismissible` | `boolean` | `false`
|
|
22
|
-
| `ondismiss` | `(e: MouseEvent) => void` | -
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
| --------------- | ------------------------------------------------------------------ | ----------- | --------------------------------------------------------------------- |
|
|
9
|
+
| `intent` | `"primary" \| "accent" \| "destructive" \| "warning" \| "success"` | - | Semantic color intent |
|
|
10
|
+
| `variant` | `"solid" \| "outline" \| "ghost" \| "soft" \| "link"` | `"soft"` | Visual variant (how colors are applied) |
|
|
11
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Pill size |
|
|
12
|
+
| `muted` | `boolean` | `false` | Reduce emphasis (lower opacity) |
|
|
13
|
+
| `active` | `boolean` | `false` | Selected/active state (filter-chip behavior) |
|
|
14
|
+
| `roundedFull` | `boolean` | `true` | Fully rounded corners (9999px). Set `false` to use the element radius |
|
|
15
|
+
| `block` | `boolean` | `false` | Render as block-level flex (full width). `inline-flex` by default |
|
|
16
|
+
| `unstyled` | `boolean` | `false` | Skip all default styling |
|
|
17
|
+
| `href` | `string` | - | Render as `<a>` with this URL |
|
|
18
|
+
| `target` | `string` | - | Link target (only when `href` is set) |
|
|
19
|
+
| `onclick` | `(e: MouseEvent) => void` | - | Render as `<button>` with this handler (when no `href`) |
|
|
20
|
+
| `disabled` | `boolean` | - | Disabled state (interactive variants only) |
|
|
21
|
+
| `dismissible` | `boolean` | `false` | Show built-in X dismiss button |
|
|
22
|
+
| `ondismiss` | `(e: MouseEvent) => void` | - | Called when X is clicked. Stops propagation |
|
|
23
|
+
| `dismissLabel` | `string` | `"Dismiss"` | Accessible name of the X dismiss button |
|
|
24
|
+
| `dot` | `boolean` | `false` | Status dot rendered before content |
|
|
25
|
+
| `contentBefore` | `THC` | - | Content rendered before children |
|
|
26
|
+
| `contentAfter` | `THC` | - | Content rendered after children |
|
|
27
|
+
| `el` | `HTMLElement` | - | Element reference (bindable) |
|
|
28
|
+
| `class` | `string` | - | Additional CSS classes |
|
|
28
29
|
|
|
29
30
|
## Element Resolution
|
|
30
31
|
|
|
@@ -172,6 +173,15 @@ A small rounded inline element for tags, badges, status indicators, and filter c
|
|
|
172
173
|
| `--stuic-pill-gap` | `0.375rem` | Gap between dot/before/children/after/dismiss |
|
|
173
174
|
| `--stuic-pill-dot-size` | `0.5rem` | Status dot diameter |
|
|
174
175
|
|
|
176
|
+
### Dismiss Button Tokens
|
|
177
|
+
|
|
178
|
+
| Variable | Default | Description |
|
|
179
|
+
| -------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------- |
|
|
180
|
+
| `--stuic-pill-dismiss-min-size` | `1.5rem` | Touch-target floor for the X button (its square never gets smaller) |
|
|
181
|
+
| `--stuic-pill-dismiss-icon-size` | `1.125em` | Size of the X glyph box (relative to the pill font size) |
|
|
182
|
+
| `--stuic-pill-dismiss-bg-hover` | `color-mix(in srgb, currentColor 12%, transparent)` | Hover background of the whole X square |
|
|
183
|
+
| `--stuic-pill-dismiss-bg-active` | `color-mix(in srgb, currentColor 20%, transparent)` | Pressed background of the whole X square |
|
|
184
|
+
|
|
175
185
|
### Size Tokens
|
|
176
186
|
|
|
177
187
|
Each size (sm, md, lg) has corresponding tokens:
|
|
@@ -181,7 +191,10 @@ Each size (sm, md, lg) has corresponding tokens:
|
|
|
181
191
|
- `--stuic-pill-font-size-{size}`
|
|
182
192
|
- `--stuic-pill-min-height-{size}`
|
|
183
193
|
|
|
184
|
-
Dismissible pills override `padding-y` to `0
|
|
194
|
+
Dismissible pills override `padding-y` and `padding-inline-end` to `0`: the X button is a
|
|
195
|
+
full-height square (side = the pill's `min-height`, floored at `--stuic-pill-dismiss-min-size`)
|
|
196
|
+
sitting flush with the pill's end edge, and the whole square is the hover/press surface — not just
|
|
197
|
+
the glyph. Its corners inherit the pill radius, so on rounded pills the hover surface is the end cap.
|
|
185
198
|
|
|
186
199
|
### Intent Color Tokens
|
|
187
200
|
|