@instantdb/components 0.0.1

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 (128) hide show
  1. package/.env +2 -0
  2. package/.turbo/turbo-build.log +18 -0
  3. package/README.md +78 -0
  4. package/app/App.css +38 -0
  5. package/app/App.tsx +61 -0
  6. package/app/index.css +18 -0
  7. package/app/main.tsx +10 -0
  8. package/dist/components/StyleMe.d.ts +15 -0
  9. package/dist/components/StyleMe.d.ts.map +1 -0
  10. package/dist/components/error-boundary.d.ts +17 -0
  11. package/dist/components/error-boundary.d.ts.map +1 -0
  12. package/dist/components/explorer/edit-namespace-dialog.d.ts +14 -0
  13. package/dist/components/explorer/edit-namespace-dialog.d.ts.map +1 -0
  14. package/dist/components/explorer/edit-row-dialog.d.ts +10 -0
  15. package/dist/components/explorer/edit-row-dialog.d.ts.map +1 -0
  16. package/dist/components/explorer/expandable-deleted-attr.d.ts +15 -0
  17. package/dist/components/explorer/expandable-deleted-attr.d.ts.map +1 -0
  18. package/dist/components/explorer/explorer-layout.d.ts +8 -0
  19. package/dist/components/explorer/explorer-layout.d.ts.map +1 -0
  20. package/dist/components/explorer/index.d.ts +44 -0
  21. package/dist/components/explorer/index.d.ts.map +1 -0
  22. package/dist/components/explorer/inner-explorer.d.ts +16 -0
  23. package/dist/components/explorer/inner-explorer.d.ts.map +1 -0
  24. package/dist/components/explorer/new-namespace-dialog.d.ts +10 -0
  25. package/dist/components/explorer/new-namespace-dialog.d.ts.map +1 -0
  26. package/dist/components/explorer/query-inspector.d.ts +11 -0
  27. package/dist/components/explorer/query-inspector.d.ts.map +1 -0
  28. package/dist/components/explorer/recently-deleted.d.ts +36 -0
  29. package/dist/components/explorer/recently-deleted.d.ts.map +1 -0
  30. package/dist/components/explorer/search-input.d.ts +9 -0
  31. package/dist/components/explorer/search-input.d.ts.map +1 -0
  32. package/dist/components/explorer/table-components.d.ts +16 -0
  33. package/dist/components/explorer/table-components.d.ts.map +1 -0
  34. package/dist/components/explorer/view-settings.d.ts +10 -0
  35. package/dist/components/explorer/view-settings.d.ts.map +1 -0
  36. package/dist/components/rosePineDawnTheme.d.ts +13 -0
  37. package/dist/components/rosePineDawnTheme.d.ts.map +1 -0
  38. package/dist/components/select.d.ts +16 -0
  39. package/dist/components/select.d.ts.map +1 -0
  40. package/dist/components/toast.d.ts +4 -0
  41. package/dist/components/toast.d.ts.map +1 -0
  42. package/dist/components/ui.d.ts +336 -0
  43. package/dist/components/ui.d.ts.map +1 -0
  44. package/dist/config.d.ts +14 -0
  45. package/dist/config.d.ts.map +1 -0
  46. package/dist/hooks/explorer.d.ts +29 -0
  47. package/dist/hooks/explorer.d.ts.map +1 -0
  48. package/dist/hooks/useAttrNotes.d.ts +10 -0
  49. package/dist/hooks/useAttrNotes.d.ts.map +1 -0
  50. package/dist/hooks/useClickOutside.d.ts +3 -0
  51. package/dist/hooks/useClickOutside.d.ts.map +1 -0
  52. package/dist/hooks/useColumnVisibility.d.ts +12 -0
  53. package/dist/hooks/useColumnVisibility.d.ts.map +1 -0
  54. package/dist/hooks/useEditBlobConstraints.d.ts +32 -0
  55. package/dist/hooks/useEditBlobConstraints.d.ts.map +1 -0
  56. package/dist/hooks/useExplorerHistory.d.ts +1 -0
  57. package/dist/hooks/useExplorerHistory.d.ts.map +1 -0
  58. package/dist/hooks/useIsOverflow.d.ts +6 -0
  59. package/dist/hooks/useIsOverflow.d.ts.map +1 -0
  60. package/dist/hooks/useLocalStorage.d.ts +2 -0
  61. package/dist/hooks/useLocalStorage.d.ts.map +1 -0
  62. package/dist/hooks/useMonacoJSONSchema.d.ts +3 -0
  63. package/dist/hooks/useMonacoJSONSchema.d.ts.map +1 -0
  64. package/dist/hooks/useStableDB.d.ts +7 -0
  65. package/dist/hooks/useStableDB.d.ts.map +1 -0
  66. package/dist/index.cjs +15 -0
  67. package/dist/index.d.ts +7 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +9270 -0
  70. package/dist/schema.d.ts +5 -0
  71. package/dist/schema.d.ts.map +1 -0
  72. package/dist/style.css +1 -0
  73. package/dist/types.d.ts +241 -0
  74. package/dist/types.d.ts.map +1 -0
  75. package/dist/utils/format.d.ts +2 -0
  76. package/dist/utils/format.d.ts.map +1 -0
  77. package/dist/utils/indexingJobs.d.ts +24 -0
  78. package/dist/utils/indexingJobs.d.ts.map +1 -0
  79. package/dist/utils/parsePermsJSON.d.ts +11 -0
  80. package/dist/utils/parsePermsJSON.d.ts.map +1 -0
  81. package/dist/utils/renames.d.ts +3 -0
  82. package/dist/utils/renames.d.ts.map +1 -0
  83. package/dist/utils/tableWidthSize.d.ts +9 -0
  84. package/dist/utils/tableWidthSize.d.ts.map +1 -0
  85. package/index.html +13 -0
  86. package/package.json +109 -0
  87. package/src/components/StyleMe.tsx +97 -0
  88. package/src/components/error-boundary.tsx +76 -0
  89. package/src/components/explorer/edit-namespace-dialog.tsx +1886 -0
  90. package/src/components/explorer/edit-row-dialog.tsx +1151 -0
  91. package/src/components/explorer/expandable-deleted-attr.tsx +170 -0
  92. package/src/components/explorer/explorer-layout.tsx +156 -0
  93. package/src/components/explorer/index.tsx +217 -0
  94. package/src/components/explorer/inner-explorer.tsx +1341 -0
  95. package/src/components/explorer/new-namespace-dialog.tsx +54 -0
  96. package/src/components/explorer/query-inspector.tsx +394 -0
  97. package/src/components/explorer/recently-deleted.tsx +344 -0
  98. package/src/components/explorer/search-input.tsx +358 -0
  99. package/src/components/explorer/table-components.tsx +341 -0
  100. package/src/components/explorer/view-settings.tsx +75 -0
  101. package/src/components/rosePineDawnTheme.ts +45 -0
  102. package/src/components/select.tsx +198 -0
  103. package/src/components/toast.tsx +18 -0
  104. package/src/components/ui.tsx +1561 -0
  105. package/src/config.ts +61 -0
  106. package/src/hooks/explorer.tsx +125 -0
  107. package/src/hooks/useAttrNotes.ts +27 -0
  108. package/src/hooks/useClickOutside.ts +23 -0
  109. package/src/hooks/useColumnVisibility.ts +39 -0
  110. package/src/hooks/useEditBlobConstraints.ts +185 -0
  111. package/src/hooks/useExplorerHistory.ts +0 -0
  112. package/src/hooks/useIsOverflow.ts +24 -0
  113. package/src/hooks/useLocalStorage.ts +51 -0
  114. package/src/hooks/useMonacoJSONSchema.ts +41 -0
  115. package/src/hooks/useStableDB.ts +30 -0
  116. package/src/index.tsx +8 -0
  117. package/src/schema.ts +285 -0
  118. package/src/style.css +5 -0
  119. package/src/types.ts +359 -0
  120. package/src/utils/format.ts +13 -0
  121. package/src/utils/indexingJobs.ts +126 -0
  122. package/src/utils/parsePermsJSON.ts +35 -0
  123. package/src/utils/renames.ts +42 -0
  124. package/src/utils/tableWidthSize.ts +62 -0
  125. package/tailwind.config.cjs +42 -0
  126. package/tsconfig.json +22 -0
  127. package/vite-env.d.ts +1 -0
  128. package/vite.config.ts +49 -0
