@nixxie-cms/core 1.0.0 → 1.0.2

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 (187) hide show
  1. package/README.md +2 -2
  2. package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.cjs.js +4 -4
  3. package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.esm.js +4 -4
  4. package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.cjs.js +2 -2
  5. package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.esm.js +2 -2
  6. package/context/dist/nixxie-cms-core-context.cjs.js +2 -2
  7. package/context/dist/nixxie-cms-core-context.esm.js +2 -2
  8. package/dist/{CreateItemDialog-33335548.esm.js → CreateItemDialog-7008b050.esm.js} +1 -1
  9. package/dist/{CreateItemDialog-56cf59b7.cjs.js → CreateItemDialog-a0cab315.cjs.js} +1 -1
  10. package/dist/{PageContainer-7db73317.esm.js → PageContainer-5ae731cc.esm.js} +25 -18
  11. package/dist/{PageContainer-27c27f10.cjs.js → PageContainer-abd7159f.cjs.js} +25 -18
  12. package/dist/{admin-meta-graphql-6f7f5331.esm.js → admin-meta-graphql-0e6e606e.esm.js} +1 -1
  13. package/dist/{admin-meta-graphql-c8f926e9.cjs.js → admin-meta-graphql-306c224a.cjs.js} +1 -1
  14. package/dist/{context-3132c3ed.esm.js → context-af9957ed.esm.js} +2 -2
  15. package/dist/{context-e7a45152.cjs.js → context-b5204629.cjs.js} +2 -2
  16. package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
  17. package/dist/declarations/src/admin-ui/components/PageContainer.d.ts.map +1 -1
  18. package/dist/declarations/src/helpers.d.ts.map +1 -1
  19. package/dist/declarations/src/index.d.ts +1 -0
  20. package/dist/declarations/src/index.d.ts.map +1 -1
  21. package/dist/declarations/src/internal-unstable/admin-ui/id-field-view.d.ts.map +1 -0
  22. package/dist/declarations/src/internal-unstable/admin-ui/pages/App/index.d.ts.map +1 -0
  23. package/dist/declarations/src/internal-unstable/admin-ui/pages/CreateItemPage/index.d.ts.map +1 -0
  24. package/dist/declarations/src/internal-unstable/admin-ui/pages/HomePage/index.d.ts.map +1 -0
  25. package/dist/declarations/src/internal-unstable/admin-ui/pages/ItemPage/index.d.ts.map +1 -0
  26. package/dist/declarations/src/internal-unstable/admin-ui/pages/ListPage/index.d.ts.map +1 -0
  27. package/dist/declarations/src/internal-unstable/admin-ui/pages/NoAccessPage/index.d.ts.map +1 -0
  28. package/dist/declarations/src/internal-unstable/artifacts.d.ts.map +1 -0
  29. package/dist/declarations/src/lib/core/initialise-lists.d.ts +1 -1
  30. package/dist/declarations/src/schema.d.ts.map +1 -1
  31. package/dist/declarations/src/types/config/index.d.ts +60 -1
  32. package/dist/declarations/src/types/config/index.d.ts.map +1 -1
  33. package/dist/declarations/src/types/config/lists.d.ts +4 -4
  34. package/dist/declarations/src/types/context.d.ts +150 -0
  35. package/dist/declarations/src/types/context.d.ts.map +1 -1
  36. package/dist/declarations/src/types/next-fields.d.ts +1 -1
  37. package/dist/{express-e9ed9a7d.cjs.js → express-455ae20c.cjs.js} +1 -1
  38. package/dist/{express-6743b918.esm.js → express-7559ca2d.esm.js} +1 -1
  39. package/dist/{index-ac01583b.cjs.js → index-89635494.cjs.js} +4 -4
  40. package/dist/{index-24b78415.esm.js → index-baa799e0.esm.js} +4 -4
  41. package/dist/nixxie-cms-core.cjs.js +104 -77
  42. package/dist/nixxie-cms-core.esm.js +104 -77
  43. package/dist/{non-null-graphql-5315718c.esm.js → non-null-graphql-a84ed64d.esm.js} +1 -1
  44. package/dist/{non-null-graphql-17b83ddc.cjs.js → non-null-graphql-add6bb3d.cjs.js} +1 -1
  45. package/dist/{resolve-hooks-66fe8a8e.cjs.js → resolve-hooks-165a9ce2.cjs.js} +1 -1
  46. package/dist/{resolve-hooks-17aafd37.esm.js → resolve-hooks-6813a045.esm.js} +2 -2
  47. package/dist/{system-dfec2f0a.esm.js → system-03e49e4f.esm.js} +8 -4
  48. package/dist/{system-48c5f6df.cjs.js → system-a321642d.cjs.js} +8 -4
  49. package/dist/{useFilter-0b5a1ee6.esm.js → useFilter-9b6db1f9.esm.js} +1 -1
  50. package/dist/{useFilter-1a4e6900.cjs.js → useFilter-acc9d413.cjs.js} +1 -1
  51. package/fields/dist/nixxie-cms-core-fields.cjs.js +16 -16
  52. package/fields/dist/nixxie-cms-core-fields.esm.js +17 -17
  53. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.js +3 -3
  54. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.esm.js +3 -3
  55. package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.cjs.js +1 -1
  56. package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.esm.js +1 -1
  57. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.js +3 -3
  58. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.esm.js +3 -3
  59. package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.cjs.js +4 -4
  60. package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.esm.js +4 -4
  61. package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.cjs.js +1 -1
  62. package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.esm.js +1 -1
  63. package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.cjs.js +1 -1
  64. package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.esm.js +1 -1
  65. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.cjs.d.ts +2 -0
  66. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.cjs.js +244 -0
  67. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.esm.js +235 -0
  68. package/internal-unstable/admin-ui/id-field-view/package.json +4 -0
  69. package/internal-unstable/admin-ui/next-config/package.json +4 -0
  70. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.d.ts +2 -0
  71. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.js +59 -0
  72. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.esm.js +55 -0
  73. package/internal-unstable/admin-ui/pages/App/package.json +4 -0
  74. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.d.ts +2 -0
  75. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.js +116 -0
  76. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.esm.js +112 -0
  77. package/internal-unstable/admin-ui/pages/CreateItemPage/package.json +4 -0
  78. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.d.ts +2 -0
  79. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.js +336 -0
  80. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.esm.js +332 -0
  81. package/internal-unstable/admin-ui/pages/HomePage/package.json +4 -0
  82. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.d.ts +2 -0
  83. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.js +463 -0
  84. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.esm.js +455 -0
  85. package/internal-unstable/admin-ui/pages/ItemPage/package.json +4 -0
  86. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.d.ts +2 -0
  87. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.js +1195 -0
  88. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.esm.js +1187 -0
  89. package/internal-unstable/admin-ui/pages/ListPage/package.json +4 -0
  90. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.cjs.d.ts +2 -0
  91. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.cjs.js +40 -0
  92. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.esm.js +35 -0
  93. package/internal-unstable/admin-ui/pages/NoAccessPage/package.json +4 -0
  94. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.d.ts +2 -0
  95. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.js +51 -0
  96. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.esm.js +38 -0
  97. package/internal-unstable/artifacts/package.json +4 -0
  98. package/package.json +44 -44
  99. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.js +44 -15
  100. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +44 -15
  101. package/scripts/dist/nixxie-cms-core-scripts.cjs.js +3 -3
  102. package/scripts/dist/nixxie-cms-core-scripts.esm.js +3 -3
  103. package/src/admin-ui/admin-meta-graphql.ts +168 -168
  104. package/src/admin-ui/components/CommandPalette.tsx +433 -431
  105. package/src/admin-ui/components/Navigation.tsx +389 -385
  106. package/src/admin-ui/components/PageContainer.tsx +311 -310
  107. package/src/admin-ui/components/WelcomeDialog.tsx +1 -1
  108. package/src/admin-ui/context.tsx +338 -338
  109. package/src/admin-ui/templates/app.ts +60 -60
  110. package/src/admin-ui/templates/create-item.ts +5 -5
  111. package/src/admin-ui/templates/home.ts +2 -2
  112. package/src/admin-ui/templates/item.tsx +5 -5
  113. package/src/admin-ui/templates/list.tsx +5 -5
  114. package/src/admin-ui/templates/next-config.ts +29 -0
  115. package/src/admin-ui/templates/no-access.ts +7 -7
  116. package/src/fields/types/bigInt/index.ts +181 -181
  117. package/src/fields/types/bytes/index.ts +275 -275
  118. package/src/fields/types/calendarDay/index.ts +194 -194
  119. package/src/fields/types/checkbox/index.ts +76 -76
  120. package/src/fields/types/decimal/index.ts +182 -182
  121. package/src/fields/types/file/index.ts +168 -168
  122. package/src/fields/types/float/index.ts +133 -133
  123. package/src/fields/types/image/index.ts +244 -244
  124. package/src/fields/types/integer/index.ts +156 -156
  125. package/src/fields/types/json/index.ts +77 -77
  126. package/src/fields/types/multiselect/index.ts +212 -212
  127. package/src/fields/types/password/index.ts +241 -241
  128. package/src/fields/types/relationship/index.ts +381 -381
  129. package/src/fields/types/relationship/views/RelationshipTable.tsx +190 -190
  130. package/src/fields/types/select/index.ts +226 -226
  131. package/src/fields/types/text/index.ts +207 -207
  132. package/src/fields/types/timestamp/index.ts +116 -116
  133. package/src/fields/types/virtual/index.ts +108 -108
  134. package/src/helpers.ts +342 -316
  135. package/src/index.ts +4 -0
  136. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.tsx +167 -167
  137. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.tsx +22 -22
  138. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.tsx +71 -71
  139. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.tsx +333 -333
  140. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/common.tsx +358 -358
  141. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.tsx +483 -483
  142. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/FilterAdd.tsx +221 -221
  143. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/PaginationControls.tsx +170 -170
  144. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/Tag.tsx +72 -72
  145. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.tsx +1006 -1006
  146. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.tsx +24 -24
  147. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.ts +5 -5
  148. package/src/lib/context/createContext.ts +165 -161
  149. package/src/lib/core/initialise-lists.ts +1097 -1097
  150. package/src/lib/id-field.ts +214 -214
  151. package/src/lib/telemetry.ts +342 -342
  152. package/src/schema.ts +237 -233
  153. package/src/scripts/telemetry.ts +1 -1
  154. package/src/types/config/index.ts +400 -333
  155. package/src/types/config/lists.ts +4 -4
  156. package/src/types/context.ts +700 -530
  157. package/src/types/next-fields.ts +499 -499
  158. package/src/types/telemetry.ts +51 -51
  159. package/tests/telemetry.test.ts +361 -361
  160. package/CHANGELOG.md +0 -3158
  161. package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/package.json +0 -4
  162. package/___internal-do-not-use-will-break-in-patch/admin-ui/next-config/package.json +0 -4
  163. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/package.json +0 -4
  164. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/package.json +0 -4
  165. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/package.json +0 -4
  166. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/package.json +0 -4
  167. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/package.json +0 -4
  168. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/package.json +0 -4
  169. package/___internal-do-not-use-will-break-in-patch/artifacts/package.json +0 -4
  170. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.d.ts.map +0 -1
  171. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.d.ts.map +0 -1
  172. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.d.ts.map +0 -1
  173. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.d.ts.map +0 -1
  174. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.d.ts.map +0 -1
  175. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.d.ts.map +0 -1
  176. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.d.ts.map +0 -1
  177. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/artifacts.d.ts.map +0 -1
  178. /package/dist/{common-1a350e11.cjs.js → common-5933f758.cjs.js} +0 -0
  179. /package/dist/{common-29fc82e6.esm.js → common-ea5c441a.esm.js} +0 -0
  180. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.d.ts +0 -0
  181. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.d.ts +0 -0
  182. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.d.ts +0 -0
  183. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.d.ts +0 -0
  184. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.d.ts +0 -0
  185. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.d.ts +0 -0
  186. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.d.ts +0 -0
  187. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.d.ts +0 -0
