@rebasepro/ui 0.17.3 → 0.18.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 (127) hide show
  1. package/README.md +4 -0
  2. package/dist/components/MultiSelect.d.ts +10 -0
  3. package/dist/index.es.js +2 -1
  4. package/dist/index.es.js.map +1 -1
  5. package/package.json +32 -23
  6. package/src/components/Alert.tsx +0 -118
  7. package/src/components/Autocomplete.tsx +0 -93
  8. package/src/components/Avatar.tsx +0 -73
  9. package/src/components/Badge.tsx +0 -44
  10. package/src/components/BooleanSwitch.tsx +0 -116
  11. package/src/components/BooleanSwitchWithLabel.tsx +0 -120
  12. package/src/components/Button.tsx +0 -110
  13. package/src/components/Card.tsx +0 -43
  14. package/src/components/CenteredView.tsx +0 -35
  15. package/src/components/Checkbox.tsx +0 -129
  16. package/src/components/Chip.tsx +0 -131
  17. package/src/components/CircularProgress.tsx +0 -53
  18. package/src/components/CircularProgressCenter.tsx +0 -27
  19. package/src/components/Collapse.tsx +0 -66
  20. package/src/components/ColorPicker.tsx +0 -140
  21. package/src/components/Container.tsx +0 -51
  22. package/src/components/DateTimeField.tsx +0 -363
  23. package/src/components/DebouncedTextField.tsx +0 -76
  24. package/src/components/Dialog.tsx +0 -159
  25. package/src/components/DialogActions.tsx +0 -29
  26. package/src/components/DialogContent.tsx +0 -27
  27. package/src/components/DialogTitle.tsx +0 -41
  28. package/src/components/ErrorBoundary.tsx +0 -236
  29. package/src/components/ExpandablePanel.tsx +0 -130
  30. package/src/components/FileUpload.tsx +0 -103
  31. package/src/components/FilterChip.tsx +0 -89
  32. package/src/components/IconButton.tsx +0 -101
  33. package/src/components/InfoLabel.tsx +0 -23
  34. package/src/components/InputLabel.tsx +0 -40
  35. package/src/components/Label.tsx +0 -32
  36. package/src/components/LoadingButton.tsx +0 -32
  37. package/src/components/Markdown.tsx +0 -55
  38. package/src/components/Menu.tsx +0 -114
  39. package/src/components/Menubar.tsx +0 -355
  40. package/src/components/MultiSelect.tsx +0 -433
  41. package/src/components/Paper.tsx +0 -23
  42. package/src/components/Popover.tsx +0 -162
  43. package/src/components/RadioGroup.tsx +0 -74
  44. package/src/components/ResizablePanels.tsx +0 -189
  45. package/src/components/SearchBar.tsx +0 -136
  46. package/src/components/Select.tsx +0 -326
  47. package/src/components/Separator.tsx +0 -28
  48. package/src/components/Sheet.tsx +0 -135
  49. package/src/components/Skeleton.tsx +0 -54
  50. package/src/components/Slider.tsx +0 -110
  51. package/src/components/Table.tsx +0 -178
  52. package/src/components/Tabs.tsx +0 -185
  53. package/src/components/TextField.tsx +0 -270
  54. package/src/components/TextareaAutosize.tsx +0 -368
  55. package/src/components/ToggleButtonGroup.tsx +0 -69
  56. package/src/components/Tooltip.tsx +0 -153
  57. package/src/components/Typography.tsx +0 -132
  58. package/src/components/VirtualTable/VirtualTable.performance.test.tsx +0 -90
  59. package/src/components/VirtualTable/VirtualTable.tsx +0 -700
  60. package/src/components/VirtualTable/VirtualTableCell.tsx +0 -59
  61. package/src/components/VirtualTable/VirtualTableHeader.tsx +0 -327
  62. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +0 -250
  63. package/src/components/VirtualTable/VirtualTableProps.tsx +0 -339
  64. package/src/components/VirtualTable/VirtualTableRow.tsx +0 -51
  65. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +0 -44
  66. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -89
  67. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +0 -71
  68. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +0 -107
  69. package/src/components/VirtualTable/fields/VirtualTableSwitch.tsx +0 -28
  70. package/src/components/VirtualTable/index.tsx +0 -10
  71. package/src/components/VirtualTable/selection/SelectionContext.tsx +0 -36
  72. package/src/components/VirtualTable/selection/SelectionStore.ts +0 -54
  73. package/src/components/VirtualTable/types.tsx +0 -47
  74. package/src/components/common/SelectInputLabel.tsx +0 -23
  75. package/src/components/index.tsx +0 -62
  76. package/src/hooks/PortalContainerContext.tsx +0 -50
  77. package/src/hooks/index.ts +0 -7
  78. package/src/hooks/useDebounceCallback.tsx +0 -21
  79. package/src/hooks/useDebounceValue.tsx +0 -20
  80. package/src/hooks/useDebouncedCallback.ts +0 -39
  81. package/src/hooks/useInjectStyles.tsx +0 -31
  82. package/src/hooks/useOutsideAlerter.tsx +0 -46
  83. package/src/icons/GitHubIcon.tsx +0 -21
  84. package/src/icons/HandleIcon.tsx +0 -23
  85. package/src/icons/Icon.tsx +0 -33
  86. package/src/icons/LucideIconByName.tsx +0 -117
  87. package/src/icons/cool_icon_keys.ts +0 -12
  88. package/src/icons/icon_keys.ts +0 -1936
  89. package/src/icons/index.ts +0 -179
  90. package/src/index.css +0 -169
  91. package/src/index.ts +0 -47
  92. package/src/scripts/fixIconSizes.cjs +0 -92
  93. package/src/scripts/fixIconSizesToConst.cjs +0 -106
  94. package/src/scripts/generateIconKeys.ts +0 -41
  95. package/src/scripts/generateIcons.ts +0 -4
  96. package/src/scripts/saveIconFiles.ts +0 -89
  97. package/src/styles.ts +0 -141
  98. package/src/theme.css +0 -168
  99. package/src/util/chip_colors.ts +0 -242
  100. package/src/util/cls.ts +0 -8
  101. package/src/util/debounce.ts +0 -28
  102. package/src/util/hash.ts +0 -11
  103. package/src/util/index.ts +0 -4
  104. package/src/util/key_to_icon_component.ts +0 -11
  105. package/src/util/lazy_chunk.ts +0 -101
  106. package/src/views/CardView.tsx +0 -281
  107. package/src/views/CollectionView/CollectionCardView.tsx +0 -265
  108. package/src/views/CollectionView/CollectionKanbanView.tsx +0 -246
  109. package/src/views/CollectionView/CollectionListView.tsx +0 -240
  110. package/src/views/CollectionView/CollectionTableView.tsx +0 -229
  111. package/src/views/CollectionView/CollectionView.tsx +0 -450
  112. package/src/views/CollectionView/CollectionViewToolbar.tsx +0 -242
  113. package/src/views/CollectionView/CollectionViewTypes.ts +0 -181
  114. package/src/views/CollectionView/DefaultCellRenderer.tsx +0 -404
  115. package/src/views/CollectionView/index.ts +0 -39
  116. package/src/views/CollectionView/resolveTitleProperty.ts +0 -52
  117. package/src/views/CollectionView/utils.ts +0 -14
  118. package/src/views/Kanban/Board.tsx +0 -384
  119. package/src/views/Kanban/BoardColumn.tsx +0 -138
  120. package/src/views/Kanban/BoardColumnTitle.tsx +0 -47
  121. package/src/views/Kanban/BoardSortableList.tsx +0 -182
  122. package/src/views/Kanban/board_types.ts +0 -80
  123. package/src/views/Kanban/index.tsx +0 -5
  124. package/src/views/Kanban/placement.ts +0 -62
  125. package/src/views/KanbanView.tsx +0 -32
  126. package/src/views/ListView.tsx +0 -296
  127. package/src/views/index.ts +0 -5
