@protobase/ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/LICENSE +202 -0
  2. package/dist/activity-chart/activity-chart.js +125 -0
  3. package/dist/activity-chart/activity-math.js +11 -0
  4. package/dist/activity-chart/activity-tooltip.js +24 -0
  5. package/dist/app/action-icon.js +10 -0
  6. package/dist/app/app.d.ts +24 -0
  7. package/dist/app/app.js +118 -0
  8. package/dist/app/batch-failure.js +21 -0
  9. package/dist/app/breadcrumb-for.js +27 -0
  10. package/dist/app/create/create-page.js +118 -0
  11. package/dist/app/create/create-record-form.js +68 -0
  12. package/dist/app/create/create-values.js +52 -0
  13. package/dist/app/delete/dialogs.js +109 -0
  14. package/dist/app/delete/record-diff.js +17 -0
  15. package/dist/app/delete/use-delete-flow.js +193 -0
  16. package/dist/app/delete/use-restore.js +9 -0
  17. package/dist/app/draft-storage.js +18 -0
  18. package/dist/app/error-banner.js +28 -0
  19. package/dist/app/field-editor.js +88 -0
  20. package/dist/app/icons.js +27 -0
  21. package/dist/app/index.d.ts +2 -0
  22. package/dist/app/index.html +12 -0
  23. package/dist/app/list-chart.js +36 -0
  24. package/dist/app/list-order.js +15 -0
  25. package/dist/app/list-page.js +213 -0
  26. package/dist/app/list-search.js +30 -0
  27. package/dist/app/main.d.ts +1 -0
  28. package/dist/app/main.js +14 -0
  29. package/dist/app/menu-icons.js +21 -0
  30. package/dist/app/meta-gate.js +46 -0
  31. package/dist/app/nav-from-meta.js +65 -0
  32. package/dist/app/nav-recent.js +33 -0
  33. package/dist/app/pages/action-href.js +7 -0
  34. package/dist/app/pages/blocks/action.js +38 -0
  35. package/dist/app/pages/blocks/block-props.js +5 -0
  36. package/dist/app/pages/blocks/card-frame.js +34 -0
  37. package/dist/app/pages/blocks/card-row.js +55 -0
  38. package/dist/app/pages/blocks/card.js +19 -0
  39. package/dist/app/pages/blocks/field.js +45 -0
  40. package/dist/app/pages/blocks/grid.js +34 -0
  41. package/dist/app/pages/blocks/link.js +27 -0
  42. package/dist/app/pages/blocks/modal-form.js +149 -0
  43. package/dist/app/pages/blocks/page-block.js +20 -0
  44. package/dist/app/pages/blocks/progress.js +54 -0
  45. package/dist/app/pages/blocks/record-card.js +56 -0
  46. package/dist/app/pages/blocks/show.js +43 -0
  47. package/dist/app/pages/blocks/stat.js +78 -0
  48. package/dist/app/pages/blocks/table.js +65 -0
  49. package/dist/app/pages/composed-page.js +19 -0
  50. package/dist/app/pages/confirm-action.js +20 -0
  51. package/dist/app/pages/field-value.js +58 -0
  52. package/dist/app/pages/project-ui.d.ts +25 -0
  53. package/dist/app/pages/project-ui.js +13 -0
  54. package/dist/app/pages/record-actions.js +40 -0
  55. package/dist/app/pages/record-scope.d.ts +16 -0
  56. package/dist/app/pages/record-scope.js +12 -0
  57. package/dist/app/pages/record-table.js +110 -0
  58. package/dist/app/pages/render-node.js +84 -0
  59. package/dist/app/pages/use-layout-data.js +73 -0
  60. package/dist/app/pages/use-path-value.js +65 -0
  61. package/dist/app/pages/use-relation-labels.js +30 -0
  62. package/dist/app/pages/use-run-action.js +88 -0
  63. package/dist/app/permissions.js +15 -0
  64. package/dist/app/record-lines.js +39 -0
  65. package/dist/app/record-page.js +318 -0
  66. package/dist/app/related-section.js +126 -0
  67. package/dist/app/relation-picker.js +69 -0
  68. package/dist/app/router.js +155 -0
  69. package/dist/app/search/search-model.js +70 -0
  70. package/dist/app/search/use-global-search.js +68 -0
  71. package/dist/app/sensitive-field.js +65 -0
  72. package/dist/app/use-lines-draft.js +45 -0
  73. package/dist/app/use-lines.js +19 -0
  74. package/dist/app/use-live-save.js +54 -0
  75. package/dist/app/use-nav-recent.js +41 -0
  76. package/dist/app/use-record-editor.js +154 -0
  77. package/dist/app/use-related-records.js +31 -0
  78. package/dist/app/user-menu-from-meta.js +36 -0
  79. package/dist/app-shell/app-shell.d.ts +4 -0
  80. package/dist/app-shell/app-shell.js +57 -0
  81. package/dist/app-shell/breadcrumb.js +37 -0
  82. package/dist/app-shell/drawer.js +30 -0
  83. package/dist/app-shell/global-search.d.ts +1 -0
  84. package/dist/app-shell/global-search.js +145 -0
  85. package/dist/app-shell/index.d.ts +9 -0
  86. package/dist/app-shell/logo.js +46 -0
  87. package/dist/app-shell/nav-open-storage.js +10 -0
  88. package/dist/app-shell/nav.d.ts +2 -0
  89. package/dist/app-shell/nav.js +85 -0
  90. package/dist/app-shell/page-header.d.ts +1 -0
  91. package/dist/app-shell/page-header.js +17 -0
  92. package/dist/app-shell/profile-menu.d.ts +2 -0
  93. package/dist/app-shell/profile-menu.js +115 -0
  94. package/dist/app-shell/sidebar-group.js +94 -0
  95. package/dist/app-shell/sidebar-item.js +46 -0
  96. package/dist/app-shell/sidebar-mode.d.ts +4 -0
  97. package/dist/app-shell/sidebar-mode.js +13 -0
  98. package/dist/app-shell/sidebar.d.ts +2 -0
  99. package/dist/app-shell/sidebar.js +64 -0
  100. package/dist/app-shell/status-dot.d.ts +1 -0
  101. package/dist/app-shell/status-dot.js +20 -0
  102. package/dist/app-shell/top-bar.js +82 -0
  103. package/dist/auth/auth-gate.js +70 -0
  104. package/dist/auth/auth-layout.js +29 -0
  105. package/dist/auth/auth-provider.js +64 -0
  106. package/dist/auth/first-run-page.js +51 -0
  107. package/dist/auth/forgot-password-form.js +75 -0
  108. package/dist/auth/forgot-password-page.js +35 -0
  109. package/dist/auth/reset-link.js +29 -0
  110. package/dist/auth/reset-password-form.js +88 -0
  111. package/dist/auth/reset-password-page.js +43 -0
  112. package/dist/auth/sign-in-form.js +74 -0
  113. package/dist/auth/sign-in-page.js +38 -0
  114. package/dist/auth/user-to-shell.js +18 -0
  115. package/dist/data/api-provider.d.ts +54 -0
  116. package/dist/data/api-provider.js +53 -0
  117. package/dist/data/meta-data.d.ts +14 -0
  118. package/dist/data/meta-data.js +9 -0
  119. package/dist/data/query-keys.js +95 -0
  120. package/dist/data/use-aggregates.d.ts +8 -0
  121. package/dist/data/use-aggregates.js +43 -0
  122. package/dist/data/use-list.d.ts +231 -0
  123. package/dist/data/use-list.js +31 -0
  124. package/dist/data/use-meta.d.ts +8 -0
  125. package/dist/data/use-meta.js +35 -0
  126. package/dist/data/use-record.d.ts +6 -0
  127. package/dist/data/use-record.js +16 -0
  128. package/dist/data/use-update-record.d.ts +15 -0
  129. package/dist/data/use-update-record.js +26 -0
  130. package/dist/data-grid/cells.js +85 -0
  131. package/dist/data-grid/column-spec.js +4 -0
  132. package/dist/data-grid/columns.js +16 -0
  133. package/dist/data-grid/data-grid.js +238 -0
  134. package/dist/data-grid/geometry.js +32 -0
  135. package/dist/data-grid/grid-footer.js +33 -0
  136. package/dist/data-grid/grid-header.js +69 -0
  137. package/dist/data-grid/grid-row.js +83 -0
  138. package/dist/data-grid/grid-template.js +12 -0
  139. package/dist/data-grid/header-menu.js +52 -0
  140. package/dist/data-grid/page-cache.js +27 -0
  141. package/dist/data-grid/pinned-storage.js +13 -0
  142. package/dist/data-grid/row-menu.js +88 -0
  143. package/dist/data-grid/use-grid-scroll.js +80 -0
  144. package/dist/data-grid/use-horizontal-scroll.js +38 -0
  145. package/dist/data-grid/use-paged-rows.js +50 -0
  146. package/dist/data-grid/use-pinned-columns.js +16 -0
  147. package/dist/filter-panel/active-filter-chips.js +34 -0
  148. package/dist/filter-panel/date-presets.js +20 -0
  149. package/dist/filter-panel/facet-group.js +48 -0
  150. package/dist/filter-panel/filter-config.js +18 -0
  151. package/dist/filter-panel/filter-menu.js +41 -0
  152. package/dist/filter-panel/filter-panel.js +112 -0
  153. package/dist/filter-panel/filter-section.js +11 -0
  154. package/dist/filter-panel/filter-state.js +63 -0
  155. package/dist/filter-panel/range-filter.js +54 -0
  156. package/dist/filter-panel/range-math.js +11 -0
  157. package/dist/filter-panel/range-slider.css +32 -0
  158. package/dist/filter-panel/toggle-row.js +13 -0
  159. package/dist/filter-panel/use-filter-state.js +15 -0
  160. package/dist/format/date.js +37 -0
  161. package/dist/format/money.js +15 -0
  162. package/dist/format/number.js +12 -0
  163. package/dist/index.d.ts +12 -0
  164. package/dist/index.js +10 -0
  165. package/dist/inline-child-table/columns.js +4 -0
  166. package/dist/inline-child-table/inline-child-table.js +120 -0
  167. package/dist/inline-child-table/line-menu.js +54 -0
  168. package/dist/inline-child-table/line-row.js +91 -0
  169. package/dist/inline-child-table/number-cell.js +25 -0
  170. package/dist/inline-child-table/reorder.js +10 -0
  171. package/dist/inline-child-table/totals-footer.js +42 -0
  172. package/dist/lib/cn.js +4 -0
  173. package/dist/lib/guarded.js +12 -0
  174. package/dist/lib/use-debounced.js +13 -0
  175. package/dist/lib/use-focus-trap.js +46 -0
  176. package/dist/lib/use-media-query.js +12 -0
  177. package/dist/live/columns-from-model.js +93 -0
  178. package/dist/live/display-value.js +24 -0
  179. package/dist/live/field-values.js +32 -0
  180. package/dist/live/filter-string.js +135 -0
  181. package/dist/live/grid-loader.js +63 -0
  182. package/dist/live/model-helpers.js +30 -0
  183. package/dist/live/naming.js +9 -0
  184. package/dist/live/relation-labels.js +53 -0
  185. package/dist/live/use-filter-config.js +88 -0
  186. package/dist/live/use-live-rows.js +45 -0
  187. package/dist/live/view-fields.js +35 -0
  188. package/dist/mocks/activity.js +24 -0
  189. package/dist/mocks/invoices.js +13 -0
  190. package/dist/mocks/products.js +167 -0
  191. package/dist/mocks/rng.js +20 -0
  192. package/dist/mocks/users.js +63 -0
  193. package/dist/primitives/avatar.js +22 -0
  194. package/dist/primitives/badge.d.ts +1 -0
  195. package/dist/primitives/badge.js +25 -0
  196. package/dist/primitives/button.js +23 -0
  197. package/dist/primitives/checkbox.js +21 -0
  198. package/dist/primitives/dialog.js +41 -0
  199. package/dist/primitives/input.js +16 -0
  200. package/dist/primitives/kbd.js +8 -0
  201. package/dist/primitives/segmented.js +14 -0
  202. package/dist/primitives/sheet.js +44 -0
  203. package/dist/primitives/skeleton.js +6 -0
  204. package/dist/primitives/spinner.js +10 -0
  205. package/dist/primitives/switch.js +14 -0
  206. package/dist/primitives/tooltip.js +13 -0
  207. package/dist/record-view/action-rail.js +28 -0
  208. package/dist/record-view/field.js +62 -0
  209. package/dist/record-view/record-header.js +50 -0
  210. package/dist/record-view/record-sidebar.js +58 -0
  211. package/dist/record-view/section.js +21 -0
  212. package/dist/styles.css +132 -0
  213. package/dist/toasts/toast-provider.js +69 -0
  214. package/dist/toasts/toast.js +45 -0
  215. package/package.json +45 -3
  216. package/README.md +0 -3