@@ -1,170 +1,170 @@
1
- import { ActionButton } from '@keystar/ui/button'
2
- import { Icon } from '@keystar/ui/icon'
3
- import { chevronLeftIcon } from '@keystar/ui/icon/icons/chevronLeftIcon'
4
- import { chevronRightIcon } from '@keystar/ui/icon/icons/chevronRightIcon'
5
- import { undo2Icon } from '@keystar/ui/icon/icons/undo2Icon'
6
- import { HStack } from '@keystar/ui/layout'
7
- import { Picker } from '@keystar/ui/picker'
8
- import { Item } from '@keystar/ui/tag'
9
- import { Tooltip, TooltipTrigger } from '@keystar/ui/tooltip'
10
- import { Text } from '@keystar/ui/typography'
11
- import type { ReactNode } from 'react'
12
- import { useMemo } from 'react'
13
-
14
- type PageItem = {
15
- label: string
16
- id: number
17
- }
18
-
19
- export function PaginationControls(props: {
20
- singular: string
21
- plural: string
22
- currentPage: number
23
- pageSize: number
24
- total: number
25
- defaultPageSize?: number
26
- onChangePage: (page: number) => void
27
- onChangePageSize: (pageSize: number) => void
28
- extraActions?: ReactNode
29
- }) {
30
- const { currentPage, total, pageSize, defaultPageSize } = props
31
- const { stats } = getPaginationStats(props)
32
-
33
- const nextPage = currentPage + 1
34
- const prevPage = currentPage - 1
35
- const lastPage = Math.max(Math.ceil(total / pageSize), 1)
36
-
37
- const pageItems = useMemo(() => {
38
- const result: PageItem[] = []
39
- for (let page = 1; page <= lastPage; page++) {
40
- result.push({
41
- id: page,
42
- label: String(page),
43
- })
44
- }
45
- return result
46
- }, [lastPage])
47
-
48
- return (
49
- <HStack
50
- as="nav"
51
- role="navigation"
52
- aria-label="Pagination"
53
- // alignItems="center"
54
- justifyContent="space-between"
55
- >
56
- {/*
57
- left-side
58
- mobile: counts
59
- desktop^: items per page (picker), counts
60
- */}
61
- <HStack gap="large" alignItems="center">
62
- <HStack isHidden={{ below: 'desktop' }} gap="regular" alignItems="center">
63
- <Text id="items-per-page">{props.plural} per page:</Text>
64
- <Picker
65
- aria-labelledby="items-per-page"
66
- items={PAGE_SIZES.map(n => ({ label: String(n), id: n }))}
67
- onSelectionChange={key => {
68
- props.onChangePageSize(Number(key))
69
- }}
70
- selectedKey={pageSize}
71
- width="scale.1000"
72
- >
73
- {item => <Item>{item.label}</Item>}
74
- </Picker>
75
- {defaultPageSize !== undefined && pageSize !== defaultPageSize ? (
76
- <TooltipTrigger>
77
- <ActionButton
78
- aria-label="reset"
79
- onPress={() => props.onChangePageSize(defaultPageSize)}
80
- prominence="low"
81
- >
82
- <Icon src={undo2Icon} />
83
- </ActionButton>
84
- <Tooltip>Reset to defaults</Tooltip>
85
- </TooltipTrigger>
86
- ) : null}
87
- </HStack>
88
- <Text color="neutralSecondary">{stats}</Text>
89
- </HStack>
90
-
91
- {/*
92
- right-side
93
- mobile: next/prev
94
- desktop^: current page (picker), next/prev
95
- */}
96
- <HStack gap="large" alignItems="center">
97
- <HStack isHidden={{ below: 'desktop' }} gap="regular" alignItems="center">
98
- <Picker
99
- // prominence="low"
100
- aria-label={`Page number, of ${lastPage} pages`}
101
- items={pageItems}
102
- onSelectionChange={page => {
103
- props.onChangePage(Number(page))
104
- }}
105
- selectedKey={currentPage}
106
- width="scale.1000"
107
- >
108
- {item => <Item>{item.label}</Item>}
109
- </Picker>
110
- <Text>of {lastPage} pages</Text>
111
- </HStack>
112
- <HStack gap="regular">
113
- <ActionButton
114
- aria-label="Previous page"
115
- isDisabled={prevPage < 1}
116
- onPress={() => props.onChangePage(prevPage)}
117
- // prominence="low"
118
- >
119
- <Icon src={chevronLeftIcon} />
120
- </ActionButton>
121
- <ActionButton
122
- aria-label="Next page"
123
- isDisabled={nextPage > lastPage}
124
- onPress={() => props.onChangePage(nextPage)}
125
- // prominence="low"
126
- >
127
- <Icon src={chevronRightIcon} />
128
- </ActionButton>
129
- {props.extraActions}
130
- </HStack>
131
- </HStack>
132
- </HStack>
133
- )
134
- }
135
-
136
- function getPaginationStats({
137
- singular,
138
- plural,
139
- pageSize,
140
- currentPage,
141
- total,
142
- }: {
143
- singular: string
144
- plural: string
145
- pageSize: number
146
- currentPage: number
147
- total: number
148
- }) {
149
- let stats = ''
150
- if (total > pageSize) {
151
- const start = pageSize * (currentPage - 1) + 1
152
- const end = Math.min(start + pageSize - 1, total)
153
- stats = `${start} - ${end} of ${total} ${plural}`
154
- } else {
155
- if (total > 1 && plural) {
156
- stats = `${total} ${plural}`
157
- } else if (total === 1 && singular) {
158
- stats = `${total} ${singular}`
159
- }
160
- }
161
- return { stats }
162
- }
163
-
164
- const PAGE_SIZES = [10, 25, 50, 100]
165
-
166
- export function snapValueToClosest(input: number, range = PAGE_SIZES) {
167
- return range.reduce((prev, curr) =>
168
- Math.abs(curr - input) < Math.abs(prev - input) ? curr : prev
169
- )
170
- }
1
+ import { ActionButton } from '@keystar/ui/button'
2
+ import { Icon } from '@keystar/ui/icon'
3
+ import { chevronLeftIcon } from '@keystar/ui/icon/icons/chevronLeftIcon'
4
+ import { chevronRightIcon } from '@keystar/ui/icon/icons/chevronRightIcon'
5
+ import { undo2Icon } from '@keystar/ui/icon/icons/undo2Icon'
6
+ import { HStack } from '@keystar/ui/layout'
7
+ import { Picker } from '@keystar/ui/picker'
8
+ import { Item } from '@keystar/ui/tag'
9
+ import { Tooltip, TooltipTrigger } from '@keystar/ui/tooltip'
10
+ import { Text } from '@keystar/ui/typography'
11
+ import type { ReactNode } from 'react'
12
+ import { useMemo } from 'react'
13
+
14
+ type PageItem = {
15
+ label: string
16
+ id: number
17
+ }
18
+
19
+ export function PaginationControls(props: {
20
+ singular: string
21
+ plural: string
22
+ currentPage: number
23
+ pageSize: number
24
+ total: number
25
+ defaultPageSize?: number
26
+ onChangePage: (page: number) => void
27
+ onChangePageSize: (pageSize: number) => void
28
+ extraActions?: ReactNode
29
+ }) {
30
+ const { currentPage, total, pageSize, defaultPageSize } = props
31
+ const { stats } = getPaginationStats(props)
32
+
33
+ const nextPage = currentPage + 1
34
+ const prevPage = currentPage - 1
35
+ const lastPage = Math.max(Math.ceil(total / pageSize), 1)
36
+
37
+ const pageItems = useMemo(() => {
38
+ const result: PageItem[] = []
39
+ for (let page = 1; page <= lastPage; page++) {
40
+ result.push({
41
+ id: page,
42
+ label: String(page),
43
+ })
44
+ }
45
+ return result
46
+ }, [lastPage])
47
+
48
+ return (
49
+ <HStack
50
+ as="nav"
51
+ role="navigation"
52
+ aria-label="Pagination"
53
+ // alignItems="center"
54
+ justifyContent="space-between"
55
+ >
56
+ {/*
57
+ left-side
58
+ mobile: counts
59
+ desktop^: items per page (picker), counts
60
+ */}
61
+ <HStack gap="large" alignItems="center">
62
+ <HStack isHidden={{ below: 'desktop' }} gap="regular" alignItems="center">
63
+ <Text id="items-per-page">{props.plural} per page:</Text>
64
+ <Picker
65
+ aria-labelledby="items-per-page"
66
+ items={PAGE_SIZES.map(n => ({ label: String(n), id: n }))}
67
+ onSelectionChange={key => {
68
+ props.onChangePageSize(Number(key))
69
+ }}
70
+ selectedKey={pageSize}
71
+ width="scale.1000"
72
+ >
73
+ {item => <Item>{item.label}</Item>}
74
+ </Picker>
75
+ {defaultPageSize !== undefined && pageSize !== defaultPageSize ? (
76
+ <TooltipTrigger>
77
+ <ActionButton
78
+ aria-label="reset"
79
+ onPress={() => props.onChangePageSize(defaultPageSize)}
80
+ prominence="low"
81
+ >
82
+ <Icon src={undo2Icon} />
83
+ </ActionButton>
84
+ <Tooltip>Reset to defaults</Tooltip>
85
+ </TooltipTrigger>
86
+ ) : null}
87
+ </HStack>
88
+ <Text color="neutralSecondary">{stats}</Text>
89
+ </HStack>
90
+
91
+ {/*
92
+ right-side
93
+ mobile: next/prev
94
+ desktop^: current page (picker), next/prev
95
+ */}
96
+ <HStack gap="large" alignItems="center">
97
+ <HStack isHidden={{ below: 'desktop' }} gap="regular" alignItems="center">
98
+ <Picker
99
+ // prominence="low"
100
+ aria-label={`Page number, of ${lastPage} pages`}
101
+ items={pageItems}
102
+ onSelectionChange={page => {
103
+ props.onChangePage(Number(page))
104
+ }}
105
+ selectedKey={currentPage}
106
+ width="scale.1000"
107
+ >
108
+ {item => <Item>{item.label}</Item>}
109
+ </Picker>
110
+ <Text>of {lastPage} pages</Text>
111
+ </HStack>
112
+ <HStack gap="regular">
113
+ <ActionButton
114
+ aria-label="Previous page"
115
+ isDisabled={prevPage < 1}
116
+ onPress={() => props.onChangePage(prevPage)}
117
+ // prominence="low"
118
+ >
119
+ <Icon src={chevronLeftIcon} />
120
+ </ActionButton>
121
+ <ActionButton
122
+ aria-label="Next page"
123
+ isDisabled={nextPage > lastPage}
124
+ onPress={() => props.onChangePage(nextPage)}
125
+ // prominence="low"
126
+ >
127
+ <Icon src={chevronRightIcon} />
128
+ </ActionButton>
129
+ {props.extraActions}
130
+ </HStack>
131
+ </HStack>
132
+ </HStack>
133
+ )
134
+ }
135
+
136
+ function getPaginationStats({
137
+ singular,
138
+ plural,
139
+ pageSize,
140
+ currentPage,
141
+ total,
142
+ }: {
143
+ singular: string
144
+ plural: string
145
+ pageSize: number
146
+ currentPage: number
147
+ total: number
148
+ }) {
149
+ let stats = ''
150
+ if (total > pageSize) {
151
+ const start = pageSize * (currentPage - 1) + 1
152
+ const end = Math.min(start + pageSize - 1, total)
153
+ stats = `${start} - ${end} of ${total} ${plural}`
154
+ } else {
155
+ if (total > 1 && plural) {
156
+ stats = `${total} ${plural}`
157
+ } else if (total === 1 && singular) {
158
+ stats = `${total} ${singular}`
159
+ }
160
+ }
161
+ return { stats }
162
+ }
163
+
164
+ const PAGE_SIZES = [10, 25, 50, 100]
165
+
166
+ export function snapValueToClosest(input: number, range = PAGE_SIZES) {
167
+ return range.reduce((prev, curr) =>
168
+ Math.abs(curr - input) < Math.abs(prev - input) ? curr : prev
169
+ )
170
+ }
@@ -1,72 +1,72 @@
1
- import { type ReactNode, useId } from 'react'
2
-
3
- import { ActionButton } from '@keystar/ui/button'
4
- import { Icon } from '@keystar/ui/icon'
5
- import { xIcon } from '@keystar/ui/icon/icons/xIcon'
6
- import { SlotProvider } from '@keystar/ui/slots'
7
- import { css, tokenSchema } from '@keystar/ui/style'
8
- import { composeId } from '@keystar/ui/utils'
9
-
10
- type TagProps = {
11
- children: ReactNode
12
- onRemove?: () => void
13
- }
14
-
15
- // TODO: move to @keystar/ui and implement properly
16
- export function Tag(props: TagProps) {
17
- const { children, onRemove } = props
18
- const rootId = useId()
19
- const textId = composeId(rootId, 'label')
20
- const removeId = composeId(rootId, 'remove')
21
-
22
- return (
23
- <ActionButton
24
- aria-labelledby={[textId, removeId].join(' ')}
25
- onKeyDown={e => {
26
- if (!onRemove) {
27
- return
28
- }
29
-
30
- if (e.key === 'Backspace' || e.key === 'Delete') {
31
- onRemove()
32
- }
33
- }}
34
- UNSAFE_className={css({
35
- borderRadius: tokenSchema.size.radius.full,
36
- height: tokenSchema.size.element.small,
37
- paddingInlineStart: tokenSchema.size.space.small,
38
- paddingInlineEnd: 0,
39
- })}
40
- >
41
- <SlotProvider slots={{ text: { id: textId } }}>{children}</SlotProvider>
42
-
43
- {onRemove && (
44
- <span
45
- role="button"
46
- className={css({
47
- alignItems: 'center',
48
- borderRadius: '50%',
49
- display: 'flex',
50
- justifyContent: 'center',
51
- height: tokenSchema.size.element.small,
52
- width: tokenSchema.size.element.small,
53
-
54
- ':hover': {
55
- backgroundColor: tokenSchema.color.alias.backgroundHovered,
56
- },
57
- ':active': {
58
- backgroundColor: tokenSchema.color.alias.backgroundPressed,
59
- },
60
- })}
61
- onClick={e => {
62
- e.preventDefault()
63
- e.stopPropagation()
64
- onRemove()
65
- }}
66
- >
67
- <Icon id={removeId} src={xIcon} aria-label="backspace to remove" />
68
- </span>
69
- )}
70
- </ActionButton>
71
- )
72
- }
1
+ import { type ReactNode, useId } from 'react'
2
+
3
+ import { ActionButton } from '@keystar/ui/button'
4
+ import { Icon } from '@keystar/ui/icon'
5
+ import { xIcon } from '@keystar/ui/icon/icons/xIcon'
6
+ import { SlotProvider } from '@keystar/ui/slots'
7
+ import { css, tokenSchema } from '@keystar/ui/style'
8
+ import { composeId } from '@keystar/ui/utils'
9
+
10
+ type TagProps = {
11
+ children: ReactNode
12
+ onRemove?: () => void
13
+ }
14
+
15
+ // TODO: move to @keystar/ui and implement properly
16
+ export function Tag(props: TagProps) {
17
+ const { children, onRemove } = props
18
+ const rootId = useId()
19
+ const textId = composeId(rootId, 'label')
20
+ const removeId = composeId(rootId, 'remove')
21
+
22
+ return (
23
+ <ActionButton
24
+ aria-labelledby={[textId, removeId].join(' ')}
25
+ onKeyDown={e => {
26
+ if (!onRemove) {
27
+ return
28
+ }
29
+
30
+ if (e.key === 'Backspace' || e.key === 'Delete') {
31
+ onRemove()
32
+ }
33
+ }}
34
+ UNSAFE_className={css({
35
+ borderRadius: tokenSchema.size.radius.full,
36
+ height: tokenSchema.size.element.small,
37
+ paddingInlineStart: tokenSchema.size.space.small,
38
+ paddingInlineEnd: 0,
39
+ })}
40
+ >
41
+ <SlotProvider slots={{ text: { id: textId } }}>{children}</SlotProvider>
42
+
43
+ {onRemove && (
44
+ <span
45
+ role="button"
46
+ className={css({
47
+ alignItems: 'center',
48
+ borderRadius: '50%',
49
+ display: 'flex',
50
+ justifyContent: 'center',
51
+ height: tokenSchema.size.element.small,
52
+ width: tokenSchema.size.element.small,
53
+
54
+ ':hover': {
55
+ backgroundColor: tokenSchema.color.alias.backgroundHovered,
56
+ },
57
+ ':active': {
58
+ backgroundColor: tokenSchema.color.alias.backgroundPressed,
59
+ },
60
+ })}
61
+ onClick={e => {
62
+ e.preventDefault()
63
+ e.stopPropagation()
64
+ onRemove()
65
+ }}
66
+ >
67
+ <Icon id={removeId} src={xIcon} aria-label="backspace to remove" />
68
+ </span>
69
+ )}
70
+ </ActionButton>
71
+ )
72
+ }