@justeattakeaway/pie-pagination 0.0.0 → 0.1.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/README.md CHANGED
@@ -30,24 +30,25 @@ Ideally, you should install the component using the **`@justeattakeaway/pie-webc
30
30
  ## Documentation
31
31
 
32
32
  ### Properties
33
- | Prop | Options | Description | Default |
34
- |------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|
35
- | | | | |
33
+ | Prop | Options | Description | Default |
34
+ |---------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
35
+ | `currentPage` | `number`| The currently active page (1-based). This component is fully controlled, so it never updates this value itself; the consumer is responsible for updating it in response to the `pie-pagination-page-change` event. | `1` |
36
+ | `totalPages` | `number`| The total number of pages to render. | `1` |
37
+ | `disabled` | `boolean`| When true, all pagination controls are disabled. | `false` |
38
+ | `aria` | `object`| The ARIA attributes for the pagination landmark. Offers a `label` used for the `aria-label` of the wrapping `<nav>` element. | `undefined` |
36
39
 
37
40
  ### Slots
38
- | Slot | Description |
39
- |----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
40
- | | |
41
+ This component does not use any slots.
41
42
 
42
43
  ### CSS Variables
43
- | Variable | Description | Default |
44
- |----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
45
- | | | |
44
+ This component does not expose any CSS variables.
46
45
 
47
46
  ### Events
48
- | Event | Type | Description |
49
- |------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
50
- | | | |
47
+ | Event | Type | Description |
48
+ |-------------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
49
+ | `pie-pagination-page-change` | `CustomEvent` | Fired when the user interacts with any pagination control. The event detail contains `{ currentPage }`, the page the user wants to navigate to. |
50
+ | `pie-pagination-prev` | `CustomEvent` | Fired when the user clicks the "previous" control. The event detail contains `{ currentPage }`. This event fires **in addition to** `pie-pagination-page-change`. |
51
+ | `pie-pagination-next` | `CustomEvent` | Fired when the user clicks the "next" control. The event detail contains `{ currentPage }`. This event fires **in addition to** `pie-pagination-page-change`. |
51
52
 
52
53
  ## Usage Examples
53
54
 
@@ -64,12 +65,44 @@ import '@justeattakeaway/pie-webc/components/pagination.js'
64
65
  <script type="module" src="/main.js"></script>
65
66
  ```
66
67
 
68
+ ```html
69
+ <pie-pagination currentPage="2" totalPages="10"></pie-pagination>
70
+
71
+ <script>
72
+ const pagination = document.querySelector('pie-pagination');
73
+
74
+ pagination.addEventListener('pie-pagination-page-change', (event) => {
75
+ // The component is controlled — update the prop yourself
76
+ pagination.currentPage = event.detail.currentPage;
77
+ });
78
+ </script>
79
+ ```
80
+
81
+ The `pie-pagination-prev` and `pie-pagination-next` events let you hook into the previous/next controls specifically. They fire in addition to `pie-pagination-page-change`, so you can use either one:
82
+
83
+ ```html
84
+ <pie-pagination currentPage="2" totalPages="10"></pie-pagination>
85
+
86
+ <script>
87
+ const pagination = document.querySelector('pie-pagination');
88
+
89
+ pagination.addEventListener('pie-pagination-prev', (event) => {
90
+ console.log('previous clicked, requested page:', event.detail.currentPage);
91
+ pagination.currentPage = event.detail.currentPage;
92
+ });
93
+
94
+ pagination.addEventListener('pie-pagination-next', (event) => {
95
+ console.log('next clicked, requested page:', event.detail.currentPage);
96
+ pagination.currentPage = event.detail.currentPage;
97
+ });
98
+ </script>
99
+ ```
100
+
67
101
  **For Native JS Applications, Vue, Angular, Svelte etc.:**
68
102
 
69
103
  ```js
70
104
  // Vue templates (using Nuxt 3)
71
105
  import '@justeattakeaway/pie-webc/components/pagination.js'
72
-
73
106
  ```
74
107
 
75
108
  **For React Applications:**
@@ -77,6 +110,22 @@ import '@justeattakeaway/pie-webc/components/pagination.js'
77
110
  ```jsx
78
111
  import { PiePagination } from '@justeattakeaway/pie-webc/react/pagination.js';
79
112
 
113
+ <PiePagination
114
+ currentPage={currentPage}
115
+ totalPages={totalPages}
116
+ onPiePaginationPageChange={(event) => setCurrentPage(event.detail.currentPage)}
117
+ />
118
+ ```
119
+
120
+ The `pie-pagination-prev` and `pie-pagination-next` events are exposed as `onPiePaginationPrev` and `onPiePaginationNext`:
121
+
122
+ ```jsx
123
+ <PiePagination
124
+ currentPage={currentPage}
125
+ totalPages={totalPages}
126
+ onPiePaginationPrev={(event) => setCurrentPage(event.detail.currentPage)}
127
+ onPiePaginationNext={(event) => setCurrentPage(event.detail.currentPage)}
128
+ />
80
129
  ```
81
130
 
82
131
  ## Questions and Support
@@ -11,8 +11,77 @@
11
11
  {
12
12
  "kind": "javascript-module",
13
13
  "path": "src/defs.js",
14
- "declarations": [],
15
- "exports": []
14
+ "declarations": [
15
+ {
16
+ "kind": "variable",
17
+ "name": "ON_PAGE_CHANGE_EVENT",
18
+ "type": {
19
+ "text": "string"
20
+ },
21
+ "default": "'pie-pagination-page-change'",
22
+ "description": "The event name dispatched when the user interacts with a pagination control.\nThe component is fully controlled: it never changes `currentPage` itself, it\nonly tells the consumer which page the user wants to navigate to."
23
+ },
24
+ {
25
+ "kind": "variable",
26
+ "name": "ON_PREV_EVENT",
27
+ "type": {
28
+ "text": "string"
29
+ },
30
+ "default": "'pie-pagination-prev'",
31
+ "description": "The event name dispatched when the user clicks the \"previous\" control."
32
+ },
33
+ {
34
+ "kind": "variable",
35
+ "name": "ON_NEXT_EVENT",
36
+ "type": {
37
+ "text": "string"
38
+ },
39
+ "default": "'pie-pagination-next'",
40
+ "description": "The event name dispatched when the user clicks the \"next\" control."
41
+ },
42
+ {
43
+ "kind": "variable",
44
+ "name": "defaultProps",
45
+ "type": {
46
+ "text": "DefaultProps"
47
+ },
48
+ "default": "{ currentPage: 1, totalPages: 1, disabled: false, }"
49
+ }
50
+ ],
51
+ "exports": [
52
+ {
53
+ "kind": "js",
54
+ "name": "ON_PAGE_CHANGE_EVENT",
55
+ "declaration": {
56
+ "name": "ON_PAGE_CHANGE_EVENT",
57
+ "module": "src/defs.js"
58
+ }
59
+ },
60
+ {
61
+ "kind": "js",
62
+ "name": "ON_PREV_EVENT",
63
+ "declaration": {
64
+ "name": "ON_PREV_EVENT",
65
+ "module": "src/defs.js"
66
+ }
67
+ },
68
+ {
69
+ "kind": "js",
70
+ "name": "ON_NEXT_EVENT",
71
+ "declaration": {
72
+ "name": "ON_NEXT_EVENT",
73
+ "module": "src/defs.js"
74
+ }
75
+ },
76
+ {
77
+ "kind": "js",
78
+ "name": "defaultProps",
79
+ "declaration": {
80
+ "name": "defaultProps",
81
+ "module": "src/defs.js"
82
+ }
83
+ }
84
+ ]
16
85
  },
