@ds-mo/ui 14.3.0 → 14.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/.package-ready.json +1 -1
  2. package/dist/agent-patterns.json +1 -1
  3. package/dist/agent.json +42 -11
  4. package/dist/angular/ds-pagination.d.ts +1 -1
  5. package/dist/angular/ds-pagination.js +3 -3
  6. package/dist/angular/ds-select.d.ts +1 -1
  7. package/dist/angular/ds-select.js +3 -3
  8. package/dist/components/ds-bar-nav.js +1 -1
  9. package/dist/components/ds-bar-title.js +1 -1
  10. package/dist/components/ds-bar-workflow.js +1 -1
  11. package/dist/components/ds-menu.js +1 -1
  12. package/dist/components/ds-mobile-header.js +1 -1
  13. package/dist/components/ds-mobile-section-switcher.js +1 -1
  14. package/dist/components/ds-pagination.js +1 -1
  15. package/dist/components/ds-panel-nav.js +1 -1
  16. package/dist/components/ds-panel-tool-header.js +1 -1
  17. package/dist/components/ds-panel-tool-search.js +1 -1
  18. package/dist/components/ds-panel-tools.js +1 -1
  19. package/dist/components/ds-select.js +1 -1
  20. package/dist/components/ds-shell-app.js +1 -1
  21. package/dist/components/ds-shell-page.js +1 -1
  22. package/dist/components/ds-shell-tools.js +1 -1
  23. package/dist/components/ds-swatch-picker.js +1 -1
  24. package/dist/components/ds-table.js +1 -1
  25. package/dist/components/ds-table.js.map +1 -1
  26. package/dist/components/ds-toast.js +1 -1
  27. package/dist/components/ds-typing-indicator.js +1 -1
  28. package/dist/components/{p-BSBQ5kGe.js → p-BDXMXH_i.js} +2 -2
  29. package/dist/components/{p-Cpqd69kg.js → p-CDF_nP74.js} +2 -2
  30. package/dist/components/{p-CWsziQQY.js → p-CKfdvOZ2.js} +2 -2
  31. package/dist/components/{p-DwqUW4Rg.js → p-CRLRjtsc.js} +2 -2
  32. package/dist/components/p-CRLRjtsc.js.map +1 -0
  33. package/dist/components/{p-Cjf54_Cq.js → p-CW7ML-3h.js} +2 -2
  34. package/dist/components/{p-qA4eKZkW.js → p-CbqdWBAC.js} +2 -2
  35. package/dist/components/p-Cc5xgR17.js +2 -0
  36. package/dist/components/p-Cc5xgR17.js.map +1 -0
  37. package/dist/components/{p-C68-8tlp.js → p-ChWnbdFS.js} +2 -2
  38. package/dist/components/{p-CkWVI16a.js → p-DF52Grw1.js} +2 -2
  39. package/dist/components/{p-Bxe6532y.js → p-DhDWmMxD.js} +2 -2
  40. package/dist/components/{p-BiBXCjjo.js → p-O3OuOaj3.js} +2 -2
  41. package/dist/components/{p-Dh_TVLnz.js → p-RLiackRN.js} +2 -2
  42. package/dist/components/{p-CW3sRYuf.js → p-b-Dlg3y_.js} +2 -2
  43. package/dist/docs/components.json +243 -13
  44. package/dist/mcp-data/registry/pagination.json +119 -13
  45. package/dist/mcp-data/registry/registry.json +41 -10
  46. package/dist/mcp-data/registry/select.json +20 -2
  47. package/dist/mcp-data/registry/table.json +19 -11
  48. package/dist/styles/table.css +11 -0
  49. package/dist/types/components/Pagination/Pagination.d.ts +15 -1
  50. package/dist/types/components/Pagination/index.d.ts +1 -1
  51. package/dist/types/components/Pagination/pagination-model.d.ts +3 -2
  52. package/dist/types/components/Pagination/pagination-types.d.ts +13 -1
  53. package/dist/types/components/Select/Select.d.ts +3 -0
  54. package/dist/types/components/Select/index.d.ts +1 -1
  55. package/dist/types/components/Table/Table.d.ts +12 -0
  56. package/dist/types/components/Table/index.d.ts +1 -1
  57. package/dist/types/components/Table/table-pagination-fit.d.ts +8 -0
  58. package/dist/types/components/Table/table-types.d.ts +30 -1
  59. package/dist/types/components.d.ts +83 -8
  60. package/package.json +1 -1
  61. package/dist/components/p-D1ZI_10t.js +0 -2
  62. package/dist/components/p-D1ZI_10t.js.map +0 -1
  63. package/dist/components/p-DwqUW4Rg.js.map +0 -1
  64. /package/dist/components/{p-BSBQ5kGe.js.map → p-BDXMXH_i.js.map} +0 -0
  65. /package/dist/components/{p-Cpqd69kg.js.map → p-CDF_nP74.js.map} +0 -0
  66. /package/dist/components/{p-CWsziQQY.js.map → p-CKfdvOZ2.js.map} +0 -0
  67. /package/dist/components/{p-Cjf54_Cq.js.map → p-CW7ML-3h.js.map} +0 -0
  68. /package/dist/components/{p-qA4eKZkW.js.map → p-CbqdWBAC.js.map} +0 -0
  69. /package/dist/components/{p-C68-8tlp.js.map → p-ChWnbdFS.js.map} +0 -0
  70. /package/dist/components/{p-CkWVI16a.js.map → p-DF52Grw1.js.map} +0 -0
  71. /package/dist/components/{p-Bxe6532y.js.map → p-DhDWmMxD.js.map} +0 -0
  72. /package/dist/components/{p-BiBXCjjo.js.map → p-O3OuOaj3.js.map} +0 -0
  73. /package/dist/components/{p-Dh_TVLnz.js.map → p-RLiackRN.js.map} +0 -0
  74. /package/dist/components/{p-CW3sRYuf.js.map → p-b-Dlg3y_.js.map} +0 -0
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-08-19T01:48:34",
2
+ "timestamp": "2026-08-19T03:44:17",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.43.5",
@@ -15771,6 +15771,119 @@
15771
15771
  "docsTags": [],
15772
15772
  "usage": {},