@@ -0,0 +1,231 @@
1
+ import { FilterInput, ListPage } from "@protobase/client";
2
+ //#region src/data/use-list.d.ts
3
+ export type UseListParams = {
4
+ filter?: FilterInput;
5
+ orderBy?: string;
6
+ pageSize?: number;
7
+ fields?: string[];
8
+ /** Start at this page token instead of the first page, for example one from `useAnchors`. */
9
+ startToken?: string;
10
+ enabled?: boolean;
11
+ };
12
+ type Row = Record<string, unknown>;
13
+ /** Infinite pages of a resource, following `next_page_token`. */
14
+ export declare const useList: (resource: string, { filter, orderBy, pageSize, fields, startToken, enabled }?: UseListParams) => {
15
+ items: Row[];
16
+ totalEstimate: number | undefined;
17
+ data: import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>;
18
+ error: Error;
19
+ isError: true;
20
+ isPending: false;
21
+ isLoading: false;
22
+ isLoadingError: false;
23
+ isRefetchError: true;
24
+ isSuccess: false;
25
+ isPlaceholderData: false;
26
+ status: "error";
27
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
28
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
29
+ hasNextPage: boolean;
30
+ hasPreviousPage: boolean;
31
+ isFetchNextPageError: boolean;
32
+ isFetchingNextPage: boolean;
33
+ isFetchPreviousPageError: boolean;
34
+ isFetchingPreviousPage: boolean;
35
+ dataUpdatedAt: number;
36
+ errorUpdatedAt: number;
37
+ failureCount: number;
38
+ failureReason: Error | null;
39
+ errorUpdateCount: number;
40
+ isFetched: boolean;
41
+ isFetchedAfterMount: boolean;
42
+ isFetching: boolean;
43
+ isInitialLoading: boolean;
44
+ isPaused: boolean;
45
+ isRefetching: boolean;
46
+ isStale: boolean;
47
+ isEnabled: boolean;
48
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
49
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
50
+ } | {
51
+ items: Row[];
52
+ totalEstimate: number | undefined;
53
+ data: import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>;
54
+ error: null;
55
+ isError: false;
56
+ isPending: false;
57
+ isLoading: false;
58
+ isLoadingError: false;
59
+ isRefetchError: false;
60
+ isFetchNextPageError: false;
61
+ isFetchPreviousPageError: false;
62
+ isSuccess: true;
63
+ isPlaceholderData: false;
64
+ status: "success";
65
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
66
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
67
+ hasNextPage: boolean;
68
+ hasPreviousPage: boolean;
69
+ isFetchingNextPage: boolean;
70
+ isFetchingPreviousPage: boolean;
71
+ dataUpdatedAt: number;
72
+ errorUpdatedAt: number;
73
+ failureCount: number;
74
+ failureReason: Error | null;
75
+ errorUpdateCount: number;
76
+ isFetched: boolean;
77
+ isFetchedAfterMount: boolean;
78
+ isFetching: boolean;
79
+ isInitialLoading: boolean;
80
+ isPaused: boolean;
81
+ isRefetching: boolean;
82
+ isStale: boolean;
83
+ isEnabled: boolean;
84
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
85
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
86
+ } | {
87
+ items: Row[];
88
+ totalEstimate: number | undefined;
89
+ data: undefined;
90
+ error: Error;
91
+ isError: true;
92
+ isPending: false;
93
+ isLoading: false;
94
+ isLoadingError: true;
95
+ isRefetchError: false;
96
+ isFetchNextPageError: false;
97
+ isFetchPreviousPageError: false;
98
+ isSuccess: false;
99
+ isPlaceholderData: false;
100
+ status: "error";
101
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
102
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
103
+ hasNextPage: boolean;
104
+ hasPreviousPage: boolean;
105
+ isFetchingNextPage: boolean;
106
+ isFetchingPreviousPage: boolean;
107
+ dataUpdatedAt: number;
108
+ errorUpdatedAt: number;
109
+ failureCount: number;
110
+ failureReason: Error | null;
111
+ errorUpdateCount: number;
112
+ isFetched: boolean;
113
+ isFetchedAfterMount: boolean;
114
+ isFetching: boolean;
115
+ isInitialLoading: boolean;
116
+ isPaused: boolean;
117
+ isRefetching: boolean;
118
+ isStale: boolean;
119
+ isEnabled: boolean;
120
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
121
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
122
+ } | {
123
+ items: Row[];
124
+ totalEstimate: number | undefined;
125
+ data: undefined;
126
+ error: null;
127
+ isError: false;
128
+ isPending: true;
129
+ isLoading: true;
130
+ isLoadingError: false;
131
+ isRefetchError: false;
132
+ isFetchNextPageError: false;
133
+ isFetchPreviousPageError: false;
134
+ isSuccess: false;
135
+ isPlaceholderData: false;
136
+ status: "pending";
137
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
138
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
139
+ hasNextPage: boolean;
140
+ hasPreviousPage: boolean;
141
+ isFetchingNextPage: boolean;
142
+ isFetchingPreviousPage: boolean;
143
+ dataUpdatedAt: number;
144
+ errorUpdatedAt: number;
145
+ failureCount: number;
146
+ failureReason: Error | null;
147
+ errorUpdateCount: number;
148
+ isFetched: boolean;
149
+ isFetchedAfterMount: boolean;
150
+ isFetching: boolean;
151
+ isInitialLoading: boolean;
152
+ isPaused: boolean;
153
+ isRefetching: boolean;
154
+ isStale: boolean;
155
+ isEnabled: boolean;
156
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
157
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
158
+ } | {
159
+ items: Row[];
160
+ totalEstimate: number | undefined;
161
+ data: undefined;
162
+ error: null;
163
+ isError: false;
164
+ isPending: true;
165
+ isLoadingError: false;
166
+ isRefetchError: false;
167
+ isFetchNextPageError: false;
168
+ isFetchPreviousPageError: false;
169
+ isSuccess: false;
170
+ isPlaceholderData: false;
171
+ status: "pending";
172
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
173
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
174
+ hasNextPage: boolean;
175
+ hasPreviousPage: boolean;
176
+ isFetchingNextPage: boolean;
177
+ isFetchingPreviousPage: boolean;
178
+ dataUpdatedAt: number;
179
+ errorUpdatedAt: number;
180
+ failureCount: number;
181
+ failureReason: Error | null;
182
+ errorUpdateCount: number;
183
+ isFetched: boolean;
184
+ isFetchedAfterMount: boolean;
185
+ isFetching: boolean;
186
+ isLoading: boolean;
187
+ isInitialLoading: boolean;
188
+ isPaused: boolean;
189
+ isRefetching: boolean;
190
+ isStale: boolean;
191
+ isEnabled: boolean;
192
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
193
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
194
+ } | {
195
+ items: Row[];
196
+ totalEstimate: number | undefined;
197
+ data: import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>;
198
+ isError: false;
199
+ error: null;
200
+ isPending: false;
201
+ isLoading: false;
202
+ isLoadingError: false;
203
+ isRefetchError: false;
204
+ isSuccess: true;
205
+ isPlaceholderData: true;
206
+ isFetchNextPageError: false;
207
+ isFetchPreviousPageError: false;
208
+ status: "success";
209
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
210
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
211
+ hasNextPage: boolean;
212
+ hasPreviousPage: boolean;
213
+ isFetchingNextPage: boolean;
214
+ isFetchingPreviousPage: boolean;
215
+ dataUpdatedAt: number;
216
+ errorUpdatedAt: number;
217
+ failureCount: number;
218
+ failureReason: Error | null;
219
+ errorUpdateCount: number;
220
+ isFetched: boolean;
221
+ isFetchedAfterMount: boolean;
222
+ isFetching: boolean;
223
+ isInitialLoading: boolean;
224
+ isPaused: boolean;
225
+ isRefetching: boolean;
226
+ isStale: boolean;
227
+ isEnabled: boolean;
228
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<Row>, unknown>, Error>>;
229
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
230
+ };
231
+ //#endregion
@@ -0,0 +1,31 @@
1
+ import { keys } from "./query-keys.js";
2
+ import { useClient } from "./api-provider.js";
3
+ import { useInfiniteQuery } from "@tanstack/react-query";
4
+ import { filterText } from "@protobase/client";
5
+ //#region src/data/use-list.ts
6
+ /** Infinite pages of a resource, following `next_page_token`. */
7
+ const useList = (resource, { filter, orderBy, pageSize = 50, fields, startToken = "", enabled = true } = {}) => {
8
+ const client = useClient();
9
+ const text = filterText(filter) ?? "";
10
+ const query = useInfiniteQuery({
11
+ queryKey: [...keys.list(resource, text, orderBy ?? "", pageSize, startToken), fields?.join(",") ?? ""],
12
+ enabled,
13
+ initialPageParam: startToken,
14
+ queryFn: ({ pageParam }) => client.list(resource, {
15
+ filter: text,
16
+ orderBy,
17
+ pageSize,
18
+ fields,
19
+ pageToken: pageParam
20
+ }),
21
+ getNextPageParam: (last) => last.nextPageToken || void 0
22
+ });
23
+ const pages = query.data?.pages ?? [];
24
+ return {
25
+ ...query,
26
+ items: pages.flatMap((page) => page.items),
27
+ totalEstimate: pages[0]?.totalSizeEstimate
28
+ };
29
+ };
30
+ //#endregion
31
+ export { useList };
@@ -0,0 +1,8 @@
1
+ import { MetaData } from "./meta-data.js";
2
+ //#region src/data/use-meta.d.ts
3
+ /**
4
+ * The resource and view models. Refetches on window focus with `If-None-Match`, so an unchanged
5
+ * `/meta` costs a 304, and the cached object keeps its identity.
6
+ */
7
+ export declare const useMeta: () => import("@tanstack/react-query").UseQueryResult<MetaData, Error>;
8
+ //#endregion
@@ -0,0 +1,35 @@
1
+ import { keys } from "./query-keys.js";
2
+ import { useClient } from "./api-provider.js";
3
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
4
+ //#region src/data/use-meta.ts
5
+ /**
6
+ * The resource and view models. Refetches on window focus with `If-None-Match`, so an unchanged
7
+ * `/meta` costs a 304, and the cached object keeps its identity.
8
+ */
9
+ const useMeta = () => {
10
+ const client = useClient();
11
+ const queryClient = useQueryClient();
12
+ return useQuery({
13
+ queryKey: keys.meta,
14
+ staleTime: 0,
15
+ refetchOnWindowFocus: "always",
16
+ queryFn: async () => {
17
+ const previous = queryClient.getQueryData(keys.meta);
18
+ const result = await client.meta(previous?.etag);
19
+ if (result.status === "unchanged") {
20
+ if (!previous) throw new Error("The server answered 304 to a request without If-None-Match");
21
+ return previous;
22
+ }
23
+ return {
24
+ etag: result.etag,
25
+ resources: Object.fromEntries(result.meta.resources.map((model) => [model.name, model])),
26
+ views: Object.fromEntries(result.meta.views.map((model) => [model.resource, model])),
27
+ pages: Object.fromEntries((result.meta.pages ?? []).map((model) => [model.name, model])),
28
+ permissions: result.meta.permissions ?? {},
29
+ ...result.meta.userMenu && { userMenu: result.meta.userMenu }
30
+ };
31
+ }
32
+ });
33
+ };
34
+ //#endregion
35
+ export { useMeta };
@@ -0,0 +1,6 @@
1
+ import { Stored } from "@protobase/client";
2
+ import { KeyValue } from "@protobase/schema";
3
+ //#region src/data/use-record.d.ts
4
+ export type LiveRecord = Stored<Record<string, unknown>>;
5
+ export declare const useRecord: (resource: string, key: KeyValue | readonly KeyValue[], enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<LiveRecord, Error>;
6
+ //#endregion
@@ -0,0 +1,16 @@
1
+ import { keys } from "./query-keys.js";
2
+ import { useClient } from "./api-provider.js";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ import { encodeKey } from "@protobase/schema";
5
+ //#region src/data/use-record.ts
6
+ const useRecord = (resource, key, enabled = true) => {
7
+ const client = useClient();
8
+ const encoded = encodeKey(key);
9
+ return useQuery({
10
+ queryKey: keys.record(resource, encoded),
11
+ enabled,
12
+ queryFn: () => client.get(resource, key)
13
+ });
14
+ };
15
+ //#endregion
16
+ export { useRecord };
@@ -0,0 +1,15 @@
1
+ import { LiveRecord } from "./use-record.js";
2
+ import { PreconditionFailedError } from "@protobase/client";
3
+ import { KeyValue } from "@protobase/schema";
4
+ //#region src/data/use-update-record.d.ts
5
+ export type UpdateArgs = {
6
+ patch: Record<string, unknown>;
7
+ etag: string;
8
+ };
9
+ /**
10
+ * PATCH with `If-Match`. On success the cached record gets the new ETag and lists refetch;
11
+ * a `412` rejects with `PreconditionFailedError`, which `isConflict` recognises.
12
+ */
13
+ export declare const useUpdateRecord: (resource: string, key: KeyValue | readonly KeyValue[]) => import("@tanstack/react-query").UseMutationResult<LiveRecord, Error, UpdateArgs, unknown>;
14
+ export declare const isConflict: (error: unknown) => error is PreconditionFailedError;
15
+ //#endregion
@@ -0,0 +1,26 @@
1
+ import { keys } from "./query-keys.js";
2
+ import { useClient } from "./api-provider.js";
3
+ import { useMutation, useQueryClient } from "@tanstack/react-query";
4
+ import { PreconditionFailedError } from "@protobase/client";
5
+ import { encodeKey } from "@protobase/schema";
6
+ //#region src/data/use-update-record.ts
7
+ /**
8
+ * PATCH with `If-Match`. On success the cached record gets the new ETag and lists refetch;
9
+ * a `412` rejects with `PreconditionFailedError`, which `isConflict` recognises.
10
+ */
11
+ const useUpdateRecord = (resource, key) => {
12
+ const client = useClient();
13
+ const queryClient = useQueryClient();
14
+ const encoded = encodeKey(key);
15
+ return useMutation({
16
+ mutationFn: ({ patch, etag }) => client.update(resource, key, patch, etag),
17
+ onSuccess: (stored) => {
18
+ queryClient.setQueryData(keys.record(resource, encoded), stored);
19
+ queryClient.invalidateQueries({ queryKey: ["page", resource] });
20
+ queryClient.invalidateQueries({ queryKey: ["list", resource] });
21
+ }
22
+ });
23
+ };
24
+ const isConflict = (error) => error instanceof PreconditionFailedError;
25
+ //#endregion
26
+ export { isConflict, useUpdateRecord };
@@ -0,0 +1,85 @@
1
+ import { cn } from "../lib/cn.js";
2
+ import { Avatar } from "../primitives/avatar.js";
3
+ import { Badge } from "../primitives/badge.js";
4
+ import { formatDate, formatDateTime } from "../format/date.js";
5
+ import { userById } from "../mocks/users.js";
6
+ import { formatMoney } from "../format/money.js";
7
+ import { formatInt, formatPercent, formatSigned } from "../format/number.js";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { Check } from "lucide-react";
10
+ import { enumLabel } from "@protobase/schema";
11
+ //#region src/data-grid/cells.tsx
12
+ const muted = (text) => /* @__PURE__ */ jsx("span", {
13
+ className: "text-faint-foreground",
14
+ children: text
15
+ });
16
+ const relationLabel = (value) => typeof value === "object" && value !== null && "name" in value ? String(value.name) : String(value);
17
+ const renderCell = (spec, value) => {
18
+ if (value === null || value === void 0) return muted("—");
19
+ switch (spec.kind) {
20
+ case "text": return /* @__PURE__ */ jsx("span", {
21
+ className: "truncate",
22
+ children: String(value)
23
+ });
24
+ case "id": return /* @__PURE__ */ jsx("span", {
25
+ className: "truncate font-mono text-xs text-muted-foreground",
26
+ children: String(value)
27
+ });
28
+ case "money": return /* @__PURE__ */ jsx("span", {
29
+ className: "tabular-nums",
30
+ children: formatMoney(Number(value), spec.currency)
31
+ });
32
+ case "date": return /* @__PURE__ */ jsx("span", {
33
+ className: "tabular-nums text-muted-foreground",
34
+ children: formatDate(Number(value))
35
+ });
36
+ case "datetime": return /* @__PURE__ */ jsx("span", {
37
+ className: "tabular-nums text-muted-foreground",
38
+ children: formatDateTime(Number(value))
39
+ });
40
+ case "number": return /* @__PURE__ */ jsx("span", {
41
+ className: "tabular-nums",
42
+ children: formatInt(Number(value))
43
+ });
44
+ case "signed": return /* @__PURE__ */ jsx("span", {
45
+ className: cn("tabular-nums", Number(value) < 0 ? "text-danger-text" : "text-success-text"),
46
+ children: formatSigned(Number(value))
47
+ });
48
+ case "percent": return Number(value) === 0 ? muted("—") : /* @__PURE__ */ jsx("span", {
49
+ className: "tabular-nums",
50
+ children: formatPercent(Number(value))
51
+ });
52
+ case "status": return /* @__PURE__ */ jsx(Badge, {
53
+ tone: spec.tones?.[String(value)] ?? "neutral",
54
+ children: enumLabel(String(value), spec.labels)
55
+ });
56
+ case "relation": return /* @__PURE__ */ jsx("span", {
57
+ className: "truncate font-medium text-primary-text hover:underline",
58
+ children: relationLabel(value)
59
+ });
60
+ case "boolean": return value ? /* @__PURE__ */ jsx("span", {
61
+ className: "inline-flex size-4 items-center justify-center rounded-full bg-success-soft text-success-text",
62
+ children: /* @__PURE__ */ jsx(Check, {
63
+ className: "size-3",
64
+ strokeWidth: 3
65
+ })
66
+ }) : muted("No");
67
+ case "user": {
68
+ const user = userById(String(value));
69
+ return /* @__PURE__ */ jsxs("span", {
70
+ className: "inline-flex items-center gap-2 truncate",
71
+ children: [/* @__PURE__ */ jsx(Avatar, {
72
+ initials: user.initials,
73
+ hue: user.hue,
74
+ size: "xs",
75
+ className: "ring-0"
76
+ }), /* @__PURE__ */ jsx("span", {
77
+ className: "truncate text-muted-foreground",
78
+ children: user.name
79
+ })]
80
+ });
81
+ }
82
+ }
83
+ };
84
+ //#endregion
85
+ export { renderCell };
@@ -0,0 +1,4 @@
1
+ //#region src/data-grid/column-spec.ts
2
+ const isRightAligned = (kind) => kind === "money" || kind === "number" || kind === "signed" || kind === "percent";
3
+ //#endregion
4
+ export { isRightAligned };
@@ -0,0 +1,16 @@
1
+ import { renderCell } from "./cells.js";
2
+ import { createColumnHelper, rowSelectionFeature, rowSortingFeature, tableFeatures } from "@tanstack/react-table";
3
+ //#region src/data-grid/columns.ts
4
+ const features = tableFeatures({
5
+ rowSortingFeature,
6
+ rowSelectionFeature
7
+ });
8
+ const helper = createColumnHelper();
9
+ const buildColumns = (specs) => helper.columns(specs.map((spec) => helper.accessor((row) => spec.value ? spec.value(row) : row[spec.id], {
10
+ id: spec.id,
11
+ header: spec.header,
12
+ enableSorting: spec.sortable ?? false,
13
+ cell: (context) => renderCell(spec, context.getValue())
14
+ })));
15
+ //#endregion
16
+ export { buildColumns, features };