@@ -0,0 +1,341 @@
1
+ import React from 'react';
2
+ import {
3
+ cn,
4
+ Fence,
5
+ Tooltip,
6
+ TooltipContent,
7
+ TooltipTrigger,
8
+ } from '@lib/components/ui';
9
+ import {
10
+ Cell,
11
+ flexRender,
12
+ Header,
13
+ HeaderGroup,
14
+ Table,
15
+ } from '@tanstack/react-table';
16
+ import { useSortable } from '@dnd-kit/sortable';
17
+ import { CSS } from '@dnd-kit/utilities';
18
+
19
+ import clsx from 'clsx';
20
+ import { CSSProperties, useEffect, useState } from 'react';
21
+ import {
22
+ ArrowDownIcon,
23
+ ArrowsUpDownIcon,
24
+ ArrowUpIcon,
25
+ } from '@heroicons/react/24/outline';
26
+ import { useIsOverflow } from '@lib/hooks/useIsOverflow';
27
+ import { isObject } from 'lodash';
28
+ import copy from 'copy-to-clipboard';
29
+ import { useExplorerProps, useExplorerState } from '.';
30
+ import { TableColMeta } from './inner-explorer';
31
+
32
+ export const TableHeader = ({
33
+ header,
34
+ table,
35
+ headerGroup,
36
+ index,
37
+ setMinViableColWidth,
38
+ onSort,
39
+ currentSortAttr,
40
+ currentSortAsc,
41
+ }: {
42
+ header: Header<any, any>;
43
+ table: Table<any>;
44
+ headerGroup: HeaderGroup<any>;
45
+ index: number;
46
+ setMinViableColWidth: (columnId: string) => void;
47
+ onSort?: (
48
+ attrName: string,
49
+ currentAttr: string | undefined,
50
+ currentAsc?: boolean,
51
+ ) => void;
52
+ currentSortAttr?: string;
53
+ currentSortAsc?: boolean;
54
+ }) => {
55
+ const {
56
+ attributes,
57
+ setActivatorNodeRef,
58
+ isDragging,
59
+ listeners,
60
+ setNodeRef,
61
+ transform,
62
+ } = useSortable({
63
+ id: header.column.id,
64
+ disabled: header.id === 'select-col',
65
+ });
66
+
67
+ const style: CSSProperties = {
68
+ opacity: isDragging ? 0.8 : 1,
69
+ position: 'relative',
70
+ transform:
71
+ header.id === 'select-col'
72
+ ? undefined
73
+ : CSS.Translate.toString(transform), // translate instead of transform to avoid squishing
74
+ transition: 'width transform 0.2s ease-in-out',
75
+ whiteSpace: 'nowrap',
76
+ width: header.column.getSize(),
77
+ zIndex: isDragging ? 1 : 0,
78
+ };
79
+
80
+ const meta = header.column.columnDef?.meta as TableColMeta | null;
81
+
82
+ const isSortable = !!meta?.sortable;
83
+
84
+ const headerText =
85
+ typeof header.column.columnDef.header === 'string'
86
+ ? header.column.columnDef.header
87
+ : '';
88
+
89
+ // Check if this column is currently sorted
90
+ const isCurrentSort =
91
+ currentSortAttr === headerText ||
92
+ (currentSortAttr === 'serverCreatedAt' && headerText === 'id');
93
+
94
+ return (
95
+ <div
96
+ key={header.id}
97
+ ref={setNodeRef}
98
+ className={clsx(
99
+ 'group relative z-10 h-8 w-full whitespace-nowrap select-none',
100
+ )}
101
+ style={{
102
+ ...style,
103
+ width: header.getSize() !== 0 ? header.getSize() : undefined,
104
+ }}
105
+ >
106
+ {header.id !== 'select-col' && (
107
+ <button
108
+ className="absolute inset-0 z-0 hover:cursor-grab active:cursor-grabbing"
109
+ {...attributes}
110
+ {...listeners}
111
+ ref={setActivatorNodeRef}
112
+ style={{ pointerEvents: 'auto' }}
113
+ />
114
+ )}
115
+ <div className="flex h-full items-stretch justify-between overflow-hidden">
116
+ <div
117
+ className={`flex shrink items-center gap-1 truncate px-2 py-1 font-semibold th-${header.column.id}`}
118
+ >
119
+ {isSortable ? (
120
+ <button
121
+ className="relative z-50 flex items-center gap-1 py-2 pr-5"
122
+ onClick={() => {
123
+ if (onSort) {
124
+ let thisAttrName =
125
+ headerText === 'id' ? 'serverCreatedAt' : headerText;
126
+ onSort(thisAttrName, currentSortAttr, currentSortAsc);
127
+ }
128
+ }}
129
+ >
130
+ <span className={cn(isCurrentSort && 'underline')}>
131
+ {header.isPlaceholder
132
+ ? null
133
+ : flexRender(
134
+ header.column.columnDef.header,
135
+ header.getContext(),
136
+ )}
137
+ </span>
138
+ <span
139
+ className="opacity-50 transition-opacity group-hover:opacity-70"
140
+ style={{
141
+ opacity: isCurrentSort ? 1 : undefined,
142
+ fontWeight: isCurrentSort ? 'bold' : 'normal',
143
+ }}
144
+ >
145
+ {isCurrentSort ? (
146
+ currentSortAsc ? (
147
+ <ArrowUpIcon strokeWidth={3} width={10} />
148
+ ) : (
149
+ <ArrowDownIcon strokeWidth={3} width={10} />
150
+ )
151
+ ) : (
152
+ <ArrowsUpDownIcon strokeWidth={3} width={10} />
153
+ )}
154
+ </span>
155
+ </button>
156
+ ) : (
157
+ <>
158
+ {header.isPlaceholder
159
+ ? null
160
+ : flexRender(
161
+ header.column.columnDef.header,
162
+ header.getContext(),
163
+ )}
164
+ </>
165
+ )}
166
+ </div>
167
+
168
+ <div className="flex h-full items-center justify-between">
169
+ <div
170
+ {...{
171
+ onDoubleClick: () => setMinViableColWidth(header.column.id),
172
+ onMouseDown: (e) => {
173
+ e.stopPropagation();
174
+ return header.getResizeHandler()(e);
175
+ },
176
+ onTouchStart: header.getResizeHandler(),
177
+ className: cn(
178
+ `resizer h-full flex justify-center z-50 ${
179
+ table.options.columnResizeDirection
180
+ } ${header.column.getIsResizing() ? 'isResizing' : ''}`,
181
+ headerGroup.headers.length - 1 == index && 'justify-end',
182
+ header.id !== 'select-col' && 'hover:cursor-col-resize',
183
+ ),
184
+ style: {
185
+ width: 8,
186
+ pointerEvents: 'auto',
187
+ },
188
+ }}
189
+ >
190
+ {headerGroup.headers.length - 1 !== index && (
191
+ <div className="h-full w-0.5 bg-neutral-200 dark:bg-neutral-700"></div>
192
+ )}
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ );
198
+ };
199
+
200
+ export const TableCell = ({ cell }: { cell: Cell<any, unknown> }) => {
201
+ const resizing = cell.column.getIsResizing();
202
+
203
+ const { history } = useExplorerState();
204
+
205
+ const meta = cell.column.columnDef.meta as TableColMeta | null;
206
+ const { isDragging, setNodeRef, transform } = useSortable({
207
+ id: cell.column.id,
208
+ disabled: cell.column.id === 'select-col',
209
+ });
210
+ const [showCopy, setShowCopy] = useState(false);
211
+ const { ref: overflowRef, isOverflow, setIsOverflow } = useIsOverflow();
212
+ const shouldShowTooltip =
213
+ (isOverflow || isObject(cell.getValue())) && !meta?.isLink;
214
+
215
+ useEffect(() => {
216
+ const observer = new ResizeObserver(() => {
217
+ const hasOverflow =
218
+ overflowRef.current.scrollWidth > overflowRef.current.clientWidth ||
219
+ overflowRef.current.scrollHeight > overflowRef.current.clientHeight;
220
+
221
+ setIsOverflow(hasOverflow);
222
+ });
223
+ observer.observe(overflowRef.current!);
224
+
225
+ return () => {
226
+ observer.disconnect();
227
+ };
228
+ }, [overflowRef.current]);
229
+
230
+ const style: CSSProperties = {
231
+ opacity: isDragging ? 0.8 : 1,
232
+ position: 'relative',
233
+ transform:
234
+ cell.column.id === 'select-col'
235
+ ? undefined
236
+ : CSS.Translate.toString(transform), // translate instead of transform to avoid squishing
237
+ transition: 'width transform 0.2s ease-in-out',
238
+ width: cell.column.getSize(),
239
+ zIndex: isDragging ? 1 : 0,
240
+ };
241
+
242
+ const disablePadding = meta?.disablePadding ?? false;
243
+
244
+ const realValue = cell.getValue();
245
+
246
+ return (
247
+ <Tooltip>
248
+ {' '}
249
+ <TooltipTrigger className="text-left">
250
+ <div
251
+ ref={(el) => {
252
+ setNodeRef(el);
253
+ overflowRef.current = el;
254
+ }}
255
+ style={{
256
+ ...style,
257
+ padding: disablePadding ? 0 : '0.5rem',
258
+ }}
259
+ className={cn(`cursor-default truncate whitespace-nowrap`)}
260
+ key={cell.id}
261
+ >
262
+ <span
263
+ className={cn(
264
+ `h-full min-h-full cursor-pointer td-${cell.column.id}`,
265
+ disablePadding ? '' : 'pr-2',
266
+ )}
267
+ onClick={() => {
268
+ if (
269
+ meta?.isLink &&
270
+ meta.attr &&
271
+ Array.isArray(realValue) &&
272
+ realValue.length > 0
273
+ ) {
274
+ const attr = meta.attr;
275
+ const linkConfigDir =
276
+ attr.linkConfig[!attr.isForward ? 'forward' : 'reverse'];
277
+
278
+ if (linkConfigDir) {
279
+ history.push({
280
+ namespace: linkConfigDir.namespace,
281
+ where: [`${linkConfigDir.attr}.id`, cell.row.original.id],
282
+ });
283
+ return;
284
+ }
285
+ }
286
+ if (meta?.copyable) {
287
+ if (copy(formatVal(realValue))) {
288
+ setShowCopy(true);
289
+ setTimeout(() => setShowCopy(false), 1000);
290
+ }
291
+ }
292
+ }}
293
+ >
294
+ {showCopy ? (
295
+ <div className="h-1">Copied!</div>
296
+ ) : (
297
+ flexRender(cell.column.columnDef.cell, cell.getContext())
298
+ )}
299
+ </span>
300
+ </div>
301
+ </TooltipTrigger>
302
+ {shouldShowTooltip && !resizing && (
303
+ <TooltipContent
304
+ className={cn(isObject(realValue) && 'p-0')}
305
+ side="bottom"
306
+ >
307
+ {typeof realValue === 'string' ? (
308
+ flexRender(cell.column.columnDef.cell, cell.getContext())
309
+ ) : (
310
+ <Val pretty data={realValue} />
311
+ )}
312
+ </TooltipContent>
313
+ )}
314
+ </Tooltip>
315
+ );
316
+ };
317
+
318
+ function formatVal(data: any, pretty?: boolean): string {
319
+ if (isObject(data)) {
320
+ return JSON.stringify(data, null, pretty ? 2 : undefined);
321
+ }
322
+
323
+ return String(data);
324
+ }
325
+
326
+ function Val({ data, pretty }: { data: any; pretty?: boolean }) {
327
+ const sanitized = formatVal(data, pretty);
328
+ const explorerProps = useExplorerProps();
329
+
330
+ if (pretty && isObject(data)) {
331
+ return (
332
+ <Fence
333
+ darkMode={explorerProps.darkMode}
334
+ code={sanitized}
335
+ language="json"
336
+ />
337
+ );
338
+ }
339
+
340
+ return <>{sanitized}</>;
341
+ }
@@ -0,0 +1,75 @@
1
+ import React from 'react';
2
+ import { Switch } from '@lib/components/ui';
3
+ import { Checkbox, Dialog, Divider, IconButton } from '@lib/components/ui';
4
+ import { useColumnVisibility } from '@lib/hooks/useColumnVisibility';
5
+ import { Cog6ToothIcon, XMarkIcon } from '@heroicons/react/24/outline';
6
+ import { useState } from 'react';
7
+
8
+ interface ViewSettingsProps {
9
+ visiblity: ReturnType<typeof useColumnVisibility>;
10
+ localDates: boolean;
11
+ setLocalDates: (v: boolean | undefined) => void;
12
+ }
13
+
14
+ export const ViewSettings = ({
15
+ visiblity,
16
+ localDates,
17
+ setLocalDates,
18
+ }: ViewSettingsProps) => {
19
+ const [dialogOpen, setDialogOpen] = useState(false);
20
+ return (
21
+ <>
22
+ <IconButton
23
+ icon={<Cog6ToothIcon width={16} />}
24
+ label="View Settings"
25
+ onClick={() => setDialogOpen(true)}
26
+ />
27
+ <Dialog
28
+ hideCloseButton={true}
29
+ onClose={() => setDialogOpen(false)}
30
+ open={dialogOpen}
31
+ >
32
+ <div className="flex items-center justify-between">
33
+ <div className="text-lg">Explorer View Settings</div>
34
+ <button onClick={() => setDialogOpen(false)}>
35
+ <XMarkIcon className="h-4 w-4 cursor-pointer" />
36
+ </button>
37
+ </div>
38
+
39
+ <div className="py-2">
40
+ <div>Visible Columns</div>
41
+ <div className="py-1">
42
+ {visiblity.attrs?.map((attr) => (
43
+ <div key={attr.id + attr.name} className="flex gap-2">
44
+ <Checkbox
45
+ label={attr.name}
46
+ checked={visiblity.visibility[attr.id + attr.name] !== false}
47
+ onChange={(checked) =>
48
+ visiblity.setVisibility((prev) => ({
49
+ ...prev,
50
+ [attr.id + attr.name]: checked,
51
+ }))
52
+ }
53
+ ></Checkbox>
54
+ </div>
55
+ ))}
56
+ </div>
57
+ </div>
58
+ <Divider className="py-2" />
59
+
60
+ <div className="flex items-center gap-2">
61
+ <div>Show Dates in Local Time</div>
62
+ <Switch
63
+ onClick={(e) => {
64
+ setLocalDates(!localDates);
65
+ }}
66
+ checked={localDates}
67
+ ></Switch>
68
+ </div>
69
+ <div className="text-xs opacity-40">
70
+ Copy to clipboard will still use the original value.
71
+ </div>
72
+ </Dialog>
73
+ </>
74
+ );
75
+ };
@@ -0,0 +1,45 @@
1
+ // Rosé Pine Dawn theme (matching prism.css)
2
+ export const rosePineDawnTheme = {
3
+ plain: {
4
+ backgroundColor: '#fff',
5
+ color: '#575279',
6
+ },
7
+ styles: [
8
+ {
9
+ types: ['comment', 'prolog', 'cdata', 'punctuation'],
10
+ style: { color: '#797593' },
11
+ },
12
+ {
13
+ types: ['delimiter', 'important', 'atrule', 'operator', 'keyword'],
14
+ style: { color: '#286983' },
15
+ },
16
+ {
17
+ types: [
18
+ 'tag',
19
+ 'doctype',
20
+ 'variable',
21
+ 'regex',
22
+ 'class-name',
23
+ 'selector',
24
+ 'inserted',
25
+ ],
26
+ style: { color: '#56949f' },
27
+ },
28
+ {
29
+ types: ['boolean', 'entity', 'number', 'symbol', 'function'],
30
+ style: { color: '#d7827e' },
31
+ },
32
+ {
33
+ types: ['string', 'char', 'property', 'attr-value'],
34
+ style: { color: '#ea9d34' },
35
+ },
36
+ {
37
+ types: ['parameter', 'url', 'attr-name', 'builtin'],
38
+ style: { color: '#907aa9' },
39
+ },
40
+ {
41
+ types: ['deleted'],
42
+ style: { color: '#b4637a' },
43
+ },
44
+ ],
45
+ };
@@ -0,0 +1,198 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import * as SelectPrimitive from '@radix-ui/react-select';
5
+ import { cn } from './ui';
6
+ import {
7
+ CheckIcon,
8
+ ChevronDownIcon,
9
+ ChevronUpIcon,
10
+ } from '@heroicons/react/24/outline';
11
+ import { useShadowRoot, useShadowDarkMode } from './StyleMe';
12
+
13
+ function Select({
14
+ ...props
15
+ }: React.ComponentProps<typeof SelectPrimitive.Root>) {
16
+ return <SelectPrimitive.Root data-slot="select" {...props} />;
17
+ }
18
+
19
+ function SelectGroup({
20
+ ...props
21
+ }: React.ComponentProps<typeof SelectPrimitive.Group>) {
22
+ return <SelectPrimitive.Group data-slot="select-group" {...props} />;
23
+ }
24
+
25
+ function SelectValue({
26
+ ...props
27
+ }: React.ComponentProps<typeof SelectPrimitive.Value>) {
28
+ return (
29
+ <SelectPrimitive.Value
30
+ className="content-[hi]"
31
+ data-slot="select-value"
32
+ {...props}
33
+ />
34
+ );
35
+ }
36
+
37
+ function SelectTrigger({
38
+ className,
39
+ size = 'default',
40
+ children,
41
+ ...props
42
+ }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
43
+ size?: 'sm' | 'default';
44
+ }) {
45
+ return (
46
+ <SelectPrimitive.Trigger
47
+ data-slot="select-trigger"
48
+ data-size={size}
49
+ className={cn(
50
+ "data-placeholder:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex w-fit items-center justify-between gap-2 rounded-sm border border-gray-300/80 bg-white px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:border-neutral-700 dark:bg-neutral-800 dark:hover:bg-neutral-700/50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
51
+ className,
52
+ )}
53
+ {...props}
54
+ >
55
+ {children}
56
+ <SelectPrimitive.Icon asChild>
57
+ <ChevronDownIcon width={14} />
58
+ </SelectPrimitive.Icon>
59
+ </SelectPrimitive.Trigger>
60
+ );
61
+ }
62
+
63
+ function SelectContent({
64
+ className,
65
+ children,
66
+ position = 'popper',
67
+ ...props
68
+ }: React.ComponentProps<typeof SelectPrimitive.Content>) {
69
+ const shadowRoot = useShadowRoot();
70
+ const darkMode = useShadowDarkMode();
71
+ return (
72
+ <SelectPrimitive.Portal container={shadowRoot}>
73
+ <SelectPrimitive.Content
74
+ data-slot="select-content"
75
+ className={cn(
76
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-32 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-sm border bg-gray-100 text-gray-900 shadow-md dark:border-neutral-700 dark:bg-neutral-800 dark:text-white',
77
+ position === 'popper' &&
78
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
79
+ darkMode ? 'dark' : '',
80
+ className,
81
+ )}
82
+ position={position}
83
+ {...props}
84
+ >
85
+ <SelectScrollUpButton />
86
+ <SelectPrimitive.Viewport
87
+ className={cn(
88
+ 'p-1',
89
+ position === 'popper' &&
90
+ 'h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width) scroll-my-1',
91
+ )}
92
+ >
93
+ {children}
94
+ </SelectPrimitive.Viewport>
95
+ <SelectScrollDownButton />
96
+ </SelectPrimitive.Content>
97
+ </SelectPrimitive.Portal>
98
+ );
99
+ }
100
+
101
+ function SelectLabel({
102
+ className,
103
+ ...props
104
+ }: React.ComponentProps<typeof SelectPrimitive.Label>) {
105
+ return (
106
+ <SelectPrimitive.Label
107
+ data-slot="select-label"
108
+ className={cn('text-muted-foreground px-2 py-1.5 text-xs', className)}
109
+ {...props}
110
+ />
111
+ );
112
+ }
113
+
114
+ function SelectItem({
115
+ className,
116
+ children,
117
+ ...props
118
+ }: React.ComponentProps<typeof SelectPrimitive.Item>) {
119
+ return (
120
+ <SelectPrimitive.Item
121
+ data-slot="select-item"
122
+ className={cn(
123
+ "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none hover:bg-gray-200/50 data-disabled:pointer-events-none data-disabled:opacity-50 dark:text-white dark:hover:bg-neutral-700 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
124
+ className,
125
+ )}
126
+ {...props}
127
+ >
128
+ <span className="absolute right-2 flex size-3.5 items-center justify-center">
129
+ <SelectPrimitive.ItemIndicator>
130
+ <CheckIcon width={12} className="size-4" />
131
+ </SelectPrimitive.ItemIndicator>
132
+ </span>
133
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
134
+ </SelectPrimitive.Item>
135
+ );
136
+ }
137
+
138
+ function SelectSeparator({
139
+ className,
140
+ ...props
141
+ }: React.ComponentProps<typeof SelectPrimitive.Separator>) {
142
+ return (
143
+ <SelectPrimitive.Separator
144
+ data-slot="select-separator"
145
+ className={cn('bg-border pointer-events-none -mx-1 my-1 h-px', className)}
146
+ {...props}
147
+ />
148
+ );
149
+ }
150
+
151
+ function SelectScrollUpButton({
152
+ className,
153
+ ...props
154
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
155
+ return (
156
+ <SelectPrimitive.ScrollUpButton
157
+ data-slot="select-scroll-up-button"
158
+ className={cn(
159
+ 'flex cursor-default items-center justify-center py-1',
160
+ className,
161
+ )}
162
+ {...props}
163
+ >
164
+ <ChevronUpIcon className="size-4" />
165
+ </SelectPrimitive.ScrollUpButton>
166
+ );
167
+ }
168
+
169
+ function SelectScrollDownButton({
170
+ className,
171
+ ...props
172
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
173
+ return (
174
+ <SelectPrimitive.ScrollDownButton
175
+ data-slot="select-scroll-down-button"
176
+ className={cn(
177
+ 'flex cursor-default items-center justify-center py-1',
178
+ className,
179
+ )}
180
+ {...props}
181
+ >
182
+ <ChevronDownIcon className="size-4" />
183
+ </SelectPrimitive.ScrollDownButton>
184
+ );
185
+ }
186
+
187
+ export {
188
+ Select,
189
+ SelectContent,
190
+ SelectGroup,
191
+ SelectItem,
192
+ SelectLabel,
193
+ SelectScrollDownButton,
194
+ SelectScrollUpButton,
195
+ SelectSeparator,
196
+ SelectTrigger,
197
+ SelectValue,
198
+ };
@@ -0,0 +1,18 @@
1
+ import { toast } from './ui';
2
+
3
+ export function infoToast(text: string) {
4
+ toast(text);
5
+ }
6
+
7
+ export function successToast(text: string) {
8
+ toast.success(text, {
9
+ richColors: true,
10
+ });
11
+ }
12
+
13
+ export function errorToast(text: string, options?: any) {
14
+ toast.error(text, {
15
+ duration: options?.autoClose,
16
+ richColors: true,
17
+ });
18
+ }