15773
15773
  "props": [
15774
+ {
15775
+ "name": "fitPageSize",
15776
+ "type": "number | undefined",
15777
+ "complexType": {
15778
+ "original": "number | undefined",
15779
+ "resolved": "number | undefined",
15780
+ "references": {}
15781
+ },
15782
+ "mutable": false,
15783
+ "attr": "fit-page-size",
15784
+ "reflectToAttr": false,
15785
+ "docs": "Effective whole-item capacity to request when Fit is selected.",
15786
+ "docsTags": [],
15787
+ "values": [
15788
+ {
15789
+ "type": "number"
15790
+ },
15791
+ {
15792
+ "type": "undefined"
15793
+ }
15794
+ ],
15795
+ "optional": false,
15796
+ "required": false,
15797
+ "getter": false,
15798
+ "setter": false
15799
+ },
15800
+ {
15801
+ "name": "fitPageSizeLabel",
15802
+ "type": "string",
15803
+ "complexType": {
15804
+ "original": "string",
15805
+ "resolved": "string",
15806
+ "references": {}
15807
+ },
15808
+ "mutable": false,
15809
+ "attr": "fit-page-size-label",
15810
+ "reflectToAttr": false,
15811
+ "docs": "Full choice-list label for Fit.",
15812
+ "docsTags": [
15813
+ {
15814
+ "name": "default",
15815
+ "text": "'Fit to page'"
15816
+ }
15817
+ ],
15818
+ "default": "'Fit to page'",
15819
+ "values": [
15820
+ {
15821
+ "type": "string"
15822
+ }
15823
+ ],
15824
+ "optional": false,
15825
+ "required": false,
15826
+ "getter": false,
15827
+ "setter": false
15828
+ },
15829
+ {
15830
+ "name": "fitPageSizeTriggerLabel",
15831
+ "type": "string",
15832
+ "complexType": {
15833
+ "original": "string",
15834
+ "resolved": "string",
15835
+ "references": {}
15836
+ },
15837
+ "mutable": false,
15838
+ "attr": "fit-page-size-trigger-label",
15839
+ "reflectToAttr": false,
15840
+ "docs": "Compact closed-trigger label while Fit is selected.",
15841
+ "docsTags": [
15842
+ {
15843
+ "name": "default",
15844
+ "text": "'Fit'"
15845
+ }
15846
+ ],
15847
+ "default": "'Fit'",
15848
+ "values": [
15849
+ {
15850
+ "type": "string"
15851
+ }
15852
+ ],
15853
+ "optional": false,
15854
+ "required": false,
15855
+ "getter": false,
15856
+ "setter": false
15857
+ },
15858
+ {
15859
+ "name": "fitToPage",
15860
+ "type": "boolean",
15861
+ "complexType": {
15862
+ "original": "boolean",
15863
+ "resolved": "boolean",
15864
+ "references": {}
15865
+ },
15866
+ "mutable": false,
15867
+ "attr": "fit-to-page",
15868
+ "reflectToAttr": false,
15869
+ "docs": "Include the Fit to page choice.",
15870
+ "docsTags": [
15871
+ {
15872
+ "name": "default",
15873
+ "text": "false"
15874
+ }
15875
+ ],
15876
+ "default": "false",
15877
+ "values": [
15878
+ {
15879
+ "type": "boolean"
15880
+ }
15881
+ ],
15882
+ "optional": false,
15883
+ "required": false,
15884
+ "getter": false,
15885
+ "setter": false
15886
+ },
15774
15887
  {
15775
15888
  "name": "itemLabel",
15776
15889
  "type": "string",
@@ -15916,6 +16029,32 @@
15916
16029
  "getter": false,
15917
16030
  "setter": false
15918
16031
  },
16032
+ {
16033
+ "name": "pageSizeAriaLabel",
16034
+ "type": "string | undefined",
16035
+ "complexType": {
16036
+ "original": "string | undefined",
16037
+ "resolved": "string | undefined",
16038
+ "references": {}
16039
+ },
16040
+ "mutable": false,
16041
+ "attr": "page-size-aria-label",
16042
+ "reflectToAttr": false,
16043
+ "docs": "Accessible page-size control label. Defaults to “{pageSizeLabel} per page”.",
16044
+ "docsTags": [],
16045
+ "values": [
16046
+ {
16047
+ "type": "string"
16048
+ },
16049
+ {
16050
+ "type": "undefined"
16051
+ }
16052
+ ],
16053
+ "optional": false,
16054
+ "required": false,
16055
+ "getter": false,
16056
+ "setter": false
16057
+ },
15919
16058
  {
15920
16059
  "name": "pageSizeLabel",
15921
16060
  "type": "string",
@@ -15931,10 +16070,10 @@
15931
16070
  "docsTags": [
15932
16071
  {
15933
16072
  "name": "default",
15934
- "text": "'Items per page'"
16073
+ "text": "'Items'"
15935
16074
  }
15936
16075
  ],
15937
- "default": "'Items per page'",
16076
+ "default": "'Items'",
15938
16077
  "values": [
15939
16078
  {
15940
16079
  "type": "string"
@@ -15945,6 +16084,47 @@
15945
16084
  "getter": false,
15946
16085
  "setter": false
15947
16086
  },
16087
+ {
16088
+ "name": "pageSizeMode",
16089
+ "type": "\"fit\" | \"fixed\"",
16090
+ "complexType": {
16091
+ "original": "PaginationPageSizeMode",
16092
+ "resolved": "\"fit\" | \"fixed\"",
16093
+ "references": {
16094
+ "PaginationPageSizeMode": {
16095
+ "location": "import",
16096
+ "path": "./pagination-types",
16097
+ "id": "src/wc/components/Pagination/pagination-types.ts::PaginationPageSizeMode",
16098
+ "referenceLocation": "PaginationPageSizeMode"
16099
+ }
16100
+ }
16101
+ },
16102
+ "mutable": false,
16103
+ "attr": "page-size-mode",
16104
+ "reflectToAttr": false,
16105
+ "docs": "Whether pageSize is a fixed choice or a measured Fit snapshot.",
16106
+ "docsTags": [
16107
+ {
16108
+ "name": "default",
16109
+ "text": "'fixed'"
16110
+ }
16111
+ ],
16112
+ "default": "'fixed'",
16113
+ "values": [
16114
+ {
16115
+ "value": "fit",
16116
+ "type": "string"
16117
+ },
16118
+ {
16119
+ "value": "fixed",
16120
+ "type": "string"
16121
+ }
16122
+ ],
16123
+ "optional": false,
16124
+ "required": false,
16125
+ "getter": false,
16126
+ "setter": false
16127
+ },
15948
16128
  {
15949
16129
  "name": "pageSizeOptions",
15950
16130
  "type": "number[]",
@@ -19572,6 +19752,46 @@
19572
19752
  "getter": false,
19573
19753
  "setter": false
19574
19754
  },
19755
+ {
19756
+ "name": "indicator",
19757
+ "type": "\"down\" | \"up-down\"",
19758
+ "complexType": {
19759
+ "original": "SelectIndicator",
19760
+ "resolved": "\"down\" | \"up-down\"",
19761
+ "references": {
19762
+ "SelectIndicator": {
19763
+ "location": "local",
19764
+ "path": "/home/runner/work/compomo/compomo/src/wc/components/Select/Select.tsx",
19765
+ "id": "src/wc/components/Select/Select.tsx::SelectIndicator"
19766
+ }
19767
+ }
19768
+ },
19769
+ "mutable": false,
19770
+ "attr": "indicator",
19771
+ "reflectToAttr": false,
19772
+ "docs": "Trailing choice indicator. Use up-down for compact value steppers such as page size.",
19773
+ "docsTags": [
19774
+ {
19775
+ "name": "default",
19776
+ "text": "'down'"
19777
+ }
19778
+ ],
19779
+ "default": "'down'",
19780
+ "values": [
19781
+ {
19782
+ "value": "down",
19783
+ "type": "string"
19784
+ },
19785
+ {
19786
+ "value": "up-down",
19787
+ "type": "string"
19788
+ }
19789
+ ],
19790
+ "optional": false,
19791
+ "required": false,
19792
+ "getter": false,
19793
+ "setter": false
19794
+ },
19575
19795
  {
19576
19796
  "name": "inputId",
19577
19797
  "type": "string | undefined",
@@ -25571,10 +25791,10 @@
25571
25791
  },
25572
25792
  {
25573
25793
  "name": "pagination",
25574
- "type": "PaginationState | null",
25794
+ "type": "TablePaginationState | null",
25575
25795
  "complexType": {
25576
25796
  "original": "TablePaginationState | null",
25577
- "resolved": "PaginationState | null",
25797
+ "resolved": "TablePaginationState | null",
25578
25798
  "references": {
25579
25799
  "TablePaginationState": {
25580
25800
  "location": "import",
@@ -25596,7 +25816,7 @@
25596
25816
  "default": "null",
25597
25817
  "values": [
25598
25818
  {
25599
- "type": "PaginationState"
25819
+ "type": "TablePaginationState"
25600
25820
  },
25601
25821
  {
25602
25822
  "type": "null"
@@ -25835,14 +26055,14 @@
25835
26055
  "mutable": false,
25836
26056
  "attr": "skeleton-rows",
25837
26057
  "reflectToAttr": false,
25838
- "docs": "",
26058
+ "docs": "Initial-loading rows. Defaults to ten so bounded tables retain a useful filled viewport.",
25839
26059
  "docsTags": [
25840
26060
  {
25841
26061
  "name": "default",
25842
- "text": "5"
26062
+ "text": "10"
25843
26063
  }
25844
26064
  ],
25845
- "default": "5",
26065
+ "default": "10",
25846
26066
  "values": [
25847
26067
  {
25848
26068
  "type": "number"
@@ -29030,6 +29250,11 @@
29030
29250
  "docstring": "",
29031
29251
  "path": "src/wc/components/Select/Select.tsx"
29032
29252
  },
29253
+ "src/wc/components/Select/Select.tsx::SelectIndicator": {
29254
+ "declaration": "export type SelectIndicator = 'down' | 'up-down';",
29255
+ "docstring": "",
29256
+ "path": "src/wc/components/Select/Select.tsx"
29257
+ },
29033
29258
  "src/wc/components/Select/Select.tsx::SelectBackground": {
29034
29259
  "declaration": "export type ChoiceBackground =\n | 'faint'\n | 'medium'\n | 'bold'\n | 'strong'\n | 'translucent'\n | 'inverted'\n | 'media'\n | 'always-dark';",
29035
29260
  "docstring": "",
@@ -29360,8 +29585,13 @@
29360
29585
  "docstring": "",
29361
29586
  "path": "src/wc/components/PanelNav/panel-nav-types.ts"
29362
29587
  },
29588
+ "src/wc/components/Pagination/pagination-types.ts::PaginationPageSizeMode": {
29589
+ "declaration": "export type PaginationPageSizeMode = 'fixed' | 'fit';",
29590
+ "docstring": "",
29591
+ "path": "src/wc/components/Pagination/pagination-types.ts"
29592
+ },
29363
29593
  "src/wc/components/Pagination/pagination-types.ts::PaginationChangeDetail": {
29364
- "declaration": "export interface PaginationChangeDetail extends PaginationState {\n previousPageIndex: number;\n previousPageSize: number;\n reason: PaginationChangeReason;\n}",
29594
+ "declaration": "export interface PaginationChangeDetail extends PaginationState {\n previousPageIndex: number;\n previousPageSize: number;\n previousPageSizeMode: PaginationPageSizeMode;\n reason: PaginationChangeReason;\n}",
29365
29595
  "docstring": "Complete next controlled state emitted for a page or page-size request.",
29366
29596
  "path": "src/wc/components/Pagination/pagination-types.ts"
29367
29597
  },
@@ -29456,7 +29686,7 @@
29456
29686
  "path": "src/wc/components/SwatchPicker/swatch-picker-types.ts"
29457
29687
  },
29458
29688
  "src/wc/components/Table/table-types.ts::TableColumn": {
29459
- "declaration": "export interface TableColumn {\n /** Stable column identity. */\n id: string;\n /** Visible column label. May be empty when headerLabel supplies a non-visual name. */\n header: string;\n /** Screen-reader-only column name for an intentionally blank visual header. */\n headerLabel?: string;\n /** Optional labels for columns that present and sort multiple related data points. */\n headerSegments?: TableHeaderSegment[];\n align?: TableCellAlign;\n sortable?: boolean;\n /** Preferred TokoMo table-column width. Numbers remain available for exceptional custom pixel widths. */\n size?: TableColumnWidth | number;\n /** Minimum accepted preferred width in CSS pixels. */\n minSize?: number;\n /** Maximum accepted preferred width in CSS pixels. */\n maxSize?: number;\n /** Wrap cell text instead of truncating it to one line. */\n wrap?: boolean;\n /** Pin one application column to either inline edge during horizontal scrolling. */\n sticky?: TableColumnSticky;\n /**\n * Declare a trailing application-action lane. Action columns keep fixed\n * geometry and may host grouped table-level controls in their header.\n */\n kind?: 'data' | 'action';\n}",
29689
+ "declaration": "export interface TableColumn {\n /** Stable column identity. */\n id: string;\n /** Visible column label. May be empty when headerLabel supplies a non-visual name. */\n header: string;\n /** Screen-reader-only column name for an intentionally blank visual header. */\n headerLabel?: string;\n /** Optional labels for columns that present and sort multiple related data points. */\n headerSegments?: TableHeaderSegment[];\n align?: TableCellAlign;\n sortable?: boolean;\n /** Preferred TokoMo table-column width. Numbers remain available for exceptional custom pixel widths. */\n size?: TableColumnWidth | number;\n /** Minimum accepted preferred width in CSS pixels. */\n minSize?: number;\n /** Maximum accepted preferred width in CSS pixels. */\n maxSize?: number;\n /** Wrap cell text instead of truncating it to one line. */\n wrap?: boolean;\n /** Pin one application column to either inline edge during horizontal scrolling. */\n sticky?: TableColumnSticky;\n /**\n * Declare a trailing application-action lane. Action columns keep fixed\n * geometry and may host grouped table-level controls in their header.\n */\n kind?: 'data' | 'action';\n /** Representative loading geometry for this column. Defaults to one text line. */\n skeleton?: TableCellSkeleton;\n}",
29460
29690
  "docstring": "",
29461
29691
  "path": "src/wc/components/Table/table-types.ts"
29462
29692
  },
@@ -29496,8 +29726,8 @@
29496
29726
  "path": "src/wc/components/Table/table-types.ts"
29497
29727
  },
29498
29728
  "src/wc/components/Table/table-types.ts::TablePaginationState": {
29499
- "declaration": "export interface PaginationState {\n /** Zero-based page index. */\n pageIndex: number;\n /** Number of top-level items on a full page. */\n pageSize: number;\n /** Total number of top-level items across every page. */\n totalItems: number;\n /** Available page sizes. Defaults to 25, 50, 100, and 200. */\n pageSizeOptions?: number[];\n /** Localized plural noun used by assistive range announcements. */\n itemLabel?: string;\n /** Visible label for the page-size selector. */\n pageSizeLabel?: string;\n /** Accessible name for the pagination navigation region. */\n ariaLabel?: string;\n}",
29500
- "docstring": "Controlled pagination state shared by Pagination and pagination-aware consumers.",
29729
+ "declaration": "export interface TablePaginationState extends PaginationState {\n /** Change to request one fresh fitted-capacity snapshot for the current query shape. */\n fitIdentity?: string | number;\n}",
29730
+ "docstring": "Controlled top-level pagination state. Rows or groups contain only the active page.",
29501
29731
  "path": "src/wc/components/Table/table-types.ts"
29502
29732
  },
29503
29733
  "src/wc/components/Table/table-types.ts::TableLoadMoreMode": {
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
3
  "name": "pagination",
4
4
  "title": "Pagination",
5
- "description": "Controlled page-size, range, and first/previous/next/last navigation for application-owned data windows.",
5
+ "description": "Controlled fixed or fitted page-size, compact range, and first/previous/next/last navigation for application-owned data windows.",
6
6
  "type": "registry:ui",
7
7
  "meta": {
8
8
  "library": "@ds-mo/ui",
@@ -13,7 +13,7 @@
13
13
  "intent": {
14
14
  "audience": "general",
15
15
  "status": "stable",
16
- "summary": "Controlled page-size, range, and first/previous/next/last navigation for application-owned data windows.",
16
+ "summary": "Controlled fixed or fitted page-size, compact range, and first/previous/next/last navigation for application-owned data windows.",
17
17
  "useWhen": [
18
18
  "A result set is divided into discrete pages and the application owns fetching or slicing each page.",
19
19
  "A table or list needs a compact page-size selector, result range, and boundary-aware navigation."
@@ -28,18 +28,20 @@
28
28
  "component:ds-button-unfilled"
29
29
  ],
30
30
  "accessibility": [
31
- "The component renders a named navigation region, labels its page-size combobox, and gives every icon-only boundary control an explicit page action name.",
32
- "The visible range and page position use tabular numerals and are repeated in a polite atomic status update with the localized item noun.",
31
+ "The component renders a named navigation region, gives its compact page-size noun a complete accessible label, and gives every icon-only boundary control an explicit page action name.",
32
+ "The visible range and page position use compact slash notation with tabular numerals. A polite atomic status update retains complete ‘of’ and ‘Page’ phrasing with the localized item noun.",
33
+ "Left and Right Arrow request the adjacent page while focus is within pagination navigation controls. The page-size combobox retains its own arrow-key behavior.",
33
34
  "Inactive boundary controls and every control during loading remain non-interactive while retaining their accessible names."
34
35
  ],
35
36
  "states": [
36
- "pageIndex, pageSize, totalItems, and pageSizeOptions are controlled inputs. dsChange reports the complete next pagination state, previous index and size, and whether the request changed the page or page size; it never mutates controlled inputs.",
37
+ "pageIndex, numeric effective pageSize, pageSizeMode, totalItems, and pageSizeOptions are controlled inputs. dsChange reports the complete next pagination state, previous index, size, and mode, and whether the request changed the page, page size, or fitted capacity; it never mutates controlled inputs.",
37
38
  "Page-size changes request the first page. Out-of-range page indexes and invalid numeric inputs normalize only for presentation; the owner remains authoritative.",
38
39
  "Zero results display 0–0 of 0 and Page 1 of 1. A partial final page caps the visible range at totalItems.",
39
- "loading preserves the full pagination surface, applies aria-busy to the navigation region, and prevents page or page-size requests."
40
+ "loading preserves the full pagination surface, applies aria-busy to the navigation region, and prevents page or page-size requests.",
41
+ "fitToPage appends a Fit to page choice. fitPageSize supplies its effective whole-item capacity; the closed trigger says Fit while the range continues to expose the resulting count. Pagination does not measure layouts itself."
40
42
  ],
41
43
  "responsiveBehavior": [
42
- "The compact controls remain on one line. When inline space is insufficient, the pagination surface scrolls horizontally rather than wrapping labels away from their controls."
44
+ "The compact controls remain on one line with noun, range, and page slash notation. When inline space is still insufficient, the pagination surface scrolls horizontally rather than wrapping labels away from their controls."
43
45
  ],
44
46
  "frameworkCaveats": {
45
47
  "customElements": [
@@ -61,6 +63,41 @@
61
63
  },
62
64
  "api": {
63
65
  "props": {
66
+ "fitPageSize": {
67
+ "type": "number | undefined",
68
+ "resolvedType": "number | undefined",
69
+ "attribute": "fit-page-size",
70
+ "required": false,
71
+ "mutable": false,
72
+ "description": "Effective whole-item capacity to request when Fit is selected."
73
+ },
74
+ "fitPageSizeLabel": {
75
+ "type": "string",
76
+ "resolvedType": "string",
77
+ "attribute": "fit-page-size-label",
78
+ "default": "'Fit to page'",
79
+ "required": false,
80
+ "mutable": false,
81
+ "description": "Full choice-list label for Fit."
82
+ },
83
+ "fitPageSizeTriggerLabel": {
84
+ "type": "string",
85
+ "resolvedType": "string",
86
+ "attribute": "fit-page-size-trigger-label",
87
+ "default": "'Fit'",
88
+ "required": false,
89
+ "mutable": false,
90
+ "description": "Compact closed-trigger label while Fit is selected."
91
+ },
92
+ "fitToPage": {
93
+ "type": "boolean",
94
+ "resolvedType": "boolean",
95
+ "attribute": "fit-to-page",
96
+ "default": "false",
97
+ "required": false,
98
+ "mutable": false,
99
+ "description": "Include the Fit to page choice."
100
+ },
64
101
  "itemLabel": {
65
102
  "type": "string",
66
103
  "resolvedType": "string",
@@ -106,15 +143,32 @@
106
143
  "mutable": false,
107
144
  "description": "Controlled number of top-level items on a full page."
108
145
  },
146
+ "pageSizeAriaLabel": {
147
+ "type": "string | undefined",
148
+ "resolvedType": "string | undefined",
149
+ "attribute": "page-size-aria-label",
150
+ "required": false,
151
+ "mutable": false,
152
+ "description": "Accessible page-size control label. Defaults to “{pageSizeLabel} per page”."
153
+ },
109
154
  "pageSizeLabel": {
110
155
  "type": "string",
111
156
  "resolvedType": "string",
112
157
  "attribute": "page-size-label",
113
- "default": "'Items per page'",
158
+ "default": "'Items'",
114
159
  "required": false,
115
160
  "mutable": false,
116
161
  "description": "Visible page-size control label."
117
162
  },
163
+ "pageSizeMode": {
164
+ "type": "PaginationPageSizeMode",
165
+ "resolvedType": "\"fit\" | \"fixed\"",
166
+ "attribute": "page-size-mode",
167
+ "default": "'fixed'",
168
+ "required": false,
169
+ "mutable": false,
170
+ "description": "Whether pageSize is a fixed choice or a measured Fit snapshot."
171
+ },
118
172
  "pageSizeOptions": {
119
173
  "type": "number[]",
120
174
  "resolvedType": "number[]",
@@ -147,6 +201,41 @@
147
201
  "slots": []
148
202
  },
149
203
  "props": {
204
+ "fitPageSize": {
205
+ "type": "number | undefined",
206
+ "resolvedType": "number | undefined",
207
+ "attribute": "fit-page-size",
208
+ "required": false,
209
+ "mutable": false,
210
+ "description": "Effective whole-item capacity to request when Fit is selected."
211
+ },
212
+ "fitPageSizeLabel": {
213
+ "type": "string",
214
+ "resolvedType": "string",
215
+ "attribute": "fit-page-size-label",
216
+ "default": "'Fit to page'",
217
+ "required": false,
218
+ "mutable": false,
219
+ "description": "Full choice-list label for Fit."
220
+ },
221
+ "fitPageSizeTriggerLabel": {
222
+ "type": "string",
223
+ "resolvedType": "string",
224
+ "attribute": "fit-page-size-trigger-label",
225
+ "default": "'Fit'",
226
+ "required": false,
227
+ "mutable": false,
228
+ "description": "Compact closed-trigger label while Fit is selected."
229
+ },
230
+ "fitToPage": {
231
+ "type": "boolean",
232
+ "resolvedType": "boolean",
233
+ "attribute": "fit-to-page",
234
+ "default": "false",
235
+ "required": false,
236
+ "mutable": false,
237
+ "description": "Include the Fit to page choice."
238
+ },
150
239
  "itemLabel": {
151
240
  "type": "string",
152
241
  "resolvedType": "string",
@@ -192,15 +281,32 @@
192
281
  "mutable": false,
193
282
  "description": "Controlled number of top-level items on a full page."
194
283
  },
284
+ "pageSizeAriaLabel": {
285
+ "type": "string | undefined",
286
+ "resolvedType": "string | undefined",
287
+ "attribute": "page-size-aria-label",
288
+ "required": false,
289
+ "mutable": false,
290
+ "description": "Accessible page-size control label. Defaults to “{pageSizeLabel} per page”."
291
+ },
195
292
  "pageSizeLabel": {
196
293
  "type": "string",
197
294
  "resolvedType": "string",
198
295
  "attribute": "page-size-label",
199
- "default": "'Items per page'",
296
+ "default": "'Items'",
200
297
  "required": false,
201
298
  "mutable": false,
202
299
  "description": "Visible page-size control label."
203
300
  },
301
+ "pageSizeMode": {
302
+ "type": "PaginationPageSizeMode",
303
+ "resolvedType": "\"fit\" | \"fixed\"",
304
+ "attribute": "page-size-mode",
305
+ "default": "'fixed'",
306
+ "required": false,
307
+ "mutable": false,
308
+ "description": "Whether pageSize is a fixed choice or a measured Fit snapshot."
309
+ },
204
310
  "pageSizeOptions": {
205
311
  "type": "number[]",
206
312
  "resolvedType": "number[]",
@@ -273,22 +379,22 @@
273
379
  "files": [
274
380
  {
275
381
  "path": "src/wc/components/Pagination/Pagination.css",
276
- "content": "@import '../../utils/visually-hidden.css';\n\n:host {\n display: block;\n box-sizing: border-box;\n min-width: 0;\n max-width: 100%;\n overflow-x: auto;\n scrollbar-width: none;\n}\n\n:host::-webkit-scrollbar {\n display: none;\n}\n\n.pagination,\n.pagination__page-size,\n.pagination__navigation {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n}\n\n.pagination {\n width: max-content;\n min-width: 100%;\n gap: var(--dimension-space-200);\n}\n\n.pagination__page-size,\n.pagination__navigation {\n flex: 0 0 auto;\n gap: var(--dimension-space-050);\n}\n\n.pagination__range,\n.pagination__page,\n.pagination__label {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n white-space: nowrap;\n}\n\n.pagination__page {\n justify-content: center;\n min-inline-size: calc(var(--dimension-size-800) + var(--dimension-space-200));\n padding-inline: var(--dimension-space-050);\n}\n",
382
+ "content": "@import '../../utils/visually-hidden.css';\n\n:host {\n display: block;\n box-sizing: border-box;\n min-width: 0;\n max-width: 100%;\n overflow-x: auto;\n scrollbar-width: none;\n}\n\n:host::-webkit-scrollbar {\n display: none;\n}\n\n.pagination,\n.pagination__page-size,\n.pagination__navigation {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n}\n\n.pagination {\n width: max-content;\n min-width: 100%;\n gap: var(--dimension-space-200);\n}\n\n.pagination__page-size,\n.pagination__navigation {\n flex: 0 0 auto;\n}\n\n.pagination__page-size {\n gap: var(--dimension-space-100);\n}\n\n.pagination__navigation {\n gap: var(--dimension-space-050);\n}\n\n.pagination__range,\n.pagination__page,\n.pagination__label {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n white-space: nowrap;\n}\n\n.pagination__page {\n justify-content: center;\n min-inline-size: calc(var(--dimension-size-800) + var(--dimension-space-200));\n padding-inline: var(--dimension-space-050);\n}\n",
277
383
  "type": "registry:ui"
278
384
  },
279
385
  {
280
386
  "path": "src/wc/components/Pagination/Pagination.tsx",
281
- "content": "import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';\nimport { resolvePaginationState } from './pagination-model';\nimport type { PaginationChangeDetail } from './pagination-types';\n\nlet paginationId = 0;\n\n@Component({\n tag: 'ds-pagination',\n styleUrl: 'Pagination.css',\n scoped: true,\n})\nexport class Pagination {\n /** Controlled zero-based page index. */\n @Prop() pageIndex: number = 0;\n /** Controlled number of top-level items on a full page. */\n @Prop() pageSize: number = 25;\n /** Controlled total number of top-level items across every page. */\n @Prop() totalItems: number = 0;\n /** Available page sizes. Assign arrays through JavaScript. */\n @Prop() pageSizeOptions: number[] = [25, 50, 100, 200];\n /** Localized plural noun used by assistive range announcements. */\n @Prop() itemLabel: string = 'items';\n /** Visible page-size control label. */\n @Prop() pageSizeLabel: string = 'Items per page';\n /** Accessible name for the pagination navigation region. */\n @Prop() label: string = 'Pagination';\n /** Prevent interaction while the owner replaces the current data page. */\n @Prop() loading: boolean = false;\n\n /** Emits the complete next controlled state after a page or page-size request. */\n @Event() dsChange!: EventEmitter<PaginationChangeDetail>;\n\n private readonly pageSizeControlId = `ds-pagination-${++paginationId}-page-size`;\n\n private requestPage(pageIndex: number): void {\n const state = this.resolvedState;\n if (this.loading || pageIndex === state.pageIndex || pageIndex < 0 || pageIndex >= state.totalPages) {\n return;\n }\n this.dsChange.emit({\n pageIndex,\n pageSize: state.pageSize,\n totalItems: state.totalItems,\n pageSizeOptions: state.pageSizeOptions,\n itemLabel: this.itemLabel,\n pageSizeLabel: this.pageSizeLabel,\n ariaLabel: this.label,\n previousPageIndex: state.pageIndex,\n previousPageSize: state.pageSize,\n reason: 'page',\n });\n }\n\n private requestPageSize(value: string | string[]): void {\n if (this.loading || typeof value !== 'string') return;\n const pageSize = Number(value);\n const state = this.resolvedState;\n if (!Number.isFinite(pageSize) || pageSize <= 0 || pageSize === state.pageSize) return;\n this.dsChange.emit({\n pageIndex: 0,\n pageSize: Math.trunc(pageSize),\n totalItems: state.totalItems,\n pageSizeOptions: state.pageSizeOptions,\n itemLabel: this.itemLabel,\n pageSizeLabel: this.pageSizeLabel,\n ariaLabel: this.label,\n previousPageIndex: state.pageIndex,\n previousPageSize: state.pageSize,\n reason: 'page-size',\n });\n }\n\n private get resolvedState() {\n return resolvePaginationState({\n pageIndex: this.pageIndex,\n pageSize: this.pageSize,\n totalItems: this.totalItems,\n pageSizeOptions: this.pageSizeOptions,\n });\n }\n\n render() {\n const state = this.resolvedState;\n const atStart = state.pageIndex === 0;\n const atEnd = state.pageIndex === state.totalPages - 1;\n const range = `${state.firstItem}–${state.lastItem} of ${state.totalItems}`;\n const page = `Page ${state.pageIndex + 1} of ${state.totalPages}`;\n\n return (\n <Host>\n <nav class=\"pagination\" aria-label={this.label} aria-busy={this.loading ? 'true' : undefined}>\n <div class=\"pagination__page-size\">\n <ds-text\n id={`${this.pageSizeControlId}-label`}\n class=\"pagination__label\"\n as=\"span\"\n variant=\"text-body-medium\"\n color=\"secondary\"\n >\n {this.pageSizeLabel}\n </ds-text>\n <ds-select\n size=\"md\"\n inputId={this.pageSizeControlId}\n ariaLabelledby={`${this.pageSizeControlId}-label`}\n options={state.pageSizeOptions.map(value => ({ label: String(value), value: String(value) }))}\n value={String(state.pageSize)}\n allowClear={false}\n activeFill={false}\n isInactive={this.loading}\n onDsChange={event => {\n event.stopPropagation();\n this.requestPageSize(event.detail);\n }}\n />\n </div>\n <ds-text\n class=\"pagination__range\"\n as=\"span\"\n variant=\"text-body-medium\"\n color=\"secondary\"\n fontFeature=\"tabular-nums\"\n >\n {range}\n </ds-text>\n <div class=\"pagination__navigation\">\n <ds-button-unfilled\n variant=\"icon\"\n size=\"md\"\n icon=\"ChevronLeftDouble\"\n ariaLabel=\"First page\"\n hasBorder={false}\n isInactive={this.loading || atStart}\n onDsClick={() => this.requestPage(0)}\n />\n <ds-button-unfilled\n variant=\"icon\"\n size=\"md\"\n icon=\"ChevronLeft\"\n ariaLabel=\"Previous page\"\n hasBorder={false}\n isInactive={this.loading || atStart}\n onDsClick={() => this.requestPage(state.pageIndex - 1)}\n />\n <ds-text\n class=\"pagination__page\"\n as=\"span\"\n variant=\"text-body-medium\"\n color=\"secondary\"\n fontFeature=\"tabular-nums\"\n >\n {page}\n </ds-text>\n <ds-button-unfilled\n variant=\"icon\"\n size=\"md\"\n icon=\"ChevronRight\"\n ariaLabel=\"Next page\"\n hasBorder={false}\n isInactive={this.loading || atEnd}\n onDsClick={() => this.requestPage(state.pageIndex + 1)}\n />\n <ds-button-unfilled\n variant=\"icon\"\n size=\"md\"\n icon=\"ChevronRightDouble\"\n ariaLabel=\"Last page\"\n hasBorder={false}\n isInactive={this.loading || atEnd}\n onDsClick={() => this.requestPage(state.totalPages - 1)}\n />\n </div>\n <span class=\"ds-visually-hidden\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {range} {this.itemLabel}. {page}.\n </span>\n </nav>\n </Host>\n );\n }\n}\n",
387
+ "content": "import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';\nimport { resolvePaginationState } from './pagination-model';\nimport type {\n PaginationChangeDetail,\n PaginationPageSizeMode,\n} from './pagination-types';\n\nlet paginationId = 0;\n\n@Component({\n tag: 'ds-pagination',\n styleUrl: 'Pagination.css',\n scoped: true,\n})\nexport class Pagination {\n /** Controlled zero-based page index. */\n @Prop() pageIndex: number = 0;\n /** Controlled number of top-level items on a full page. */\n @Prop() pageSize: number = 25;\n /** Whether pageSize is a fixed choice or a measured Fit snapshot. */\n @Prop() pageSizeMode: PaginationPageSizeMode = 'fixed';\n /** Controlled total number of top-level items across every page. */\n @Prop() totalItems: number = 0;\n /** Available page sizes. Assign arrays through JavaScript. */\n @Prop() pageSizeOptions: number[] = [25, 50, 100, 200];\n /** Include the Fit to page choice. */\n @Prop() fitToPage: boolean = false;\n /** Effective whole-item capacity to request when Fit is selected. */\n @Prop() fitPageSize: number | undefined;\n /** Full choice-list label for Fit. */\n @Prop() fitPageSizeLabel: string = 'Fit to page';\n /** Compact closed-trigger label while Fit is selected. */\n @Prop() fitPageSizeTriggerLabel: string = 'Fit';\n /** Localized plural noun used by assistive range announcements. */\n @Prop() itemLabel: string = 'items';\n /** Visible page-size control label. */\n @Prop() pageSizeLabel: string = 'Items';\n /** Accessible page-size control label. Defaults to “{pageSizeLabel} per page”. */\n @Prop() pageSizeAriaLabel: string | undefined;\n /** Accessible name for the pagination navigation region. */\n @Prop() label: string = 'Pagination';\n /** Prevent interaction while the owner replaces the current data page. */\n @Prop() loading: boolean = false;\n\n /** Emits the complete next controlled state after a page or page-size request. */\n @Event() dsChange!: EventEmitter<PaginationChangeDetail>;\n\n private readonly pageSizeControlId = `ds-pagination-${++paginationId}-page-size`;\n\n private requestPage(pageIndex: number): void {\n const state = this.resolvedState;\n if (this.loading || pageIndex === state.pageIndex || pageIndex < 0 || pageIndex >= state.totalPages) {\n return;\n }\n this.dsChange.emit({\n pageIndex,\n pageSize: state.pageSize,\n pageSizeMode: state.pageSizeMode,\n totalItems: state.totalItems,\n pageSizeOptions: state.pageSizeOptions,\n fitToPage: this.fitToPage,\n fitPageSize: this.resolvedFitPageSize,\n fitPageSizeLabel: this.fitPageSizeLabel,\n fitPageSizeTriggerLabel: this.fitPageSizeTriggerLabel,\n itemLabel: this.itemLabel,\n pageSizeLabel: this.pageSizeLabel,\n ariaLabel: this.label,\n previousPageIndex: state.pageIndex,\n previousPageSize: state.pageSize,\n previousPageSizeMode: state.pageSizeMode,\n reason: 'page',\n });\n }\n\n private requestPageSize(value: string | string[]): void {\n if (this.loading || typeof value !== 'string') return;\n const state = this.resolvedState;\n const nextMode: PaginationPageSizeMode = value === 'fit' ? 'fit' : 'fixed';\n const pageSize = nextMode === 'fit' ? this.resolvedFitPageSize : Number(value);\n if (!pageSize || (pageSize === state.pageSize && nextMode === state.pageSizeMode)) return;\n this.dsChange.emit({\n pageIndex: 0,\n pageSize: Math.trunc(pageSize),\n pageSizeMode: nextMode,\n totalItems: state.totalItems,\n pageSizeOptions: state.pageSizeOptions,\n fitToPage: this.fitToPage,\n fitPageSize: this.resolvedFitPageSize,\n fitPageSizeLabel: this.fitPageSizeLabel,\n fitPageSizeTriggerLabel: this.fitPageSizeTriggerLabel,\n itemLabel: this.itemLabel,\n pageSizeLabel: this.pageSizeLabel,\n ariaLabel: this.label,\n previousPageIndex: state.pageIndex,\n previousPageSize: state.pageSize,\n previousPageSizeMode: state.pageSizeMode,\n reason: 'page-size',\n });\n }\n\n private handleKeyDown(event: KeyboardEvent): void {\n if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {\n return;\n }\n const fromChoiceControl = event.composedPath().some(node =>\n node instanceof HTMLElement &&\n (node.tagName === 'DS-SELECT' || ['INPUT', 'SELECT', 'TEXTAREA'].includes(node.tagName)),\n );\n if (fromChoiceControl || (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight')) return;\n const state = this.resolvedState;\n const pageIndex = event.key === 'ArrowLeft' ? state.pageIndex - 1 : state.pageIndex + 1;\n if (this.loading || pageIndex < 0 || pageIndex >= state.totalPages) return;\n event.preventDefault();\n this.requestPage(pageIndex);\n }\n\n private get resolvedFitPageSize(): number | undefined {\n return Number.isFinite(this.fitPageSize) && Number(this.fitPageSize) > 0\n ? Math.trunc(Number(this.fitPageSize))\n : undefined;\n }\n\n private get resolvedState() {\n return resolvePaginationState({\n pageIndex: this.pageIndex,\n pageSize: this.pageSize,\n pageSizeMode: this.pageSizeMode,\n totalItems: this.totalItems,\n pageSizeOptions: this.pageSizeOptions,\n });\n }\n\n render() {\n const state = this.resolvedState;\n const atStart = state.pageIndex === 0;\n const atEnd = state.pageIndex === state.totalPages - 1;\n const range = `${state.firstItem}–${state.lastItem} / ${state.totalItems}`;\n const page = `${state.pageIndex + 1} / ${state.totalPages}`;\n const announcedRange = `${state.firstItem}–${state.lastItem} of ${state.totalItems}`;\n const announcedPage = `Page ${state.pageIndex + 1} of ${state.totalPages}`;\n const pageSizeAriaLabel = this.pageSizeAriaLabel ?? `${this.pageSizeLabel} per page`;\n const options: Array<{ label: string; value: string; isInactive?: boolean }> =\n state.pageSizeOptions.map(value => ({ label: String(value), value: String(value) }));\n if (this.fitToPage) {\n options.push({\n label: this.fitPageSizeLabel,\n value: 'fit',\n isInactive: this.resolvedFitPageSize === undefined,\n });\n }\n\n return (\n <Host>\n <nav\n class=\"pagination\"\n aria-label={this.label}\n aria-busy={this.loading ? 'true' : undefined}\n onKeyDown={event => this.handleKeyDown(event)}\n >\n <div class=\"pagination__page-size\">\n <ds-text\n class=\"pagination__label\"\n as=\"span\"\n variant=\"text-body-medium\"\n color=\"secondary\"\n aria-hidden=\"true\"\n >\n {this.pageSizeLabel}:\n </ds-text>\n <span id={`${this.pageSizeControlId}-label`} class=\"ds-visually-hidden\">\n {pageSizeAriaLabel}\n </span>\n <ds-select\n size=\"md\"\n inputId={this.pageSizeControlId}\n ariaLabelledby={`${this.pageSizeControlId}-label`}\n options={options}\n value={state.pageSizeMode === 'fit' ? 'fit' : String(state.pageSize)}\n triggerLabel={state.pageSizeMode === 'fit' ? this.fitPageSizeTriggerLabel : undefined}\n indicator=\"up-down\"\n allowClear={false}\n activeFill={false}\n isInactive={this.loading}\n onDsChange={event => {\n event.stopPropagation();\n this.requestPageSize(event.detail);\n }}\n />\n </div>\n <ds-text\n class=\"pagination__range\"\n as=\"span\"\n variant=\"text-body-medium\"\n color=\"secondary\"\n fontFeature=\"tabular-nums\"\n >\n {range}\n </ds-text>\n <div class=\"pagination__navigation\">\n <ds-button-unfilled\n variant=\"icon\"\n size=\"md\"\n icon=\"ChevronLeftDouble\"\n ariaLabel=\"First page\"\n hasBorder={false}\n isInactive={this.loading || atStart}\n onDsClick={() => this.requestPage(0)}\n />\n <ds-button-unfilled\n variant=\"icon\"\n size=\"md\"\n icon=\"ChevronLeft\"\n ariaLabel=\"Previous page\"\n hasBorder={false}\n isInactive={this.loading || atStart}\n onDsClick={() => this.requestPage(state.pageIndex - 1)}\n />\n <ds-text\n class=\"pagination__page\"\n as=\"span\"\n variant=\"text-body-medium\"\n color=\"secondary\"\n fontFeature=\"tabular-nums\"\n >\n {page}\n </ds-text>\n <ds-button-unfilled\n variant=\"icon\"\n size=\"md\"\n icon=\"ChevronRight\"\n ariaLabel=\"Next page\"\n hasBorder={false}\n isInactive={this.loading || atEnd}\n onDsClick={() => this.requestPage(state.pageIndex + 1)}\n />\n <ds-button-unfilled\n variant=\"icon\"\n size=\"md\"\n icon=\"ChevronRightDouble\"\n ariaLabel=\"Last page\"\n hasBorder={false}\n isInactive={this.loading || atEnd}\n onDsClick={() => this.requestPage(state.totalPages - 1)}\n />\n </div>\n <span class=\"ds-visually-hidden\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {announcedRange} {this.itemLabel}. {announcedPage}.\n </span>\n </nav>\n </Host>\n );\n }\n}\n",
282
388
  "type": "registry:ui"
283
389
  },
284
390
  {
285
391
  "path": "src/wc/components/Pagination/pagination-model.ts",
286
- "content": "import type { PaginationState } from './pagination-types';\n\nexport const DEFAULT_PAGE_SIZE_OPTIONS = [25, 50, 100, 200] as const;\n\nexport interface ResolvedPaginationState {\n pageIndex: number;\n pageSize: number;\n totalItems: number;\n totalPages: number;\n firstItem: number;\n lastItem: number;\n pageSizeOptions: number[];\n}\n\nfunction nonNegativeInteger(value: number): number {\n return Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;\n}\n\nfunction positiveInteger(value: number, fallback: number): number {\n return Number.isFinite(value) && value > 0 ? Math.trunc(value) : fallback;\n}\n\nexport function resolvePaginationState(\n state: Pick<PaginationState, 'pageIndex' | 'pageSize' | 'totalItems' | 'pageSizeOptions'>,\n): ResolvedPaginationState {\n const pageSize = positiveInteger(state.pageSize, DEFAULT_PAGE_SIZE_OPTIONS[0]);\n const totalItems = nonNegativeInteger(state.totalItems);\n const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));\n const pageIndex = Math.min(nonNegativeInteger(state.pageIndex), totalPages - 1);\n const options = (state.pageSizeOptions?.length\n ? state.pageSizeOptions\n : DEFAULT_PAGE_SIZE_OPTIONS\n )\n .map(value => positiveInteger(value, 0))\n .filter(value => value > 0);\n const pageSizeOptions = [...new Set([...options, pageSize])].sort((left, right) => left - right);\n const firstItem = totalItems === 0 ? 0 : pageIndex * pageSize + 1;\n const lastItem = totalItems === 0 ? 0 : Math.min(totalItems, firstItem + pageSize - 1);\n\n return {\n pageIndex,\n pageSize,\n totalItems,\n totalPages,\n firstItem,\n lastItem,\n pageSizeOptions,\n };\n}\n",
392
+ "content": "import type { PaginationPageSizeMode, PaginationState } from './pagination-types';\n\nexport const DEFAULT_PAGE_SIZE_OPTIONS = [25, 50, 100, 200] as const;\n\nexport interface ResolvedPaginationState {\n pageIndex: number;\n pageSize: number;\n pageSizeMode: PaginationPageSizeMode;\n totalItems: number;\n totalPages: number;\n firstItem: number;\n lastItem: number;\n pageSizeOptions: number[];\n}\n\nfunction nonNegativeInteger(value: number): number {\n return Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;\n}\n\nfunction positiveInteger(value: number, fallback: number): number {\n return Number.isFinite(value) && value > 0 ? Math.trunc(value) : fallback;\n}\n\nexport function resolvePaginationState(\n state: Pick<\n PaginationState,\n 'pageIndex' | 'pageSize' | 'pageSizeMode' | 'totalItems' | 'pageSizeOptions'\n >,\n): ResolvedPaginationState {\n const pageSize = positiveInteger(state.pageSize, DEFAULT_PAGE_SIZE_OPTIONS[0]);\n const pageSizeMode = state.pageSizeMode === 'fit' ? 'fit' : 'fixed';\n const totalItems = nonNegativeInteger(state.totalItems);\n const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));\n const pageIndex = Math.min(nonNegativeInteger(state.pageIndex), totalPages - 1);\n const options = (state.pageSizeOptions?.length\n ? state.pageSizeOptions\n : DEFAULT_PAGE_SIZE_OPTIONS\n )\n .map(value => positiveInteger(value, 0))\n .filter(value => value > 0);\n const pageSizeOptions = [\n ...new Set(pageSizeMode === 'fixed' ? [...options, pageSize] : options),\n ].sort((left, right) => left - right);\n const firstItem = totalItems === 0 ? 0 : pageIndex * pageSize + 1;\n const lastItem = totalItems === 0 ? 0 : Math.min(totalItems, firstItem + pageSize - 1);\n\n return {\n pageIndex,\n pageSize,\n pageSizeMode,\n totalItems,\n totalPages,\n firstItem,\n lastItem,\n pageSizeOptions,\n };\n}\n",
287
393
  "type": "registry:ui"
288
394
  },
289
395
  {
290
396
  "path": "src/wc/components/Pagination/pagination-types.ts",
291
- "content": "export type PaginationChangeReason = 'page' | 'page-size';\n\n/** Controlled pagination state shared by Pagination and pagination-aware consumers. */\nexport interface PaginationState {\n /** Zero-based page index. */\n pageIndex: number;\n /** Number of top-level items on a full page. */\n pageSize: number;\n /** Total number of top-level items across every page. */\n totalItems: number;\n /** Available page sizes. Defaults to 25, 50, 100, and 200. */\n pageSizeOptions?: number[];\n /** Localized plural noun used by assistive range announcements. */\n itemLabel?: string;\n /** Visible label for the page-size selector. */\n pageSizeLabel?: string;\n /** Accessible name for the pagination navigation region. */\n ariaLabel?: string;\n}\n\n/** Complete next controlled state emitted for a page or page-size request. */\nexport interface PaginationChangeDetail extends PaginationState {\n previousPageIndex: number;\n previousPageSize: number;\n reason: PaginationChangeReason;\n}\n",
397
+ "content": "export type PaginationChangeReason = 'page' | 'page-size' | 'fit';\nexport type PaginationPageSizeMode = 'fixed' | 'fit';\n\n/** Controlled pagination state shared by Pagination and pagination-aware consumers. */\nexport interface PaginationState {\n /** Zero-based page index. */\n pageIndex: number;\n /** Number of top-level items on a full page. */\n pageSize: number;\n /** Whether pageSize is a chosen fixed value or a measured Fit snapshot. */\n pageSizeMode?: PaginationPageSizeMode;\n /** Total number of top-level items across every page. */\n totalItems: number;\n /** Available page sizes. Defaults to 25, 50, 100, and 200. */\n pageSizeOptions?: number[];\n /** Include a Fit to page option. The owner supplies the effective fitted size. */\n fitToPage?: boolean;\n /** Effective page size proposed when Fit to page is selected. */\n fitPageSize?: number;\n /** Full option label for Fit in the open choice list. */\n fitPageSizeLabel?: string;\n /** Compact trigger label while Fit is selected. */\n fitPageSizeTriggerLabel?: string;\n /** Localized plural noun used by assistive range announcements. */\n itemLabel?: string;\n /** Visible label for the page-size selector. */\n pageSizeLabel?: string;\n /** Accessible name for the pagination navigation region. */\n ariaLabel?: string;\n}\n\n/** Complete next controlled state emitted for a page or page-size request. */\nexport interface PaginationChangeDetail extends PaginationState {\n previousPageIndex: number;\n previousPageSize: number;\n previousPageSizeMode: PaginationPageSizeMode;\n reason: PaginationChangeReason;\n}\n",
292
398
  "type": "registry:ui"
293
399
  }
294
400
  ]