@@ -1,404 +0,0 @@
1
- import React from "react";
2
- import { ImageIcon } from "lucide-react";
3
- import { cls } from "../../util";
4
- import { Typography } from "../../components/Typography";
5
- import { Chip } from "../../components/Chip";
6
- import { BooleanSwitch } from "../../components/BooleanSwitch";
7
- import { Markdown } from "../../components/Markdown";
8
- import { Tooltip } from "../../components/Tooltip";
9
- import { iconSize } from "../../icons";
10
- import type { CellRendererProps, CollectionPropertyConfig, CollectionEnumValueConfig } from "./CollectionViewTypes";
11
-
12
- // ——— Helpers ———
13
-
14
- /**
15
- * Resolve an enum key to its display label and optional color.
16
- */
17
- function resolveEnumLabel(
18
- enumValues: CollectionPropertyConfig["enum"],
19
- value: unknown
20
- ): { label: string; color?: string } | undefined {
21
- if (!enumValues) return undefined;
22
- const key = String(value);
23
- if (enumValues instanceof Map) {
24
- const config: CollectionEnumValueConfig | undefined = enumValues.get(value as string | number);
25
- if (!config) return undefined;
26
- if (typeof config === "string") return { label: config };
27
- return { label: config.label, color: config.color };
28
- }
29
- const config: CollectionEnumValueConfig | undefined = enumValues[key];
30
- if (!config) return undefined;
31
- if (typeof config === "string") return { label: config };
32
- return { label: config.label, color: config.color };
33
- }
34
-
35
- /**
36
- * Format a date value using Intl.DateTimeFormat.
37
- */
38
- function formatDate(value: unknown, includeTime: boolean): string {
39
- if (value == null) return "—";
40
- const date = value instanceof Date ? value : new Date(String(value));
41
- if (isNaN(date.getTime())) return String(value);
42
-
43
- const options: Intl.DateTimeFormatOptions = includeTime
44
- ? { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }
45
- : { year: "numeric", month: "short", day: "numeric" };
46
-
47
- return new Intl.DateTimeFormat(undefined, options).format(date);
48
- }
49
-
50
- /**
51
- * Type guard for geopoint-like objects.
52
- */
53
- function isGeoPoint(value: unknown): value is { lat: number; lng: number } {
54
- if (typeof value !== "object" || value === null) return false;
55
- const obj = value as Record<string, unknown>;
56
- return typeof obj.lat === "number" && typeof obj.lng === "number";
57
- }
58
-
59
- // ——— Component ———
60
-
61
- /**
62
- * Default cell renderer for the headless CollectionView.
63
- * Handles all built-in property types without depending on any Rebase core types.
64
- *
65
- * @group Preview components
66
- */
67
- export function DefaultCellRenderer({
68
- row,
69
- propertyKey,
70
- property,
71
- value,
72
- size,
73
- width,
74
- height
75
- }: CellRendererProps) {
76
-
77
- // 1. Null / undefined → em-dash
78
- if (value === null || value === undefined) {
79
- return (
80
- <Typography variant="body2"
81
- color="secondary"
82
- className="px-1">
83
-
84
- </Typography>
85
- );
86
- }
87
-
88
- // 2. Custom Preview component override
89
- if (property.Preview) {
90
- const PreviewComponent = property.Preview;
91
- return (
92
- <PreviewComponent
93
- row={row}
94
- propertyKey={propertyKey}
95
- property={property}
96
- value={value}
97
- size={size}
98
- width={width}
99
- height={height}
100
- />
101
- );
102
- }
103
-
104
- // ——— Type-specific renderers ———
105
-
106
- switch (property.type) {
107
- case "string":
108
- return renderString(property, value);
109
-
110
- case "number":
111
- return renderNumber(property, value);
112
-
113
- case "boolean":
114
- return renderBoolean(value);
115
-
116
- case "date":
117
- return renderDate(property, value);
118
-
119
- case "array":
120
- return renderArray(property, value);
121
-
122
- case "map":
123
- return renderMap(value);
124
-
125
- case "reference":
126
- case "relation":
127
- return renderReference(value);
128
-
129
- case "geopoint":
130
- return renderGeopoint(value);
131
-
132
- default:
133
- return (
134
- <Typography variant="body2"
135
- color="secondary"
136
- noWrap
137
- className="px-1">
138
- {JSON.stringify(value)}
139
- </Typography>
140
- );
141
- }
142
- }
143
-
144
- // ——— Per-type render functions ———
145
-
146
- function renderString(property: CollectionPropertyConfig, value: unknown): React.ReactElement {
147
- const strValue = String(value);
148
-
149
- // Enum → Chip
150
- if (property.enum) {
151
- const resolved = resolveEnumLabel(property.enum, value);
152
- return (
153
- <Chip size="small"
154
- colorScheme={resolved?.color ? { color: resolved.color, text: "#fff" } : undefined}>
155
- {resolved?.label ?? strValue}
156
- </Chip>
157
- );
158
- }
159
-
160
- // Preview as tag → Chip
161
- if (property.previewAsTag) {
162
- return (
163
- <Chip size="small">
164
- {strValue}
165
- </Chip>
166
- );
167
- }
168
-
169
- // URL → clickable link
170
- if (property.url) {
171
- const href = typeof property.url === "string" ? property.url : strValue;
172
- return (
173
- <Typography variant="body2"
174
- noWrap
175
- component="a"
176
- href={href}
177
- target="_blank"
178
- rel="noopener noreferrer"
179
- className={cls(
180
- "px-1 text-primary hover:underline cursor-pointer"
181
- )}>
182
- {strValue}
183
- </Typography>
184
- );
185
- }
186
-
187
- // Email → mailto link
188
- if (property.email) {
189
- return (
190
- <Typography variant="body2"
191
- noWrap
192
- component="a"
193
- href={`mailto:${strValue}`}
194
- className={cls(
195
- "px-1 text-primary hover:underline cursor-pointer"
196
- )}>
197
- {strValue}
198
- </Typography>
199
- );
200
- }
201
-
202
- // Markdown → rendered markdown
203
- if (property.markdown) {
204
- return (
205
- <div className="px-1 max-h-[100px] overflow-hidden">
206
- <Markdown source={strValue} size="small" />
207
- </div>
208
- );
209
- }
210
-
211
- // Storage → image preview with fallback
212
- if (property.storage) {
213
- return (
214
- <div className={cls(
215
- "px-1 flex items-center justify-center",
216
- "w-[40px] h-[40px] rounded overflow-hidden"
217
- )}>
218
- {strValue ? (
219
- <img
220
- src={strValue}
221
- alt=""
222
- className="w-full h-full object-cover"
223
- onError={(e) => {
224
- const target = e.currentTarget;
225
- target.style.display = "none";
226
- const fallback = target.nextElementSibling;
227
- if (fallback instanceof HTMLElement) {
228
- fallback.style.display = "flex";
229
- }
230
- }}
231
- />
232
- ) : null}
233
- <div className={cls(
234
- "w-full h-full items-center justify-center rounded",
235
- "bg-surface-100 dark:bg-surface-800 text-text-secondary dark:text-text-secondary-dark",
236
- strValue ? "hidden" : "flex"
237
- )}>
238
- <ImageIcon size={iconSize.small} />
239
- </div>
240
- </div>
241
- );
242
- }
243
-
244
- // Default string → truncated text
245
- return (
246
- <Tooltip title={strValue.length > 50 ? strValue : undefined}
247
- side="bottom">
248
- <Typography variant="body2"
249
- noWrap
250
- className="px-1">
251
- {strValue}
252
- </Typography>
253
- </Tooltip>
254
- );
255
- }
256
-
257
- function renderNumber(property: CollectionPropertyConfig, value: unknown): React.ReactElement {
258
- const numStr = String(value);
259
-
260
- // Enum → Chip
261
- if (property.enum) {
262
- const resolved = resolveEnumLabel(property.enum, value);
263
- return (
264
- <Chip size="small"
265
- colorScheme={resolved?.color ? { color: resolved.color, text: "#fff" } : undefined}>
266
- {resolved?.label ?? numStr}
267
- </Chip>
268
- );
269
- }
270
-
271
- // Default → right-aligned
272
- return (
273
- <Typography variant="body2"
274
- noWrap
275
- align="right"
276
- className="px-1 tabular-nums">
277
- {numStr}
278
- </Typography>
279
- );
280
- }
281
-
282
- function renderBoolean(value: unknown): React.ReactElement {
283
- return (
284
- <div className="px-1 flex items-center">
285
- <BooleanSwitch value={!!value}
286
- size="small"
287
- disabled />
288
- </div>
289
- );
290
- }
291
-
292
- function renderDate(property: CollectionPropertyConfig, value: unknown): React.ReactElement {
293
- const includeTime = property.mode === "date_time";
294
- const formatted = formatDate(value, includeTime);
295
-
296
- return (
297
- <Typography variant="body2"
298
- noWrap
299
- className="px-1 tabular-nums">
300
- {formatted}
301
- </Typography>
302
- );
303
- }
304
-
305
- function renderArray(property: CollectionPropertyConfig, value: unknown): React.ReactElement {
306
- if (!Array.isArray(value)) {
307
- return (
308
- <Typography variant="body2"
309
- color="secondary"
310
- className="px-1">
311
-
312
- </Typography>
313
- );
314
- }
315
-
316
- // Array of enum values → row of chips
317
- if (property.of?.enum && value.length > 0) {
318
- return (
319
- <div className="px-1 flex flex-wrap gap-1 overflow-hidden">
320
- {value.map((item, i) => {
321
- const resolved = resolveEnumLabel(property.of!.enum, item);
322
- return (
323
- <Chip key={i}
324
- size="smallest"
325
- colorScheme={resolved?.color ? { color: resolved.color, text: "#fff" } : undefined}>
326
- {resolved?.label ?? String(item)}
327
- </Chip>
328
- );
329
- })}
330
- </div>
331
- );
332
- }
333
-
334
- // Array of strings → comma-separated
335
- if (value.length > 0 && value.every((item) => typeof item === "string")) {
336
- return (
337
- <Typography variant="body2"
338
- noWrap
339
- className="px-1">
340
- {(value as string[]).join(", ")}
341
- </Typography>
342
- );
343
- }
344
-
345
- // Generic array → item count
346
- return (
347
- <Typography variant="body2"
348
- color="secondary"
349
- className="px-1">
350
- {value.length} {value.length === 1 ? "item" : "items"}
351
- </Typography>
352
- );
353
- }
354
-
355
- function renderMap(value: unknown): React.ReactElement {
356
- if (typeof value !== "object" || value === null) {
357
- return (
358
- <Typography variant="body2"
359
- color="secondary"
360
- className="px-1">
361
-
362
- </Typography>
363
- );
364
- }
365
-
366
- const fieldCount = Object.keys(value as Record<string, unknown>).length;
367
- return (
368
- <Typography variant="body2"
369
- color="secondary"
370
- className="px-1">
371
- {fieldCount} {fieldCount === 1 ? "field" : "fields"}
372
- </Typography>
373
- );
374
- }
375
-
376
- function renderReference(value: unknown): React.ReactElement {
377
- return (
378
- <Typography variant="body2"
379
- noWrap
380
- className="px-1">
381
- {String(value)}
382
- </Typography>
383
- );
384
- }
385
-
386
- function renderGeopoint(value: unknown): React.ReactElement {
387
- if (isGeoPoint(value)) {
388
- return (
389
- <Typography variant="body2"
390
- noWrap
391
- className="px-1 tabular-nums">
392
- {value.lat.toFixed(6)}, {value.lng.toFixed(6)}
393
- </Typography>
394
- );
395
- }
396
-
397
- return (
398
- <Typography variant="body2"
399
- color="secondary"
400
- className="px-1">
401
- {String(value)}
402
- </Typography>
403
- );
404
- }
@@ -1,39 +0,0 @@
1
- /**
2
- * Headless Collection View components.
3
- *
4
- * Data-agnostic collection rendering — table, card, list, and kanban views
5
- * driven entirely by property configurations and callbacks.
6
- *
7
- * Zero imports from any entity or data layer.
8
- *
9
- * @module CollectionView
10
- */
11
-
12
- // Types
13
- export type {
14
- CollectionViewMode,
15
- CollectionViewSize,
16
- CollectionEnumValueConfig,
17
- CollectionPropertyConfig,
18
- CollectionDataController,
19
- CellRendererProps,
20
- CellRendererOverride,
21
- CollectionSelectionController,
22
- KanbanPropertyOption
23
- } from "./CollectionViewTypes";
24
-
25
- // Components
26
- //
27
- // `CollectionView` is the entry point. The per-mode views
28
- // (table/card/list/kanban), the toolbar and the default cell renderer are
29
- // internal: `CollectionView` selects and wires them from `mode`, and nothing
30
- // outside this package consumed them directly. Their prop types stay exported
31
- // so callers can still type overrides.
32
- export { CollectionView } from "./CollectionView";
33
- export type { CollectionViewProps } from "./CollectionView";
34
-
35
- export type { CollectionViewToolbarProps } from "./CollectionViewToolbar";
36
- export type { CollectionTableViewProps } from "./CollectionTableView";
37
- export type { CollectionCardViewProps } from "./CollectionCardView";
38
- export type { CollectionListViewProps } from "./CollectionListView";
39
- export type { CollectionKanbanViewProps } from "./CollectionKanbanView";
@@ -1,52 +0,0 @@
1
- import type { CollectionPropertyConfig } from "./CollectionViewTypes";
2
-
3
- /**
4
- * Pick the property that acts as a row's title.
5
- *
6
- * Headless mirror of the ranking in `@rebasepro/common`: identifiers are kept
7
- * out of the title slot structurally (the id property, images, hidden fields),
8
- * and among what is left a plain text field beats a description, an enum or a
9
- * relation. Falls back to the id property only when a collection has nothing
10
- * else to show.
11
- */
12
- export function resolveTitlePropertyKey(
13
- order: string[],
14
- properties: Record<string, CollectionPropertyConfig>,
15
- idProperty: string,
16
- titleProperty?: string
17
- ): string {
18
- if (titleProperty) return titleProperty;
19
-
20
- const SCORE = {
21
- RELATION: 10,
22
- LONG_TEXT: 20,
23
- ENUM: 30,
24
- EMAIL: 45,
25
- PLAIN_TEXT: 60,
26
- NAMED: 100
27
- };
28
- const titleLikeKeys = new Set(["name", "fullname", "displayname", "title", "label", "heading", "subject", "username", "nickname"]);
29
-
30
- let best: { key: string; score: number } | undefined;
31
-
32
- order.forEach(key => {
33
- const property = properties[key];
34
- if (!property || property.hideFromCollection) return;
35
- if (key === idProperty) return;
36
- if (property.storage || property.url === "image") return;
37
-
38
- let score: number;
39
- if (property.type === "relation" || property.type === "reference") score = SCORE.RELATION;
40
- else if (property.type !== "string") return;
41
- else if (property.enum) score = SCORE.ENUM;
42
- else if (property.multiline || property.markdown) score = SCORE.LONG_TEXT;
43
- else if (property.email) score = SCORE.EMAIL;
44
- else if (titleLikeKeys.has(key.toLowerCase().replace(/[^a-z0-9]/g, ""))) score = SCORE.NAMED;
45
- else score = SCORE.PLAIN_TEXT;
46
-
47
- if (!best || score > best.score) best = { key,
48
- score };
49
- });
50
-
51
- return best?.key ?? idProperty;
52
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Traverse an object by dot-separated path.
3
- * Returns `undefined` if any segment is missing.
4
- */
5
- export function getValueInPath(obj: Record<string, unknown> | undefined, path: string): unknown {
6
- if (!obj) return undefined;
7
- const parts = path.split(".");
8
- let current: unknown = obj;
9
- for (const part of parts) {
10
- if (current === null || current === undefined || typeof current !== "object") return undefined;
11
- current = (current as Record<string, unknown>)[part];
12
- }
13
- return current;
14
- }