@health-samurai/react-components 0.0.0-alpha.5 → 0.0.0-alpha.7
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/bundle.css +318 -31
- package/dist/src/components/button-dropdown.d.ts +10 -0
- package/dist/src/components/button-dropdown.d.ts.map +1 -0
- package/dist/src/components/button-dropdown.js +70 -0
- package/dist/src/components/button-dropdown.js.map +1 -0
- package/dist/src/components/button-dropdown.stories.d.ts +11 -0
- package/dist/src/components/button-dropdown.stories.d.ts.map +1 -0
- package/dist/src/components/button-dropdown.stories.js +48 -0
- package/dist/src/components/button-dropdown.stories.js.map +1 -0
- package/dist/src/components/code-editor/index.d.ts +3 -2
- package/dist/src/components/code-editor/index.d.ts.map +1 -1
- package/dist/src/components/code-editor/index.js +152 -4
- package/dist/src/components/code-editor/index.js.map +1 -1
- package/dist/src/components/code-editor.stories.d.ts +1 -0
- package/dist/src/components/code-editor.stories.d.ts.map +1 -1
- package/dist/src/components/code-editor.stories.js +252 -1
- package/dist/src/components/code-editor.stories.js.map +1 -1
- package/dist/src/components/copy-icon.d.ts +5 -1
- package/dist/src/components/copy-icon.d.ts.map +1 -1
- package/dist/src/components/copy-icon.js +41 -3
- package/dist/src/components/copy-icon.js.map +1 -1
- package/dist/src/components/data-table.d.ts +9 -0
- package/dist/src/components/data-table.d.ts.map +1 -0
- package/dist/src/components/data-table.js +66 -0
- package/dist/src/components/data-table.js.map +1 -0
- package/dist/src/components/data-table.stories.d.ts +7 -0
- package/dist/src/components/data-table.stories.d.ts.map +1 -0
- package/dist/src/components/data-table.stories.js +240 -0
- package/dist/src/components/data-table.stories.js.map +1 -0
- package/dist/src/components/fhir-structure-view.d.ts +34 -0
- package/dist/src/components/fhir-structure-view.d.ts.map +1 -0
- package/dist/src/components/fhir-structure-view.js +226 -0
- package/dist/src/components/fhir-structure-view.js.map +1 -0
- package/dist/src/components/fhir-structure-view.stories.d.ts +7 -0
- package/dist/src/components/fhir-structure-view.stories.d.ts.map +1 -0
- package/dist/src/components/fhir-structure-view.stories.js +447 -0
- package/dist/src/components/fhir-structure-view.stories.js.map +1 -0
- package/dist/src/components/request-line-editor.d.ts +3 -1
- package/dist/src/components/request-line-editor.d.ts.map +1 -1
- package/dist/src/components/request-line-editor.js +26 -5
- package/dist/src/components/request-line-editor.js.map +1 -1
- package/dist/src/components/segment-control.d.ts +16 -0
- package/dist/src/components/segment-control.d.ts.map +1 -0
- package/dist/src/components/segment-control.js +48 -0
- package/dist/src/components/segment-control.js.map +1 -0
- package/dist/src/components/segment-control.stories.d.ts +15 -0
- package/dist/src/components/segment-control.stories.d.ts.map +1 -0
- package/dist/src/components/segment-control.stories.js +33 -0
- package/dist/src/components/segment-control.stories.js.map +1 -0
- package/dist/src/components/split-button.d.ts +5 -0
- package/dist/src/components/split-button.d.ts.map +1 -0
- package/dist/src/components/split-button.js +12 -0
- package/dist/src/components/split-button.js.map +1 -0
- package/dist/src/components/split-button.stories.d.ts +7 -0
- package/dist/src/components/split-button.stories.d.ts.map +1 -0
- package/dist/src/components/split-button.stories.js +57 -0
- package/dist/src/components/split-button.stories.js.map +1 -0
- package/dist/src/components/tree-view.d.ts +16 -7
- package/dist/src/components/tree-view.d.ts.map +1 -1
- package/dist/src/components/tree-view.js +75 -19
- package/dist/src/components/tree-view.js.map +1 -1
- package/dist/src/components/tree-view.stories.d.ts +3 -3
- package/dist/src/components/tree-view.stories.d.ts.map +1 -1
- package/dist/src/components/tree-view.stories.js +14 -5
- package/dist/src/components/tree-view.stories.js.map +1 -1
- package/dist/src/icons.d.ts +6 -0
- package/dist/src/icons.d.ts.map +1 -1
- package/dist/src/icons.js +235 -3
- package/dist/src/icons.js.map +1 -1
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/shadcn/components/ui/alert-dialog.d.ts +3 -1
- package/dist/src/shadcn/components/ui/alert-dialog.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/alert-dialog.js +5 -2
- package/dist/src/shadcn/components/ui/alert-dialog.js.map +1 -1
- package/dist/src/shadcn/components/ui/badge.d.ts +1 -1
- package/dist/src/shadcn/components/ui/card.d.ts +5 -1
- package/dist/src/shadcn/components/ui/card.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/card.js +21 -8
- package/dist/src/shadcn/components/ui/card.js.map +1 -1
- package/dist/src/shadcn/components/ui/card.stories.d.ts +302 -1
- package/dist/src/shadcn/components/ui/card.stories.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/card.stories.js +23 -2
- package/dist/src/shadcn/components/ui/card.stories.js.map +1 -1
- package/dist/src/shadcn/components/ui/combobox.d.ts +13 -0
- package/dist/src/shadcn/components/ui/combobox.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/combobox.js +102 -0
- package/dist/src/shadcn/components/ui/combobox.js.map +1 -1
- package/dist/src/shadcn/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/dropdown-menu.js +1 -1
- package/dist/src/shadcn/components/ui/dropdown-menu.js.map +1 -1
- package/dist/src/shadcn/components/ui/input.d.ts +3 -1
- package/dist/src/shadcn/components/ui/input.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/input.js +39 -1
- package/dist/src/shadcn/components/ui/input.js.map +1 -1
- package/dist/src/shadcn/components/ui/pagination.d.ts +8 -1
- package/dist/src/shadcn/components/ui/pagination.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/pagination.js +36 -19
- package/dist/src/shadcn/components/ui/pagination.js.map +1 -1
- package/dist/src/shadcn/components/ui/pagination.stories.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/pagination.stories.js +44 -37
- package/dist/src/shadcn/components/ui/pagination.stories.js.map +1 -1
- package/dist/src/shadcn/components/ui/table.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/table.js +1 -1
- package/dist/src/shadcn/components/ui/table.js.map +1 -1
- package/dist/src/shadcn/components/ui/tabs.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/tabs.js +1 -0
- package/dist/src/shadcn/components/ui/tabs.js.map +1 -1
- package/dist/src/shadcn/components/ui/tree.d.ts +10 -2
- package/dist/src/shadcn/components/ui/tree.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/tree.js +31 -8
- package/dist/src/shadcn/components/ui/tree.js.map +1 -1
- package/dist/src/typography.css +36 -8
- package/package.json +5 -1
- package/src/components/button-dropdown.stories.tsx +41 -0
- package/src/components/button-dropdown.tsx +95 -0
- package/src/components/code-editor/index.tsx +129 -4
- package/src/components/code-editor.stories.tsx +294 -0
- package/src/components/copy-icon.tsx +57 -3
- package/src/components/data-table.stories.tsx +89 -0
- package/src/components/data-table.tsx +120 -0
- package/src/components/fhir-structure-view.stories.tsx +439 -0
- package/src/components/fhir-structure-view.tsx +229 -0
- package/src/components/request-line-editor.tsx +30 -4
- package/src/components/segment-control.stories.tsx +29 -0
- package/src/components/segment-control.tsx +81 -0
- package/src/components/split-button.stories.tsx +49 -0
- package/src/components/split-button.tsx +17 -0
- package/src/components/tree-view.stories.tsx +20 -15
- package/src/components/tree-view.tsx +118 -15
- package/src/icons.tsx +245 -3
- package/src/index.tsx +10 -2
- package/src/shadcn/components/ui/alert-dialog.tsx +6 -2
- package/src/shadcn/components/ui/card.stories.tsx +17 -3
- package/src/shadcn/components/ui/card.tsx +52 -8
- package/src/shadcn/components/ui/combobox.tsx +127 -0
- package/src/shadcn/components/ui/dropdown-menu.tsx +1 -2
- package/src/shadcn/components/ui/input.tsx +119 -0
- package/src/shadcn/components/ui/pagination.stories.tsx +8 -2
- package/src/shadcn/components/ui/pagination.tsx +54 -3
- package/src/shadcn/components/ui/table.tsx +6 -1
- package/src/shadcn/components/ui/tabs.tsx +1 -0
- package/src/shadcn/components/ui/tree.tsx +63 -10
- package/src/typography.css +36 -8
|
@@ -118,6 +118,119 @@ export function Combobox({
|
|
|
118
118
|
);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
interface MultiComboboxProps {
|
|
122
|
+
options: ComboboxOption[];
|
|
123
|
+
value?: string[];
|
|
124
|
+
onValueChange?: (value: string[]) => void;
|
|
125
|
+
placeholder?: string;
|
|
126
|
+
searchPlaceholder?: string;
|
|
127
|
+
emptyText?: string;
|
|
128
|
+
disabled?: boolean;
|
|
129
|
+
className?: string;
|
|
130
|
+
maxDisplay?: number;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function MultiCombobox({
|
|
134
|
+
options,
|
|
135
|
+
value = [],
|
|
136
|
+
onValueChange,
|
|
137
|
+
placeholder = "Select options...",
|
|
138
|
+
searchPlaceholder = "Search...",
|
|
139
|
+
emptyText = "No options found.",
|
|
140
|
+
disabled = false,
|
|
141
|
+
className,
|
|
142
|
+
maxDisplay = 2,
|
|
143
|
+
}: MultiComboboxProps) {
|
|
144
|
+
const [open, setOpen] = React.useState(false);
|
|
145
|
+
const [searchValue, setSearchValue] = React.useState("");
|
|
146
|
+
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
147
|
+
|
|
148
|
+
const filteredOptions = React.useMemo(() => {
|
|
149
|
+
if (!searchValue) return options;
|
|
150
|
+
return options.filter((option) =>
|
|
151
|
+
option.label.toLowerCase().includes(searchValue.toLowerCase()),
|
|
152
|
+
);
|
|
153
|
+
}, [options, searchValue]);
|
|
154
|
+
|
|
155
|
+
const selectedOptions = React.useMemo(
|
|
156
|
+
() => options.filter((option) => value.includes(option.value)),
|
|
157
|
+
[options, value],
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const displayText = React.useMemo(() => {
|
|
161
|
+
if (selectedOptions.length === 0) return placeholder;
|
|
162
|
+
if (selectedOptions.length <= maxDisplay) {
|
|
163
|
+
return selectedOptions.map((opt) => opt.label).join(", ");
|
|
164
|
+
}
|
|
165
|
+
return `${selectedOptions
|
|
166
|
+
.slice(0, maxDisplay)
|
|
167
|
+
.map((opt) => opt.label)
|
|
168
|
+
.join(", ")} +${selectedOptions.length - maxDisplay}`;
|
|
169
|
+
}, [selectedOptions, placeholder, maxDisplay]);
|
|
170
|
+
|
|
171
|
+
const handleSelect = (selectedValue: string) => {
|
|
172
|
+
const newValue = value.includes(selectedValue)
|
|
173
|
+
? value.filter((v) => v !== selectedValue)
|
|
174
|
+
: [...value, selectedValue];
|
|
175
|
+
onValueChange?.(newValue);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Reset search when closing and auto-focus when opening
|
|
179
|
+
React.useEffect(() => {
|
|
180
|
+
if (!open) {
|
|
181
|
+
setSearchValue("");
|
|
182
|
+
} else {
|
|
183
|
+
// Auto-focus on search input when opening
|
|
184
|
+
setTimeout(() => {
|
|
185
|
+
inputRef.current?.focus();
|
|
186
|
+
}, 0);
|
|
187
|
+
}
|
|
188
|
+
}, [open]);
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<Select open={open} onOpenChange={setOpen}>
|
|
192
|
+
<SelectTrigger
|
|
193
|
+
className={`${className} ${displayText ? "!text-text-primary" : undefined}`}
|
|
194
|
+
disabled={disabled}
|
|
195
|
+
>
|
|
196
|
+
<SelectValue placeholder={displayText || placeholder} />
|
|
197
|
+
</SelectTrigger>
|
|
198
|
+
<SelectContent className="p-0 [&_[data-radix-select-viewport]]:p-0">
|
|
199
|
+
<Command className="w-full">
|
|
200
|
+
<CommandInput
|
|
201
|
+
ref={inputRef}
|
|
202
|
+
placeholder={searchPlaceholder}
|
|
203
|
+
value={searchValue}
|
|
204
|
+
onValueChange={setSearchValue}
|
|
205
|
+
/>
|
|
206
|
+
<CommandList>
|
|
207
|
+
<CommandEmpty>{emptyText}</CommandEmpty>
|
|
208
|
+
|
|
209
|
+
{filteredOptions.map((option) => (
|
|
210
|
+
<CommandItem
|
|
211
|
+
key={option.value}
|
|
212
|
+
value={option.value}
|
|
213
|
+
data-state={
|
|
214
|
+
value.includes(option.value) ? "checked" : undefined
|
|
215
|
+
}
|
|
216
|
+
onSelect={handleSelect}
|
|
217
|
+
>
|
|
218
|
+
{option.label}
|
|
219
|
+
<CheckIcon
|
|
220
|
+
className={cn(
|
|
221
|
+
"ml-auto size-4",
|
|
222
|
+
value.includes(option.value) ? "opacity-100" : "opacity-0",
|
|
223
|
+
)}
|
|
224
|
+
/>
|
|
225
|
+
</CommandItem>
|
|
226
|
+
))}
|
|
227
|
+
</CommandList>
|
|
228
|
+
</Command>
|
|
229
|
+
</SelectContent>
|
|
230
|
+
</Select>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
121
234
|
// Demo component for Storybook
|
|
122
235
|
const demoOptions = [
|
|
123
236
|
{ value: "next.js", label: "Next.js" },
|
|
@@ -140,3 +253,17 @@ export function ComboboxDemo() {
|
|
|
140
253
|
/>
|
|
141
254
|
);
|
|
142
255
|
}
|
|
256
|
+
|
|
257
|
+
export function MultiComboboxDemo() {
|
|
258
|
+
const [value, setValue] = React.useState<string[]>([]);
|
|
259
|
+
|
|
260
|
+
return (
|
|
261
|
+
<MultiCombobox
|
|
262
|
+
options={demoOptions}
|
|
263
|
+
value={value}
|
|
264
|
+
onValueChange={setValue}
|
|
265
|
+
placeholder="Select frameworks..."
|
|
266
|
+
searchPlaceholder="Search framework..."
|
|
267
|
+
/>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
@@ -105,6 +105,37 @@ const iconRightItemClasses = cn(
|
|
|
105
105
|
"duration-300",
|
|
106
106
|
);
|
|
107
107
|
|
|
108
|
+
// Prefix styles
|
|
109
|
+
const prefixClasses = cn(
|
|
110
|
+
// Borders
|
|
111
|
+
"border-border-primary",
|
|
112
|
+
"border",
|
|
113
|
+
"border-r-0",
|
|
114
|
+
|
|
115
|
+
// Background & Colors
|
|
116
|
+
"bg-bg-tertiary",
|
|
117
|
+
"text-text-tertiary",
|
|
118
|
+
|
|
119
|
+
// Layout & Flexbox
|
|
120
|
+
"flex",
|
|
121
|
+
"items-center",
|
|
122
|
+
|
|
123
|
+
// Spacing & Sizing
|
|
124
|
+
"rounded-l-md",
|
|
125
|
+
"px-3",
|
|
126
|
+
"py-1",
|
|
127
|
+
|
|
128
|
+
// Typography
|
|
129
|
+
"typo-body",
|
|
130
|
+
|
|
131
|
+
// Cursor & Interactions
|
|
132
|
+
"cursor-default",
|
|
133
|
+
|
|
134
|
+
// Transitions
|
|
135
|
+
"transition-colors",
|
|
136
|
+
"duration-300",
|
|
137
|
+
);
|
|
138
|
+
|
|
108
139
|
// Suffix styles
|
|
109
140
|
const suffixClasses = cn(
|
|
110
141
|
// Borders
|
|
@@ -135,6 +166,36 @@ const suffixClasses = cn(
|
|
|
135
166
|
"duration-300",
|
|
136
167
|
);
|
|
137
168
|
|
|
169
|
+
// Disabled prefix styles
|
|
170
|
+
const prefixDisabledClasses = cn(
|
|
171
|
+
// Borders
|
|
172
|
+
"border-border-primary",
|
|
173
|
+
"border",
|
|
174
|
+
|
|
175
|
+
// Background & Colors
|
|
176
|
+
"bg-bg-tertiary",
|
|
177
|
+
"text-text-disabled",
|
|
178
|
+
|
|
179
|
+
// Layout & Flexbox
|
|
180
|
+
"flex",
|
|
181
|
+
"items-center",
|
|
182
|
+
|
|
183
|
+
// Spacing & Sizing
|
|
184
|
+
"rounded-l-md",
|
|
185
|
+
"px-3",
|
|
186
|
+
"py-1",
|
|
187
|
+
|
|
188
|
+
// Typography
|
|
189
|
+
"typo-body",
|
|
190
|
+
|
|
191
|
+
// Cursor & Interactions
|
|
192
|
+
"hover:cursor-not-allowed",
|
|
193
|
+
|
|
194
|
+
// Transitions
|
|
195
|
+
"transition-colors",
|
|
196
|
+
"duration-300",
|
|
197
|
+
);
|
|
198
|
+
|
|
138
199
|
// Disabled suffix styles
|
|
139
200
|
const suffixDisabledClasses = cn(
|
|
140
201
|
// Borders
|
|
@@ -165,6 +226,36 @@ const suffixDisabledClasses = cn(
|
|
|
165
226
|
"duration-300",
|
|
166
227
|
);
|
|
167
228
|
|
|
229
|
+
// Invalid prefix styles
|
|
230
|
+
const prefixInvalidClasses = cn(
|
|
231
|
+
// Borders
|
|
232
|
+
"border-border-error",
|
|
233
|
+
"border",
|
|
234
|
+
|
|
235
|
+
// Background & Colors
|
|
236
|
+
"bg-bg-secondary",
|
|
237
|
+
"text-text-tertiary",
|
|
238
|
+
|
|
239
|
+
// Layout & Flexbox
|
|
240
|
+
"flex",
|
|
241
|
+
"items-center",
|
|
242
|
+
|
|
243
|
+
// Spacing & Sizing
|
|
244
|
+
"rounded-l-md",
|
|
245
|
+
"px-3",
|
|
246
|
+
"py-1",
|
|
247
|
+
|
|
248
|
+
// Typography
|
|
249
|
+
"typo-body",
|
|
250
|
+
|
|
251
|
+
// Cursor & Interactions
|
|
252
|
+
"cursor-default",
|
|
253
|
+
|
|
254
|
+
// Transitions
|
|
255
|
+
"transition-colors",
|
|
256
|
+
"duration-300",
|
|
257
|
+
);
|
|
258
|
+
|
|
168
259
|
// Invalid suffix styles
|
|
169
260
|
const suffixInvalidClasses = cn(
|
|
170
261
|
// Borders
|
|
@@ -279,6 +370,17 @@ const inputVariants = cva(
|
|
|
279
370
|
"pr-9",
|
|
280
371
|
),
|
|
281
372
|
},
|
|
373
|
+
hasPrefix: {
|
|
374
|
+
true: cn(
|
|
375
|
+
// Border adjustments for prefix
|
|
376
|
+
"rounded-r-md",
|
|
377
|
+
"rounded-l-none",
|
|
378
|
+
|
|
379
|
+
// Focus adjustments
|
|
380
|
+
"focus-visible:ring-offset-0",
|
|
381
|
+
"focus-visible:border-l-1",
|
|
382
|
+
),
|
|
383
|
+
},
|
|
282
384
|
hasSuffix: {
|
|
283
385
|
true: cn(
|
|
284
386
|
// Border adjustments for suffix
|
|
@@ -309,6 +411,7 @@ const inputVariants = cva(
|
|
|
309
411
|
},
|
|
310
412
|
},
|
|
311
413
|
defaultVariants: {
|
|
414
|
+
hasPrefix: false,
|
|
312
415
|
hasSuffix: false,
|
|
313
416
|
invalid: false,
|
|
314
417
|
},
|
|
@@ -319,6 +422,7 @@ interface InputProps
|
|
|
319
422
|
extends React.ComponentProps<"input">,
|
|
320
423
|
VariantProps<typeof inputVariants> {
|
|
321
424
|
type?: "text" | "password";
|
|
425
|
+
prefixValue?: React.ReactNode;
|
|
322
426
|
suffix?: string;
|
|
323
427
|
invalid?: boolean;
|
|
324
428
|
leftSlot?: React.ReactNode;
|
|
@@ -329,6 +433,7 @@ function Input({
|
|
|
329
433
|
className,
|
|
330
434
|
type,
|
|
331
435
|
invalid,
|
|
436
|
+
prefixValue,
|
|
332
437
|
suffix,
|
|
333
438
|
leftSlot,
|
|
334
439
|
rightSlot,
|
|
@@ -390,6 +495,7 @@ function Input({
|
|
|
390
495
|
invalid,
|
|
391
496
|
hasLeftSlot: !!leftSlot,
|
|
392
497
|
hasRightSlot: !!rightSlot,
|
|
498
|
+
hasPrefix: !!prefixValue,
|
|
393
499
|
hasSuffix: !!suffix,
|
|
394
500
|
className,
|
|
395
501
|
}),
|
|
@@ -400,6 +506,19 @@ function Input({
|
|
|
400
506
|
|
|
401
507
|
return (
|
|
402
508
|
<div className="flex w-full min-w-0">
|
|
509
|
+
{prefixValue && (
|
|
510
|
+
<div
|
|
511
|
+
className={
|
|
512
|
+
props.disabled
|
|
513
|
+
? prefixDisabledClasses
|
|
514
|
+
: invalid
|
|
515
|
+
? prefixInvalidClasses
|
|
516
|
+
: prefixClasses
|
|
517
|
+
}
|
|
518
|
+
>
|
|
519
|
+
{prefixValue}
|
|
520
|
+
</div>
|
|
521
|
+
)}
|
|
403
522
|
<div className="flex-1 relative">
|
|
404
523
|
{renderLeftSlot()}
|
|
405
524
|
{inputElement}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
PaginationItem,
|
|
8
8
|
PaginationLink,
|
|
9
9
|
PaginationNext,
|
|
10
|
+
PaginationPageSizeSelector,
|
|
10
11
|
PaginationPrevious,
|
|
11
12
|
} from "#shadcn/components/ui/pagination";
|
|
12
13
|
|
|
@@ -20,6 +21,11 @@ type Story = StoryObj<typeof meta>;
|
|
|
20
21
|
export const Demo = {
|
|
21
22
|
render: () => (
|
|
22
23
|
<Pagination>
|
|
24
|
+
<PaginationPageSizeSelector
|
|
25
|
+
pageSize={10}
|
|
26
|
+
onPageSizeChange={(_: number) => {}}
|
|
27
|
+
className="p-2"
|
|
28
|
+
/>
|
|
23
29
|
<PaginationContent>
|
|
24
30
|
<PaginationItem>
|
|
25
31
|
<PaginationPrevious href="#" />
|
|
@@ -33,10 +39,10 @@ export const Demo = {
|
|
|
33
39
|
</PaginationLink>
|
|
34
40
|
</PaginationItem>
|
|
35
41
|
<PaginationItem>
|
|
36
|
-
<
|
|
42
|
+
<PaginationEllipsis />
|
|
37
43
|
</PaginationItem>
|
|
38
44
|
<PaginationItem>
|
|
39
|
-
<
|
|
45
|
+
<PaginationLink href="#">3</PaginationLink>
|
|
40
46
|
</PaginationItem>
|
|
41
47
|
<PaginationItem>
|
|
42
48
|
<PaginationNext href="#" />
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ChevronDownIcon,
|
|
2
3
|
ChevronLeftIcon,
|
|
3
4
|
ChevronRightIcon,
|
|
4
5
|
MoreHorizontalIcon,
|
|
5
6
|
} from "lucide-react";
|
|
6
7
|
import type * as React from "react";
|
|
7
8
|
import { type Button, buttonVariants } from "#shadcn/components/ui/button";
|
|
9
|
+
import {
|
|
10
|
+
DropdownMenu,
|
|
11
|
+
DropdownMenuContent,
|
|
12
|
+
DropdownMenuItem,
|
|
13
|
+
DropdownMenuTrigger,
|
|
14
|
+
} from "#shadcn/components/ui/dropdown-menu";
|
|
8
15
|
import { cn } from "#shadcn/lib/utils";
|
|
9
16
|
|
|
10
17
|
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
|
|
@@ -15,7 +22,7 @@ function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
|
|
|
15
22
|
role="navigation"
|
|
16
23
|
aria-label="pagination"
|
|
17
24
|
data-slot="pagination"
|
|
18
|
-
className={cn("
|
|
25
|
+
className={cn("flex", "justify-center", className)}
|
|
19
26
|
{...props}
|
|
20
27
|
/>
|
|
21
28
|
);
|
|
@@ -84,7 +91,6 @@ function PaginationPrevious({
|
|
|
84
91
|
{...props}
|
|
85
92
|
>
|
|
86
93
|
<ChevronLeftIcon />
|
|
87
|
-
<span className="hidden sm:block">Previous</span>
|
|
88
94
|
</PaginationLink>
|
|
89
95
|
);
|
|
90
96
|
}
|
|
@@ -100,7 +106,6 @@ function PaginationNext({
|
|
|
100
106
|
className={cn("gap-1", "px-2.5", "sm:pr-2.5", className)}
|
|
101
107
|
{...props}
|
|
102
108
|
>
|
|
103
|
-
<span className="hidden sm:block">Next</span>
|
|
104
109
|
<ChevronRightIcon />
|
|
105
110
|
</PaginationLink>
|
|
106
111
|
);
|
|
@@ -129,6 +134,51 @@ function PaginationEllipsis({
|
|
|
129
134
|
);
|
|
130
135
|
}
|
|
131
136
|
|
|
137
|
+
type PaginationPageSizeSelectorProps = {
|
|
138
|
+
pageSize: number;
|
|
139
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
140
|
+
pageSizeOptions?: number[];
|
|
141
|
+
className?: string;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
function PaginationPageSizeSelector({
|
|
145
|
+
pageSize,
|
|
146
|
+
onPageSizeChange,
|
|
147
|
+
pageSizeOptions = [10, 20, 50, 100],
|
|
148
|
+
className,
|
|
149
|
+
}: PaginationPageSizeSelectorProps) {
|
|
150
|
+
return (
|
|
151
|
+
<DropdownMenu>
|
|
152
|
+
<DropdownMenuTrigger
|
|
153
|
+
className={cn(
|
|
154
|
+
"flex",
|
|
155
|
+
"items-center",
|
|
156
|
+
"gap-1",
|
|
157
|
+
"text-sm",
|
|
158
|
+
"text-text-secondary",
|
|
159
|
+
"hover:text-text-primary",
|
|
160
|
+
"outline-none",
|
|
161
|
+
className,
|
|
162
|
+
)}
|
|
163
|
+
data-slot="pagination-page-size-selector"
|
|
164
|
+
>
|
|
165
|
+
{pageSize} / Page
|
|
166
|
+
<ChevronDownIcon className="size-4" />
|
|
167
|
+
</DropdownMenuTrigger>
|
|
168
|
+
<DropdownMenuContent>
|
|
169
|
+
{pageSizeOptions.map((option) => (
|
|
170
|
+
<DropdownMenuItem
|
|
171
|
+
key={option}
|
|
172
|
+
onClick={() => onPageSizeChange(option)}
|
|
173
|
+
>
|
|
174
|
+
{option}
|
|
175
|
+
</DropdownMenuItem>
|
|
176
|
+
))}
|
|
177
|
+
</DropdownMenuContent>
|
|
178
|
+
</DropdownMenu>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
132
182
|
export {
|
|
133
183
|
Pagination,
|
|
134
184
|
PaginationContent,
|
|
@@ -137,4 +187,5 @@ export {
|
|
|
137
187
|
PaginationPrevious,
|
|
138
188
|
PaginationNext,
|
|
139
189
|
PaginationEllipsis,
|
|
190
|
+
PaginationPageSizeSelector,
|
|
140
191
|
};
|
|
@@ -3,7 +3,12 @@ import type * as React from "react";
|
|
|
3
3
|
import { cn } from "#shadcn/lib/utils";
|
|
4
4
|
|
|
5
5
|
// Table container styles
|
|
6
|
-
const tableContainerStyles = cn(
|
|
6
|
+
const tableContainerStyles = cn(
|
|
7
|
+
"relative",
|
|
8
|
+
"h-full",
|
|
9
|
+
"w-full",
|
|
10
|
+
"overflow-auto",
|
|
11
|
+
);
|
|
7
12
|
|
|
8
13
|
// Table styles
|
|
9
14
|
const tableStyles = cn("w-full", "caption-bottom", "text-sm");
|
|
@@ -101,6 +101,7 @@ const tabsVariants = cva("", {
|
|
|
101
101
|
`**:data-[slot=tabs-trigger]:max-w-80
|
|
102
102
|
**:data-[slot=tabs-trigger]:w-60
|
|
103
103
|
**:data-[slot=tabs-trigger]:min-w-40
|
|
104
|
+
**:data-[slot=tabs-trigger]:data-[state=inactive]:text-text-secondary
|
|
104
105
|
**:data-[slot=tabs-trigger]:data-[state=inactive]:border-b-1
|
|
105
106
|
**:data-[slot=tabs-trigger]:data-[state=inactive]:border-b-border-secondary
|
|
106
107
|
**:data-[slot=tabs-trigger]:data-[state=inactive]:pt-[9px]
|
|
@@ -5,6 +5,12 @@ import * as React from "react";
|
|
|
5
5
|
|
|
6
6
|
import { cn } from "#shadcn/lib/utils";
|
|
7
7
|
|
|
8
|
+
type WithMeta = {
|
|
9
|
+
meta?: {
|
|
10
|
+
lastNode?: boolean;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
|
|
8
14
|
// biome-ignore lint/suspicious/noExplicitAny: FIXME Origin UI as-is
|
|
9
15
|
interface TreeContextValue<T = any> {
|
|
10
16
|
indent: number;
|
|
@@ -42,7 +48,7 @@ function Tree({ indent = 20, tree, className, ...props }: TreeProps) {
|
|
|
42
48
|
const mergedStyle = {
|
|
43
49
|
...propStyle,
|
|
44
50
|
"--tree-indent": `${indent}px`,
|
|
45
|
-
"--border": `var(--color-
|
|
51
|
+
"--border": `var(--color-border-separator)`,
|
|
46
52
|
} as React.CSSProperties;
|
|
47
53
|
|
|
48
54
|
return (
|
|
@@ -87,7 +93,7 @@ function TreeItem<T = any>({
|
|
|
87
93
|
"--tree-padding": `${item.getItemMeta().level * indent}px`,
|
|
88
94
|
} as React.CSSProperties;
|
|
89
95
|
|
|
90
|
-
const Comp = asChild ? Slot.Root : "
|
|
96
|
+
const Comp = asChild ? Slot.Root : "span";
|
|
91
97
|
|
|
92
98
|
return (
|
|
93
99
|
<TreeContext.Provider value={{ indent, currentItem: item }}>
|
|
@@ -124,7 +130,16 @@ function TreeItem<T = any>({
|
|
|
124
130
|
: undefined
|
|
125
131
|
}
|
|
126
132
|
aria-expanded={item.isExpanded()}
|
|
127
|
-
{...
|
|
133
|
+
{...Object.fromEntries(
|
|
134
|
+
Object.entries(otherProps).filter(
|
|
135
|
+
([key]) => key !== "onClick" && key !== "onDragStart",
|
|
136
|
+
),
|
|
137
|
+
)}
|
|
138
|
+
onDragStart={(e) => {
|
|
139
|
+
if ((e.target as HTMLElement).dataset.slot === "drag-handle") {
|
|
140
|
+
item.getProps().onDragStart(e);
|
|
141
|
+
}
|
|
142
|
+
}}
|
|
128
143
|
>
|
|
129
144
|
{children}
|
|
130
145
|
</Comp>
|
|
@@ -135,17 +150,22 @@ function TreeItem<T = any>({
|
|
|
135
150
|
// biome-ignore lint/suspicious/noExplicitAny: FIXME Origin UI as-is
|
|
136
151
|
interface TreeItemLabelProps<T = any>
|
|
137
152
|
extends React.HTMLAttributes<HTMLSpanElement> {
|
|
153
|
+
hideChevron?: boolean;
|
|
154
|
+
disableHover?: boolean;
|
|
138
155
|
item?: ItemInstance<T>;
|
|
156
|
+
horizontalLines?: boolean;
|
|
139
157
|
}
|
|
140
158
|
|
|
141
|
-
|
|
142
|
-
function TreeItemLabel<T = any>({
|
|
159
|
+
function TreeItemLabel<T>({
|
|
143
160
|
item: propItem,
|
|
144
161
|
children,
|
|
145
162
|
className,
|
|
163
|
+
disableHover,
|
|
164
|
+
horizontalLines,
|
|
165
|
+
hideChevron,
|
|
146
166
|
...props
|
|
147
|
-
}: TreeItemLabelProps<T>) {
|
|
148
|
-
const { currentItem } = useTreeContext<T>();
|
|
167
|
+
}: TreeItemLabelProps<T & WithMeta>) {
|
|
168
|
+
const { currentItem } = useTreeContext<T & WithMeta>();
|
|
149
169
|
const item = propItem || currentItem;
|
|
150
170
|
|
|
151
171
|
if (!item) {
|
|
@@ -153,17 +173,50 @@ function TreeItemLabel<T = any>({
|
|
|
153
173
|
return null;
|
|
154
174
|
}
|
|
155
175
|
|
|
176
|
+
const data = item.getItemData?.();
|
|
177
|
+
const isLastNode = data?.meta?.lastNode;
|
|
178
|
+
const itemMeta = item.getItemMeta();
|
|
179
|
+
|
|
156
180
|
return (
|
|
157
181
|
<span
|
|
158
182
|
data-slot="tree-item-label"
|
|
159
183
|
className={cn(
|
|
160
|
-
"group/tree-item-label
|
|
184
|
+
"group/tree-item-label relative select-text in-focus-visible:ring-ring/50 bg-background text-text-secondary in-data-[drag-target=true]:bg-accent flex items-center gap-2 pr-2 pl-2.5 py-1.5 text-sm transition-colors not-in-data-[folder=true]:ps-2.5 in-focus-visible:ring-[3px] in-data-[search-match=true]:bg-blue-400/20! [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
185
|
+
!disableHover &&
|
|
186
|
+
"in-data-[selected=true]:bg-bg-secondary in-data-[selected=true]:text-text-primary",
|
|
187
|
+
!disableHover &&
|
|
188
|
+
item.isFolder() &&
|
|
189
|
+
"hover:bg-bg-secondary hover:text-text-primary cursor-pointer",
|
|
190
|
+
disableHover && "text-text-primary",
|
|
161
191
|
className,
|
|
162
192
|
)}
|
|
163
193
|
{...props}
|
|
164
194
|
>
|
|
165
195
|
{item.isFolder() && (
|
|
166
|
-
<
|
|
196
|
+
<button
|
|
197
|
+
type="button"
|
|
198
|
+
className="self-start mt-0.5 cursor-pointer"
|
|
199
|
+
onClick={() => {
|
|
200
|
+
item.isExpanded() ? item.collapse() : item.expand();
|
|
201
|
+
}}
|
|
202
|
+
>
|
|
203
|
+
<ChevronDownIcon className="text-muted-foreground size-4 in-aria-[expanded=false]:-rotate-90" />
|
|
204
|
+
</button>
|
|
205
|
+
)}
|
|
206
|
+
{!item.isFolder() && horizontalLines && (
|
|
207
|
+
<div
|
|
208
|
+
className={`w-5 min-w-5 h-px border-t mt-2 -ml-1 self-start`}
|
|
209
|
+
></div>
|
|
210
|
+
)}
|
|
211
|
+
{item.isFolder() && item.isExpanded() && horizontalLines && (
|
|
212
|
+
<div
|
|
213
|
+
className={`absolute left-4.25 top-8 w-px min-h-full h-full border-l mt-2.25 self-start `}
|
|
214
|
+
></div>
|
|
215
|
+
)}
|
|
216
|
+
{horizontalLines && (
|
|
217
|
+
<div
|
|
218
|
+
className={`absolute left-0 top-4.75 -m-[5px] border-t w-4 ${isLastNode ? "h-full bg-inherit " : ""} ${itemMeta.level === 0 ? "hidden" : ""}`}
|
|
219
|
+
></div>
|
|
167
220
|
)}
|
|
168
221
|
{children ||
|
|
169
222
|
(typeof item.getItemName === "function" ? item.getItemName() : null)}
|
|
@@ -197,4 +250,4 @@ function TreeDragLine({
|
|
|
197
250
|
);
|
|
198
251
|
}
|
|
199
252
|
|
|
200
|
-
export { Tree, TreeItem, TreeItemLabel, TreeDragLine };
|
|
253
|
+
export { Tree, TreeItem, TreeItemLabel, TreeDragLine, type ItemInstance };
|
package/src/typography.css
CHANGED
|
@@ -42,6 +42,18 @@ body {
|
|
|
42
42
|
font-weight: var(--font-weight-normal);
|
|
43
43
|
line-height: var(--font-leading-4);
|
|
44
44
|
}
|
|
45
|
+
.typo-body-xs {
|
|
46
|
+
font-size: var(--font-size-xs);
|
|
47
|
+
font-family: var(--font-family-sans);
|
|
48
|
+
font-weight: var(--font-weight-normal);
|
|
49
|
+
line-height: var(--font-leading-3);
|
|
50
|
+
}
|
|
51
|
+
.typo-label-xs {
|
|
52
|
+
font-size: var(--font-size-xs);
|
|
53
|
+
font-family: var(--font-family-sans);
|
|
54
|
+
font-weight: var(--font-weight-medium);
|
|
55
|
+
line-height: var(--font-leading-3);
|
|
56
|
+
}
|
|
45
57
|
|
|
46
58
|
.h1 {
|
|
47
59
|
font-size: var(--font-size-4xl);
|
|
@@ -57,14 +69,6 @@ body {
|
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
.h2 {
|
|
61
|
-
font-size: var(--font-size-3xl);
|
|
62
|
-
font-family: var(--font-family-sans);
|
|
63
|
-
font-weight: var(--font-weight-semibold);
|
|
64
|
-
line-height: var(--font-leading-none);
|
|
65
|
-
letter-spacing: var(--font-tracking-tight);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
72
|
.h3 {
|
|
69
73
|
font-size: var(--font-size-2xl);
|
|
70
74
|
font-family: var(--font-family-sans);
|
|
@@ -96,3 +100,27 @@ body {
|
|
|
96
100
|
line-height: var(--font-leading-none);
|
|
97
101
|
letter-spacing: var(--font-tracking-tight);
|
|
98
102
|
}
|
|
103
|
+
|
|
104
|
+
.h2 {
|
|
105
|
+
font-size: var(--font-size-4xl);
|
|
106
|
+
font-family: var(--font-family-sans);
|
|
107
|
+
font-weight: var(--font-weight-bold);
|
|
108
|
+
line-height: var(--font-leading-10);
|
|
109
|
+
letter-spacing: var(--font-tracking-normal);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.body16 {
|
|
113
|
+
font-size: var(--font-size-base);
|
|
114
|
+
font-family: var(--font-family-sans);
|
|
115
|
+
font-weight: var(--font-weight-normal);
|
|
116
|
+
line-height: var(--font-leading-6);
|
|
117
|
+
letter-spacing: var(--font-tracking-normal);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.body12 {
|
|
121
|
+
font-size: var(--font-size-xs);
|
|
122
|
+
font-family: var(--font-family-sans);
|
|
123
|
+
font-weight: var(--font-weight-normal);
|
|
124
|
+
line-height: var(--font-leading-4);
|
|
125
|
+
letter-spacing: var(--font-tracking-normal);
|
|
126
|
+
}
|