From d7ce9fb68be405047e1a45d68fe865b6ae1304a8 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Thu, 22 Aug 2024 15:20:01 -0400 Subject: [PATCH 01/26] initial conversion of size-selecotr to ts --- .changeset/hungry-cycles-drum.md | 6 ++++++ .../hds/pagination/size-selector/{index.js => index.ts} | 0 2 files changed, 6 insertions(+) create mode 100644 .changeset/hungry-cycles-drum.md rename packages/components/src/components/hds/pagination/size-selector/{index.js => index.ts} (100%) diff --git a/.changeset/hungry-cycles-drum.md b/.changeset/hungry-cycles-drum.md new file mode 100644 index 00000000000..11704a390ea --- /dev/null +++ b/.changeset/hungry-cycles-drum.md @@ -0,0 +1,6 @@ +--- +"@hashicorp/design-system-components": minor +--- + +`Hds::Pagination` +- Converted to Typescript diff --git a/packages/components/src/components/hds/pagination/size-selector/index.js b/packages/components/src/components/hds/pagination/size-selector/index.ts similarity index 100% rename from packages/components/src/components/hds/pagination/size-selector/index.js rename to packages/components/src/components/hds/pagination/size-selector/index.ts From e6a09c9577e03102b5b26ebeffac5e4c899579ff Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Thu, 22 Aug 2024 15:45:51 -0400 Subject: [PATCH 02/26] finished converting SizeSelector --- .../hds/pagination/size-selector/index.hbs | 1 - .../hds/pagination/size-selector/index.ts | 49 ++++++++----------- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/packages/components/src/components/hds/pagination/size-selector/index.hbs b/packages/components/src/components/hds/pagination/size-selector/index.hbs index 54942368621..97791f2bbe7 100644 --- a/packages/components/src/components/hds/pagination/size-selector/index.hbs +++ b/packages/components/src/components/hds/pagination/size-selector/index.hbs @@ -1,4 +1,3 @@ -{{! @glint-nocheck: not typesafe yet }} {{! Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: MPL-2.0 diff --git a/packages/components/src/components/hds/pagination/size-selector/index.ts b/packages/components/src/components/hds/pagination/size-selector/index.ts index bd7beab61a9..0878fbaeab7 100644 --- a/packages/components/src/components/hds/pagination/size-selector/index.ts +++ b/packages/components/src/components/hds/pagination/size-selector/index.ts @@ -8,21 +8,23 @@ import { assert } from '@ember/debug'; import { guidFor } from '@ember/object/internals'; import { action } from '@ember/object'; -export default class HdsPaginationSizeSelectorComponent extends Component { - /** - * Generates a unique ID for the pageSize select - * - * @param SizeSelectorId - */ +import type { HdsFormSelectBaseSignature } from '../../form/select/base'; + +interface HdsPaginationSizeSelectorSignature { + Args: { + pageSizes: number[]; + label?: string; + selectedSize?: number; + onChange?: (size: number) => void; + }; + Element: HTMLDivElement; +} + +export default class HdsPaginationSizeSelectorComponent extends Component { SizeSelectorId = 'pagination-size-selector-' + guidFor(this); - /** - * @param pageSizes - * @type {array of numbers} - * @description Set the page sizes users can select from. - */ get pageSizes() { - let { pageSizes } = this.args; + const { pageSizes } = this.args; assert( '@pageSizes for "Pagination::SizeSelector" must be defined', @@ -32,13 +34,8 @@ export default class HdsPaginationSizeSelectorComponent extends Component { return pageSizes; } - /** - * @param selectedSize - * @type integer - * @description The selected ("current") page size - */ get selectedSize() { - let { selectedSize } = this.args; + const { selectedSize } = this.args; assert( `@selectedSize for "Pagination::SizeSelector" must one of the @pageSizes provided (${this.pageSizes.join( @@ -50,24 +47,20 @@ export default class HdsPaginationSizeSelectorComponent extends Component { return selectedSize; } - /** - * @param label - * @type string - * @default "Items per page" - * @description The label text for the select - */ get label() { - let { label = 'Items per page' } = this.args; + const { label = 'Items per page' } = this.args; return label; } @action - onChange(e) { - let { onChange } = this.args; + onChange(e: Event) { + const { onChange } = this.args; + + const target = e.target as HdsFormSelectBaseSignature['Element']; if (typeof onChange === 'function') { - onChange(parseInt(e.target.value)); + onChange(parseInt(target.value)); } } } From 6a9dcb6b492373ff0322b53e09e911d65bec4096 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Thu, 22 Aug 2024 15:46:28 -0400 Subject: [PATCH 03/26] initial conversion of Pagination::Info to ts --- .../src/components/hds/pagination/info/{index.js => index.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/components/src/components/hds/pagination/info/{index.js => index.ts} (100%) diff --git a/packages/components/src/components/hds/pagination/info/index.js b/packages/components/src/components/hds/pagination/info/index.ts similarity index 100% rename from packages/components/src/components/hds/pagination/info/index.js rename to packages/components/src/components/hds/pagination/info/index.ts From 6b51e97b9878a415570dfd2f7bba48cd9b1491d4 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Thu, 22 Aug 2024 15:51:36 -0400 Subject: [PATCH 04/26] finished initial conversion of HdsPaginationInfo component --- .../components/hds/pagination/info/index.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/components/src/components/hds/pagination/info/index.ts b/packages/components/src/components/hds/pagination/info/index.ts index d8a3bcfb6ee..b86a47ccc63 100644 --- a/packages/components/src/components/hds/pagination/info/index.ts +++ b/packages/components/src/components/hds/pagination/info/index.ts @@ -5,12 +5,20 @@ import Component from '@glimmer/component'; -export default class HdsPaginationInfoComponent extends Component { - /** - * @param showTotalItems - * @type {boolean} - * @description Controls the visibility of the total items - */ +interface HdsPaginationInfoSignature { + Args: { + // TODO: Convert this to be the parent arg + itemsRangeStart: number; + // TODO: Convert this to be the parent arg + itemsRangeEnd: number; + // TODO: Convert this to be the parent arg + showTotalItems?: boolean; + totalItems: number; + }; + Element: HTMLDivElement; +} + +export default class HdsPaginationInfoComponent extends Component { get showTotalItems() { return this.args.showTotalItems ?? true; } From 9daa2b3fa51bb059a7b7e71ee23cb13aea96b282 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Thu, 22 Aug 2024 15:52:09 -0400 Subject: [PATCH 05/26] initial conversion of pagination::numbered component --- .../src/components/hds/pagination/numbered/{index.js => index.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/components/src/components/hds/pagination/numbered/{index.js => index.ts} (100%) diff --git a/packages/components/src/components/hds/pagination/numbered/index.js b/packages/components/src/components/hds/pagination/numbered/index.ts similarity index 100% rename from packages/components/src/components/hds/pagination/numbered/index.js rename to packages/components/src/components/hds/pagination/numbered/index.ts From 1b025fb56d655bbac731d2c7438dae2c61668dbe Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Thu, 22 Aug 2024 17:18:01 -0400 Subject: [PATCH 06/26] finished initial conversion of hds::pagination::numbered --- packages/components/package.json | 1 + .../components/hds/pagination/elliptize.ts | 69 ++++++++ .../components/hds/pagination/info/index.ts | 1 - .../hds/pagination/numbered/index.ts | 158 ++++++++---------- .../src/components/hds/pagination/types.ts | 19 +++ 5 files changed, 157 insertions(+), 91 deletions(-) create mode 100644 packages/components/src/components/hds/pagination/elliptize.ts create mode 100644 packages/components/src/components/hds/pagination/types.ts diff --git a/packages/components/package.json b/packages/components/package.json index 70054835824..35cdb85e427 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -240,6 +240,7 @@ "./components/hds/page-header/subtitle.js": "./dist/_app_/components/hds/page-header/subtitle.js", "./components/hds/page-header/title.js": "./dist/_app_/components/hds/page-header/title.js", "./components/hds/pagination/compact/index.js": "./dist/_app_/components/hds/pagination/compact/index.js", + "./components/hds/pagination/elliptize.js": "./dist/_app_/components/hds/pagination/elliptize.js", "./components/hds/pagination/info/index.js": "./dist/_app_/components/hds/pagination/info/index.js", "./components/hds/pagination/nav/arrow.js": "./dist/_app_/components/hds/pagination/nav/arrow.js", "./components/hds/pagination/nav/ellipsis.js": "./dist/_app_/components/hds/pagination/nav/ellipsis.js", diff --git a/packages/components/src/components/hds/pagination/elliptize.ts b/packages/components/src/components/hds/pagination/elliptize.ts new file mode 100644 index 00000000000..34ed3093883 --- /dev/null +++ b/packages/components/src/components/hds/pagination/elliptize.ts @@ -0,0 +1,69 @@ +import type { HdsPaginationElliptizedPageArray } from './types'; + +const ELLIPSIS = '…'; + +interface ElliptizeProps { + pages: number[]; + current: number; + limit?: number; +} + +export const elliptize = ({ + pages, + current, + limit = 7, +}: ElliptizeProps): HdsPaginationElliptizedPageArray => { + const length = pages.length; + + let result = []; + let start; + let end; + + if (length <= limit) { + return pages; + } + + if (current <= length / 2) { + start = Math.ceil(limit / 2); + end = limit - start; + } else { + end = Math.ceil(limit / 2); + start = limit - end; + } + + const sliceStart: HdsPaginationElliptizedPageArray = pages.slice(0, start); + const sliceEnd: HdsPaginationElliptizedPageArray = pages.slice(-end); + + if (sliceStart.includes(current) && sliceStart.includes(current + 1)) { + // "current" (and its next sibling) is contained within the "sliceStart" block + sliceEnd.splice(0, 1, ELLIPSIS); + result = ([] as HdsPaginationElliptizedPageArray).concat( + sliceStart, + sliceEnd + ); + } else if (sliceEnd.includes(current - 1) && sliceEnd.includes(current)) { + // "current" (and its prev sibling) is contained within the "sliceEnd" block + sliceStart.splice(-1, 1, ELLIPSIS); + result = ([] as HdsPaginationElliptizedPageArray).concat( + sliceStart, + sliceEnd + ); + } else { + // this is a bit more tricky :) + // we need to calculate how many items there are before/after the current item + // since both the initial and ending blocks are always 2 items long (number + ellipsis) + // and there is always the "current" item, we can just subtract 5 from the limit + const delta = (limit - 5) / 2; // this is why the limit needs to be an odd number + // we slice the array starting at the "current" index, minus the delta, minus one because it's an array (zero-based) + const sliceCurr = pages.slice(current - delta - 1, current + delta); + result = ([] as HdsPaginationElliptizedPageArray).concat( + sliceStart.shift() as number, + ELLIPSIS, + sliceCurr, + ELLIPSIS, + sliceEnd.pop() as number + ); + } + + return result; +}; diff --git a/packages/components/src/components/hds/pagination/info/index.ts b/packages/components/src/components/hds/pagination/info/index.ts index b86a47ccc63..69f1305b2d2 100644 --- a/packages/components/src/components/hds/pagination/info/index.ts +++ b/packages/components/src/components/hds/pagination/info/index.ts @@ -4,7 +4,6 @@ */ import Component from '@glimmer/component'; - interface HdsPaginationInfoSignature { Args: { // TODO: Convert this to be the parent arg diff --git a/packages/components/src/components/hds/pagination/numbered/index.ts b/packages/components/src/components/hds/pagination/numbered/index.ts index 66f6ebceb9c..507c94c1b11 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.ts +++ b/packages/components/src/components/hds/pagination/numbered/index.ts @@ -7,71 +7,44 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; +import { elliptize } from '../elliptize.ts'; + +import type { + HdsPaginationPage, + HdsPaginationRoutingProps, + HdsPaginationElliptizedPageArray, + HdsPaginationElliptizedPageArrayItem, +} from '../types'; +interface HdsPaginationNumberedSignature { + Args: { + ariaLabel?: string; + totalItems: number; + showLabels?: boolean; + isTruncated?: boolean; + currentPage?: number; + showInfo?: boolean; //TODO: Add this to the docs + showPageNumbers?: boolean; //TODO: Add this to the docs + showSizeSelector?: boolean; + sizeSelectorLabel?: string; + pageSizes?: number[]; + currentPageSize?: number; + // route stuff + route?: string; + model?: unknown; + models?: unknown[]; + replace?: boolean; + queryFunction?: (page: number, pageSize: number) => Record; + // end route stuff + onPageChange?: (page: number, pageSize: number) => unknown; + onPageSizeChange?: (pageSize: number) => unknown; + }; + Element: HTMLDivElement; +} // for context about the decision to use these values, see: // https://hashicorp.slack.com/archives/C03A0N1QK8S/p1673546329082759 export const DEFAULT_PAGE_SIZES = [10, 30, 50]; - -/** - * Elliptize a list of pages - * - * @param pages - array with all the "pages" (integer numbers) - * @param current - "current" page (array's index) - * @param limit - number of "page numbers" to be shown at a time (should always be an odd number!) - * - * @return - array of integers ("pages") + `...` strings ("ellipsis") - */ -export const elliptize = ({ pages, current, limit = 7 }) => { - const length = pages.length; - const ellipsis = '…'; - let result = []; - let start; - let end; - - if (length <= limit) { - return pages; - } - - if (current <= length / 2) { - start = Math.ceil(limit / 2); - end = limit - start; - } else { - end = Math.ceil(limit / 2); - start = limit - end; - } - - const sliceStart = pages.slice(0, start); - const sliceEnd = pages.slice(-end); - - if (sliceStart.includes(current) && sliceStart.includes(current + 1)) { - // "current" (and its next sibling) is contained within the "sliceStart" block - sliceEnd.splice(0, 1, ellipsis); - result = [].concat(sliceStart, sliceEnd); - } else if (sliceEnd.includes(current - 1) && sliceEnd.includes(current)) { - // "current" (and its prev sibling) is contained within the "sliceEnd" block - sliceStart.splice(-1, 1, ellipsis); - result = [].concat(sliceStart, sliceEnd); - } else { - // this is a bit more tricky :) - // we need to calculate how many items there are before/after the current item - // since both the initial and ending blocks are always 2 items long (number + ellipsis) - // and there is always the "current" item, we can just subtract 5 from the limit - const delta = (limit - 5) / 2; // this is why the limit needs to be an odd number - // we slice the array starting at the "current" index, minus the delta, minus one because it's an array (zero-based) - const sliceCurr = pages.slice(current - delta - 1, current + delta); - result = [].concat( - sliceStart.shift(), - ellipsis, - sliceCurr, - ellipsis, - sliceEnd.pop() - ); - } - - return result; -}; - -export default class HdsPaginationNumberedIndexComponent extends Component { +export default class HdsPaginationNumberedComponent extends Component { // These two private variables are used to differentiate between // "uncontrolled" component (where the state is handled internally) and // "controlled" component (where the state is handled externally, by the consumer's code). @@ -81,7 +54,8 @@ export default class HdsPaginationNumberedIndexComponent extends Component { // at rendering time, but from that moment on they're not updated anymore, no matter what interaction the user // has with the component (the state is controlled externally, eg. via query parameters) @tracked _currentPage = this.args.currentPage ?? 1; - @tracked _currentPageSize = this.args.currentPageSize ?? this.pageSizes[0]; + // we assert that `this.pageSizes` will always be an array with at least one item + @tracked _currentPageSize = this.args.currentPageSize ?? this.pageSizes[0]!; @tracked isControlled; showInfo = this.args.showInfo ?? true; // if the "info" block is visible @@ -90,10 +64,10 @@ export default class HdsPaginationNumberedIndexComponent extends Component { showPageNumbers = this.args.showPageNumbers ?? true; // if the "page numbers" block is visible isTruncated = this.args.isTruncated ?? true; // if the list of "page numbers" is truncated - constructor() { - super(...arguments); + constructor(owner: unknown, args: HdsPaginationNumberedSignature['Args']) { + super(owner, args); - let { queryFunction } = this.args; + const { queryFunction } = this.args; // This component works in two different ways, depending if we need to support // routing through links (`LinkTo`) for the "navigation controls", or not. @@ -149,7 +123,8 @@ export default class HdsPaginationNumberedIndexComponent extends Component { get currentPage() { if (this.isControlled) { - return this.args.currentPage; + // if the component is controlled, `@currentPage` is asserted to be a number + return this.args.currentPage as number; } else { return this._currentPage; } @@ -159,13 +134,15 @@ export default class HdsPaginationNumberedIndexComponent extends Component { if (this.isControlled) { // noop } else { - this._currentPage = value; + // if `this.isControlled` is `false` + this._currentPage = value as number; } } get currentPageSize() { if (this.isControlled) { - return this.args.currentPageSize; + // if the component is controlled, `@currentPageSize` is asserted to be a number + return this.args.currentPageSize as number; } else { return this._currentPageSize; } @@ -179,18 +156,13 @@ export default class HdsPaginationNumberedIndexComponent extends Component { } } - /** - * @param pageSizes - * @type {array of numbers} - * @description Set the page sizes users can select from. - * @default [10, 30, 50] - */ get pageSizes() { - let { pageSizes = DEFAULT_PAGE_SIZES } = this.args; + const { pageSizes = DEFAULT_PAGE_SIZES } = this.args; assert( - `pageSizes argument must be an array. Received: ${pageSizes}`, - Array.isArray(pageSizes) === true + // TODO: Add test for this + `pageSizes argument must be an array with at least one item. Received: ${pageSizes}`, + Array.isArray(pageSizes) === true && pageSizes.length > 0 ); return pageSizes; @@ -217,8 +189,8 @@ export default class HdsPaginationNumberedIndexComponent extends Component { } } - get pages() { - let pages = []; + get pages(): HdsPaginationElliptizedPageArray { + const pages = []; for (let i = 1; i <= this.totalPages; i++) { pages.push(i); @@ -235,16 +207,21 @@ export default class HdsPaginationNumberedIndexComponent extends Component { return Math.max(Math.ceil(this.args.totalItems / this.currentPageSize), 1); } - buildQueryParamsObject(page, pageSize) { - if (this.isControlled) { - return this.args.queryFunction(page, pageSize); + buildQueryParamsObject( + page: HdsPaginationElliptizedPageArrayItem, + pageSize: number + ): Record { + // `page` may also be ellipsis + if (this.isControlled && typeof page === 'number') { + // if the component is controlled, `@queryFunction` is asserted to be a function + return this.args.queryFunction!(page, pageSize); } else { return {}; } } - get routing() { - let routing = { + get routing(): HdsPaginationRoutingProps { + const routing: HdsPaginationRoutingProps = { route: this.args.route ?? undefined, model: this.args.model ?? undefined, models: this.args.models ?? undefined, @@ -267,7 +244,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component { routing.queryPages = {}; this.pages.forEach( (page) => - (routing.queryPages[page] = this.buildQueryParamsObject( + (routing.queryPages![page] = this.buildQueryParamsObject( page, this.currentPageSize )) @@ -290,7 +267,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component { } @action - onPageChange(page) { + onPageChange(page: HdsPaginationPage) { let gotoPageNumber; if (page === 'prev' && this.currentPage > 1) { gotoPageNumber = this.currentPage - 1; @@ -302,9 +279,10 @@ export default class HdsPaginationNumberedIndexComponent extends Component { // we want to invoke the `onPageChange` callback only on actual page change if (gotoPageNumber !== this.currentPage) { - this.currentPage = gotoPageNumber; + // we have already determined that `gotoPageNumber` is not `prev` or `next` + this.currentPage = gotoPageNumber as number; - let { onPageChange } = this.args; + const { onPageChange } = this.args; if (typeof onPageChange === 'function') { onPageChange(this.currentPage, this.currentPageSize); @@ -313,8 +291,8 @@ export default class HdsPaginationNumberedIndexComponent extends Component { } @action - onPageSizeChange(newPageSize) { - let { onPageSizeChange } = this.args; + onPageSizeChange(newPageSize: number) { + const { onPageSizeChange } = this.args; if (!this.isControlled) { // notice: we agreed to reset the pagination to the first element (any alternative would result in an unpredictable UX) diff --git a/packages/components/src/components/hds/pagination/types.ts b/packages/components/src/components/hds/pagination/types.ts new file mode 100644 index 00000000000..f6c4ae6b8d9 --- /dev/null +++ b/packages/components/src/components/hds/pagination/types.ts @@ -0,0 +1,19 @@ +type HdsPaginationPaginationDirection = 'next' | 'prev'; + +export type HdsPaginationPage = HdsPaginationPaginationDirection | number; + +export type HdsPaginationElliptizedPageArrayItem = string | number; + +export type HdsPaginationElliptizedPageArray = + HdsPaginationElliptizedPageArrayItem[]; + +export interface HdsPaginationRoutingProps { + route?: string; + model?: unknown; + models?: unknown[]; + replace?: boolean; + queryByPage?: Record; + queryNext?: Record; + queryPrev?: Record; + queryPages?: Record; +} From deef85140bacb84c49bb1c3acc2eae8ba8d54b58 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Fri, 23 Aug 2024 10:04:24 -0400 Subject: [PATCH 07/26] finished conversion --- .../components/hds/pagination/info/index.ts | 10 ++++------ .../hds/pagination/numbered/index.ts | 18 +++++++++--------- .../src/components/hds/pagination/types.ts | 9 +++++++-- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/components/src/components/hds/pagination/info/index.ts b/packages/components/src/components/hds/pagination/info/index.ts index 69f1305b2d2..d92b150e7e3 100644 --- a/packages/components/src/components/hds/pagination/info/index.ts +++ b/packages/components/src/components/hds/pagination/info/index.ts @@ -4,21 +4,19 @@ */ import Component from '@glimmer/component'; +import type { HdsPaginationNumberedSignature } from '../numbered/index'; interface HdsPaginationInfoSignature { Args: { - // TODO: Convert this to be the parent arg itemsRangeStart: number; - // TODO: Convert this to be the parent arg itemsRangeEnd: number; - // TODO: Convert this to be the parent arg - showTotalItems?: boolean; - totalItems: number; + showTotalItems?: HdsPaginationNumberedSignature['Args']['showTotalItems']; + totalItems: HdsPaginationNumberedSignature['Args']['totalItems']; }; Element: HTMLDivElement; } export default class HdsPaginationInfoComponent extends Component { - get showTotalItems() { + get showTotalItems(): boolean { return this.args.showTotalItems ?? true; } } diff --git a/packages/components/src/components/hds/pagination/numbered/index.ts b/packages/components/src/components/hds/pagination/numbered/index.ts index 507c94c1b11..c3ab2b7f2c7 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.ts +++ b/packages/components/src/components/hds/pagination/numbered/index.ts @@ -8,6 +8,7 @@ import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; import { elliptize } from '../elliptize.ts'; +import { HdsPaginationDirectionValues } from '../types.ts'; import type { HdsPaginationPage, @@ -15,7 +16,7 @@ import type { HdsPaginationElliptizedPageArray, HdsPaginationElliptizedPageArrayItem, } from '../types'; -interface HdsPaginationNumberedSignature { +export interface HdsPaginationNumberedSignature { Args: { ariaLabel?: string; totalItems: number; @@ -24,6 +25,7 @@ interface HdsPaginationNumberedSignature { currentPage?: number; showInfo?: boolean; //TODO: Add this to the docs showPageNumbers?: boolean; //TODO: Add this to the docs + showTotalItems?: boolean; //TODO: Add this to the docs showSizeSelector?: boolean; sizeSelectorLabel?: string; pageSizes?: number[]; @@ -99,12 +101,7 @@ export default class HdsPaginationNumberedComponent extends Component 1) { + if (page === HdsPaginationDirectionValues.Prev && this.currentPage > 1) { gotoPageNumber = this.currentPage - 1; - } else if (page === 'next' && this.currentPage < this.totalPages) { + } else if ( + page === HdsPaginationDirectionValues.Next && + this.currentPage < this.totalPages + ) { gotoPageNumber = this.currentPage + 1; } else { gotoPageNumber = page; diff --git a/packages/components/src/components/hds/pagination/types.ts b/packages/components/src/components/hds/pagination/types.ts index f6c4ae6b8d9..1e336a74167 100644 --- a/packages/components/src/components/hds/pagination/types.ts +++ b/packages/components/src/components/hds/pagination/types.ts @@ -1,6 +1,11 @@ -type HdsPaginationPaginationDirection = 'next' | 'prev'; +export enum HdsPaginationDirectionValues { + Next = 'next', + Prev = 'prev', +} + +type HdsPaginationDirections = `${HdsPaginationDirectionValues}`; -export type HdsPaginationPage = HdsPaginationPaginationDirection | number; +export type HdsPaginationPage = HdsPaginationDirections | number; export type HdsPaginationElliptizedPageArrayItem = string | number; From befa2bfbd89b5bccd5baf918546c85322a6ed68d Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 10:38:26 -0400 Subject: [PATCH 08/26] ts conversion in-progress --- .../hds/pagination/nav/{arrow.js => arrow.ts} | 40 ++++++++++--------- .../hds/pagination/nav/ellipsis.hbs | 1 - .../components/hds/pagination/nav/ellipsis.ts | 15 +++++++ .../pagination/nav/{number.js => number.ts} | 34 ++++++++++------ .../src/components/hds/pagination/types.ts | 2 +- 5 files changed, 60 insertions(+), 32 deletions(-) rename packages/components/src/components/hds/pagination/nav/{arrow.js => arrow.ts} (59%) create mode 100644 packages/components/src/components/hds/pagination/nav/ellipsis.ts rename packages/components/src/components/hds/pagination/nav/{number.js => number.ts} (52%) diff --git a/packages/components/src/components/hds/pagination/nav/arrow.js b/packages/components/src/components/hds/pagination/nav/arrow.ts similarity index 59% rename from packages/components/src/components/hds/pagination/nav/arrow.js rename to packages/components/src/components/hds/pagination/nav/arrow.ts index 3c3531e65cf..0d287196968 100644 --- a/packages/components/src/components/hds/pagination/nav/arrow.js +++ b/packages/components/src/components/hds/pagination/nav/arrow.ts @@ -6,12 +6,27 @@ import Component from '@glimmer/component'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; +import { HdsPaginationDirectionValues } from '../types.ts'; + +import type { HdsInteractiveSignature } from '../../interactive'; +import type { HdsPaginationDirections } from '../types'; export const DIRECTIONS = ['prev', 'next']; -export default class HdsPaginationControlArrowComponent extends Component { +interface HdsPaginationControlArrowSignature { + Args: { + direction: HdsPaginationDirections; + disabled?: boolean; + showLabel?: boolean; + onClick?: (direction: HdsPaginationDirections) => void; + // TODO: Add the rest of the arguments + }; + Element: HdsInteractiveSignature['Element']; +} + +export default class HdsPaginationControlArrowComponent extends Component { get content() { - let { direction } = this.args; + const { direction } = this.args; assert( `@direction for "Pagination::Nav::Arrow" must be one of the following: ${DIRECTIONS.join( @@ -21,14 +36,14 @@ export default class HdsPaginationControlArrowComponent extends Component { ); let content; - if (direction === 'prev') { + if (direction === HdsPaginationDirectionValues.Prev) { content = { label: 'Previous', icon: 'chevron-left', ariaLabel: 'Previous page', }; } - if (direction === 'next') { + if (direction === HdsPaginationDirectionValues.Next) { content = { label: 'Next', icon: 'chevron-right', @@ -39,25 +54,14 @@ export default class HdsPaginationControlArrowComponent extends Component { return content; } - /** - * @param showLabel - * @type {boolean} - * @default true - * @description Show the labels for the control - */ get showLabel() { - let { showLabel = true } = this.args; + const { showLabel = true } = this.args; return showLabel; } - /** - * Get the class names to apply to the component. - * @method classNames - * @return {string} The "class" attribute to apply to the component. - */ get classNames() { - let classes = [ + const classes = [ 'hds-pagination-nav__control', 'hds-pagination-nav__arrow', `hds-pagination-nav__arrow--direction-${this.args.direction}`, @@ -68,7 +72,7 @@ export default class HdsPaginationControlArrowComponent extends Component { @action onClick() { - let { onClick } = this.args; + const { onClick } = this.args; if (typeof onClick === 'function') { onClick(this.args.direction); diff --git a/packages/components/src/components/hds/pagination/nav/ellipsis.hbs b/packages/components/src/components/hds/pagination/nav/ellipsis.hbs index a9f50fac81e..e9792614948 100644 --- a/packages/components/src/components/hds/pagination/nav/ellipsis.hbs +++ b/packages/components/src/components/hds/pagination/nav/ellipsis.hbs @@ -1,4 +1,3 @@ -{{! @glint-nocheck: not typesafe yet }} {{! Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: MPL-2.0 diff --git a/packages/components/src/components/hds/pagination/nav/ellipsis.ts b/packages/components/src/components/hds/pagination/nav/ellipsis.ts new file mode 100644 index 00000000000..584f7e1c74b --- /dev/null +++ b/packages/components/src/components/hds/pagination/nav/ellipsis.ts @@ -0,0 +1,15 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import TemplateOnlyComponent from '@ember/component/template-only'; + +export interface HdsApplicationPaginationNavEllipsisSignature { + Element: HTMLDivElement; +} + +const HdsApplicationPaginationNavEllipsisComponent = + TemplateOnlyComponent(); + +export default HdsApplicationPaginationNavEllipsisComponent; diff --git a/packages/components/src/components/hds/pagination/nav/number.js b/packages/components/src/components/hds/pagination/nav/number.ts similarity index 52% rename from packages/components/src/components/hds/pagination/nav/number.js rename to packages/components/src/components/hds/pagination/nav/number.ts index 9e4e7a48e59..4a07f196831 100644 --- a/packages/components/src/components/hds/pagination/nav/number.js +++ b/packages/components/src/components/hds/pagination/nav/number.ts @@ -7,9 +7,21 @@ import Component from '@glimmer/component'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; -export default class HdsPaginationControlNumberComponent extends Component { - get page() { - let { page } = this.args; +import type { HdsInteractiveSignature } from '../../interactive'; + +interface HdsPaginationNavNumberSignature { + Args: { + page: number; + isSelected: boolean; + onClick: (page: number) => void; + // TODO: Add the rest + }; + Element: HdsInteractiveSignature['Element']; +} + +export default class HdsPaginationControlNumberComponent extends Component { + get page(): number { + const { page } = this.args; assert( '@page for "Pagination::Nav::Number" must have a valid value', @@ -19,13 +31,11 @@ export default class HdsPaginationControlNumberComponent extends Component { return page; } - /** - * Get the class names to apply to the component. - * @method classNames - * @return {string} The "class" attribute to apply to the component. - */ - get classNames() { - let classes = ['hds-pagination-nav__control', 'hds-pagination-nav__number']; + get classNames(): string { + const classes = [ + 'hds-pagination-nav__control', + 'hds-pagination-nav__number', + ]; if (this.args.isSelected) { classes.push(`hds-pagination-nav__number--is-selected`); @@ -35,8 +45,8 @@ export default class HdsPaginationControlNumberComponent extends Component { } @action - onClick() { - let { onClick } = this.args; + onClick(): void { + const { onClick } = this.args; if (typeof onClick === 'function') { onClick(this.args.page); diff --git a/packages/components/src/components/hds/pagination/types.ts b/packages/components/src/components/hds/pagination/types.ts index 1e336a74167..9a133abb05f 100644 --- a/packages/components/src/components/hds/pagination/types.ts +++ b/packages/components/src/components/hds/pagination/types.ts @@ -3,7 +3,7 @@ export enum HdsPaginationDirectionValues { Prev = 'prev', } -type HdsPaginationDirections = `${HdsPaginationDirectionValues}`; +export type HdsPaginationDirections = `${HdsPaginationDirectionValues}`; export type HdsPaginationPage = HdsPaginationDirections | number; From dcf4b327895be752e179211ddae00941db5625b6 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 10:44:58 -0400 Subject: [PATCH 09/26] initial conversion of the compact navigation component to ts --- .../src/components/hds/pagination/compact/{index.js => index.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/components/src/components/hds/pagination/compact/{index.js => index.ts} (100%) diff --git a/packages/components/src/components/hds/pagination/compact/index.js b/packages/components/src/components/hds/pagination/compact/index.ts similarity index 100% rename from packages/components/src/components/hds/pagination/compact/index.js rename to packages/components/src/components/hds/pagination/compact/index.ts From 0e72ea3f7da716de39c43ce7d0aa4baf6acf56ce Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 11:32:42 -0400 Subject: [PATCH 10/26] finished conversion of the compact pagination component --- .../hds/pagination/compact/index.ts | 100 ++++++++++++------ 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/packages/components/src/components/hds/pagination/compact/index.ts b/packages/components/src/components/hds/pagination/compact/index.ts index 4e2325cd77c..d01efa46999 100644 --- a/packages/components/src/components/hds/pagination/compact/index.ts +++ b/packages/components/src/components/hds/pagination/compact/index.ts @@ -7,12 +7,44 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; +import { HdsPaginationDirectionValues } from '../types.ts'; + +import type { + HdsPaginationRoutingProps, + HdsPaginationDirections, +} from '../types'; + +type HdsPaginationCompactSignatureRoutingProps = Pick< + HdsPaginationRoutingProps, + 'route' | 'model' | 'models' | 'replace' | 'queryPrev' | 'queryNext' +>; + +interface HdsPaginationCompactArgs { + ariaLabel?: string; + showLabels?: boolean; + isDisabledPrev?: boolean; + isDisabledNext?: boolean; + showSizeSelector?: boolean; + sizeSelectorLabel?: string; + pageSizes?: number[]; + currentPageSize?: number; + queryFunction?: ( + page: HdsPaginationDirections, + pageSize: number + ) => Record; + onPageChange?: (page: HdsPaginationDirections) => void; + onPageSizeChange?: (pageSize: number) => void; +} + +interface HdsPaginationCompactSignature { + Args: HdsPaginationCompactArgs & HdsPaginationCompactSignatureRoutingProps; + Element: HTMLDivElement; +} // for context about the decision to use these values, see: // https://hashicorp.slack.com/archives/C03A0N1QK8S/p1673546329082759 export const DEFAULT_PAGE_SIZES = [10, 30, 50]; - -export default class HdsPaginationCompactIndexComponent extends Component { +export default class HdsPaginationCompactComponent extends Component { // This private variable is used to differentiate between // "uncontrolled" component (where the state is handled internally) and // "controlled" component (where the state is handled externally, by the consumer's code). @@ -21,16 +53,17 @@ export default class HdsPaginationCompactIndexComponent extends Component { // In the second case, the variable stores *only* the initial state of the component (coming from the arguments) // at rendering time, but from that moment on it's not updated anymore, no matter what interaction the user // has with the component (the state is controlled externally, eg. via query parameters) - @tracked _currentPageSize = this.args.currentPageSize ?? this.pageSizes[0]; + @tracked _currentPageSize: number = + this.args.currentPageSize ?? (this.pageSizes[0] as number); // we assert that pageSizes is a non-empty array in its getter @tracked isControlled; showLabels = this.args.showLabels ?? true; // if the labels for the "prev/next" controls are visible showSizeSelector = this.args.showSizeSelector ?? false; // if the "size selector" block is visible - constructor() { - super(...arguments); + constructor(owner: unknown, args: HdsPaginationCompactSignature['Args']) { + super(owner, args); - let { queryFunction } = this.args; + const { queryFunction } = this.args; // This component works in two different ways, depending if we need to support // routing through links (`LinkTo`) for the "navigation controls", or not. @@ -51,12 +84,7 @@ export default class HdsPaginationCompactIndexComponent extends Component { } } - /** - * @param ariaLabel - * @type {string} - * @default 'Pagination' - */ - get ariaLabel() { + get ariaLabel(): string { return this.args.ariaLabel ?? 'Pagination'; } @@ -73,14 +101,20 @@ export default class HdsPaginationCompactIndexComponent extends Component { // is *always* determined by the component's internal logic (and updated according to the user interaction with it). // For this reason the "get" and "set" methods always read from or write to the private internal state (_variable). - get currentPageSize() { + get currentPageSize(): number { if (this.isControlled) { + // TODO: Add a test for this assertion + // QUESTION: Should the docs mention that this is required if the component is controlled? + assert( + '@currentPageSize must be defined when the component is controlled', + this.args.currentPageSize !== undefined + ); + return this.args.currentPageSize; } else { return this._currentPageSize; } } - set currentPageSize(value) { if (this.isControlled) { // noop @@ -89,33 +123,31 @@ export default class HdsPaginationCompactIndexComponent extends Component { } } - /** - * @param pageSizes - * @type {array of numbers} - * @description Set the page sizes users can select from. - * @default [10, 30, 50] - */ - get pageSizes() { - let { pageSizes = DEFAULT_PAGE_SIZES } = this.args; + get pageSizes(): number[] { + const { pageSizes = DEFAULT_PAGE_SIZES } = this.args; assert( `pageSizes argument must be an array. Received: ${pageSizes}`, - Array.isArray(pageSizes) === true + Array.isArray(pageSizes) === true && pageSizes.length > 0 ); return pageSizes; } - buildQueryParamsObject(page, pageSize) { + buildQueryParamsObject( + page: HdsPaginationDirections, + pageSize: number + ): Record { if (this.isControlled) { - return this.args.queryFunction(page, pageSize); + // if the component is controlled, we can assert that the queryFunction is defined + return this.args.queryFunction!(page, pageSize); } else { return {}; } } - get routing() { - let routing = { + get routing(): HdsPaginationRoutingProps { + const routing: HdsPaginationRoutingProps = { route: this.args.route ?? undefined, model: this.args.model ?? undefined, models: this.args.models ?? undefined, @@ -125,11 +157,11 @@ export default class HdsPaginationCompactIndexComponent extends Component { // the "query" is dynamic and needs to be calculated if (this.isControlled) { routing.queryPrev = this.buildQueryParamsObject( - 'prev', + HdsPaginationDirectionValues.Prev, this.currentPageSize ); routing.queryNext = this.buildQueryParamsObject( - 'next', + HdsPaginationDirectionValues.Next, this.currentPageSize ); } else { @@ -141,10 +173,8 @@ export default class HdsPaginationCompactIndexComponent extends Component { } @action - onPageChange(newPage) { - this.currentPage = newPage; - - let { onPageChange } = this.args; + onPageChange(newPage: HdsPaginationDirections): void { + const { onPageChange } = this.args; if (typeof onPageChange === 'function') { onPageChange(newPage); @@ -152,8 +182,8 @@ export default class HdsPaginationCompactIndexComponent extends Component { } @action - onPageSizeChange(newPageSize) { - let { onPageSizeChange } = this.args; + onPageSizeChange(newPageSize: number): void { + const { onPageSizeChange } = this.args; // invoke the callback function if (typeof onPageSizeChange === 'function') { From 3a8475160425019f3dbdbf71b3a3169010736232 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 11:38:43 -0400 Subject: [PATCH 11/26] added ts files to component registry --- packages/components/src/components.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/components/src/components.ts b/packages/components/src/components.ts index 537e3e13349..6eb81d4a9b2 100644 --- a/packages/components/src/components.ts +++ b/packages/components/src/components.ts @@ -86,6 +86,13 @@ import HdsModalBodyComponent from './components/hds/modal/body.ts'; import HdsModalFooter from './components/hds/modal/footer.ts'; import HdsModalHeader from './components/hds/modal/header.ts'; import HdsPageHeader from './components/hds/page-header/index.ts'; +import HdsPaginationCompactComponent from './components/hds/pagination/compact/index.ts'; +import HdsPaginationControlInfoComponent from './components/hds/pagination/info/index.ts'; +import HdsPaginationControlArrowComponent from './components/hds/pagination/nav/arrow.ts'; +import HdsPaginationControlEllipsisComponent from './components/hds/pagination/nav/ellipsis.ts'; +import HdsPaginationControlNumberComponent from './components/hds/pagination/nav/number.ts'; +import HdsPaginationNumberedComponent from './components/hds/pagination/numbered/index.ts'; +import HdsPaginationSizeSelectorComponent from './components/hds/pagination/size-selector/index.ts'; import HdsPopoverPrimitive from './components/hds/popover-primitive/index.ts'; import HdsReveal from './components/hds/reveal/index.ts'; import HdsRichTooltip from './components/hds/rich-tooltip/index.ts'; @@ -201,6 +208,13 @@ export { HdsModalFooter, HdsModalHeader, HdsPageHeader, + HdsPaginationCompactComponent, + HdsPaginationControlInfoComponent, + HdsPaginationControlArrowComponent, + HdsPaginationControlEllipsisComponent, + HdsPaginationControlNumberComponent, + HdsPaginationNumberedComponent, + HdsPaginationSizeSelectorComponent, HdsPopoverPrimitive, HdsReveal, HdsRichTooltip, From 26b5e6c3b88bc842eeef457085bf281535583fea Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 11:59:54 -0400 Subject: [PATCH 12/26] cleaned up the number component --- .../src/components/hds/pagination/nav/number.hbs | 1 - .../src/components/hds/pagination/nav/number.ts | 13 +++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/components/src/components/hds/pagination/nav/number.hbs b/packages/components/src/components/hds/pagination/nav/number.hbs index 5e2790c9b26..c14b276bfcf 100644 --- a/packages/components/src/components/hds/pagination/nav/number.hbs +++ b/packages/components/src/components/hds/pagination/nav/number.hbs @@ -1,4 +1,3 @@ -{{! @glint-nocheck: not typesafe yet }} {{! Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: MPL-2.0 diff --git a/packages/components/src/components/hds/pagination/nav/number.ts b/packages/components/src/components/hds/pagination/nav/number.ts index 4a07f196831..bfa811147d8 100644 --- a/packages/components/src/components/hds/pagination/nav/number.ts +++ b/packages/components/src/components/hds/pagination/nav/number.ts @@ -9,13 +9,14 @@ import { assert } from '@ember/debug'; import type { HdsInteractiveSignature } from '../../interactive'; +interface HdsPaginationNavNumberArgs { + page: number; + onClick: (page: number) => void; + isSelected: boolean; +} + interface HdsPaginationNavNumberSignature { - Args: { - page: number; - isSelected: boolean; - onClick: (page: number) => void; - // TODO: Add the rest - }; + Args: HdsPaginationNavNumberArgs & HdsInteractiveSignature['Args']; Element: HdsInteractiveSignature['Element']; } From e0093444c694a01a46d8fcdb5c147006ebab3d35 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 14:17:24 -0400 Subject: [PATCH 13/26] finished converting the arrow component --- .../components/hds/pagination/nav/arrow.hbs | 2 +- .../components/hds/pagination/nav/arrow.ts | 69 +++++++++++++------ .../src/components/hds/pagination/types.ts | 23 +++++++ 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/packages/components/src/components/hds/pagination/nav/arrow.hbs b/packages/components/src/components/hds/pagination/nav/arrow.hbs index 4f1083a8fa7..3cdcc112822 100644 --- a/packages/components/src/components/hds/pagination/nav/arrow.hbs +++ b/packages/components/src/components/hds/pagination/nav/arrow.hbs @@ -1,8 +1,8 @@ -{{! @glint-nocheck: not typesafe yet }} {{! Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: MPL-2.0 }} + {{#if @disabled}} diff --git a/packages/components/src/components/hds/pagination/nav/arrow.ts b/packages/components/src/components/hds/pagination/nav/arrow.ts index 0d287196968..803d4102887 100644 --- a/packages/components/src/components/hds/pagination/nav/arrow.ts +++ b/packages/components/src/components/hds/pagination/nav/arrow.ts @@ -6,26 +6,53 @@ import Component from '@glimmer/component'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; -import { HdsPaginationDirectionValues } from '../types.ts'; +import { + HdsPaginationDirectionValues, + HdsPaginationDirectionAriaLabelValues, + HdsPaginationDirectionLabelValues, + HdsPaginationDirectionIconValues, +} from '../types.ts'; import type { HdsInteractiveSignature } from '../../interactive'; -import type { HdsPaginationDirections } from '../types'; +import type { + HdsPaginationDirections, + HdsPaginationRoutingProps, + HdsPaginationDirectionAriaLabels, + HdsPaginationDirectionLabels, + HdsPaginationDirectionIcons, +} from '../types'; -export const DIRECTIONS = ['prev', 'next']; +type HdsPaginationControlArrowRoutingProps = Pick< + HdsPaginationRoutingProps, + 'route' | 'model' | 'models' | 'replace' +>; + +interface HdsPaginationControlArrowContent { + label?: HdsPaginationDirectionLabels; + icon?: HdsPaginationDirectionIcons; + ariaLabel?: HdsPaginationDirectionAriaLabels; +} + +interface HdsPaginationControlArrowArgs { + direction: HdsPaginationDirections; + disabled?: boolean; + showLabel?: boolean; + query?: Record; + onClick?: (direction: HdsPaginationDirections) => void; +} interface HdsPaginationControlArrowSignature { - Args: { - direction: HdsPaginationDirections; - disabled?: boolean; - showLabel?: boolean; - onClick?: (direction: HdsPaginationDirections) => void; - // TODO: Add the rest of the arguments - }; + Args: HdsPaginationControlArrowArgs & HdsPaginationControlArrowRoutingProps; Element: HdsInteractiveSignature['Element']; } +export const DIRECTIONS: HdsPaginationDirections[] = [ + HdsPaginationDirectionValues.Prev, + HdsPaginationDirectionValues.Next, +]; + export default class HdsPaginationControlArrowComponent extends Component { - get content() { + get content(): HdsPaginationControlArrowContent { const { direction } = this.args; assert( @@ -35,32 +62,32 @@ export default class HdsPaginationControlArrowComponent extends Component Date: Mon, 26 Aug 2024 14:28:35 -0400 Subject: [PATCH 14/26] cleaned up the info component --- .../components/src/components/hds/pagination/info/index.hbs | 1 - .../components/src/components/hds/pagination/info/index.ts | 3 ++- .../components/src/components/hds/pagination/nav/arrow.hbs | 1 - packages/components/src/components/hds/pagination/nav/arrow.ts | 1 - .../components/src/components/hds/pagination/nav/number.ts | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/components/src/components/hds/pagination/info/index.hbs b/packages/components/src/components/hds/pagination/info/index.hbs index 50b630e0442..2323b6d10d2 100644 --- a/packages/components/src/components/hds/pagination/info/index.hbs +++ b/packages/components/src/components/hds/pagination/info/index.hbs @@ -1,4 +1,3 @@ -{{! @glint-nocheck: not typesafe yet }} {{! Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: MPL-2.0 diff --git a/packages/components/src/components/hds/pagination/info/index.ts b/packages/components/src/components/hds/pagination/info/index.ts index d92b150e7e3..9fc0ea13aa1 100644 --- a/packages/components/src/components/hds/pagination/info/index.ts +++ b/packages/components/src/components/hds/pagination/info/index.ts @@ -5,6 +5,7 @@ import Component from '@glimmer/component'; import type { HdsPaginationNumberedSignature } from '../numbered/index'; +import type { HdsTextBodySignature } from '../../text/body'; interface HdsPaginationInfoSignature { Args: { itemsRangeStart: number; @@ -12,7 +13,7 @@ interface HdsPaginationInfoSignature { showTotalItems?: HdsPaginationNumberedSignature['Args']['showTotalItems']; totalItems: HdsPaginationNumberedSignature['Args']['totalItems']; }; - Element: HTMLDivElement; + Element: HdsTextBodySignature['Element']; } export default class HdsPaginationInfoComponent extends Component { diff --git a/packages/components/src/components/hds/pagination/nav/arrow.hbs b/packages/components/src/components/hds/pagination/nav/arrow.hbs index 3cdcc112822..daed0ea7b31 100644 --- a/packages/components/src/components/hds/pagination/nav/arrow.hbs +++ b/packages/components/src/components/hds/pagination/nav/arrow.hbs @@ -2,7 +2,6 @@ Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: MPL-2.0 }} - {{#if @disabled}} diff --git a/packages/components/src/components/hds/pagination/nav/arrow.ts b/packages/components/src/components/hds/pagination/nav/arrow.ts index 803d4102887..1f291c7a178 100644 --- a/packages/components/src/components/hds/pagination/nav/arrow.ts +++ b/packages/components/src/components/hds/pagination/nav/arrow.ts @@ -2,7 +2,6 @@ * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ - import Component from '@glimmer/component'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; diff --git a/packages/components/src/components/hds/pagination/nav/number.ts b/packages/components/src/components/hds/pagination/nav/number.ts index bfa811147d8..c54d67c2732 100644 --- a/packages/components/src/components/hds/pagination/nav/number.ts +++ b/packages/components/src/components/hds/pagination/nav/number.ts @@ -2,7 +2,6 @@ * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ - import Component from '@glimmer/component'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; From b00aa80da9a53b1593deba47b8e3d5f07b451570 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 14:38:50 -0400 Subject: [PATCH 15/26] added to template-registry: --- .../components/hds/pagination/nav/ellipsis.ts | 1 - .../hds/pagination/numbered/index.hbs | 1 - .../hds/pagination/numbered/index.ts | 1 - packages/components/src/template-registry.ts | 29 +++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/components/src/components/hds/pagination/nav/ellipsis.ts b/packages/components/src/components/hds/pagination/nav/ellipsis.ts index 584f7e1c74b..104b4ada49d 100644 --- a/packages/components/src/components/hds/pagination/nav/ellipsis.ts +++ b/packages/components/src/components/hds/pagination/nav/ellipsis.ts @@ -2,7 +2,6 @@ * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ - import TemplateOnlyComponent from '@ember/component/template-only'; export interface HdsApplicationPaginationNavEllipsisSignature { diff --git a/packages/components/src/components/hds/pagination/numbered/index.hbs b/packages/components/src/components/hds/pagination/numbered/index.hbs index 8d7d0bcb46b..715af860e80 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.hbs +++ b/packages/components/src/components/hds/pagination/numbered/index.hbs @@ -1,4 +1,3 @@ -{{! @glint-nocheck: not typesafe yet }} {{! Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: MPL-2.0 diff --git a/packages/components/src/components/hds/pagination/numbered/index.ts b/packages/components/src/components/hds/pagination/numbered/index.ts index c3ab2b7f2c7..e74dceb536d 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.ts +++ b/packages/components/src/components/hds/pagination/numbered/index.ts @@ -2,7 +2,6 @@ * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ - import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; diff --git a/packages/components/src/template-registry.ts b/packages/components/src/template-registry.ts index ab67a072c82..b05079a38dc 100644 --- a/packages/components/src/template-registry.ts +++ b/packages/components/src/template-registry.ts @@ -128,6 +128,13 @@ import type HdsPageHeaderBadgesComponent from './components/hds/page-header/badg import type HdsPageHeaderDescriptionComponent from './components/hds/page-header/description'; import type HdsPageHeaderSubtitleComponent from './components/hds/page-header/subtitle'; import type HdsPageHeaderTitleComponent from './components/hds/page-header/title'; +import type HdsPaginationCompactComponent from './components/hds/pagination/compact/index'; +import type HdsPaginationControlInfoComponent from './components/hds/pagination/info/index'; +import type HdsPaginationControlArrowComponent from './components/hds/pagination/nav/arrow'; +import type HdsPaginationControlEllipsisComponent from './components/hds/pagination/nav/ellipsis'; +import type HdsPaginationControlNumberComponent from './components/hds/pagination/nav/number'; +import type HdsPaginationNumberedComponent from './components/hds/pagination/numbered/index'; +import type HdsPaginationSizeSelectorComponent from './components/hds/pagination/size-selector/index'; import type HdsPopoverPrimitiveComponent from './components/hds/popover-primitive'; import type HdsRevealComponent from './components/hds/reveal'; import type HdsRevealToggleButtonComponent from './components/hds/reveal/toggle/button'; @@ -627,6 +634,28 @@ export default interface HdsComponentsRegistry { 'Hds::PageHeader::Title': typeof HdsPageHeaderTitleComponent; 'hds/page-header/title': typeof HdsPageHeaderTitleComponent; + // Pagination + 'Hds::Pagination::Compact': typeof HdsPaginationCompactComponent; + 'hds/pagination/compact': typeof HdsPaginationCompactComponent; + + 'Hds::Pagination::Info': typeof HdsPaginationControlInfoComponent; + 'hds/pagination/info': typeof HdsPaginationControlInfoComponent; + + 'Hds::Pagination::Nav::Arrow': typeof HdsPaginationControlArrowComponent; + 'hds/pagination/nav/arrow': typeof HdsPaginationControlArrowComponent; + + 'Hds::Pagination::Nav::Ellipsis': typeof HdsPaginationControlEllipsisComponent; + 'hds/pagination/nav/ellipsis': typeof HdsPaginationControlEllipsisComponent; + + 'Hds::Pagination::Nav::Number': typeof HdsPaginationControlNumberComponent; + 'hds/pagination/nav/number': typeof HdsPaginationControlNumberComponent; + + 'Hds::Pagination::Numbered': typeof HdsPaginationNumberedComponent; + 'hds/pagination/numbered': typeof HdsPaginationNumberedComponent; + + 'Hds::Pagination::SizeSelector': typeof HdsPaginationSizeSelectorComponent; + 'hds/pagination/size-selector': typeof HdsPaginationSizeSelectorComponent; + // PopoverPrimitive 'Hds::PopoverPrimitive': typeof HdsPopoverPrimitiveComponent; 'hds/popover-primitive': typeof HdsPopoverPrimitiveComponent; From 180807b5894318baffdd0e1096e17f90f5acd391 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 16:23:12 -0400 Subject: [PATCH 16/26] cleaning up types --- .../hds/pagination/numbered/index.ts | 47 ++++++++++--------- .../hds/pagination/size-selector/index.ts | 8 ++-- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/packages/components/src/components/hds/pagination/numbered/index.ts b/packages/components/src/components/hds/pagination/numbered/index.ts index e74dceb536d..532e1adcb7b 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.ts +++ b/packages/components/src/components/hds/pagination/numbered/index.ts @@ -15,30 +15,31 @@ import type { HdsPaginationElliptizedPageArray, HdsPaginationElliptizedPageArrayItem, } from '../types'; + +type HdsPaginationNumberedRoutingProps = Pick< + HdsPaginationRoutingProps, + 'route' | 'model' | 'models' | 'replace' +>; +interface HdsPaginationNumberedArgs { + ariaLabel?: string; + totalItems: number; + showLabels?: boolean; + isTruncated?: boolean; + currentPage?: number; + showInfo?: boolean; //TODO: Add this to the docs + showPageNumbers?: boolean; //TODO: Add this to the docs + showTotalItems?: boolean; //TODO: Add this to the docs + showSizeSelector?: boolean; + sizeSelectorLabel?: string; + pageSizes?: number[]; + currentPageSize?: number; + queryFunction?: (page: number, pageSize: number) => Record; + onPageChange?: (page: number, pageSize: number) => unknown; + onPageSizeChange?: (pageSize: number) => unknown; +} + export interface HdsPaginationNumberedSignature { - Args: { - ariaLabel?: string; - totalItems: number; - showLabels?: boolean; - isTruncated?: boolean; - currentPage?: number; - showInfo?: boolean; //TODO: Add this to the docs - showPageNumbers?: boolean; //TODO: Add this to the docs - showTotalItems?: boolean; //TODO: Add this to the docs - showSizeSelector?: boolean; - sizeSelectorLabel?: string; - pageSizes?: number[]; - currentPageSize?: number; - // route stuff - route?: string; - model?: unknown; - models?: unknown[]; - replace?: boolean; - queryFunction?: (page: number, pageSize: number) => Record; - // end route stuff - onPageChange?: (page: number, pageSize: number) => unknown; - onPageSizeChange?: (pageSize: number) => unknown; - }; + Args: HdsPaginationNumberedArgs & HdsPaginationNumberedRoutingProps; Element: HTMLDivElement; } diff --git a/packages/components/src/components/hds/pagination/size-selector/index.ts b/packages/components/src/components/hds/pagination/size-selector/index.ts index 0878fbaeab7..d43ae2ab044 100644 --- a/packages/components/src/components/hds/pagination/size-selector/index.ts +++ b/packages/components/src/components/hds/pagination/size-selector/index.ts @@ -23,7 +23,7 @@ interface HdsPaginationSizeSelectorSignature { export default class HdsPaginationSizeSelectorComponent extends Component { SizeSelectorId = 'pagination-size-selector-' + guidFor(this); - get pageSizes() { + get pageSizes(): number[] { const { pageSizes } = this.args; assert( @@ -34,7 +34,7 @@ export default class HdsPaginationSizeSelectorComponent extends Component Date: Mon, 26 Aug 2024 16:53:44 -0400 Subject: [PATCH 17/26] cleaning up types --- .../hds/pagination/compact/index.ts | 14 ++++----- .../components/hds/pagination/nav/arrow.ts | 7 +---- .../hds/pagination/numbered/index.ts | 29 +++++++++---------- .../src/components/hds/pagination/types.ts | 4 --- 4 files changed, 22 insertions(+), 32 deletions(-) diff --git a/packages/components/src/components/hds/pagination/compact/index.ts b/packages/components/src/components/hds/pagination/compact/index.ts index d01efa46999..02529196ffe 100644 --- a/packages/components/src/components/hds/pagination/compact/index.ts +++ b/packages/components/src/components/hds/pagination/compact/index.ts @@ -14,10 +14,10 @@ import type { HdsPaginationDirections, } from '../types'; -type HdsPaginationCompactSignatureRoutingProps = Pick< - HdsPaginationRoutingProps, - 'route' | 'model' | 'models' | 'replace' | 'queryPrev' | 'queryNext' ->; +type HdsPaginationCompactRoutingQueryProps = HdsPaginationRoutingProps & { + queryNext?: Record; + queryPrev?: Record; +}; interface HdsPaginationCompactArgs { ariaLabel?: string; @@ -37,7 +37,7 @@ interface HdsPaginationCompactArgs { } interface HdsPaginationCompactSignature { - Args: HdsPaginationCompactArgs & HdsPaginationCompactSignatureRoutingProps; + Args: HdsPaginationCompactArgs & HdsPaginationRoutingProps; Element: HTMLDivElement; } @@ -146,8 +146,8 @@ export default class HdsPaginationCompactComponent extends Component; - interface HdsPaginationControlArrowContent { label?: HdsPaginationDirectionLabels; icon?: HdsPaginationDirectionIcons; @@ -41,7 +36,7 @@ interface HdsPaginationControlArrowArgs { } interface HdsPaginationControlArrowSignature { - Args: HdsPaginationControlArrowArgs & HdsPaginationControlArrowRoutingProps; + Args: HdsPaginationControlArrowArgs & HdsPaginationRoutingProps; Element: HdsInteractiveSignature['Element']; } diff --git a/packages/components/src/components/hds/pagination/numbered/index.ts b/packages/components/src/components/hds/pagination/numbered/index.ts index 532e1adcb7b..6990ccecdd3 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.ts +++ b/packages/components/src/components/hds/pagination/numbered/index.ts @@ -16,10 +16,12 @@ import type { HdsPaginationElliptizedPageArrayItem, } from '../types'; -type HdsPaginationNumberedRoutingProps = Pick< - HdsPaginationRoutingProps, - 'route' | 'model' | 'models' | 'replace' ->; +type HdsPaginationNumberedRoutingQueryProps = HdsPaginationRoutingProps & { + queryNext?: Record; + queryPrev?: Record; + queryPages?: Record; +}; + interface HdsPaginationNumberedArgs { ariaLabel?: string; totalItems: number; @@ -39,7 +41,7 @@ interface HdsPaginationNumberedArgs { } export interface HdsPaginationNumberedSignature { - Args: HdsPaginationNumberedArgs & HdsPaginationNumberedRoutingProps; + Args: HdsPaginationNumberedArgs & HdsPaginationRoutingProps; Element: HTMLDivElement; } @@ -118,7 +120,7 @@ export default class HdsPaginationNumberedComponent extends Component; - queryNext?: Record; - queryPrev?: Record; - queryPages?: Record; } From 12a64d0690ecaa03be5c8dd51f4b569714b5b9cf Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Mon, 26 Aug 2024 17:45:51 -0400 Subject: [PATCH 18/26] cleaning up types --- .../components/hds/pagination/compact/index.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/components/src/components/hds/pagination/compact/index.ts b/packages/components/src/components/hds/pagination/compact/index.ts index 02529196ffe..9a263041ce9 100644 --- a/packages/components/src/components/hds/pagination/compact/index.ts +++ b/packages/components/src/components/hds/pagination/compact/index.ts @@ -30,7 +30,7 @@ interface HdsPaginationCompactArgs { currentPageSize?: number; queryFunction?: ( page: HdsPaginationDirections, - pageSize: number + pageSize?: number ) => Record; onPageChange?: (page: HdsPaginationDirections) => void; onPageSizeChange?: (pageSize: number) => void; @@ -53,8 +53,7 @@ export default class HdsPaginationCompactComponent extends Component { if (this.isControlled) { // if the component is controlled, we can assert that the queryFunction is defined From 77227954a6f3af950b68b48d58345576f77bd1e0 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Tue, 27 Aug 2024 13:44:13 -0400 Subject: [PATCH 19/26] no more type errors --- .../hds/pagination/compact/index.hbs | 1 - .../hds/pagination/compact/index.ts | 11 ++++--- .../components/hds/pagination/nav/arrow.ts | 4 +-- .../hds/pagination/numbered/index.hbs | 2 +- .../hds/pagination/numbered/index.ts | 30 +++++++++++++++---- .../src/components/hds/pagination/types.ts | 12 ++++---- 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/components/src/components/hds/pagination/compact/index.hbs b/packages/components/src/components/hds/pagination/compact/index.hbs index 14861eb00ce..c808653449d 100644 --- a/packages/components/src/components/hds/pagination/compact/index.hbs +++ b/packages/components/src/components/hds/pagination/compact/index.hbs @@ -1,4 +1,3 @@ -{{! @glint-nocheck: not typesafe yet }} {{! Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: MPL-2.0 diff --git a/packages/components/src/components/hds/pagination/compact/index.ts b/packages/components/src/components/hds/pagination/compact/index.ts index 9a263041ce9..31636d41f3a 100644 --- a/packages/components/src/components/hds/pagination/compact/index.ts +++ b/packages/components/src/components/hds/pagination/compact/index.ts @@ -13,10 +13,13 @@ import type { HdsPaginationRoutingProps, HdsPaginationDirections, } from '../types'; +import type { HdsInteractiveSignature } from '../../interactive'; + +type HdsInteractiveQuery = HdsInteractiveSignature['Args']['query']; type HdsPaginationCompactRoutingQueryProps = HdsPaginationRoutingProps & { - queryNext?: Record; - queryPrev?: Record; + queryNext?: HdsInteractiveQuery; + queryPrev?: HdsInteractiveQuery; }; interface HdsPaginationCompactArgs { @@ -31,7 +34,7 @@ interface HdsPaginationCompactArgs { queryFunction?: ( page: HdsPaginationDirections, pageSize?: number - ) => Record; + ) => HdsInteractiveQuery; onPageChange?: (page: HdsPaginationDirections) => void; onPageSizeChange?: (pageSize: number) => void; } @@ -129,7 +132,7 @@ export default class HdsPaginationCompactComponent extends Component { + ): HdsInteractiveQuery { if (this.isControlled) { // if the component is controlled, we can assert that the queryFunction is defined return this.args.queryFunction!(page, pageSize); diff --git a/packages/components/src/components/hds/pagination/nav/arrow.ts b/packages/components/src/components/hds/pagination/nav/arrow.ts index 8af1b511034..a465985ccee 100644 --- a/packages/components/src/components/hds/pagination/nav/arrow.ts +++ b/packages/components/src/components/hds/pagination/nav/arrow.ts @@ -15,7 +15,6 @@ import { import type { HdsInteractiveSignature } from '../../interactive'; import type { HdsPaginationDirections, - HdsPaginationRoutingProps, HdsPaginationDirectionAriaLabels, HdsPaginationDirectionLabels, HdsPaginationDirectionIcons, @@ -31,12 +30,11 @@ interface HdsPaginationControlArrowArgs { direction: HdsPaginationDirections; disabled?: boolean; showLabel?: boolean; - query?: Record; onClick?: (direction: HdsPaginationDirections) => void; } interface HdsPaginationControlArrowSignature { - Args: HdsPaginationControlArrowArgs & HdsPaginationRoutingProps; + Args: HdsPaginationControlArrowArgs & HdsInteractiveSignature['Args']; Element: HdsInteractiveSignature['Element']; } diff --git a/packages/components/src/components/hds/pagination/numbered/index.hbs b/packages/components/src/components/hds/pagination/numbered/index.hbs index 715af860e80..39bee9b2207 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.hbs +++ b/packages/components/src/components/hds/pagination/numbered/index.hbs @@ -32,7 +32,7 @@ {{else}} ; - queryPrev?: Record; - queryPages?: Record; + queryNext?: HdsInteractiveQuery; + queryPrev?: HdsInteractiveQuery; + queryPages?: Record< + HdsPaginationElliptizedPageArrayItem, + HdsInteractiveQuery + >; }; interface HdsPaginationNumberedArgs { @@ -35,7 +41,7 @@ interface HdsPaginationNumberedArgs { sizeSelectorLabel?: string; pageSizes?: number[]; currentPageSize?: number; - queryFunction?: (page: number, pageSize: number) => Record; + queryFunction?: (page: number, pageSize: number) => HdsInteractiveQuery; onPageChange?: (page: number, pageSize: number) => unknown; onPageSizeChange?: (pageSize: number) => unknown; } @@ -207,7 +213,7 @@ export default class HdsPaginationNumberedComponent extends Component { + ): HdsInteractiveQuery { // `page` may also be ellipsis if (this.isControlled && typeof page === 'number') { // if the component is controlled, `@queryFunction` is asserted to be a function @@ -304,4 +310,18 @@ export default class HdsPaginationNumberedComponent extends Component { + if (typeof item === 'number') { + return item; + } else { + throw new Error('Expected a number, but got an ellipsis'); + } + }; + + getPageNumberQuery(page: HdsPaginationElliptizedPageArrayItem) { + return this.routing.queryPages![this.elliptizedPageArrayItemAsNumber(page)]; + } } diff --git a/packages/components/src/components/hds/pagination/types.ts b/packages/components/src/components/hds/pagination/types.ts index 809581f0f97..a2488bcf7a2 100644 --- a/packages/components/src/components/hds/pagination/types.ts +++ b/packages/components/src/components/hds/pagination/types.ts @@ -1,3 +1,5 @@ +import type { HdsInteractiveSignature } from '../interactive'; + export enum HdsPaginationDirectionValues { Next = 'next', Prev = 'prev', @@ -35,9 +37,7 @@ export type HdsPaginationElliptizedPageArrayItem = string | number; export type HdsPaginationElliptizedPageArray = HdsPaginationElliptizedPageArrayItem[]; -export interface HdsPaginationRoutingProps { - route?: string; - model?: unknown; - models?: unknown[]; - replace?: boolean; -} +export type HdsPaginationRoutingProps = Pick< + HdsInteractiveSignature['Args'], + 'route' | 'model' | 'models' | 'replace' +>; From eb5ed484104bfaffc78d553493273b6526573ca4 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Tue, 27 Aug 2024 14:17:19 -0400 Subject: [PATCH 20/26] fixed ts errors after rebase --- .../src/components/hds/pagination/nav/arrow.ts | 17 ++++++++--------- .../src/components/hds/pagination/types.ts | 7 ------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/packages/components/src/components/hds/pagination/nav/arrow.ts b/packages/components/src/components/hds/pagination/nav/arrow.ts index a465985ccee..a718c8b0dad 100644 --- a/packages/components/src/components/hds/pagination/nav/arrow.ts +++ b/packages/components/src/components/hds/pagination/nav/arrow.ts @@ -9,21 +9,20 @@ import { HdsPaginationDirectionValues, HdsPaginationDirectionAriaLabelValues, HdsPaginationDirectionLabelValues, - HdsPaginationDirectionIconValues, } from '../types.ts'; +import type { HdsIconSignature } from '../../icon/index.ts'; import type { HdsInteractiveSignature } from '../../interactive'; import type { HdsPaginationDirections, HdsPaginationDirectionAriaLabels, HdsPaginationDirectionLabels, - HdsPaginationDirectionIcons, } from '../types'; interface HdsPaginationControlArrowContent { - label?: HdsPaginationDirectionLabels; - icon?: HdsPaginationDirectionIcons; - ariaLabel?: HdsPaginationDirectionAriaLabels; + label: HdsPaginationDirectionLabels; + icon: HdsIconSignature['Args']['name']; + ariaLabel: HdsPaginationDirectionAriaLabels; } interface HdsPaginationControlArrowArgs { @@ -54,23 +53,23 @@ export default class HdsPaginationControlArrowComponent extends Component = {}; if (direction === HdsPaginationDirectionValues.Prev) { content = { label: HdsPaginationDirectionLabelValues.Prev, - icon: HdsPaginationDirectionIconValues.ChevronLeft, + icon: 'chevron-left', ariaLabel: HdsPaginationDirectionAriaLabelValues.Prev, }; } if (direction === HdsPaginationDirectionValues.Next) { content = { label: HdsPaginationDirectionLabelValues.Next, - icon: HdsPaginationDirectionIconValues.ChevronRight, + icon: 'chevron-right', ariaLabel: HdsPaginationDirectionAriaLabelValues.Next, }; } - return content; + return content as HdsPaginationControlArrowContent; } get showLabel(): boolean { diff --git a/packages/components/src/components/hds/pagination/types.ts b/packages/components/src/components/hds/pagination/types.ts index a2488bcf7a2..735d2863e13 100644 --- a/packages/components/src/components/hds/pagination/types.ts +++ b/packages/components/src/components/hds/pagination/types.ts @@ -25,13 +25,6 @@ export enum HdsPaginationDirectionLabelValues { export type HdsPaginationDirectionLabels = `${HdsPaginationDirectionLabelValues}`; -export enum HdsPaginationDirectionIconValues { - ChevronLeft = 'chevron-left', - ChevronRight = 'chevron-right', -} - -export type HdsPaginationDirectionIcons = `${HdsPaginationDirectionIconValues}`; - export type HdsPaginationElliptizedPageArrayItem = string | number; export type HdsPaginationElliptizedPageArray = From c16f8e67ad698259681f1151cb7985c327ff5f4b Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Tue, 27 Aug 2024 14:38:07 -0400 Subject: [PATCH 21/26] fixing tests --- packages/components/package.json | 1 - .../components/hds/pagination/elliptize.ts | 69 ------------------- .../hds/pagination/numbered/index.ts | 68 +++++++++++++++++- .../elliptize-test.js} | 0 4 files changed, 67 insertions(+), 71 deletions(-) delete mode 100644 packages/components/src/components/hds/pagination/elliptize.ts rename showcase/tests/unit/components/hds/{pagination-test.js => pagination/elliptize-test.js} (100%) diff --git a/packages/components/package.json b/packages/components/package.json index 35cdb85e427..70054835824 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -240,7 +240,6 @@ "./components/hds/page-header/subtitle.js": "./dist/_app_/components/hds/page-header/subtitle.js", "./components/hds/page-header/title.js": "./dist/_app_/components/hds/page-header/title.js", "./components/hds/pagination/compact/index.js": "./dist/_app_/components/hds/pagination/compact/index.js", - "./components/hds/pagination/elliptize.js": "./dist/_app_/components/hds/pagination/elliptize.js", "./components/hds/pagination/info/index.js": "./dist/_app_/components/hds/pagination/info/index.js", "./components/hds/pagination/nav/arrow.js": "./dist/_app_/components/hds/pagination/nav/arrow.js", "./components/hds/pagination/nav/ellipsis.js": "./dist/_app_/components/hds/pagination/nav/ellipsis.js", diff --git a/packages/components/src/components/hds/pagination/elliptize.ts b/packages/components/src/components/hds/pagination/elliptize.ts deleted file mode 100644 index 34ed3093883..00000000000 --- a/packages/components/src/components/hds/pagination/elliptize.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { HdsPaginationElliptizedPageArray } from './types'; - -const ELLIPSIS = '…'; - -interface ElliptizeProps { - pages: number[]; - current: number; - limit?: number; -} - -export const elliptize = ({ - pages, - current, - limit = 7, -}: ElliptizeProps): HdsPaginationElliptizedPageArray => { - const length = pages.length; - - let result = []; - let start; - let end; - - if (length <= limit) { - return pages; - } - - if (current <= length / 2) { - start = Math.ceil(limit / 2); - end = limit - start; - } else { - end = Math.ceil(limit / 2); - start = limit - end; - } - - const sliceStart: HdsPaginationElliptizedPageArray = pages.slice(0, start); - const sliceEnd: HdsPaginationElliptizedPageArray = pages.slice(-end); - - if (sliceStart.includes(current) && sliceStart.includes(current + 1)) { - // "current" (and its next sibling) is contained within the "sliceStart" block - sliceEnd.splice(0, 1, ELLIPSIS); - result = ([] as HdsPaginationElliptizedPageArray).concat( - sliceStart, - sliceEnd - ); - } else if (sliceEnd.includes(current - 1) && sliceEnd.includes(current)) { - // "current" (and its prev sibling) is contained within the "sliceEnd" block - sliceStart.splice(-1, 1, ELLIPSIS); - result = ([] as HdsPaginationElliptizedPageArray).concat( - sliceStart, - sliceEnd - ); - } else { - // this is a bit more tricky :) - // we need to calculate how many items there are before/after the current item - // since both the initial and ending blocks are always 2 items long (number + ellipsis) - // and there is always the "current" item, we can just subtract 5 from the limit - const delta = (limit - 5) / 2; // this is why the limit needs to be an odd number - // we slice the array starting at the "current" index, minus the delta, minus one because it's an array (zero-based) - const sliceCurr = pages.slice(current - delta - 1, current + delta); - result = ([] as HdsPaginationElliptizedPageArray).concat( - sliceStart.shift() as number, - ELLIPSIS, - sliceCurr, - ELLIPSIS, - sliceEnd.pop() as number - ); - } - - return result; -}; diff --git a/packages/components/src/components/hds/pagination/numbered/index.ts b/packages/components/src/components/hds/pagination/numbered/index.ts index 031c0d40441..96f6e93bbd9 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.ts +++ b/packages/components/src/components/hds/pagination/numbered/index.ts @@ -6,7 +6,6 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; -import { elliptize } from '../elliptize.ts'; import { HdsPaginationDirectionValues } from '../types.ts'; import type { @@ -16,6 +15,11 @@ import type { HdsPaginationElliptizedPageArrayItem, } from '../types'; import type { HdsInteractiveSignature } from '../../interactive/index.ts'; +interface ElliptizeProps { + pages: number[]; + current: number; + limit?: number; +} type HdsInteractiveQuery = HdsInteractiveSignature['Args']['query']; @@ -51,9 +55,71 @@ export interface HdsPaginationNumberedSignature { Element: HTMLDivElement; } +const ELLIPSIS = '…'; + // for context about the decision to use these values, see: // https://hashicorp.slack.com/archives/C03A0N1QK8S/p1673546329082759 export const DEFAULT_PAGE_SIZES = [10, 30, 50]; + +const elliptize = ({ + pages, + current, + limit = 7, +}: ElliptizeProps): HdsPaginationElliptizedPageArray => { + const length = pages.length; + + let result = []; + let start; + let end; + + if (length <= limit) { + return pages; + } + + if (current <= length / 2) { + start = Math.ceil(limit / 2); + end = limit - start; + } else { + end = Math.ceil(limit / 2); + start = limit - end; + } + + const sliceStart: HdsPaginationElliptizedPageArray = pages.slice(0, start); + const sliceEnd: HdsPaginationElliptizedPageArray = pages.slice(-end); + + if (sliceStart.includes(current) && sliceStart.includes(current + 1)) { + // "current" (and its next sibling) is contained within the "sliceStart" block + sliceEnd.splice(0, 1, ELLIPSIS); + result = ([] as HdsPaginationElliptizedPageArray).concat( + sliceStart, + sliceEnd + ); + } else if (sliceEnd.includes(current - 1) && sliceEnd.includes(current)) { + // "current" (and its prev sibling) is contained within the "sliceEnd" block + sliceStart.splice(-1, 1, ELLIPSIS); + result = ([] as HdsPaginationElliptizedPageArray).concat( + sliceStart, + sliceEnd + ); + } else { + // this is a bit more tricky :) + // we need to calculate how many items there are before/after the current item + // since both the initial and ending blocks are always 2 items long (number + ellipsis) + // and there is always the "current" item, we can just subtract 5 from the limit + const delta = (limit - 5) / 2; // this is why the limit needs to be an odd number + // we slice the array starting at the "current" index, minus the delta, minus one because it's an array (zero-based) + const sliceCurr = pages.slice(current - delta - 1, current + delta); + result = ([] as HdsPaginationElliptizedPageArray).concat( + sliceStart.shift() as number, + ELLIPSIS, + sliceCurr, + ELLIPSIS, + sliceEnd.pop() as number + ); + } + + return result; +}; export default class HdsPaginationNumberedComponent extends Component { // These two private variables are used to differentiate between // "uncontrolled" component (where the state is handled internally) and diff --git a/showcase/tests/unit/components/hds/pagination-test.js b/showcase/tests/unit/components/hds/pagination/elliptize-test.js similarity index 100% rename from showcase/tests/unit/components/hds/pagination-test.js rename to showcase/tests/unit/components/hds/pagination/elliptize-test.js From 0fafc62236c69a698d46120062e82dd19aa7517d Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Tue, 27 Aug 2024 14:56:22 -0400 Subject: [PATCH 22/26] fixing tests --- .../components/src/components/hds/pagination/numbered/index.ts | 2 +- .../hds/pagination/{elliptize-test.js => numbered-test.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename showcase/tests/unit/components/hds/pagination/{elliptize-test.js => numbered-test.js} (100%) diff --git a/packages/components/src/components/hds/pagination/numbered/index.ts b/packages/components/src/components/hds/pagination/numbered/index.ts index 96f6e93bbd9..1d4b66fcf70 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.ts +++ b/packages/components/src/components/hds/pagination/numbered/index.ts @@ -61,7 +61,7 @@ const ELLIPSIS = '…'; // https://hashicorp.slack.com/archives/C03A0N1QK8S/p1673546329082759 export const DEFAULT_PAGE_SIZES = [10, 30, 50]; -const elliptize = ({ +export const elliptize = ({ pages, current, limit = 7, diff --git a/showcase/tests/unit/components/hds/pagination/elliptize-test.js b/showcase/tests/unit/components/hds/pagination/numbered-test.js similarity index 100% rename from showcase/tests/unit/components/hds/pagination/elliptize-test.js rename to showcase/tests/unit/components/hds/pagination/numbered-test.js From fa1156b12e61b6037c21902320d48f1d4b3839f9 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Wed, 28 Aug 2024 09:49:49 -0400 Subject: [PATCH 23/26] Update changeset to be more inline with others Co-authored-by: Lee White --- .changeset/hungry-cycles-drum.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/hungry-cycles-drum.md b/.changeset/hungry-cycles-drum.md index 11704a390ea..02db1b8fd2b 100644 --- a/.changeset/hungry-cycles-drum.md +++ b/.changeset/hungry-cycles-drum.md @@ -2,5 +2,5 @@ "@hashicorp/design-system-components": minor --- -`Hds::Pagination` +`Hds::Pagination` - Converted component to Typescript - Converted to Typescript From ed4ef8f5e426671357d4fdf1e9f5e70f6b5460fe Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Wed, 28 Aug 2024 10:02:12 -0400 Subject: [PATCH 24/26] responding to PR feedback --- .../components/hds/pagination/nav/arrow.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/components/src/components/hds/pagination/nav/arrow.ts b/packages/components/src/components/hds/pagination/nav/arrow.ts index a718c8b0dad..80cdd06d9e7 100644 --- a/packages/components/src/components/hds/pagination/nav/arrow.ts +++ b/packages/components/src/components/hds/pagination/nav/arrow.ts @@ -53,23 +53,23 @@ export default class HdsPaginationControlArrowComponent extends Component = {}; - if (direction === HdsPaginationDirectionValues.Prev) { - content = { + const hdsPaginationNavArrowContentDirectionMap: Record< + HdsPaginationDirections, + HdsPaginationControlArrowContent + > = { + [HdsPaginationDirectionValues.Prev]: { label: HdsPaginationDirectionLabelValues.Prev, icon: 'chevron-left', ariaLabel: HdsPaginationDirectionAriaLabelValues.Prev, - }; - } - if (direction === HdsPaginationDirectionValues.Next) { - content = { + }, + [HdsPaginationDirectionValues.Next]: { label: HdsPaginationDirectionLabelValues.Next, icon: 'chevron-right', ariaLabel: HdsPaginationDirectionAriaLabelValues.Next, - }; - } + }, + }; - return content as HdsPaginationControlArrowContent; + return hdsPaginationNavArrowContentDirectionMap[direction]; } get showLabel(): boolean { From b665e93818723dcb581caff60da1f5c69292aa52 Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Wed, 28 Aug 2024 11:39:25 -0400 Subject: [PATCH 25/26] responding to PR feedback --- .changeset/hungry-cycles-drum.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.changeset/hungry-cycles-drum.md b/.changeset/hungry-cycles-drum.md index 02db1b8fd2b..e90fd696e25 100644 --- a/.changeset/hungry-cycles-drum.md +++ b/.changeset/hungry-cycles-drum.md @@ -2,5 +2,4 @@ "@hashicorp/design-system-components": minor --- -`Hds::Pagination` - Converted component to Typescript -- Converted to Typescript +`Hds::Pagination` - Converted component to Typescript \ No newline at end of file From 8f5a3b22fce64ca3ec111ac6bbee1fc0a3c93c1d Mon Sep 17 00:00:00 2001 From: Zack Moore Date: Wed, 28 Aug 2024 12:27:50 -0400 Subject: [PATCH 26/26] removed dev comments --- .../src/components/hds/pagination/numbered/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/src/components/hds/pagination/numbered/index.ts b/packages/components/src/components/hds/pagination/numbered/index.ts index 1d4b66fcf70..6440ce6e862 100644 --- a/packages/components/src/components/hds/pagination/numbered/index.ts +++ b/packages/components/src/components/hds/pagination/numbered/index.ts @@ -38,9 +38,9 @@ interface HdsPaginationNumberedArgs { showLabels?: boolean; isTruncated?: boolean; currentPage?: number; - showInfo?: boolean; //TODO: Add this to the docs - showPageNumbers?: boolean; //TODO: Add this to the docs - showTotalItems?: boolean; //TODO: Add this to the docs + showInfo?: boolean; + showPageNumbers?: boolean; + showTotalItems?: boolean; showSizeSelector?: boolean; sizeSelectorLabel?: string; pageSizes?: number[];