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