@rovula/ui 0.1.27 → 0.1.29
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.
- package/dist/cjs/bundle.css +513 -67
- package/dist/cjs/bundle.js +589 -589
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/Avatar/Avatar.d.ts +1 -1
- package/dist/cjs/types/components/Avatar/Avatar.stories.d.ts +1 -1
- package/dist/cjs/types/components/Avatar/Avatar.styles.d.ts +1 -0
- package/dist/cjs/types/components/DataTable/DataTable.d.ts +195 -4
- package/dist/cjs/types/components/DataTable/DataTable.editing.d.ts +20 -0
- package/dist/cjs/types/components/DataTable/DataTable.editing.types.d.ts +145 -0
- package/dist/cjs/types/components/DataTable/DataTable.stories.d.ts +268 -6
- package/dist/cjs/types/components/Dropdown/Dropdown.d.ts +22 -0
- package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +4 -0
- package/dist/cjs/types/components/ScrollArea/ScrollArea.d.ts +3 -3
- package/dist/cjs/types/components/ScrollArea/ScrollArea.stories.d.ts +4 -0
- package/dist/cjs/types/components/Table/Table.d.ts +33 -3
- package/dist/cjs/types/components/Table/Table.stories.d.ts +86 -4
- package/dist/cjs/types/components/TextInput/TextInput.stories.d.ts +8 -0
- package/dist/cjs/types/components/TextInput/TextInput.styles.d.ts +1 -0
- package/dist/components/Avatar/Avatar.js +2 -1
- package/dist/components/Avatar/Avatar.styles.js +3 -0
- package/dist/components/Avatar/AvatarBase.js +1 -1
- package/dist/components/DataTable/DataTable.editing.js +385 -0
- package/dist/components/DataTable/DataTable.editing.types.js +1 -0
- package/dist/components/DataTable/DataTable.js +983 -50
- package/dist/components/DataTable/DataTable.stories.js +1077 -25
- package/dist/components/Dropdown/Dropdown.js +8 -6
- package/dist/components/ScrollArea/ScrollArea.js +2 -2
- package/dist/components/ScrollArea/ScrollArea.stories.js +68 -2
- package/dist/components/Table/Table.js +103 -13
- package/dist/components/Table/Table.stories.js +226 -9
- package/dist/components/TextInput/TextInput.js +6 -4
- package/dist/components/TextInput/TextInput.stories.js +8 -0
- package/dist/components/TextInput/TextInput.styles.js +7 -1
- package/dist/esm/bundle.css +513 -67
- package/dist/esm/bundle.js +1545 -1545
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/Avatar/Avatar.d.ts +1 -1
- package/dist/esm/types/components/Avatar/Avatar.stories.d.ts +1 -1
- package/dist/esm/types/components/Avatar/Avatar.styles.d.ts +1 -0
- package/dist/esm/types/components/DataTable/DataTable.d.ts +195 -4
- package/dist/esm/types/components/DataTable/DataTable.editing.d.ts +20 -0
- package/dist/esm/types/components/DataTable/DataTable.editing.types.d.ts +145 -0
- package/dist/esm/types/components/DataTable/DataTable.stories.d.ts +268 -6
- package/dist/esm/types/components/Dropdown/Dropdown.d.ts +22 -0
- package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +4 -0
- package/dist/esm/types/components/ScrollArea/ScrollArea.d.ts +3 -3
- package/dist/esm/types/components/ScrollArea/ScrollArea.stories.d.ts +4 -0
- package/dist/esm/types/components/Table/Table.d.ts +33 -3
- package/dist/esm/types/components/Table/Table.stories.d.ts +86 -4
- package/dist/esm/types/components/TextInput/TextInput.stories.d.ts +8 -0
- package/dist/esm/types/components/TextInput/TextInput.styles.d.ts +1 -0
- package/dist/index.d.ts +493 -122
- package/dist/src/theme/global.css +762 -96
- package/package.json +14 -2
- package/src/components/Avatar/Avatar.styles.ts +4 -1
- package/src/components/Avatar/Avatar.tsx +3 -2
- package/src/components/Avatar/AvatarBase.tsx +3 -3
- package/src/components/DataTable/DataTable.editing.tsx +861 -0
- package/src/components/DataTable/DataTable.editing.types.ts +192 -0
- package/src/components/DataTable/DataTable.stories.tsx +2169 -31
- package/src/components/DataTable/DataTable.test.tsx +696 -0
- package/src/components/DataTable/DataTable.tsx +2260 -94
- package/src/components/Dropdown/Dropdown.tsx +22 -6
- package/src/components/ScrollArea/ScrollArea.stories.tsx +146 -3
- package/src/components/ScrollArea/ScrollArea.tsx +6 -6
- package/src/components/Table/Table.stories.tsx +789 -44
- package/src/components/Table/Table.tsx +294 -28
- package/src/components/TextInput/TextInput.stories.tsx +80 -0
- package/src/components/TextInput/TextInput.styles.ts +7 -1
- package/src/components/TextInput/TextInput.tsx +21 -14
- package/src/test/setup.ts +50 -0
- package/src/theme/global.css +81 -42
- package/src/theme/presets/colors.js +12 -0
- package/src/theme/themes/variable.css +27 -28
- package/src/theme/tokens/baseline.css +2 -1
- package/src/theme/tokens/components/scrollbar.css +9 -4
- package/src/theme/tokens/components/table.css +63 -0
|
@@ -79,6 +79,17 @@ export type DropdownProps = {
|
|
|
79
79
|
selectedOption: Options | null | undefined;
|
|
80
80
|
onClick: (option: Options) => void;
|
|
81
81
|
}) => ReactNode;
|
|
82
|
+
/**
|
|
83
|
+
* When `true`, keep focus on the input after selecting an option so the
|
|
84
|
+
* menu stays open (useful for inline row-editing where the user may Tab
|
|
85
|
+
* to the next field instead of closing the dropdown).
|
|
86
|
+
*/
|
|
87
|
+
keepOpenAfterSelect?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Render the options list via a React portal so it escapes containers
|
|
90
|
+
* with `overflow: hidden/auto` (e.g. DataTable scroll wrappers).
|
|
91
|
+
*/
|
|
92
|
+
portal?: boolean;
|
|
82
93
|
} & Omit<InputProps, "value" | "onSelect">;
|
|
83
94
|
|
|
84
95
|
// ---------------------------------------------------------------------------
|
|
@@ -110,6 +121,8 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
|
|
|
110
121
|
optionItemClassName,
|
|
111
122
|
optionNotFoundItemClassName,
|
|
112
123
|
segmentedInput = true,
|
|
124
|
+
keepOpenAfterSelect = false,
|
|
125
|
+
portal = false,
|
|
113
126
|
...props
|
|
114
127
|
},
|
|
115
128
|
ref,
|
|
@@ -142,12 +155,12 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
|
|
|
142
155
|
setQuery("");
|
|
143
156
|
if (option) {
|
|
144
157
|
onSelect?.(option);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
158
|
+
if (!keepOpenAfterSelect) {
|
|
159
|
+
setTimeout(() => inputRef.current?.blur(), 0);
|
|
160
|
+
}
|
|
148
161
|
}
|
|
149
162
|
},
|
|
150
|
-
[onSelect],
|
|
163
|
+
[onSelect, keepOpenAfterSelect],
|
|
151
164
|
);
|
|
152
165
|
|
|
153
166
|
const handleInputChange = useCallback(
|
|
@@ -259,7 +272,6 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
|
|
|
259
272
|
/>
|
|
260
273
|
}
|
|
261
274
|
label={label}
|
|
262
|
-
placeholder=" "
|
|
263
275
|
autoComplete="off"
|
|
264
276
|
rounded={rounded}
|
|
265
277
|
variant={variant}
|
|
@@ -288,8 +300,12 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
|
|
|
288
300
|
* z-[51] beats the Dialog overlay (z-50) for items that visually overflow.
|
|
289
301
|
*/}
|
|
290
302
|
<ComboboxOptions
|
|
303
|
+
{...(portal
|
|
304
|
+
? { portal: true, anchor: { to: "bottom start" as const, gap: 4 } }
|
|
305
|
+
: {})}
|
|
291
306
|
className={cn(
|
|
292
|
-
"absolute top-full left-0 w-full -mt-3 z-[51]",
|
|
307
|
+
!portal && "absolute top-full left-0 w-full -mt-3 z-[51]",
|
|
308
|
+
portal && "z-[51] !max-h-60 w-[var(--input-width)]",
|
|
293
309
|
"min-w-[154px] max-h-60 overflow-y-auto",
|
|
294
310
|
"rounded-md bg-modal-dropdown-surface border border-bg-stroke3 text-text-g-contrast-high",
|
|
295
311
|
optionContainerClassName,
|
|
@@ -10,7 +10,7 @@ const meta = {
|
|
|
10
10
|
},
|
|
11
11
|
decorators: [
|
|
12
12
|
(Story) => (
|
|
13
|
-
<div className="p-10 flex gap-8 flex-wrap bg-
|
|
13
|
+
<div className="p-10 flex gap-8 flex-wrap bg-page-bg-main min-h-screen">
|
|
14
14
|
<Story />
|
|
15
15
|
</div>
|
|
16
16
|
),
|
|
@@ -19,7 +19,10 @@ const meta = {
|
|
|
19
19
|
|
|
20
20
|
export default meta;
|
|
21
21
|
|
|
22
|
-
const ITEMS = Array.from(
|
|
22
|
+
const ITEMS = Array.from(
|
|
23
|
+
{ length: 12 },
|
|
24
|
+
(_, i) => `Option Description ${i + 1}`,
|
|
25
|
+
);
|
|
23
26
|
|
|
24
27
|
// ---------------------------------------------------------------------------
|
|
25
28
|
// Size variants (Figma: Size=M / S / XS)
|
|
@@ -32,6 +35,7 @@ export const Sizes = {
|
|
|
32
35
|
<div key={size}>
|
|
33
36
|
<p className="typography-small4 text-text-g-contrast-medium mb-2 uppercase">
|
|
34
37
|
Size {size}
|
|
38
|
+
{size === "m" ? " (default)" : ""}
|
|
35
39
|
</p>
|
|
36
40
|
<ScrollArea
|
|
37
41
|
scrollbarSize={size}
|
|
@@ -61,7 +65,9 @@ export const VerticalScroll = {
|
|
|
61
65
|
<div>
|
|
62
66
|
<p className="typography-small4 text-text-g-contrast-medium mb-2">
|
|
63
67
|
Single scrollable list — use{" "}
|
|
64
|
-
<code className="text-xs"
|
|
68
|
+
<code className="text-xs">
|
|
69
|
+
<ScrollArea className="max-h-[...]">
|
|
70
|
+
</code>
|
|
65
71
|
</p>
|
|
66
72
|
<ScrollArea className="max-h-[270px] w-[230px] rounded-lg bg-modal-surface">
|
|
67
73
|
{ITEMS.map((label) => (
|
|
@@ -227,3 +233,140 @@ export const WithDropdownMenu = {
|
|
|
227
233
|
);
|
|
228
234
|
},
|
|
229
235
|
} satisfies StoryObj;
|
|
236
|
+
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
// Both axes — vertical + horizontal scroll simultaneously
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
|
|
241
|
+
const WIDE_COLS = [
|
|
242
|
+
"ID",
|
|
243
|
+
"Name",
|
|
244
|
+
"Category",
|
|
245
|
+
"Type",
|
|
246
|
+
"Format",
|
|
247
|
+
"Source",
|
|
248
|
+
"Default",
|
|
249
|
+
"Required",
|
|
250
|
+
"Nullable",
|
|
251
|
+
"Description",
|
|
252
|
+
];
|
|
253
|
+
const WIDE_ROWS = Array.from({ length: 30 }, (_, i) => ({
|
|
254
|
+
id: `ROW-${String(i + 1).padStart(3, "0")}`,
|
|
255
|
+
name: `item_name_${i + 1}`,
|
|
256
|
+
category: ["Alpha", "Beta", "Gamma", "Delta", "Epsilon"][i % 5],
|
|
257
|
+
type: ["String", "Number", "Boolean", "Date", "Enum"][i % 5],
|
|
258
|
+
format: ["Text", "Integer", "true/false", "ISO 8601", "1–5"][i % 5],
|
|
259
|
+
source: ["System", "Manual", "Device", "Auth", "Import"][i % 5],
|
|
260
|
+
defaultVal: ["-", "auto", "true", "now()", "0"][i % 5],
|
|
261
|
+
required: i % 3 === 0 ? "Yes" : "No",
|
|
262
|
+
nullable: i % 2 === 0 ? "Yes" : "No",
|
|
263
|
+
description: `Description text for row ${i + 1}`,
|
|
264
|
+
}));
|
|
265
|
+
|
|
266
|
+
const WideContent = () => (
|
|
267
|
+
<div className="min-w-[800px]">
|
|
268
|
+
<div className="flex sticky top-0 z-10 bg-modal-surface border-b border-[var(--dropdown-menu-seperator-bg)]">
|
|
269
|
+
{WIDE_COLS.map((col) => (
|
|
270
|
+
<div
|
|
271
|
+
key={col}
|
|
272
|
+
className="shrink-0 w-[120px] px-3 py-2 typography-small2 text-text-g-contrast-medium whitespace-nowrap"
|
|
273
|
+
>
|
|
274
|
+
{col}
|
|
275
|
+
</div>
|
|
276
|
+
))}
|
|
277
|
+
</div>
|
|
278
|
+
{WIDE_ROWS.map((row) => (
|
|
279
|
+
<div
|
|
280
|
+
key={row.id}
|
|
281
|
+
className="flex border-b border-[var(--dropdown-menu-seperator-bg)] hover:bg-[var(--transparent-grey2-8,rgba(145,158,171,0.08))] transition-colors"
|
|
282
|
+
>
|
|
283
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap font-medium">
|
|
284
|
+
{row.id}
|
|
285
|
+
</div>
|
|
286
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
287
|
+
{row.name}
|
|
288
|
+
</div>
|
|
289
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
290
|
+
{row.category}
|
|
291
|
+
</div>
|
|
292
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
293
|
+
{row.type}
|
|
294
|
+
</div>
|
|
295
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
296
|
+
{row.format}
|
|
297
|
+
</div>
|
|
298
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
299
|
+
{row.source}
|
|
300
|
+
</div>
|
|
301
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
302
|
+
{row.defaultVal}
|
|
303
|
+
</div>
|
|
304
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
305
|
+
{row.required}
|
|
306
|
+
</div>
|
|
307
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
308
|
+
{row.nullable}
|
|
309
|
+
</div>
|
|
310
|
+
<div className="shrink-0 w-[120px] px-3 py-2 typography-subtitle4 text-text-g-contrast-high whitespace-nowrap">
|
|
311
|
+
{row.description}
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
))}
|
|
315
|
+
</div>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
export const BothAxes = {
|
|
319
|
+
name: "Both Axes",
|
|
320
|
+
render: () => {
|
|
321
|
+
const cases: { label: string; xSize: string; ySize: string }[] = [
|
|
322
|
+
{
|
|
323
|
+
label: "X = M (16px) + Y = M (16px) — same",
|
|
324
|
+
xSize: "ui-scrollbar-x-m",
|
|
325
|
+
ySize: "ui-scrollbar-y-m",
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
label: "X = S (10px) + Y = S (10px) — same",
|
|
329
|
+
xSize: "ui-scrollbar-x-s",
|
|
330
|
+
ySize: "ui-scrollbar-y-s",
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
label: "X = XS (4px) + Y = XS (4px) — same",
|
|
334
|
+
xSize: "ui-scrollbar-x-xs",
|
|
335
|
+
ySize: "ui-scrollbar-y-xs",
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
label: "X = M (16px) + Y = S (10px) — mixed",
|
|
339
|
+
xSize: "ui-scrollbar-x-m",
|
|
340
|
+
ySize: "ui-scrollbar-y-s",
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
label: "X = S (10px) + Y = M (16px) — mixed",
|
|
344
|
+
xSize: "ui-scrollbar-x-s",
|
|
345
|
+
ySize: "ui-scrollbar-y-m",
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
label: "X = M (16px) + Y = XS (4px) — mixed",
|
|
349
|
+
xSize: "ui-scrollbar-x-m",
|
|
350
|
+
ySize: "ui-scrollbar-y-xs",
|
|
351
|
+
},
|
|
352
|
+
];
|
|
353
|
+
|
|
354
|
+
return (
|
|
355
|
+
<div className="flex flex-col gap-8 w-full">
|
|
356
|
+
{cases.map(({ label, xSize, ySize }) => (
|
|
357
|
+
<div key={label} className="flex flex-col gap-2">
|
|
358
|
+
<p className="typography-subtitle4 text-text-g-contrast-high">
|
|
359
|
+
{label}
|
|
360
|
+
</p>
|
|
361
|
+
<ScrollArea
|
|
362
|
+
direction="both"
|
|
363
|
+
className={`h-[220px] w-[480px] rounded-lg bg-modal-surface ${xSize} ${ySize}`}
|
|
364
|
+
>
|
|
365
|
+
<WideContent />
|
|
366
|
+
</ScrollArea>
|
|
367
|
+
</div>
|
|
368
|
+
))}
|
|
369
|
+
</div>
|
|
370
|
+
);
|
|
371
|
+
},
|
|
372
|
+
} satisfies StoryObj;
|
|
@@ -6,9 +6,9 @@ export type ScrollbarSize = "m" | "s" | "xs";
|
|
|
6
6
|
export interface ScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
7
7
|
/**
|
|
8
8
|
* Scrollbar thickness.
|
|
9
|
-
* - `m` — 12 px (shows track border)
|
|
10
|
-
* - `s` — 6 px (
|
|
11
|
-
* - `xs` — 2 px (
|
|
9
|
+
* - `m` — 12 px (default, shows track border + 2px thumb inset)
|
|
10
|
+
* - `s` — 6 px (shows track border + 2px thumb inset)
|
|
11
|
+
* - `xs` — 2 px (no track border, no thumb inset)
|
|
12
12
|
*/
|
|
13
13
|
scrollbarSize?: ScrollbarSize;
|
|
14
14
|
/**
|
|
@@ -19,8 +19,8 @@ export interface ScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const sizeClass: Record<ScrollbarSize, string> = {
|
|
22
|
-
m:
|
|
23
|
-
s:
|
|
22
|
+
m: "ui-scrollbar", // default = M, no extra class needed
|
|
23
|
+
s: "ui-scrollbar ui-scrollbar-s",
|
|
24
24
|
xs: "ui-scrollbar ui-scrollbar-xs",
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -53,7 +53,7 @@ const directionClass: Record<NonNullable<ScrollAreaProps["direction"]>, string>
|
|
|
53
53
|
*/
|
|
54
54
|
export const ScrollArea = React.forwardRef<HTMLDivElement, ScrollAreaProps>(
|
|
55
55
|
(
|
|
56
|
-
{ className, scrollbarSize = "
|
|
56
|
+
{ className, scrollbarSize = "m", direction = "vertical", children, ...props },
|
|
57
57
|
ref
|
|
58
58
|
) => (
|
|
59
59
|
<div
|