17
86
  {
18
87
  "kind": "javascript-module",
@@ -22,7 +91,133 @@
22
91
  "kind": "class",
23
92
  "description": "",
24
93
  "name": "PiePagination",
25
- "members": [],
94
+ "members": [
95
+ {
96
+ "kind": "field",
97
+ "name": "aria",
98
+ "type": {
99
+ "text": "PaginationProps['aria']"
100
+ },
101
+ "privacy": "public",
102
+ "attribute": "aria"
103
+ },
104
+ {
105
+ "kind": "field",
106
+ "name": "currentPage",
107
+ "privacy": "public",
108
+ "attribute": "currentPage"
109
+ },
110
+ {
111
+ "kind": "field",
112
+ "name": "totalPages",
113
+ "privacy": "public",
114
+ "attribute": "totalPages"
115
+ },
116
+ {
117
+ "kind": "field",
118
+ "name": "disabled",
119
+ "privacy": "public",
120
+ "attribute": "disabled"
121
+ },
122
+ {
123
+ "kind": "method",
124
+ "name": "_emitPageChange",
125
+ "privacy": "private",
126
+ "parameters": [
127
+ {
128
+ "name": "currentPage",
129
+ "type": {
130
+ "text": "number"
131
+ }
132
+ }
133
+ ],
134
+ "description": "Emits the page change event with the page the user wants to navigate to.\nThe component never updates `currentPage` itself."
135
+ },
136
+ {
137
+ "kind": "method",
138
+ "name": "_handlePreviousClick",
139
+ "privacy": "private",
140
+ "description": "Handles a click on the \"previous\" control."
141
+ },
142
+ {
143
+ "kind": "method",
144
+ "name": "_handleNextClick",
145
+ "privacy": "private",
146
+ "description": "Handles a click on the \"next\" control."
147
+ },
148
+ {
149
+ "kind": "method",
150
+ "name": "_handlePageClick",
151
+ "privacy": "private",
152
+ "parameters": [
153
+ {
154
+ "name": "page",
155
+ "type": {
156
+ "text": "number"
157
+ }
158
+ }
159
+ ],
160
+ "description": "Handles a click on a page number control."
161
+ },
162
+ {
163
+ "kind": "method",
164
+ "name": "_renderChevronIcon",
165
+ "privacy": "private",
166
+ "parameters": [
167
+ {
168
+ "name": "direction",
169
+ "type": {
170
+ "text": "'previous' | 'next'"
171
+ }
172
+ }
173
+ ],
174
+ "description": "Renders the chevron icon for the previous/next controls, mirroring it for RTL."
175
+ }
176
+ ],
177
+ "events": [
178
+ {
179
+ "type": {
180
+ "text": "CustomEvent"
181
+ },
182
+ "description": "when the user interacts with a pagination control.",
183
+ "name": "pie-pagination-page-change"
184
+ },
185
+ {
186
+ "type": {
187
+ "text": "CustomEvent"
188
+ },
189
+ "description": "when the user clicks the \"previous\" control.",
190
+ "name": "pie-pagination-prev"
191
+ },
192
+ {
193
+ "type": {
194
+ "text": "CustomEvent"
195
+ },
196
+ "description": "when the user clicks the \"next\" control.",
197
+ "name": "pie-pagination-next"
198
+ }
199
+ ],
200
+ "attributes": [
201
+ {
202
+ "name": "aria",
203
+ "type": {
204
+ "text": "PaginationProps['aria']"
205
+ },
206
+ "fieldName": "aria"
207
+ },
208
+ {
209
+ "name": "currentPage",
210
+ "fieldName": "currentPage"
211
+ },
212
+ {
213
+ "name": "totalPages",
214
+ "fieldName": "totalPages"
215
+ },
216
+ {
217
+ "name": "disabled",
218
+ "fieldName": "disabled"
219
+ }
220
+ ],
26
221
  "mixins": [
27
222
  {
28
223
  "name": "RtlMixin",
package/dist/index.d.ts CHANGED
@@ -1,16 +1,107 @@
1
+ import { ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
1
2
  import { CSSResult } from 'lit';
2
3
  import { GenericConstructor } from '@justeattakeaway/pie-webc-core';
3
4
  import { PieElement } from '@justeattakeaway/pie-webc-core/src/internals/PieElement';
5
+ import { PropertyValues } from 'lit';
4
6
  import { RTLInterface } from '@justeattakeaway/pie-webc-core';
5
7
  import { TemplateResult } from 'lit-html';
6
8
 
9
+ declare type AriaProps = {
10
+ label?: string;
11
+ };
12
+
13
+ export declare type DefaultProps = ComponentDefaultProps<PaginationProps, 'currentPage' | 'totalPages' | 'disabled'>;
14
+
15
+ export declare const defaultProps: DefaultProps;
16
+
17
+ /**
18
+ * The event name dispatched when the user clicks the "next" control.
19
+ * @constant
20
+ */
21
+ export declare const ON_NEXT_EVENT = "pie-pagination-next";
22
+
23
+ /**
24
+ * The event name dispatched when the user interacts with a pagination control.
25
+ * The component is fully controlled: it never changes `currentPage` itself, it
26
+ * only tells the consumer which page the user wants to navigate to.
27
+ * @constant
28
+ */
29
+ export declare const ON_PAGE_CHANGE_EVENT = "pie-pagination-page-change";
30
+
31
+ /**
32
+ * The event name dispatched when the user clicks the "previous" control.
33
+ * @constant
34
+ */
35
+ export declare const ON_PREV_EVENT = "pie-pagination-prev";
36
+
7
37
  export declare interface PaginationProps {
38
+ /**
39
+ * The ARIA attributes for the pagination landmark. Offers a `label` used for
40
+ * the `aria-label` of the wrapping `<nav>` element.
41
+ */
42
+ aria?: AriaProps;
43
+ /**
44
+ * The currently active page (1-based). This component is fully controlled, so
45
+ * it never updates this value itself; the consumer is responsible for updating
46
+ * it in response to the `pie-pagination-page-change` event.
47
+ * @default 1
48
+ */
49
+ currentPage?: number;
50
+ /**
51
+ * The total number of pages to render.
52
+ * @default 1
53
+ */
54
+ totalPages?: number;
55
+ /**
56
+ * When true, all pagination controls are disabled.
57
+ * @default false
58
+ */
59
+ disabled?: boolean;
8
60
  }
9
61
 
10
62
  /**
11
63
  * @tagname pie-pagination
64
+ * @event {CustomEvent} pie-pagination-page-change - when the user interacts with a pagination control.
65
+ * @event {CustomEvent} pie-pagination-prev - when the user clicks the "previous" control.
66
+ * @event {CustomEvent} pie-pagination-next - when the user clicks the "next" control.
12
67
  */
13
68
  export declare class PiePagination extends PiePagination_base implements PaginationProps {
69
+ aria: PaginationProps['aria'];
70
+ currentPage: number;
71
+ totalPages: number;
72
+ disabled: boolean;
73
+ protected updated(changedProperties: PropertyValues<this>): void;
74
+ /**
75
+ * Emits the page change event with the page the user wants to navigate to.
76
+ * The component never updates `currentPage` itself.
77
+ *
78
+ * @private
79
+ */
80
+ private _emitPageChange;
81
+ /**
82
+ * Handles a click on the "previous" control.
83
+ *
84
+ * @private
85
+ */
86
+ private _handlePreviousClick;
87
+ /**
88
+ * Handles a click on the "next" control.
89
+ *
90
+ * @private
91
+ */
92
+ private _handleNextClick;
93
+ /**
94
+ * Handles a click on a page number control.
95
+ *
96
+ * @private
97
+ */
98
+ private _handlePageClick;
99
+ /**
100
+ * Renders the chevron icon for the previous/next controls, mirroring it for RTL.
101
+ *
102
+ * @private
103
+ */
104
+ private _renderChevronIcon;
14
105
  render(): TemplateResult<1>;
15
106
  static styles: CSSResult;
16
107
  }
package/dist/index.js CHANGED
@@ -1,27 +1,160 @@
1
- import { LitElement as f, html as h, unsafeCSS as v } from "lit";
2
- import { RtlMixin as c, safeCustomElement as d } from "@justeattakeaway/pie-webc-core";
3
- const e = class e extends f {
1
+ import { LitElement as u, html as p, unsafeCSS as x } from "lit";
2
+ import { property as g } from "lit/decorators.js";
3
+ import { classMap as f } from "lit/directives/class-map.js";
4
+ import { ifDefined as P } from "lit/directives/if-defined.js";
5
+ import { RtlMixin as y, dispatchCustomEvent as b, safeCustomElement as z } from "@justeattakeaway/pie-webc-core";
6
+ import "@justeattakeaway/pie-icon-button";
7
+ import "@justeattakeaway/pie-icons-webc/dist/IconChevronLeft.js";
8
+ import "@justeattakeaway/pie-icons-webc/dist/IconChevronRight.js";
9
+ const v = class v extends u {
4
10
  willUpdate() {
5
- this.getAttribute("v") || this.setAttribute("v", e.v);
11
+ this.getAttribute("v") || this.setAttribute("v", v.v);
6
12
  }
7
13
  };
8
- e.v = "0.0.0";
9
- let i = e;
10
- const g = "*,*:after,*:before{box-sizing:inherit}:host{display:block}";
11
- var u = Object.getOwnPropertyDescriptor, b = (a, n, p, o) => {
12
- for (var t = o > 1 ? void 0 : o ? u(n, p) : n, s = a.length - 1, l; s >= 0; s--)
13
- (l = a[s]) && (t = l(t) || t);
14
- return t;
14
+ v.v = "0.1.0";
15
+ let m = v;
16
+ const _ = "*,*:after,*:before{box-sizing:inherit}:host{display:inline-block}.c-pagination{display:inline-block}.c-pagination-list{display:flex;align-items:center;gap:var(--dt-spacing-b);margin:0;padding:0;list-style:none}.c-pagination-item{display:flex;align-items:center}.c-pagination-control{--btn-border-radius: var(--dt-radius-rounded-e);--btn-font-family: var(--dt-font-interactive-l-family);--btn-font-weight: var(--dt-font-interactive-l-weight);--int-states-mixin-bg-color: var(--dt-color-interactive-brand);--btn-text-color: var(--dt-color-content-interactive-light-solid);--btn-padding-vertical-xsmall: 6px;--btn-padding-vertical-small-expressive: 8px;--btn-padding-vertical-small-productive: 10px;--btn-padding-vertical-medium: 12px;--btn-padding-vertical-large: 16px;--btn-padding-horizontal-small: var(--dt-spacing-b);--btn-padding-horizontal-medium: var(--dt-spacing-d);--btn-padding-horizontal-large: var(--dt-spacing-e);position:relative;display:inline-flex;gap:var(--dt-spacing-b);align-items:center;justify-content:center;border:none;border-radius:var(--btn-border-radius);outline:none;background-color:var(--int-states-mixin-bg-color);cursor:pointer;-webkit-user-select:none;user-select:none;text-decoration:none;font-family:var(--btn-font-family);font-size:var(--btn-font-size);font-weight:var(--btn-font-weight);color:var(--btn-text-color);line-height:var(--btn-line-height);inline-size:var(--btn-inline-size)}.c-pagination-control:focus-visible{box-shadow:0 0 0 2px var(--dt-color-focus-inner),0 0 0 4px var(--dt-color-focus-outer);outline:none}.c-pagination-control{--btn-font-size: calc(var(--dt-font-interactive-xs-size) * 1px);--btn-line-height: calc(var(--dt-font-interactive-xs-line-height) * 1px);--btn-icon-size: 16px;--icon-size-override: 16px;padding:var(--btn-padding-vertical-xsmall) var(--btn-padding-horizontal-small)}@media(min-width:769px){.c-pagination-control.c-button--responsive{--btn-font-size: calc(var(--dt-font-interactive-s-size) * 1px);--btn-line-height: calc(var(--dt-font-interactive-s-line-height) * 1px);--btn-icon-size: 20px;--icon-size-override: 20px;padding:var(--btn-padding-vertical-small-productive) var(--btn-padding-horizontal-medium)}.c-pagination-control.c-button--responsive.c-button--expressive{--btn-font-size: calc(var(--dt-font-interactive-l-size) * 1px);--btn-line-height: calc(var(--dt-font-interactive-l-line-height) * 1px);--btn-icon-size: 20px;--icon-size-override: 20px;padding:var(--btn-padding-vertical-small-expressive) var(--btn-padding-horizontal-medium)}}.c-pagination-control.c-button--outline,.c-pagination-control.c-button--outline-inverse{padding:calc(var(--btn-padding-vertical-xsmall) - 1px) var(--btn-padding-horizontal-small)}@media(min-width:769px){.c-pagination-control.c-button--outline.c-button--responsive,.c-pagination-control.c-button--outline-inverse.c-button--responsive{padding:calc(var(--btn-padding-vertical-small-productive) - 1px) var(--btn-padding-horizontal-medium)}.c-pagination-control.c-button--outline.c-button--responsive.c-button--expressive,.c-pagination-control.c-button--outline-inverse.c-button--responsive.c-button--expressive{padding:calc(var(--btn-padding-vertical-small-expressive) - 1px) var(--btn-padding-horizontal-medium)}}.c-pagination-control{--int-states-mixin-bg-color: transparent;--btn-text-color: var(--dt-color-content-interactive-secondary-solid)}@media(hover:hover){.c-pagination-control:hover:not(:disabled,.is-disabled,.is-dismissible){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--hover-modifier: var(--dt-color-hover-01);--int-states-mixin-bg-color: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--hover-modifier));--int-states-mixin-bg-color: hsl(var(--dt-color-transparent-h), var(--dt-color-transparent-s), calc(var(--dt-color-transparent-l) + var(--hover-modifier)))}}.c-pagination-control:active:not(:disabled,.is-disabled,.is-dismissible),.c-pagination-control.is-loading:not(:disabled,.is-disabled){--active-modifier: calc(-1 * var(--dt-color-active-01));--active-modifier: var(--dt-color-active-01);--int-states-mixin-bg-color: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--active-modifier));--int-states-mixin-bg-color: hsl(var(--dt-color-transparent-h), var(--dt-color-transparent-s), calc(var(--dt-color-transparent-l) + var(--active-modifier)))}@supports (background-color: color-mix(in srgb,black,white)){@media(hover:hover){.c-pagination-control:hover:not(:disabled,.is-disabled,.is-dismissible){--int-states-mixin-bg-color: color-mix(in srgb, var(--dt-color-hover-01-bg) var(--dt-color-hover-01), var(--dt-color-transparent))}}.c-pagination-control:active:not(:disabled,.is-disabled,.is-dismissible),.c-pagination-control.is-loading:not(:disabled,.is-disabled){--int-states-mixin-bg-color: color-mix(in srgb, var(--dt-color-active-01-bg) var(--dt-color-active-01), var(--dt-color-transparent))}}.c-pagination-control{inline-size:32px;block-size:32px;padding:0;--btn-font-weight: var(--dt-font-body-s-weight)}.c-pagination-control.c-pagination-control--current{--int-states-mixin-bg-color: var(--dt-color-interactive-primary);--btn-text-color: var(--dt-color-content-interactive-primary)}@media(hover:hover){.c-pagination-control.c-pagination-control--current:hover:not(:disabled,.is-disabled,.is-dismissible){--hover-modifier: var(--dt-color-hover-02);--int-states-mixin-bg-color: hsl(var(--dt-color-interactive-primary-h), var(--dt-color-interactive-primary-s), calc(var(--dt-color-interactive-primary-l) + var(--hover-modifier)))}}.c-pagination-control.c-pagination-control--current:active:not(:disabled,.is-disabled,.is-dismissible),.c-pagination-control.c-pagination-control--current.is-loading:not(:disabled,.is-disabled){--active-modifier: var(--dt-color-active-02);--int-states-mixin-bg-color: hsl(var(--dt-color-interactive-primary-h), var(--dt-color-interactive-primary-s), calc(var(--dt-color-interactive-primary-l) + var(--active-modifier)))}@supports (background-color: color-mix(in srgb,black,white)){@media(hover:hover){.c-pagination-control.c-pagination-control--current:hover:not(:disabled,.is-disabled,.is-dismissible){--int-states-mixin-bg-color: color-mix(in srgb, var(--dt-color-hover-02-bg) var(--dt-color-hover-02), var(--dt-color-interactive-primary))}}.c-pagination-control.c-pagination-control--current:active:not(:disabled,.is-disabled,.is-dismissible),.c-pagination-control.c-pagination-control--current.is-loading:not(:disabled,.is-disabled){--int-states-mixin-bg-color: color-mix(in srgb, var(--dt-color-active-02-bg) var(--dt-color-active-02), var(--dt-color-interactive-primary))}}.c-pagination-control.c-pagination-control--current{--btn-font-weight: var(--dt-font-body-strong-s-weight)}.c-pagination-control:disabled{--int-states-mixin-bg-color: transparent;--btn-text-color: var(--dt-color-content-disabled-solid);cursor:not-allowed}", w = "pie-pagination-page-change", $ = "pie-pagination-prev", k = "pie-pagination-next", h = {
17
+ currentPage: 1,
18
+ totalPages: 1,
19
+ disabled: !1
15
20
  };
16
- let r = class extends c(i) {
21
+ var C = Object.defineProperty, N = Object.getOwnPropertyDescriptor, l = (t, i, n, e) => {
22
+ for (var a = e > 1 ? void 0 : e ? N(i, n) : i, r = t.length - 1, s; r >= 0; r--)
23
+ (s = t[r]) && (a = (e ? s(i, n, a) : s(a)) || a);
24
+ return e && a && C(i, n, a), a;
25
+ };
26
+ let o = class extends y(m) {
27
+ constructor() {
28
+ super(...arguments), this.currentPage = h.currentPage, this.totalPages = h.totalPages, this.disabled = h.disabled;
29
+ }
30
+ updated(t) {
31
+ t.has("totalPages") && this.totalPages < 1 && console.warn(`pie-pagination: "totalPages" must be at least 1, received "${this.totalPages}".`), t.has("currentPage") && this.currentPage < 1 && console.warn(`pie-pagination: "currentPage" must be at least 1, received "${this.currentPage}".`), t.has("currentPage") && this.currentPage > this.totalPages && console.warn(`pie-pagination: "currentPage" (${this.currentPage}) cannot be greater than "totalPages" (${this.totalPages}).`);
32
+ }
33
+ /**
34
+ * Emits the page change event with the page the user wants to navigate to.
35
+ * The component never updates `currentPage` itself.
36
+ *
37
+ * @private
38
+ */
39
+ _emitPageChange(t) {
40
+ b(this, w, { currentPage: t });
41
+ }
42
+ /**
43
+ * Handles a click on the "previous" control.
44
+ *
45
+ * @private
46
+ */
47
+ _handlePreviousClick() {
48
+ if (this.disabled || this.currentPage <= 1) return;
49
+ const t = this.currentPage - 1;
50
+ b(this, $, { currentPage: t }), this._emitPageChange(t);
51
+ }
52
+ /**
53
+ * Handles a click on the "next" control.
54
+ *
55
+ * @private
56
+ */
57
+ _handleNextClick() {
58
+ if (this.disabled || this.currentPage >= this.totalPages) return;
59
+ const t = this.currentPage + 1;
60
+ b(this, k, { currentPage: t }), this._emitPageChange(t);
61
+ }
62
+ /**
63
+ * Handles a click on a page number control.
64
+ *
65
+ * @private
66
+ */
67
+ _handlePageClick(t) {
68
+ this.disabled || t === this.currentPage || this._emitPageChange(t);
69
+ }
70
+ /**
71
+ * Renders the chevron icon for the previous/next controls, mirroring it for RTL.
72
+ *
73
+ * @private
74
+ */
75
+ _renderChevronIcon(t) {
76
+ return (t === "previous" ? !this.isRTL : this.isRTL) ? p`<icon-chevron-left></icon-chevron-left>` : p`<icon-chevron-right></icon-chevron-right>`;
77
+ }
17
78
  render() {
18
- return h`<h1 data-test-id="pie-pagination">Hello world!</h1>`;
79
+ const {
80
+ aria: t,
81
+ currentPage: i,
82
+ disabled: n,
83
+ totalPages: e
84
+ } = this, a = Array.from({ length: Math.max(e, 0) }, (c, d) => d + 1), r = n || i <= 1, s = n || i >= e;
85
+ return p`
86
+ <nav
87
+ class="c-pagination"
88
+ aria-label="${(t == null ? void 0 : t.label) ?? "Pagination"}"
89
+ data-test-id="pie-pagination">
90
+ <ol class="c-pagination-list" data-test-id="pie-pagination-list">
91
+ <li class="c-pagination-item">
92
+ <pie-icon-button
93
+ data-test-id="pie-pagination-previous"
94
+ size="xsmall"
95
+ variant="ghost-secondary"
96
+ ?disabled="${r}"
97
+ .aria="${{ label: "Previous page" }}"
98
+ @click="${this._handlePreviousClick}">
99
+ ${this._renderChevronIcon("previous")}
100
+ </pie-icon-button>
101
+ </li>
102
+
103
+ ${a.map((c) => {
104
+ const d = c === i;
105
+ return p`
106
+ <li class="c-pagination-item">
107
+ <button
108
+ type="button"
109
+ class="${f({
110
+ "c-pagination-control": !0,
111
+ "c-pagination-control--current": d
112
+ })}"
113
+ data-test-id="pie-pagination-page"
114
+ ?disabled="${n}"
115
+ aria-current="${P(d ? "page" : void 0)}"
116
+ aria-label="Page ${c}"
117
+ @click="${() => this._handlePageClick(c)}">
118
+ ${c}
119
+ </button>
120
+ </li>`;
121
+ })}
122
+
123
+ <li class="c-pagination-item">
124
+ <pie-icon-button
125
+ data-test-id="pie-pagination-next"
126
+ size="xsmall"
127
+ variant="ghost-secondary"
128
+ ?disabled="${s}"
129
+ .aria="${{ label: "Next page" }}"
130
+ @click="${this._handleNextClick}">
131
+ ${this._renderChevronIcon("next")}
132
+ </pie-icon-button>
133
+ </li>
134
+ </ol>
135
+ </nav>`;
19
136
  }
20
137
  };
21
- r.styles = v(g);
22
- r = b([
23
- d("pie-pagination")
24
- ], r);
138
+ o.styles = x(_);
139
+ l([
140
+ g({ type: Object })
141
+ ], o.prototype, "aria", 2);
142
+ l([
143
+ g({ type: Number })
144
+ ], o.prototype, "currentPage", 2);
145
+ l([
146
+ g({ type: Number })
147
+ ], o.prototype, "totalPages", 2);
148
+ l([
149
+ g({ type: Boolean })
150
+ ], o.prototype, "disabled", 2);
151
+ o = l([
152
+ z("pie-pagination")
153
+ ], o);
25
154
  export {
26
- r as PiePagination
155
+ k as ON_NEXT_EVENT,
156
+ w as ON_PAGE_CHANGE_EVENT,
157
+ $ as ON_PREV_EVENT,
158
+ o as PiePagination,
159
+ h as defaultProps
27
160
  };
package/dist/react.d.ts CHANGED
@@ -1,25 +1,122 @@
1
+ import { ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
1
2
  import { CSSResult } from 'lit';
2
3
  import { GenericConstructor } from '@justeattakeaway/pie-webc-core';
3
4
  import { PieElement } from '@justeattakeaway/pie-webc-core/src/internals/PieElement';
5
+ import { PropertyValues } from 'lit';
4
6
  import * as React_2 from 'react';
5
7
  import { RTLInterface } from '@justeattakeaway/pie-webc-core';
6
8
  import { TemplateResult } from 'lit-html';
7
9
 
10
+ declare type AriaProps = {
11
+ label?: string;
12
+ };
13
+
14
+ export declare type DefaultProps = ComponentDefaultProps<PaginationProps, 'currentPage' | 'totalPages' | 'disabled'>;
15
+
16
+ export declare const defaultProps: DefaultProps;
17
+
18
+ /**
19
+ * The event name dispatched when the user clicks the "next" control.
20
+ * @constant
21
+ */
22
+ export declare const ON_NEXT_EVENT = "pie-pagination-next";
23
+
24
+ /**
25
+ * The event name dispatched when the user interacts with a pagination control.
26
+ * The component is fully controlled: it never changes `currentPage` itself, it
27
+ * only tells the consumer which page the user wants to navigate to.
28
+ * @constant
29
+ */
30
+ export declare const ON_PAGE_CHANGE_EVENT = "pie-pagination-page-change";
31
+
32
+ /**
33
+ * The event name dispatched when the user clicks the "previous" control.
34
+ * @constant
35
+ */
36
+ export declare const ON_PREV_EVENT = "pie-pagination-prev";
37
+
8
38
  export declare interface PaginationProps {
39
+ /**
40
+ * The ARIA attributes for the pagination landmark. Offers a `label` used for
41
+ * the `aria-label` of the wrapping `<nav>` element.
42
+ */
43
+ aria?: AriaProps;
44
+ /**
45
+ * The currently active page (1-based). This component is fully controlled, so
46
+ * it never updates this value itself; the consumer is responsible for updating
47
+ * it in response to the `pie-pagination-page-change` event.
48
+ * @default 1
49
+ */
50
+ currentPage?: number;
51
+ /**
52
+ * The total number of pages to render.
53
+ * @default 1
54
+ */
55
+ totalPages?: number;
56
+ /**
57
+ * When true, all pagination controls are disabled.
58
+ * @default false
59
+ */
60
+ disabled?: boolean;
9
61
  }
10
62
 
11
- export declare const PiePagination: React_2.ForwardRefExoticComponent<React_2.PropsWithChildren<Omit<React_2.PropsWithoutRef<PaginationProps>, "children">> & React_2.RefAttributes<PiePagination_2> & ReactBaseType>;
63
+ export declare const PiePagination: React_2.ForwardRefExoticComponent<React_2.PropsWithChildren<Omit<React_2.PropsWithoutRef<PaginationProps>, "children">> & React_2.RefAttributes<PiePagination_2> & PiePaginationEvents & ReactBaseType>;
12
64
 
13
65
  /**
14
66
  * @tagname pie-pagination
67
+ * @event {CustomEvent} pie-pagination-page-change - when the user interacts with a pagination control.
68
+ * @event {CustomEvent} pie-pagination-prev - when the user clicks the "previous" control.
69
+ * @event {CustomEvent} pie-pagination-next - when the user clicks the "next" control.
15
70
  */
16
71
  declare class PiePagination_2 extends PiePagination_base implements PaginationProps {
72
+ aria: PaginationProps['aria'];
73
+ currentPage: number;
74
+ totalPages: number;
75
+ disabled: boolean;
76
+ protected updated(changedProperties: PropertyValues<this>): void;
77
+ /**
78
+ * Emits the page change event with the page the user wants to navigate to.
79
+ * The component never updates `currentPage` itself.
80
+ *
81
+ * @private
82
+ */
83
+ private _emitPageChange;
84
+ /**
85
+ * Handles a click on the "previous" control.
86
+ *
87
+ * @private
88
+ */
89
+ private _handlePreviousClick;
90
+ /**
91
+ * Handles a click on the "next" control.
92
+ *
93
+ * @private
94
+ */
95
+ private _handleNextClick;
96
+ /**
97
+ * Handles a click on a page number control.
98
+ *
99
+ * @private
100
+ */
101
+ private _handlePageClick;
102
+ /**
103
+ * Renders the chevron icon for the previous/next controls, mirroring it for RTL.
104
+ *
105
+ * @private
106
+ */
107
+ private _renderChevronIcon;
17
108
  render(): TemplateResult<1>;
18
109
  static styles: CSSResult;
19
110
  }
20
111
 
21
112
  declare const PiePagination_base: GenericConstructor<RTLInterface> & typeof PieElement;
22
113
 
114
+ declare type PiePaginationEvents = {
115
+ onPiePaginationPageChange?: (event: CustomEvent) => void;
116
+ onPiePaginationPrev?: (event: CustomEvent) => void;
117
+ onPiePaginationNext?: (event: CustomEvent) => void;
118
+ };
119
+
23
120
  declare type ReactBaseType = React_2.HTMLAttributes<HTMLElement>;
24
121
 
25
122
  export { }
package/dist/react.js CHANGED
@@ -1,13 +1,25 @@
1
1
  import * as a from "react";
2
2
  import { createComponent as i } from "@lit/react";
3
3
  import { PiePagination as e } from "./index.js";
4
- const t = i({
4
+ import { ON_NEXT_EVENT as r, ON_PAGE_CHANGE_EVENT as m, ON_PREV_EVENT as N, defaultProps as E } from "./index.js";
5
+ const n = i({
5
6
  displayName: "PiePagination",
6
7
  elementClass: e,
7
8
  react: a,
8
9
  tagName: "pie-pagination",
9
- events: {}
10
- }), m = t;
10
+ events: {
11
+ onPiePaginationPageChange: "pie-pagination-page-change",
12
+ // when the user interacts with a pagination control.
13
+ onPiePaginationPrev: "pie-pagination-prev",
14
+ // when the user clicks the "previous" control.
15
+ onPiePaginationNext: "pie-pagination-next"
16
+ // when the user clicks the "next" control.
17
+ }
18
+ }), P = n;
11
19
  export {
12
- m as PiePagination
20
+ r as ON_NEXT_EVENT,
21
+ m as ON_PAGE_CHANGE_EVENT,
22
+ N as ON_PREV_EVENT,
23
+ P as PiePagination,
24
+ E as defaultProps
13
25
  };
package/package.json CHANGED
@@ -1,7 +1,13 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-pagination",
3
- "description": "PIE Design System Pagination built using Web Components",
4
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
+ "description": "PIE design system pagination built using web components",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/justeattakeaway/pie",
8
+ "directory": "packages/components/pie-pagination"
9
+ },
10
+ "homepage": "https://webc.pie.design/?path=/docs/components-pagination--overview",
5
11
  "type": "module",
6
12
  "main": "dist/index.js",
7
13
  "module": "dist/index.js",
@@ -37,13 +43,17 @@
37
43
  "devDependencies": {
38
44
  "@justeattakeaway/pie-components-config": "0.21.5",
39
45
  "@justeattakeaway/pie-css": "1.9.1",
40
- "@justeattakeaway/pie-monorepo-utils": "0.9.12"
41
- },
42
- "dependencies": {
43
- "@justeattakeaway/pie-webc-core": "22.0.1"
46
+ "@justeattakeaway/pie-monorepo-utils": "0.9.12",
47
+ "@justeattakeaway/pie-wrapper-react": "0.14.5"
44
48
  },
45
49
  "customElements": "custom-elements.json",
46
50
  "sideEffects": [
47
51
  "dist/*.js"
48
- ]
52
+ ],
53
+ "dependencies": {
54
+ "@justeattakeaway/pie-button": "1.15.1",
55
+ "@justeattakeaway/pie-icon-button": "2.8.1",
56
+ "@justeattakeaway/pie-icons-webc": "1.29.5",
57
+ "@justeattakeaway/pie-webc-core": "22.0.1"
58
+ }
49
59
  }
package/src/defs-react.ts CHANGED
@@ -1,8 +1,3 @@
1
1
  import type React from 'react';
2
- /**
3
- * TODO: Verify if ReactBaseType can be set as a more specific React interface
4
- * Use the React IntrinsicElements interface to find how to map standard HTML elements to existing React Interfaces
5
- * Example: an HTML button maps to `React.ButtonHTMLAttributes<HTMLButtonElement>`
6
- * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0bb210867d16170c4a08d9ce5d132817651a0f80/types/react/index.d.ts#L2829
7
- */
8
- export type ReactBaseType = React.HTMLAttributes<HTMLElement>
2
+
3
+ export type ReactBaseType = React.HTMLAttributes<HTMLElement>;
package/src/defs.ts CHANGED
@@ -1,3 +1,61 @@
1
- // TODO - please remove the eslint disable comment below when you add props to this interface
2
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
3
- export interface PaginationProps {}
1
+ import { type ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
2
+
3
+ /**
4
+ * The event name dispatched when the user interacts with a pagination control.
5
+ * The component is fully controlled: it never changes `currentPage` itself, it
6
+ * only tells the consumer which page the user wants to navigate to.
7
+ * @constant
8
+ */
9
+ export const ON_PAGE_CHANGE_EVENT = 'pie-pagination-page-change';
10
+
11
+ /**
12
+ * The event name dispatched when the user clicks the "previous" control.
13
+ * @constant
14
+ */
15
+ export const ON_PREV_EVENT = 'pie-pagination-prev';
16
+
17
+ /**
18
+ * The event name dispatched when the user clicks the "next" control.
19
+ * @constant
20
+ */
21
+ export const ON_NEXT_EVENT = 'pie-pagination-next';
22
+
23
+ type AriaProps = {
24
+ label?: string;
25
+ };
26
+
27
+ export interface PaginationProps {
28
+ /**
29
+ * The ARIA attributes for the pagination landmark. Offers a `label` used for
30
+ * the `aria-label` of the wrapping `<nav>` element.
31
+ */
32
+ aria?: AriaProps;
33
+
34
+ /**
35
+ * The currently active page (1-based). This component is fully controlled, so
36
+ * it never updates this value itself; the consumer is responsible for updating
37
+ * it in response to the `pie-pagination-page-change` event.
38
+ * @default 1
39
+ */
40
+ currentPage?: number;
41
+
42
+ /**
43
+ * The total number of pages to render.
44
+ * @default 1
45
+ */
46
+ totalPages?: number;
47
+
48
+ /**
49
+ * When true, all pagination controls are disabled.
50
+ * @default false
51
+ */
52
+ disabled?: boolean;
53
+ }
54
+
55
+ export type DefaultProps = ComponentDefaultProps<PaginationProps, 'currentPage' | 'totalPages' | 'disabled'>;
56
+
57
+ export const defaultProps: DefaultProps = {
58
+ currentPage: 1,
59
+ totalPages: 1,
60
+ disabled: false,
61
+ };
package/src/index.ts CHANGED
@@ -1,12 +1,29 @@
1
+ import {
2
+ html, unsafeCSS, type PropertyValues,
3
+ } from 'lit';
4
+ import { property } from 'lit/decorators.js';
5
+ import { classMap } from 'lit/directives/class-map.js';
6
+ import { ifDefined } from 'lit/directives/if-defined.js';
1
7
 
2
- import { html, unsafeCSS } from 'lit';
3
8
  import { PieElement } from '@justeattakeaway/pie-webc-core/src/internals/PieElement';
4
9
  import {
10
+ dispatchCustomEvent,
5
11
  RtlMixin,
6
12
  safeCustomElement,
7
13
  } from '@justeattakeaway/pie-webc-core';
14
+
15
+ import '@justeattakeaway/pie-icon-button';
16
+ import '@justeattakeaway/pie-icons-webc/dist/IconChevronLeft.js';
17
+ import '@justeattakeaway/pie-icons-webc/dist/IconChevronRight.js';
18
+
8
19
  import styles from './pagination.scss?inline';
9
- import { type PaginationProps } from './defs';
20
+ import {
21
+ type PaginationProps,
22
+ defaultProps,
23
+ ON_PAGE_CHANGE_EVENT,
24
+ ON_PREV_EVENT,
25
+ ON_NEXT_EVENT,
26
+ } from './defs';
10
27
 
11
28
  // Valid values available to consumers
12
29
  export * from './defs';
@@ -15,11 +32,161 @@ const componentSelector = 'pie-pagination';
15
32
 
16
33
  /**
17
34
  * @tagname pie-pagination
35
+ * @event {CustomEvent} pie-pagination-page-change - when the user interacts with a pagination control.
36
+ * @event {CustomEvent} pie-pagination-prev - when the user clicks the "previous" control.
37
+ * @event {CustomEvent} pie-pagination-next - when the user clicks the "next" control.
18
38
  */
19
39
  @safeCustomElement('pie-pagination')
20
40
  export class PiePagination extends RtlMixin(PieElement) implements PaginationProps {
41
+ @property({ type: Object })
42
+ public aria: PaginationProps['aria'];
43
+
44
+ @property({ type: Number })
45
+ public currentPage = defaultProps.currentPage;
46
+
47
+ @property({ type: Number })
48
+ public totalPages = defaultProps.totalPages;
49
+
50
+ @property({ type: Boolean })
51
+ public disabled = defaultProps.disabled;
52
+
53
+ protected updated (changedProperties: PropertyValues<this>): void {
54
+ if (changedProperties.has('totalPages') && this.totalPages < 1) {
55
+ console.warn(`pie-pagination: "totalPages" must be at least 1, received "${this.totalPages}".`);
56
+ }
57
+
58
+ if (changedProperties.has('currentPage') && this.currentPage < 1) {
59
+ console.warn(`pie-pagination: "currentPage" must be at least 1, received "${this.currentPage}".`);
60
+ }
61
+
62
+ if (changedProperties.has('currentPage') && this.currentPage > this.totalPages) {
63
+ console.warn(`pie-pagination: "currentPage" (${this.currentPage}) cannot be greater than "totalPages" (${this.totalPages}).`);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Emits the page change event with the page the user wants to navigate to.
69
+ * The component never updates `currentPage` itself.
70
+ *
71
+ * @private
72
+ */
73
+ private _emitPageChange (currentPage: number) {
74
+ dispatchCustomEvent(this, ON_PAGE_CHANGE_EVENT, { currentPage });
75
+ }
76
+
77
+ /**
78
+ * Handles a click on the "previous" control.
79
+ *
80
+ * @private
81
+ */
82
+ private _handlePreviousClick () {
83
+ if (this.disabled || this.currentPage <= 1) return;
84
+
85
+ const requestedPage = this.currentPage - 1;
86
+
87
+ dispatchCustomEvent(this, ON_PREV_EVENT, { currentPage: requestedPage });
88
+ this._emitPageChange(requestedPage);
89
+ }
90
+
91
+ /**
92
+ * Handles a click on the "next" control.
93
+ *
94
+ * @private
95
+ */
96
+ private _handleNextClick () {
97
+ if (this.disabled || this.currentPage >= this.totalPages) return;
98
+
99
+ const requestedPage = this.currentPage + 1;
100
+
101
+ dispatchCustomEvent(this, ON_NEXT_EVENT, { currentPage: requestedPage });
102
+ this._emitPageChange(requestedPage);
103
+ }
104
+
105
+ /**
106
+ * Handles a click on a page number control.
107
+ *
108
+ * @private
109
+ */
110
+ private _handlePageClick (page: number) {
111
+ if (this.disabled || page === this.currentPage) return;
112
+ this._emitPageChange(page);
113
+ }
114
+
115
+ /**
116
+ * Renders the chevron icon for the previous/next controls, mirroring it for RTL.
117
+ *
118
+ * @private
119
+ */
120
+ private _renderChevronIcon (direction: 'previous' | 'next') {
121
+ const pointsLeft = direction === 'previous' ? !this.isRTL : this.isRTL;
122
+
123
+ return pointsLeft
124
+ ? html`<icon-chevron-left></icon-chevron-left>`
125
+ : html`<icon-chevron-right></icon-chevron-right>`;
126
+ }
127
+
21
128
  render () {
22
- return html`<h1 data-test-id="pie-pagination">Hello world!</h1>`;
129
+ const {
130
+ aria, currentPage, disabled, totalPages,
131
+ } = this;
132
+
133
+ const pages = Array.from({ length: Math.max(totalPages, 0) }, (_, index) => index + 1);
134
+ const isPreviousDisabled = disabled || currentPage <= 1;
135
+ const isNextDisabled = disabled || currentPage >= totalPages;
136
+
137
+ return html`
138
+ <nav
139
+ class="c-pagination"
140
+ aria-label="${aria?.label ?? 'Pagination'}"
141
+ data-test-id="pie-pagination">
142
+ <ol class="c-pagination-list" data-test-id="pie-pagination-list">
143
+ <li class="c-pagination-item">
144
+ <pie-icon-button
145
+ data-test-id="pie-pagination-previous"
146
+ size="xsmall"
147
+ variant="ghost-secondary"
148
+ ?disabled="${isPreviousDisabled}"
149
+ .aria="${{ label: 'Previous page' }}"
150
+ @click="${this._handlePreviousClick}">
151
+ ${this._renderChevronIcon('previous')}
152
+ </pie-icon-button>
153
+ </li>
154
+
155
+ ${pages.map((page) => {
156
+ const isCurrent = page === currentPage;
157
+ const classes = {
158
+ 'c-pagination-control': true,
159
+ 'c-pagination-control--current': isCurrent,
160
+ };
161
+
162
+ return html`
163
+ <li class="c-pagination-item">
164
+ <button
165
+ type="button"
166
+ class="${classMap(classes)}"
167
+ data-test-id="pie-pagination-page"
168
+ ?disabled="${disabled}"
169
+ aria-current="${ifDefined(isCurrent ? 'page' : undefined)}"
170
+ aria-label="Page ${page}"
171
+ @click="${() => this._handlePageClick(page)}">
172
+ ${page}
173
+ </button>
174
+ </li>`;
175
+ })}
176
+
177
+ <li class="c-pagination-item">
178
+ <pie-icon-button
179
+ data-test-id="pie-pagination-next"
180
+ size="xsmall"
181
+ variant="ghost-secondary"
182
+ ?disabled="${isNextDisabled}"
183
+ .aria="${{ label: 'Next page' }}"
184
+ @click="${this._handleNextClick}">
185
+ ${this._renderChevronIcon('next')}
186
+ </pie-icon-button>
187
+ </li>
188
+ </ol>
189
+ </nav>`;
23
190
  }
24
191
 
25
192
  // Renders a `CSSResult` generated from SCSS by Vite
@@ -1,7 +1,53 @@
1
1
  @use '@justeattakeaway/pie-css/scss' as p;
2
+ @use '@justeattakeaway/pie-css/scss/mixins/components/button' as btn;
2
3
 
3
4
  :host {
4
- // Note: For consistency sake, the recommended display should be either
5
- // "block" or "inline-block", otherwise it can be ommited for floating elements
6
- display: block;
5
+ display: inline-block;
6
+ }
7
+
8
+ .c-pagination {
9
+ display: inline-block;
10
+ }
11
+
12
+ .c-pagination-list {
13
+ display: flex;
14
+ align-items: center;
15
+ gap: var(--dt-spacing-b);
16
+ margin: 0;
17
+ padding: 0;
18
+ list-style: none;
19
+ }
20
+
21
+ .c-pagination-item {
22
+ display: flex;
23
+ align-items: center;
24
+ }
25
+
26
+ // Page number control.
27
+ // Built from the shared PIE button mixins so it inherits the same typography,
28
+ // interactive states and focus ring as pie-button, but sized as a fixed
29
+ // 32x32 circular control to match the Figma specification.
30
+ .c-pagination-control {
31
+ @include btn.button-base($include-icon-selector: false);
32
+ @include btn.button-size('xsmall');
33
+ @include btn.button-variant('ghost');
34
+
35
+ inline-size: 32px;
36
+ block-size: 32px;
37
+ padding: 0;
38
+
39
+ --btn-font-weight: var(--dt-font-body-s-weight);
40
+
41
+ &.c-pagination-control--current {
42
+ @include btn.button-variant('primary-alternative');
43
+
44
+ --btn-font-weight: var(--dt-font-body-strong-s-weight);
45
+ }
46
+
47
+ &:disabled {
48
+ --int-states-mixin-bg-color: transparent;
49
+ --btn-text-color: var(--dt-color-content-disabled-solid);
50
+
51
+ cursor: not-allowed;
52
+ }
7
53
  }
package/src/react.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { createComponent } from '@lit/react';
2
+ import { createComponent, type EventName } from '@lit/react';
3
3
  import { PiePagination as PiePaginationLit } from './index';
4
4
  import { type PaginationProps } from './defs';
5
5
 
@@ -10,10 +10,20 @@ const PiePaginationReact = createComponent({
10
10
  elementClass: PiePaginationLit,
11
11
  react: React,
12
12
  tagName: 'pie-pagination',
13
- events: {},
13
+ events: {
14
+ onPiePaginationPageChange: 'pie-pagination-page-change' as EventName<CustomEvent>, // when the user interacts with a pagination control.
15
+ onPiePaginationPrev: 'pie-pagination-prev' as EventName<CustomEvent>, // when the user clicks the "previous" control.
16
+ onPiePaginationNext: 'pie-pagination-next' as EventName<CustomEvent>, // when the user clicks the "next" control.
17
+ },
14
18
  });
15
19
 
16
- type ReactBaseType = React.HTMLAttributes<HTMLElement>
20
+ type ReactBaseType = React.HTMLAttributes<HTMLElement>;
21
+
22
+ type PiePaginationEvents = {
23
+ onPiePaginationPageChange?: (event: CustomEvent) => void;
24
+ onPiePaginationPrev?: (event: CustomEvent) => void;
25
+ onPiePaginationNext?: (event: CustomEvent) => void;
26
+ };
17
27
 
18
28
  export const PiePagination = PiePaginationReact as React.ForwardRefExoticComponent<React.PropsWithChildren<Omit<React.PropsWithoutRef<PaginationProps>, 'children'>>
19
- & React.RefAttributes<PiePaginationLit> & ReactBaseType>;
29
+ & React.RefAttributes<PiePaginationLit> & PiePaginationEvents & ReactBaseType>;