@limetech/lime-elements 40.4.2 → 40.5.1

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.
Files changed (131) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/component-UyqdiWGc.js +1576 -0
  3. package/dist/cjs/lime-elements.cjs.js +1 -1
  4. package/dist/cjs/limel-action-bar_3.cjs.entry.js +1 -1
  5. package/dist/cjs/limel-ai-avatar.cjs.entry.js +1 -1
  6. package/dist/cjs/{limel-breadcrumbs_8.cjs.entry.js → limel-breadcrumbs_6.cjs.entry.js} +188 -2164
  7. package/dist/cjs/limel-callout.cjs.entry.js +1 -1
  8. package/dist/cjs/limel-chart.cjs.entry.js +1 -1
  9. package/dist/cjs/limel-chip-set.cjs.entry.js +1 -1
  10. package/dist/cjs/limel-chip_2.cjs.entry.js +1 -1
  11. package/dist/cjs/limel-code-diff.cjs.entry.js +1 -1
  12. package/dist/cjs/limel-code-editor.cjs.entry.js +1 -1
  13. package/dist/cjs/limel-collapsible-section.cjs.entry.js +1 -1
  14. package/dist/cjs/limel-drag-handle.cjs.entry.js +1 -1
  15. package/dist/cjs/limel-email-viewer.cjs.entry.js +1 -1
  16. package/dist/cjs/limel-file-viewer.cjs.entry.js +1 -1
  17. package/dist/cjs/limel-file.cjs.entry.js +1 -1
  18. package/dist/cjs/limel-flatpickr-adapter.cjs.entry.js +1 -1
  19. package/dist/cjs/limel-helper-line_3.cjs.entry.js +454 -0
  20. package/dist/cjs/limel-hotkey_4.cjs.entry.js +26 -5
  21. package/dist/cjs/limel-list-item.cjs.entry.js +1 -1
  22. package/dist/cjs/limel-pagination-jump.cjs.entry.js +182 -0
  23. package/dist/cjs/limel-pagination.cjs.entry.js +165 -126
  24. package/dist/cjs/limel-picker.cjs.entry.js +1 -1
  25. package/dist/cjs/limel-profile-picture.cjs.entry.js +1 -1
  26. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +1 -1
  27. package/dist/cjs/limel-slider.cjs.entry.js +1 -1
  28. package/dist/cjs/limel-snackbar.cjs.entry.js +1 -1
  29. package/dist/cjs/limel-table.cjs.entry.js +1 -1
  30. package/dist/cjs/limel-text-editor-link-menu.cjs.entry.js +1 -1
  31. package/dist/cjs/loader.cjs.js +1 -1
  32. package/dist/cjs/pagination.util-B5zzH8vg.js +135 -0
  33. package/dist/cjs/{translations-C5T2-_rH.js → translations-DFFpR6AZ.js} +32 -0
  34. package/dist/collection/collection-manifest.json +1 -0
  35. package/dist/collection/components/pagination/jump/pagination-jump.css +11 -0
  36. package/dist/collection/components/pagination/jump/pagination-jump.js +331 -0
  37. package/dist/collection/components/pagination/pagination.css +8 -4
  38. package/dist/collection/components/pagination/pagination.js +167 -10
  39. package/dist/collection/components/pagination/pagination.util.js +25 -8
  40. package/dist/collection/components/portal/portal.js +26 -5
  41. package/dist/collection/translations/da.js +4 -0
  42. package/dist/collection/translations/de.js +4 -0
  43. package/dist/collection/translations/en.js +4 -0
  44. package/dist/collection/translations/fi.js +4 -0
  45. package/dist/collection/translations/fr.js +4 -0
  46. package/dist/collection/translations/nl.js +4 -0
  47. package/dist/collection/translations/no.js +4 -0
  48. package/dist/collection/translations/sv.js +4 -0
  49. package/dist/esm/component-B2Vy44Z3.js +1570 -0
  50. package/dist/esm/lime-elements.js +1 -1
  51. package/dist/esm/limel-action-bar_3.entry.js +1 -1
  52. package/dist/esm/limel-ai-avatar.entry.js +1 -1
  53. package/dist/esm/{limel-breadcrumbs_8.entry.js → limel-breadcrumbs_6.entry.js} +3 -1977
  54. package/dist/esm/limel-callout.entry.js +1 -1
  55. package/dist/esm/limel-chart.entry.js +1 -1
  56. package/dist/esm/limel-chip-set.entry.js +1 -1
  57. package/dist/esm/limel-chip_2.entry.js +1 -1
  58. package/dist/esm/limel-code-diff.entry.js +1 -1
  59. package/dist/esm/limel-code-editor.entry.js +1 -1
  60. package/dist/esm/limel-collapsible-section.entry.js +1 -1
  61. package/dist/esm/limel-drag-handle.entry.js +1 -1
  62. package/dist/esm/limel-email-viewer.entry.js +1 -1
  63. package/dist/esm/limel-file-viewer.entry.js +1 -1
  64. package/dist/esm/limel-file.entry.js +1 -1
  65. package/dist/esm/limel-flatpickr-adapter.entry.js +1 -1
  66. package/dist/esm/limel-helper-line_3.entry.js +450 -0
  67. package/dist/esm/limel-hotkey_4.entry.js +26 -5
  68. package/dist/esm/limel-list-item.entry.js +1 -1
  69. package/dist/esm/limel-pagination-jump.entry.js +180 -0
  70. package/dist/esm/limel-pagination.entry.js +165 -126
  71. package/dist/esm/limel-picker.entry.js +1 -1
  72. package/dist/esm/limel-profile-picture.entry.js +1 -1
  73. package/dist/esm/limel-prosemirror-adapter.entry.js +1 -1
  74. package/dist/esm/limel-slider.entry.js +1 -1
  75. package/dist/esm/limel-snackbar.entry.js +1 -1
  76. package/dist/esm/limel-table.entry.js +1 -1
  77. package/dist/esm/limel-text-editor-link-menu.entry.js +1 -1
  78. package/dist/esm/loader.js +1 -1
  79. package/dist/esm/pagination.util-CSC2LJ7P.js +132 -0
  80. package/dist/esm/{translations-Bwm2y2E4.js → translations-DMtX4tTX.js} +32 -0
  81. package/dist/lime-elements/lime-elements.esm.js +1 -1
  82. package/dist/lime-elements/{p-2bbdac10.entry.js → p-11a96a8c.entry.js} +1 -1
  83. package/dist/lime-elements/p-1e93473a.entry.js +1 -0
  84. package/dist/lime-elements/{p-6b7ff8e0.entry.js → p-2daf0482.entry.js} +1 -1
  85. package/dist/lime-elements/{p-a41b5ff3.entry.js → p-2e568c56.entry.js} +1 -1
  86. package/dist/lime-elements/{p-de631fc3.entry.js → p-2f57c3fa.entry.js} +1 -1
  87. package/dist/lime-elements/p-3735111e.entry.js +1 -0
  88. package/dist/lime-elements/{p-c823054d.entry.js → p-452b9b01.entry.js} +1 -1
  89. package/dist/lime-elements/{p-f333f12d.entry.js → p-4855dc9b.entry.js} +1 -1
  90. package/dist/lime-elements/{p-a462aeb7.entry.js → p-4902fb3f.entry.js} +1 -1
  91. package/dist/lime-elements/p-507cc8a1.entry.js +159 -0
  92. package/dist/lime-elements/{p-dadd2e17.entry.js → p-531b6a64.entry.js} +1 -1
  93. package/dist/lime-elements/{p-b194a212.entry.js → p-5698e493.entry.js} +1 -1
  94. package/dist/lime-elements/{p-65a9adfc.entry.js → p-67f02b69.entry.js} +1 -1
  95. package/dist/lime-elements/{p-1162dd39.entry.js → p-867681aa.entry.js} +1 -1
  96. package/dist/lime-elements/{p-f72ee01b.entry.js → p-90df3e1b.entry.js} +1 -1
  97. package/dist/lime-elements/{p-22f85b99.entry.js → p-955292eb.entry.js} +1 -1
  98. package/dist/lime-elements/{p-c2ff132c.entry.js → p-9b631363.entry.js} +1 -1
  99. package/dist/lime-elements/{p-8af3e4a1.entry.js → p-9d3437ac.entry.js} +1 -1
  100. package/dist/lime-elements/p-B8hoCfhT.js +1 -0
  101. package/dist/lime-elements/p-BwJGg-WI.js +89 -0
  102. package/dist/lime-elements/p-CSC2LJ7P.js +1 -0
  103. package/dist/lime-elements/p-a1de9bbe.entry.js +1 -0
  104. package/dist/lime-elements/{p-b5484494.entry.js → p-acba5700.entry.js} +1 -1
  105. package/dist/lime-elements/{p-f6361b03.entry.js → p-b8c76487.entry.js} +1 -1
  106. package/dist/lime-elements/{p-ac9c5c88.entry.js → p-cafec335.entry.js} +1 -1
  107. package/dist/lime-elements/{p-48928b4f.entry.js → p-d146feda.entry.js} +1 -1
  108. package/dist/lime-elements/{p-532ea234.entry.js → p-deceda00.entry.js} +1 -1
  109. package/dist/lime-elements/{p-e508771f.entry.js → p-f04f7c8e.entry.js} +1 -1
  110. package/dist/lime-elements/{p-51dc5f0b.entry.js → p-f3c108c9.entry.js} +1 -1
  111. package/dist/lime-elements/{p-24041bbb.entry.js → p-fbcd99a3.entry.js} +1 -1
  112. package/dist/types/components/pagination/jump/pagination-jump.d.ts +102 -0
  113. package/dist/types/components/pagination/pagination.d.ts +81 -0
  114. package/dist/types/components/pagination/pagination.util.d.ts +12 -2
  115. package/dist/types/components/portal/portal.d.ts +3 -0
  116. package/dist/types/components.d.ts +145 -0
  117. package/dist/types/translations/da.d.ts +4 -0
  118. package/dist/types/translations/de.d.ts +4 -0
  119. package/dist/types/translations/en.d.ts +4 -0
  120. package/dist/types/translations/fi.d.ts +4 -0
  121. package/dist/types/translations/fr.d.ts +4 -0
  122. package/dist/types/translations/nl.d.ts +4 -0
  123. package/dist/types/translations/no.d.ts +4 -0
  124. package/dist/types/translations/sv.d.ts +4 -0
  125. package/package.json +1 -1
  126. package/dist/cjs/limel-helper-line.cjs.entry.js +0 -42
  127. package/dist/esm/limel-helper-line.entry.js +0 -40
  128. package/dist/lime-elements/p-497b7be1.entry.js +0 -248
  129. package/dist/lime-elements/p-DAFuhe5e.js +0 -1
  130. package/dist/lime-elements/p-b4988a9b.entry.js +0 -1
  131. package/dist/lime-elements/p-f81dc23a.entry.js +0 -1
@@ -3,7 +3,7 @@ import { g as getIconName } from './get-icon-props-CgNJbSP4.js';
3
3
  import { c as createRandomString } from './random-string-JbKhhoXs.js';
4
4
  import { r as renderListComponent } from './render-list-component-cicbMp0l.js';
5
5
  import { C as CheckboxTemplate } from './checkbox.template-Cx_3u92S.js';
6
- import { t as translate } from './translations-Bwm2y2E4.js';
6
+ import { t as translate } from './translations-DMtX4tTX.js';
7
7
  import { I as ImageTemplate } from './image.template-wqMwmOF-.js';
8
8
  import './language-C3hECvXE.js';
9
9
 
@@ -0,0 +1,180 @@
1
+ import { r as registerInstance, c as createEvent, h, H as Host } from './index-Bnc9lzk2.js';
2
+ import { t as translate } from './translations-DMtX4tTX.js';
3
+ import { a as ENTER } from './keycodes-C4_9qUMP.js';
4
+ import { p as pageFromInput } from './pagination.util-CSC2LJ7P.js';
5
+ import './language-C3hECvXE.js';
6
+
7
+ const paginationJumpCss = () => `:host{display:flex;flex-direction:column;gap:0.75rem;padding:0.75rem;min-width:12rem}:host(:not([open])){display:none}`;
8
+
9
+ const FIRST_PAGE = 1;
10
+ const FALLBACK_LANGUAGE = 'en';
11
+ const PaginationJump = class {
12
+ constructor(hostRef) {
13
+ registerInstance(this, hostRef);
14
+ this.jump = createEvent(this, "jump", 7);
15
+ /**
16
+ * Whether the field is being shown.
17
+ */
18
+ this.open = false;
19
+ /**
20
+ * The page to start from, which is the one the user is on.
21
+ */
22
+ this.page = FIRST_PAGE;
23
+ /**
24
+ * How many pages there are, which is as far as a jump can go.
25
+ */
26
+ this.pageCount = FIRST_PAGE;
27
+ /**
28
+ * Set while a page is being fetched, so that another cannot be asked for.
29
+ */
30
+ this.loading = false;
31
+ /**
32
+ * The language used for the labels and for the way numbers are written.
33
+ */
34
+ this.language = 'en';
35
+ /** What the field shows: the page it opened with, then what is typed. */
36
+ this.value = '';
37
+ this.shouldFocusField = false;
38
+ /**
39
+ * Only to keep what is on screen honest. `limel-input-field` draws an
40
+ * unfocused number through its `value` prop, so a field left pinned to
41
+ * the page it opened with would show that again the moment the keyboard
42
+ * moved to the button, while the button submitted something else.
43
+ *
44
+ * @param event - the field reporting what it now holds
45
+ */
46
+ this.handleChange = (event) => {
47
+ var _a;
48
+ event.stopPropagation();
49
+ this.value = String((_a = event.detail) !== null && _a !== void 0 ? _a : '');
50
+ };
51
+ this.handleKeyDown = (event) => {
52
+ if (event.key !== ENTER) {
53
+ return;
54
+ }
55
+ event.preventDefault();
56
+ this.commit();
57
+ };
58
+ this.commit = () => {
59
+ const page = this.target;
60
+ if (page === null || this.loading) {
61
+ return;
62
+ }
63
+ this.jump.emit(page);
64
+ };
65
+ this.setField = (element) => {
66
+ this.field = element;
67
+ };
68
+ this.translate = (key, params) => {
69
+ return translate.get(key, this.language, params);
70
+ };
71
+ }
72
+ componentWillLoad() {
73
+ this.handleOpenChange();
74
+ }
75
+ handleLanguageChange() {
76
+ this.numberFormat = undefined;
77
+ }
78
+ /**
79
+ * Opening starts the field again rather than leaving what was last typed,
80
+ * so it always offers the page the user is on now.
81
+ */
82
+ handleOpenChange() {
83
+ if (!this.open) {
84
+ return;
85
+ }
86
+ this.value = String(this.page);
87
+ this.shouldFocusField = true;
88
+ }
89
+ componentDidRender() {
90
+ if (!this.shouldFocusField) {
91
+ return;
92
+ }
93
+ this.shouldFocusField = false;
94
+ this.focusField();
95
+ }
96
+ render() {
97
+ if (!this.open) {
98
+ return;
99
+ }
100
+ return (h(Host, { onKeyDown: this.handleKeyDown }, h("limel-input-field", { type: "number", label: this.translate('pagination.page-number'), placeholder: this.pageRange, value: this.value, onChange: this.handleChange, min: FIRST_PAGE, max: this.pageCount, step: 1, ref: this.setField }), h("limel-button", { primary: true, label: this.translate('pagination.go'), disabled: this.loading, onClick: this.commit })));
101
+ }
102
+ /**
103
+ * The page that is in the field now, or `null` when it holds none.
104
+ *
105
+ * Read from the field itself rather than from its `change` event, which
106
+ * arrives on a debounce: a page typed and submitted inside that window
107
+ * would otherwise be submitted as whatever preceded it.
108
+ */
109
+ get target() {
110
+ var _a, _b;
111
+ const typed = (_b = (_a = this.nativeField) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : this.value;
112
+ return pageFromInput(typed, this.pageCount);
113
+ }
114
+ /** `1–492`, so that being moved to 492 is a stated bound, not a surprise. */
115
+ get pageRange() {
116
+ return this.translate('pagination.page-range', {
117
+ first: this.formatNumber(FIRST_PAGE),
118
+ last: this.formatNumber(this.pageCount),
119
+ });
120
+ }
121
+ /** `limel-input-field` wraps a native field but does not expose it. */
122
+ get nativeField() {
123
+ var _a, _b;
124
+ return (_b = (_a = this.field) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('input');
125
+ }
126
+ /**
127
+ * The field delegates focus to the input it wraps, so focusing the host
128
+ * is enough. Selecting as well, so the page the user is on is both the
129
+ * starting value and out of the way of the first keystroke.
130
+ */
131
+ focusField() {
132
+ const host = this.field;
133
+ host === null || host === void 0 ? void 0 : host.componentOnReady().then(() => {
134
+ // A frame later, so the popover has been put where it belongs
135
+ // before the field takes the keyboard.
136
+ requestAnimationFrame(() => {
137
+ var _a, _b;
138
+ host.focus();
139
+ (_b = (_a = host.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('input')) === null || _b === void 0 ? void 0 : _b.select();
140
+ });
141
+ });
142
+ }
143
+ /**
144
+ * The parent warns about a language it cannot use, so this one only has
145
+ * to keep drawing.
146
+ *
147
+ * @param value - the number to write out
148
+ * @returns the number in the current language
149
+ */
150
+ formatNumber(value) {
151
+ var _a;
152
+ (_a = this.numberFormat) !== null && _a !== void 0 ? _a : (this.numberFormat = this.createNumberFormat());
153
+ return this.numberFormat.format(value);
154
+ }
155
+ /**
156
+ * The pagination hands down the language it settled on, so this only has
157
+ * to survive being handed one directly, as the example page does.
158
+ *
159
+ * @returns a formatter, in that language where it can be used
160
+ */
161
+ createNumberFormat() {
162
+ try {
163
+ return new Intl.NumberFormat(this.language);
164
+ }
165
+ catch (_a) {
166
+ return new Intl.NumberFormat(FALLBACK_LANGUAGE);
167
+ }
168
+ }
169
+ static get watchers() { return {
170
+ "language": [{
171
+ "handleLanguageChange": 0
172
+ }],
173
+ "open": [{
174
+ "handleOpenChange": 0
175
+ }]
176
+ }; }
177
+ };
178
+ PaginationJump.style = paginationJumpCss();
179
+
180
+ export { PaginationJump as limel_pagination_jump };
@@ -1,123 +1,10 @@
1
- import { r as registerInstance, c as createEvent, h, H as Host } from './index-Bnc9lzk2.js';
2
- import { t as translate } from './translations-Bwm2y2E4.js';
1
+ import { r as registerInstance, c as createEvent, h, H as Host, a as getElement } from './index-Bnc9lzk2.js';
2
+ import { t as translate } from './translations-DMtX4tTX.js';
3
3
  import { c as createRandomString } from './random-string-JbKhhoXs.js';
4
4
  import { g as getPrimarySubtag } from './language-C3hECvXE.js';
5
+ import { g as getPageSlots } from './pagination.util-CSC2LJ7P.js';
5
6
 
6
- /**
7
- * How many positions are rendered at once, counting both page numbers and gap
8
- * markers. Constant, so the control keeps its width as the user pages through
9
- * a set — a gap and a page number take up the same room, so what matters is
10
- * how many positions there are, not how many of them are numbers.
11
- */
12
- const VISIBLE_SLOTS = 7;
13
- /** How many pages to keep either side of the current one. */
14
- const SIBLINGS = 1;
15
- const FIRST_PAGE$1 = 1;
16
- /**
17
- * Build the list of positions to render for a given page count.
18
- *
19
- * The first and the last page are always included, so both ends of the set are
20
- * always one click away. The rest of the room goes to the pages around the
21
- * current one, and whatever is skipped becomes a gap.
22
- *
23
- * `Number.isSafeInteger` rather than `Number.isInteger`: past 2^53 arithmetic
24
- * on page numbers stops being exact. The component validates these too; this
25
- * guards them again because the cost of being wrong here is a wrong window
26
- * during render.
27
- *
28
- * @param currentPage - the page the user is on, 1-based
29
- * @param totalPages - how many pages there are in total
30
- * @returns the positions to render, in order
31
- */
32
- function getPageSlots(currentPage, totalPages) {
33
- if (!Number.isSafeInteger(totalPages) || totalPages < FIRST_PAGE$1) {
34
- return [];
35
- }
36
- const pages = collectVisiblePages(clampToSet(currentPage, totalPages), totalPages);
37
- return withGaps(pages);
38
- }
39
- /**
40
- * @param page - the page to pull into the set
41
- * @param totalPages - how many pages there are in total
42
- * @returns a whole page number within `1..totalPages`
43
- */
44
- function clampToSet(page, totalPages) {
45
- if (!Number.isSafeInteger(Math.floor(page))) {
46
- return FIRST_PAGE$1;
47
- }
48
- return Math.min(Math.max(FIRST_PAGE$1, Math.floor(page)), totalPages);
49
- }
50
- /**
51
- * Pick which page numbers to render, so that `withGaps` turns them into
52
- * exactly `VISIBLE_SLOTS` positions.
53
- *
54
- * Which of the three shapes applies depends only on whether there is anything
55
- * to skip on each side. With one gap there is room for six numbers, with two
56
- * there is room for five, and the gaps make up the difference.
57
- *
58
- * @param currentPage - the page the user is on, 1-based
59
- * @param totalPages - how many pages there are in total
60
- * @returns the page numbers to render, ascending
61
- */
62
- function collectVisiblePages(currentPage, totalPages) {
63
- if (totalPages <= VISIBLE_SLOTS) {
64
- return range(FIRST_PAGE$1, totalPages);
65
- }
66
- const firstSibling = Math.max(currentPage - SIBLINGS, FIRST_PAGE$1);
67
- const lastSibling = Math.min(currentPage + SIBLINGS, totalPages);
68
- if (firstSibling <= FIRST_PAGE$1 + 1) {
69
- return [...range(FIRST_PAGE$1, VISIBLE_SLOTS - 2), totalPages];
70
- }
71
- if (lastSibling >= totalPages - 1) {
72
- return [
73
- FIRST_PAGE$1,
74
- ...range(totalPages - (VISIBLE_SLOTS - 3), totalPages),
75
- ];
76
- }
77
- return [FIRST_PAGE$1, ...range(firstSibling, lastSibling), totalPages];
78
- }
79
- /**
80
- * @param from - the first number, inclusive
81
- * @param to - the last number, inclusive
82
- * @returns every whole number between the two
83
- */
84
- function range(from, to) {
85
- return Array.from({ length: to - from + 1 }, (_, step) => from + step);
86
- }
87
- /**
88
- * Insert a gap wherever the rendered page numbers are not consecutive.
89
- *
90
- * A gap that would hide a single page is rendered as that page instead: the
91
- * marker is as wide as a page number, so it would save no room.
92
- *
93
- * @param pages - the page numbers to render, ascending
94
- * @returns the positions to render, in order
95
- */
96
- function withGaps(pages) {
97
- return pages.flatMap((page, index) => {
98
- const slot = { kind: 'page', page: page };
99
- if (index === 0) {
100
- return [slot];
101
- }
102
- const skipped = page - pages[index - 1] - 1;
103
- if (skipped === 0) {
104
- return [slot];
105
- }
106
- if (skipped === 1) {
107
- return [{ kind: 'page', page: page - 1 }, slot];
108
- }
109
- return [
110
- {
111
- kind: 'gap',
112
- from: pages[index - 1] + 1,
113
- to: page - 1,
114
- },
115
- slot,
116
- ];
117
- });
118
- }
119
-
120
- const paginationCss = () => `@charset "UTF-8";:host(limel-pagination){display:block;box-sizing:border-box}*{box-sizing:border-box}nav{display:flex;align-items:center}button{appearance:none;background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;text-align:inherit}button:focus{outline:none}button:focus-visible{outline:none;box-shadow:var(--shadow-depth-8-focused)}button{position:relative;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;height:1.75rem;min-width:1.75rem;border-radius:1.75rem;padding:0 0.5rem;font-variant-numeric:tabular-nums}button:not([aria-disabled=true]):not([aria-current=page]){transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:rgb(var(--contrast-1100));background-color:transparent}button:not([aria-disabled=true]):not([aria-current=page]):hover,button:not([aria-disabled=true]):not([aria-current=page]):focus,button:not([aria-disabled=true]):not([aria-current=page]):focus-visible{will-change:color, background-color, box-shadow, transform}button:not([aria-disabled=true]):not([aria-current=page]):hover,button:not([aria-disabled=true]):not([aria-current=page]):focus-visible{transform:translate3d(0, 0.01rem, 0);color:var(--limel-theme-on-surface-color);background-color:var(--lime-elevated-surface-background-color)}button:not([aria-disabled=true]):not([aria-current=page]):hover{box-shadow:var(--button-shadow-hovered)}button:not([aria-disabled=true]):not([aria-current=page]):active{--limel-clickable-transform-timing-function:cubic-bezier( 0.83, -0.15, 0.49, 1.16 );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}button:not([aria-disabled=true]):not([aria-current=page]):hover,button:not([aria-disabled=true]):not([aria-current=page]):active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}button[aria-disabled=true]:not([aria-current=page]){opacity:0.4}button[aria-disabled=true]{cursor:default}button[aria-current=page]{background-color:var(--limel-theme-surface-background-color);box-shadow:var(--button-shadow-inset)}button limel-spinner{position:absolute;pointer-events:none}.gap{display:inline-flex;align-items:center;justify-content:center;height:1.75rem;width:1.75rem;color:rgb(var(--contrast-1100))}.arrow span{display:block;border-style:solid;border-color:transparent;border-width:0.25rem 0 0.25rem 0.375rem;border-left-color:currentColor;transition:transform 0.2s ease}.arrow.previous span{transform:rotateZ(180deg)}.arrow:not([aria-disabled=true]):hover.next span{transform:translate3d(0.1rem, 0, 0)}.arrow:not([aria-disabled=true]):hover.previous span{transform:translate3d(-0.1rem, 0, 0) rotateZ(180deg)}.live-region{position:absolute;width:0;height:0;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0, 0, 0, 0);clip-path:inset(50%);white-space:nowrap}`;
7
+ const paginationCss = () => `@charset "UTF-8";:host(limel-pagination){display:block;box-sizing:border-box}*{box-sizing:border-box}nav{display:flex;align-items:center}button{appearance:none;background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;text-align:inherit}button:focus{outline:none}button:focus-visible{outline:none;box-shadow:var(--shadow-depth-8-focused)}button{position:relative;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;height:1.75rem;min-width:1.75rem;border-radius:1.75rem;padding:0 0.5rem;font-variant-numeric:tabular-nums}button:not([aria-disabled=true]):not([aria-current=page]){transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:rgb(var(--contrast-1100));background-color:transparent}button:not([aria-disabled=true]):not([aria-current=page]):hover,button:not([aria-disabled=true]):not([aria-current=page]):focus,button:not([aria-disabled=true]):not([aria-current=page]):focus-visible{will-change:color, background-color, box-shadow, transform}button:not([aria-disabled=true]):not([aria-current=page]):hover,button:not([aria-disabled=true]):not([aria-current=page]):focus-visible{transform:translate3d(0, 0.01rem, 0);color:var(--limel-theme-on-surface-color);background-color:var(--lime-elevated-surface-background-color)}button:not([aria-disabled=true]):not([aria-current=page]):hover{box-shadow:var(--button-shadow-hovered)}button:not([aria-disabled=true]):not([aria-current=page]):active{--limel-clickable-transform-timing-function:cubic-bezier( 0.83, -0.15, 0.49, 1.16 );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}button:not([aria-disabled=true]):not([aria-current=page]):hover,button:not([aria-disabled=true]):not([aria-current=page]):active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}button[aria-disabled=true]:not([aria-current=page]){opacity:0.4}button[aria-disabled=true]{cursor:default}button[aria-current=page]{background-color:var(--limel-theme-surface-background-color);box-shadow:var(--button-shadow-inset)}button limel-spinner{position:absolute;pointer-events:none}limel-popover{display:inline-flex}.gap{width:1.75rem;padding:0;color:rgb(var(--contrast-1100))}.gap[aria-expanded=true]{box-shadow:var(--button-shadow-inset-pressed) !important}.arrow span{display:block;border-style:solid;border-color:transparent;border-width:0.25rem 0 0.25rem 0.375rem;border-left-color:currentColor;transition:transform 0.2s ease}.arrow.previous span{transform:rotateZ(180deg)}.arrow:not([aria-disabled=true]):hover.next span{transform:translate3d(0.1rem, 0, 0)}.arrow:not([aria-disabled=true]):hover.previous span{transform:translate3d(-0.1rem, 0, 0) rotateZ(180deg)}.live-region{position:absolute;width:0;height:0;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0, 0, 0, 0);clip-path:inset(50%);white-space:nowrap}`;
121
8
 
122
9
  const FIRST_PAGE = 1;
123
10
  const DEFAULT_PAGE_SIZE = 100;
@@ -163,12 +50,15 @@ const Pagination = class {
163
50
  this.idPrefix = createRandomString();
164
51
  /** The value each prop was last complained about with. */
165
52
  this.warnedAbout = new Map();
53
+ /** The language `numberFormat` settled on, which may not be the prop. */
54
+ this.settledLanguage = FALLBACK_LANGUAGE;
166
55
  /** Settled once per render, and the only thing `render` reads. */
167
56
  this.view = {
168
57
  page: FIRST_PAGE,
169
58
  pageCount: null,
170
59
  pageSize: DEFAULT_PAGE_SIZE,
171
60
  totalItems: null,
61
+ slots: [],
172
62
  };
173
63
  /**
174
64
  * A gap marker, or a page button.
@@ -179,11 +69,38 @@ const Pagination = class {
179
69
  */
180
70
  this.renderSlot = (slot, index) => {
181
71
  if (slot.kind === 'gap') {
182
- return (h("span", { key: `gap-${index}`, class: "gap", "aria-hidden": "true" }, "\u00B7\u00B7\u00B7"));
72
+ return this.renderGap(index);
183
73
  }
184
74
  const isCurrent = slot.page === this.currentPage;
185
75
  return (h("button", { key: `page-${index}`, id: this.slotId(index), class: "page", "aria-current": isCurrent ? 'page' : null, "aria-disabled": this.loading ? 'true' : null, "aria-label": this.pageLabel(slot.page, isCurrent), "data-page": slot.page, onClick: this.selectPage }, this.formatNumber(slot.page), this.renderSpinner(isCurrent), this.renderTooltip(slot.page, index)));
186
76
  };
77
+ this.openJump = (event) => {
78
+ if (this.loading) {
79
+ return;
80
+ }
81
+ const { index } = event.currentTarget.dataset;
82
+ this.openGap = Number(index);
83
+ };
84
+ this.closeJump = () => {
85
+ this.openGap = undefined;
86
+ };
87
+ /**
88
+ * The control is told what to show, so a jump only asks. Focus goes back
89
+ * to the marker the field came out of, which is still on screen and will
90
+ * still be somewhere sensible if the consumer declines.
91
+ *
92
+ * @param event - the page the field asks for
93
+ */
94
+ this.handleJump = (event) => {
95
+ event.stopPropagation();
96
+ const page = event.detail;
97
+ this.focusGap(this.openGap);
98
+ this.openGap = undefined;
99
+ if (this.goTo(page)) {
100
+ this.awaitedJump = page;
101
+ this.jumpedFrom = this.view.page;
102
+ }
103
+ };
187
104
  // Bound once: a handler built per render is a new identity each time, so
188
105
  // every button would have its listener swapped on every page change.
189
106
  this.step = (event) => {
@@ -195,9 +112,6 @@ const Pagination = class {
195
112
  this.goTo(this.currentPage + (direction === 'next' ? 1 : -1));
196
113
  };
197
114
  this.selectPage = (event) => {
198
- if (this.loading) {
199
- return;
200
- }
201
115
  const { page } = event.currentTarget.dataset;
202
116
  this.goTo(Number(page));
203
117
  };
@@ -227,7 +141,9 @@ const Pagination = class {
227
141
  pageCount: pageCount,
228
142
  pageSize: pageSize,
229
143
  totalItems: totalItems,
144
+ slots: this.slotsFor(page, pageCount),
230
145
  };
146
+ this.closeJumpWithoutAGap();
231
147
  this.readOut(page);
232
148
  this.reconcile(page, usable);
233
149
  this.shownPage = page;
@@ -244,6 +160,10 @@ const Pagination = class {
244
160
  return Math.max(FIRST_PAGE, Math.ceil(total / pageSize));
245
161
  }
246
162
  componentDidRender() {
163
+ this.reportCorrection();
164
+ this.followJumpedPage();
165
+ }
166
+ reportCorrection() {
247
167
  const page = this.pendingCorrection;
248
168
  if (page === undefined) {
249
169
  return;
@@ -350,10 +270,23 @@ const Pagination = class {
350
270
  handleLanguageChange() {
351
271
  this.numberFormat = undefined;
352
272
  }
273
+ /**
274
+ * A gap is remembered by the position it sits in, and the positions are
275
+ * worked out afresh every render. A page set from outside can put a page
276
+ * number where the open gap was, taking the popover down without it ever
277
+ * closing — and leaving it to spring open by itself the next time a gap
278
+ * lands there.
279
+ */
280
+ closeJumpWithoutAGap() {
281
+ var _a;
282
+ const open = this.openGap;
283
+ if (open !== undefined && ((_a = this.view.slots[open]) === null || _a === void 0 ? void 0 : _a.kind) !== 'gap') {
284
+ this.openGap = undefined;
285
+ }
286
+ }
353
287
  render() {
354
- const { page, pageCount } = this.view;
355
- const slots = this.slotsFor(page, pageCount);
356
- return (h(Host, { key: '40d6123ac887f519fc31690fce7fcb46e73f2199' }, h("nav", { key: '183d264e761d168c74b8e2bfa8d04f3ee391c937', "aria-label": this.translate('pagination.label'), "aria-busy": this.loading ? 'true' : null }, this.renderArrow('previous'), slots.map((slot, index) => this.renderSlot(slot, index)), this.renderArrow('next')), h("span", { key: 'e59f62c2644a9a4a513ab3a3455854084434aabc', class: "live-region", "aria-live": "polite" }, this.liveMessage)));
288
+ const { slots } = this.view;
289
+ return (h(Host, { key: 'fac46260ef2a4e1e8d4aad962c90477831b6497f' }, h("nav", { key: '239f0ba745b9a385064c4a2c91a572e70a9e6525', "aria-label": this.translate('pagination.label'), "aria-busy": this.loading ? 'true' : null }, this.renderArrow('previous'), slots.map((slot, index) => this.renderSlot(slot, index)), this.renderArrow('next')), h("span", { key: '82fa3c9fb3fa8063be64d8373158d3d0e93138c1', class: "live-region", "aria-live": "polite" }, this.liveMessage)));
357
290
  }
358
291
  /**
359
292
  * Without a count we know where the user is but not how far the set goes,
@@ -370,6 +303,92 @@ const Pagination = class {
370
303
  }
371
304
  return getPageSlots(page, pageCount);
372
305
  }
306
+ /**
307
+ * A gap is a button, not a marker: the pages it stands for are still
308
+ * reachable, and typing one is the only way to reach any of them in a
309
+ * single move.
310
+ *
311
+ * Both gaps open the same field, and it accepts any page in the set.
312
+ * Scoping each one to the pages it happens to hide would make two
313
+ * identical markers behave differently, with nothing on screen to say
314
+ * which is which.
315
+ *
316
+ * @param index - where the gap sits in the window
317
+ * @returns the rendered gap
318
+ */
319
+ renderGap(index) {
320
+ const { pageCount } = this.view;
321
+ // A gap stands for pages that were left out, which cannot have
322
+ // happened before the count arrived: until then `slotsFor` renders
323
+ // the page the user is on and nothing else.
324
+ if (pageCount === null) {
325
+ return;
326
+ }
327
+ return (h("limel-popover", { key: `gap-${index}`, open: this.openGap === index, openDirection: "bottom", onClose: this.closeJump }, h("button", { slot: "trigger", class: "gap", id: this.slotId(index), "aria-label": this.translate('pagination.jump-to-a-page'), "aria-disabled": this.loading ? 'true' : null, "data-index": index, onClick: this.openJump }, "\u00B7\u00B7\u00B7"), h("limel-pagination-jump", { open: this.openGap === index, page: this.view.page, pageCount: pageCount, loading: this.loading, language: this.languageForNumbers, onJump: this.handleJump })));
328
+ }
329
+ focusGap(index) {
330
+ var _a;
331
+ const gap = (_a = this.host.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(`[id="${this.slotId(index)}"]`);
332
+ gap === null || gap === void 0 ? void 0 : gap.focus();
333
+ this.jumpFocus = gap;
334
+ }
335
+ /**
336
+ * Put the keyboard on the page a jump asked for, once the consumer has
337
+ * shown it.
338
+ *
339
+ * Committing tears down the popover the field was in, so between asking
340
+ * and arriving focus is on nothing. If the user has since put it somewhere
341
+ * of their own, arriving is no longer ours to report.
342
+ */
343
+ followJumpedPage() {
344
+ if (this.awaitedJump === undefined) {
345
+ return;
346
+ }
347
+ if (!this.ownsFocus()) {
348
+ this.forgetJump();
349
+ return;
350
+ }
351
+ if (this.view.page !== this.awaitedJump) {
352
+ // Still showing the page the jump was asked from is what waiting
353
+ // looks like. Anywhere else is an answer too — the consumer chose
354
+ // to show something else — and a later arrival at the page we
355
+ // asked for is then no longer ours to follow.
356
+ if (this.view.page !== this.jumpedFrom) {
357
+ this.forgetJump();
358
+ }
359
+ return;
360
+ }
361
+ this.forgetJump();
362
+ this.focusCurrentPage();
363
+ }
364
+ forgetJump() {
365
+ this.awaitedJump = undefined;
366
+ this.jumpedFrom = undefined;
367
+ }
368
+ /**
369
+ * Whether the keyboard is still where the jump put it. Somewhere else
370
+ * inside this component means the user moved it and it is theirs.
371
+ *
372
+ * The marker itself can also go: jumping from the left gap to page 3
373
+ * turns that slot into a page number, and the button holding focus is
374
+ * taken away with it. A browser answers that by focusing the body rather
375
+ * than nothing, so the marker having left the page is what we look for.
376
+ */
377
+ ownsFocus() {
378
+ var _a, _b;
379
+ const inside = (_a = this.host.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement;
380
+ if (inside === this.jumpFocus) {
381
+ return true;
382
+ }
383
+ return (!((_b = this.jumpFocus) === null || _b === void 0 ? void 0 : _b.isConnected) &&
384
+ document.activeElement === document.body);
385
+ }
386
+ focusCurrentPage() {
387
+ var _a;
388
+ const button = (_a = this.host.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('[aria-current="page"]');
389
+ button === null || button === void 0 ? void 0 : button.focus();
390
+ this.jumpFocus = undefined;
391
+ }
373
392
  /**
374
393
  * A spinner around the page the user is heading for, while it loads.
375
394
  *
@@ -432,13 +451,19 @@ const Pagination = class {
432
451
  return pageCount === null || page >= pageCount;
433
452
  }
434
453
  /**
454
+ * The one path every move the user asks for goes through, and so the one
455
+ * place that refuses while a page is still being fetched.
456
+ *
435
457
  * @param page - the page to ask for, 1-based
458
+ * @returns whether it was asked for
436
459
  */
437
460
  goTo(page) {
438
- if (page === this.currentPage) {
439
- return;
461
+ this.awaitedJump = undefined;
462
+ if (this.loading || page === this.currentPage) {
463
+ return false;
440
464
  }
441
465
  this.emitGoToPage(page, 'user');
466
+ return true;
442
467
  }
443
468
  /** The page on screen: the one asked for, within the range that exists. */
444
469
  get currentPage() {
@@ -574,6 +599,17 @@ const Pagination = class {
574
599
  (_a = this.numberFormat) !== null && _a !== void 0 ? _a : (this.numberFormat = this.createNumberFormat());
575
600
  return this.numberFormat.format(value);
576
601
  }
602
+ /**
603
+ * What the jump form is given, so that the one warning about a language
604
+ * this browser cannot write numbers in describes both of us. A tag it
605
+ * accepts but does not support, `zz`, resolves to the viewer's own locale
606
+ * rather than throwing, so asking the formatter is the only way to know.
607
+ */
608
+ get languageForNumbers() {
609
+ var _a;
610
+ (_a = this.numberFormat) !== null && _a !== void 0 ? _a : (this.numberFormat = this.createNumberFormat());
611
+ return this.settledLanguage;
612
+ }
577
613
  /**
578
614
  * `Intl.NumberFormat` throws on a language it cannot parse, and this is
579
615
  * called from `render`, so an unusable one would leave the control drawing
@@ -594,6 +630,7 @@ const Pagination = class {
594
630
  const resolved = format.resolvedOptions().locale;
595
631
  if (getPrimarySubtag(resolved) === getPrimarySubtag(language)) {
596
632
  this.warnedAbout.delete('language');
633
+ this.settledLanguage = language;
597
634
  return format;
598
635
  }
599
636
  }
@@ -604,8 +641,10 @@ const Pagination = class {
604
641
  // Where the translations land for the same unusable value, rather than
605
642
  // the viewer's own locale — English labels beside system digit
606
643
  // grouping would read differently on every machine.
644
+ this.settledLanguage = FALLBACK_LANGUAGE;
607
645
  return new Intl.NumberFormat(FALLBACK_LANGUAGE);
608
646
  }
647
+ get host() { return getElement(this); }
609
648
  static get watchers() { return {
610
649
  "language": [{
611
650
  "handleLanguageChange": 0
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, c as createEvent, h, a as getElement } from './index-Bnc9lzk2.js';
2
- import { t as translate } from './translations-Bwm2y2E4.js';
2
+ import { t as translate } from './translations-DMtX4tTX.js';
3
3
  import { i as isDescendant } from './dom-B9Ofc5RB.js';
4
4
  import { E as ESCAPE, T as TAB, a as ENTER, A as ARROW_UP, b as ARROW_DOWN } from './keycodes-C4_9qUMP.js';
5
5
  import { c as createRandomString } from './random-string-JbKhhoXs.js';
@@ -1,7 +1,7 @@
1
1
  import { r as registerInstance, c as createEvent, h, H as Host } from './index-Bnc9lzk2.js';
2
2
  import { i as isTypeAccepted } from './files-DnkFEKoB.js';
3
3
  import { g as getIconName } from './get-icon-props-CgNJbSP4.js';
4
- import { t as translate } from './translations-Bwm2y2E4.js';
4
+ import { t as translate } from './translations-DMtX4tTX.js';
5
5
  import { c as createRandomString } from './random-string-JbKhhoXs.js';
6
6
  import { r as resizeImage } from './image-resize-BTSG--2-.js';
7
7
  import { I as ImageTemplate } from './image.template-wqMwmOF-.js';
@@ -2,7 +2,7 @@ import { r as registerInstance, c as createEvent, h, H as Host, a as getElement
2
2
  import { L as LevelMapping, E as EditorMenuTypes, i as isInlineImageTag, M as MouseButtons, e as editorMenuTypesArray } from './types-C_Yu8dOg.js';
3
3
  import { g as getLinkAttributes, m as markdownToHTML, s as sanitizeHTML } from './markdown-parser-DrxxGLF5.js';
4
4
  import { h as cloneDeep } from './cloneDeep-CL7UD3mR.js';
5
- import { t as translate } from './translations-Bwm2y2E4.js';
5
+ import { t as translate } from './translations-DMtX4tTX.js';
6
6
  import { c as decodeHTML, e as decodeHTMLStrict } from './index-CbciMfiU.js';
7
7
  import { c as createRandomString } from './random-string-JbKhhoXs.js';
8
8
  import { i as isItem } from './is-item-CrvUOVvg.js';
@@ -1,6 +1,6 @@
1
1
  import { r as registerInstance, c as createEvent, h, H as Host } from './index-Bnc9lzk2.js';
2
2
  import { c as createRandomString } from './random-string-JbKhhoXs.js';
3
- import { t as translate } from './translations-Bwm2y2E4.js';
3
+ import { t as translate } from './translations-DMtX4tTX.js';
4
4
  import './language-C3hECvXE.js';
5
5
 
6
6
  /**
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, c as createEvent, h, a as getElement } from './index-Bnc9lzk2.js';
2
- import { t as translate } from './translations-Bwm2y2E4.js';
2
+ import { t as translate } from './translations-DMtX4tTX.js';
3
3
  import { c as createRandomString } from './random-string-JbKhhoXs.js';
4
4
  import './language-C3hECvXE.js';
5
5
 
@@ -2,7 +2,7 @@ import { r as registerInstance, c as createEvent, h, H as Host, a as getElement
2
2
  import { p as pickBy, n as negate, h as has } from './pickBy-C4C3CM4m.js';
3
3
  import { _ as _mapLayout } from './layout-C4zsCPOF.js';
4
4
  import { i as isEqual } from './isEqual-4tbMaaf_.js';
5
- import { t as translate } from './translations-Bwm2y2E4.js';
5
+ import { t as translate } from './translations-DMtX4tTX.js';
6
6
  import './_baseIteratee-CEZRuq23.js';
7
7
  import './_baseIsEqual-B6bIeexY.js';
8
8
  import './eq-CZ30nDJE.js';
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, c as createEvent, h } from './index-Bnc9lzk2.js';
2
- import { t as translate } from './translations-Bwm2y2E4.js';
2
+ import { t as translate } from './translations-DMtX4tTX.js';
3
3
  import { a as ENTER, E as ESCAPE } from './keycodes-C4_9qUMP.js';
4
4
  import './language-C3hECvXE.js';
5
5