@alexgorbatchev/shadcn 0.0.35 → 0.0.37

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/README.md CHANGED
@@ -306,6 +306,8 @@ Compose `QuestionnaireItem`, `QuestionnaireTitle`, and answer controls inside `Q
306
306
 
307
307
  `VirtualDataGrid` renders a TanStack Table instance built with `dataGridFeatures` through `VirtualTable`: every filtered and sorted row, without pagination, in a fixed-layout table. Column `meta` sets `label`, `textAlign`, `truncate`, `visibleFrom`, `fill`, and `sortColumnIds`; a `fill` column takes the width the sized columns leave, and `sortColumnIds` names other columns the header sorts with its own buttons so its `aria-sort` reports them. Other resizable columns get a window-splitter handle that resizes by dragging, by the arrow keys, Home, and End, and resets on double-click. Set `columnResizeMode: "onChange"` so columns follow the pointer while dragging; TanStack's default `"onEnd"` resizes only on release. Widths change through CSS variables, so a `useTable` selector can omit `columnSizing` and `columnResizing` to keep resizing from rendering rows. `renderRow` receives each row and its measurement props; spread the props onto a `TableRow` and render `DataGridCells` inside it to wrap rows in menus or drag sources. `retainedRowIds` keeps rows mounted while they hold editors. `DataGridColumnOptions` shows, hides, and reorders the columns that allow hiding; its reset restores the table's initial visibility, order, and sizes.
308
308
 
309
+ Column `meta.filter` offers a column in `DataGridFilters`, hidden columns included. A `range` filter edits `[min, max]` bounds, `null` for an open end, for `filterFn: "inNumberRange"`; its inputs suggest the range of the rows the other filters leave, formatted through the filter's `Intl.NumberFormatOptions`. An `options` filter chooses among labelled string values, one or several, listed in its `options` or, when they depend on runtime data, in the `options` prop of `DataGridFilters` and `DataGridFilterSummary` keyed by column ID, for `filterFn: "arrHas"` (one value per row), `"arrIncludesSome"` (an array per row), or a custom `filterFn`; each option counts the rows the other filters leave with that value, so a column whose rows hold several values or values in another form supplies them through `getUniqueValues`. Column filters combine with each other and with the global filter. `DataGridFilterSummary` lists the active filters with buttons that remove them, and both controls clear every column filter at once.
310
+
309
311
  `StarRating` takes a controlled numeric `value` from 0 to 5, `onValueChange`, and an accessible `label`. Its native radio buttons support keyboard selection and an Unrated option to clear the rating. Set `disabled` while saving. `Avatar shape="square"` displays square artwork with matching image, fallback, and border corners.
310
312
 
311
313
  `DialogContent size="wide"` uses a desktop maximum width of 576px; `size="narrow"` uses 192px, and the default uses 384px. Dialogs remain bounded by the viewport. `FieldGroup columns={2}` arranges fields in two columns on desktop and one on mobile.
@@ -166,7 +166,7 @@ Reviewed source: https://github.com/keenthemes/reui/tree/067aa0dc7f8bbfec1cd76fc
166
166
 
167
167
  ## TanStack Table examples
168
168
 
169
- VirtualDataGrid and DataGridColumnOptions follow the MIT-licensed TanStack Table React examples for virtualized rows, performant column resizing through CSS variables, column ordering, and column visibility. The package implementation, styling, keyboard resizing and behavioral tests are package-owned.
169
+ VirtualDataGrid, DataGridColumnOptions, and DataGridFilters follow the MIT-licensed TanStack Table React examples for virtualized rows, performant column resizing through CSS variables, column ordering, column visibility, and faceted filters. The package implementation, styling, keyboard resizing and behavioral tests are package-owned.
170
170
 
171
171
  Reviewed source: https://github.com/TanStack/table/tree/main/examples/react
172
172
 
@@ -0,0 +1,397 @@
1
+ import {
2
+ useDensity
3
+ } from "./chunk-e6hk39ev.js";
4
+ import {
5
+ usePortalContainer2
6
+ } from "./chunk-j89xg1ak.js";
7
+ import {
8
+ usePortalNode,
9
+ PortalProvider2
10
+ } from "./chunk-aa7m22zj.js";
11
+ import {
12
+ cn2
13
+ } from "./chunk-cp2m7y7v.js";
14
+ import {
15
+ Button2
16
+ } from "./chunk-q7p28b89.js";
17
+ import {
18
+ InputGroup2,
19
+ InputGroupAddon2,
20
+ InputGroupButton2,
21
+ InputGroupInput2
22
+ } from "./chunk-57jj9v64.js";
23
+
24
+ // src/components/Combobox.tsx
25
+ import { useDirection } from "@base-ui/react/direction-provider";
26
+ import { Combobox as ComboboxPrimitive } from "@base-ui/react/combobox";
27
+ import { ChevronDownIcon, XIcon, CheckIcon } from "lucide-react";
28
+ import { jsx, jsxs } from "react/jsx-runtime";
29
+ var Combobox2 = ComboboxPrimitive.Root;
30
+ function ComboboxValue2({ ...props }) {
31
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Value, {
32
+ ...props
33
+ });
34
+ }
35
+ function ComboboxTrigger2({ density, className, children, ...props }) {
36
+ return /* @__PURE__ */ jsxs(ComboboxPrimitive.Trigger, {
37
+ "data-density": density,
38
+ "data-slot": "combobox-trigger",
39
+ className: (state) => cn2("[&_svg:not([class*='size-'])]:size-4", typeof className === "function" ? className(state) : className),
40
+ ...props,
41
+ children: [
42
+ children,
43
+ /* @__PURE__ */ jsx(ChevronDownIcon, {
44
+ className: "pointer-events-none size-4 text-muted-foreground"
45
+ })
46
+ ]
47
+ });
48
+ }
49
+ function ComboboxClear({ density, className, ...props }) {
50
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Clear, {
51
+ "data-density": density,
52
+ "data-slot": "combobox-clear",
53
+ render: /* @__PURE__ */ jsx(InputGroupButton2, {
54
+ variant: "ghost",
55
+ size: "icon-xs"
56
+ }),
57
+ className: (state) => cn2(typeof className === "function" ? className(state) : className),
58
+ ...props,
59
+ children: /* @__PURE__ */ jsx(XIcon, {
60
+ className: "pointer-events-none"
61
+ })
62
+ });
63
+ }
64
+ function ComboboxInput2({
65
+ density,
66
+ className,
67
+ children,
68
+ disabled = false,
69
+ showTrigger = true,
70
+ showClear = false,
71
+ frameClassName,
72
+ triggerLabel = "Open popup",
73
+ clearLabel = "Clear selection",
74
+ ...props
75
+ }) {
76
+ return /* @__PURE__ */ jsxs(InputGroup2, {
77
+ density,
78
+ className: cn2("w-auto", frameClassName),
79
+ children: [
80
+ /* @__PURE__ */ jsx(ComboboxPrimitive.Input, {
81
+ disabled,
82
+ className,
83
+ render: /* @__PURE__ */ jsx(InputGroupInput2, {}),
84
+ ...props
85
+ }),
86
+ /* @__PURE__ */ jsxs(InputGroupAddon2, {
87
+ align: "inline-end",
88
+ children: [
89
+ showTrigger && /* @__PURE__ */ jsx(InputGroupButton2, {
90
+ size: "icon-xs",
91
+ variant: "ghost",
92
+ render: /* @__PURE__ */ jsx(ComboboxTrigger2, {}),
93
+ "aria-label": triggerLabel,
94
+ "data-density": density,
95
+ "data-slot": "input-group-button",
96
+ className: "group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent",
97
+ disabled
98
+ }),
99
+ showClear && /* @__PURE__ */ jsx(ComboboxClear, {
100
+ disabled,
101
+ "aria-label": clearLabel
102
+ })
103
+ ]
104
+ }),
105
+ children
106
+ ]
107
+ });
108
+ }
109
+ function ComboboxContent2({
110
+ density,
111
+ className,
112
+ side = "bottom",
113
+ sideOffset = 6,
114
+ align = "start",
115
+ alignOffset = 0,
116
+ anchor,
117
+ ...props
118
+ }) {
119
+ const resolvedDensity = useDensity(density);
120
+ const direction = useDirection();
121
+ const container = usePortalContainer2();
122
+ const portal = usePortalNode();
123
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Portal, {
124
+ container,
125
+ ref: portal.ref,
126
+ children: /* @__PURE__ */ jsx(PortalProvider2, {
127
+ container: portal.node,
128
+ children: /* @__PURE__ */ jsx(ComboboxPrimitive.Positioner, {
129
+ side,
130
+ sideOffset,
131
+ align,
132
+ alignOffset,
133
+ anchor,
134
+ className: "isolate ",
135
+ children: /* @__PURE__ */ jsx(ComboboxPrimitive.Popup, {
136
+ dir: direction,
137
+ "data-density": resolvedDensity,
138
+ "data-slot": "combobox-content",
139
+ "data-chips": !!anchor,
140
+ className: (state) => cn2("group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-md bg-popover text-popover-foreground border border-frame-edge shadow-frame duration-120 data-[chips=true]:min-w-(--anchor-width) *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-control *:data-[slot=input-group]:border-input/30 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:shadow-none data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 motion-reduce:data-open:animate-none motion-reduce:data-closed:animate-none", typeof className === "function" ? className(state) : className),
141
+ ...props
142
+ })
143
+ })
144
+ })
145
+ });
146
+ }
147
+ function ComboboxList2({ density, className, ...props }) {
148
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.List, {
149
+ "data-density": density,
150
+ "data-slot": "combobox-list",
151
+ className: (state) => cn2("no-scrollbar max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0", typeof className === "function" ? className(state) : className),
152
+ ...props
153
+ });
154
+ }
155
+ function ComboboxItem2({ density, className, children, ...props }) {
156
+ return /* @__PURE__ */ jsxs(ComboboxPrimitive.Item, {
157
+ "data-density": density,
158
+ "data-slot": "combobox-item",
159
+ className: (state) => cn2("relative flex w-full cursor-default items-center gap-2 rounded-md py-1 pe-8 ps-1.5 text-sm outline-hidden select-none data-highlighted:bg-accent data-highlighted:text-accent-foreground not-data-[variant=destructive]:data-highlighted:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", typeof className === "function" ? className(state) : className),
160
+ ...props,
161
+ children: [
162
+ children,
163
+ /* @__PURE__ */ jsx(ComboboxPrimitive.ItemIndicator, {
164
+ render: /* @__PURE__ */ jsx("span", {
165
+ className: "pointer-events-none absolute end-2 flex size-4 items-center justify-center"
166
+ }),
167
+ children: /* @__PURE__ */ jsx(CheckIcon, {
168
+ className: "pointer-events-none"
169
+ })
170
+ })
171
+ ]
172
+ });
173
+ }
174
+ function ComboboxGroup2({ density, className, ...props }) {
175
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Group, {
176
+ "data-density": density,
177
+ "data-slot": "combobox-group",
178
+ className: (state) => cn2(typeof className === "function" ? className(state) : className),
179
+ ...props
180
+ });
181
+ }
182
+ function ComboboxLabel2({ density, className, ...props }) {
183
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.GroupLabel, {
184
+ "data-density": density,
185
+ "data-slot": "combobox-label",
186
+ className: (state) => cn2("px-2 py-1.5 text-xs text-muted-foreground", typeof className === "function" ? className(state) : className),
187
+ ...props
188
+ });
189
+ }
190
+ function ComboboxCollection2({ ...props }) {
191
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Collection, {
192
+ ...props
193
+ });
194
+ }
195
+ function ComboboxEmpty2({ density, className, ...props }) {
196
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Empty, {
197
+ "data-density": density,
198
+ "data-slot": "combobox-empty",
199
+ className: (state) => cn2("flex w-full justify-center py-2 empty:p-0 text-center text-sm text-muted-foreground", typeof className === "function" ? className(state) : className),
200
+ ...props
201
+ });
202
+ }
203
+ function ComboboxSeparator2({ density, className, ...props }) {
204
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Separator, {
205
+ "data-density": density,
206
+ "data-slot": "combobox-separator",
207
+ className: (state) => cn2("-mx-1 my-1 h-px bg-border", typeof className === "function" ? className(state) : className),
208
+ ...props
209
+ });
210
+ }
211
+ function ComboboxChips2({ density, className, ...props }) {
212
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Chips, {
213
+ "data-density": density,
214
+ "data-slot": "combobox-chips",
215
+ className: (state) => cn2("flex min-h-control flex-wrap items-center gap-1 rounded-sm border border-input bg-transparent bg-clip-padding px-control-x py-px text-sm transition-colors focus-within:border-ring focus-within:ring-1 focus-within:ring-ring has-aria-invalid:border-destructive has-aria-invalid:ring-3 has-aria-invalid:ring-destructive has-data-[slot=combobox-chip]:px-1", typeof className === "function" ? className(state) : className),
216
+ ...props
217
+ });
218
+ }
219
+ function ComboboxChip2({
220
+ density,
221
+ className,
222
+ children,
223
+ showRemove = true,
224
+ removeLabel = "Remove item",
225
+ ...props
226
+ }) {
227
+ return /* @__PURE__ */ jsxs(ComboboxPrimitive.Chip, {
228
+ "data-density": density,
229
+ "data-slot": "combobox-chip",
230
+ className: (state) => cn2("flex h-tag w-fit items-center justify-center gap-1 rounded-sm bg-muted px-1.5 text-xs font-medium whitespace-nowrap text-foreground has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50 has-data-[slot=combobox-chip-remove]:pe-0", typeof className === "function" ? className(state) : className),
231
+ ...props,
232
+ children: [
233
+ children,
234
+ showRemove && /* @__PURE__ */ jsx(ComboboxPrimitive.ChipRemove, {
235
+ render: /* @__PURE__ */ jsx(Button2, {
236
+ variant: "ghost",
237
+ size: "icon-xs"
238
+ }),
239
+ className: "size-tag -ms-1 opacity-50 hover:opacity-100",
240
+ "data-slot": "combobox-chip-remove",
241
+ "aria-label": removeLabel,
242
+ children: /* @__PURE__ */ jsx(XIcon, {
243
+ className: "pointer-events-none"
244
+ })
245
+ })
246
+ ]
247
+ });
248
+ }
249
+ function ComboboxChipsInput2({ density, className, ...props }) {
250
+ return /* @__PURE__ */ jsx(ComboboxPrimitive.Input, {
251
+ "data-density": density,
252
+ "data-slot": "combobox-chip-input",
253
+ className: (state) => cn2("h-tag min-w-16 flex-1 py-0 text-sm leading-none outline-none", typeof className === "function" ? className(state) : className),
254
+ ...props
255
+ });
256
+ }
257
+
258
+ // src/hooks/useComboboxAnchor.ts
259
+ import { useRef } from "react";
260
+ function useComboboxAnchor2() {
261
+ return useRef(null);
262
+ }
263
+
264
+ // src/components/ScrollArea.tsx
265
+ import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
266
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
267
+ function ScrollArea2({
268
+ density,
269
+ className,
270
+ children,
271
+ scrollbars = /* @__PURE__ */ jsx2(ScrollBar2, {}),
272
+ ...props
273
+ }) {
274
+ return /* @__PURE__ */ jsxs2(ScrollAreaPrimitive.Root, {
275
+ "data-density": density,
276
+ "data-slot": "scroll-area",
277
+ className: (state) => cn2("relative flex min-h-0 flex-col", typeof className === "function" ? className(state) : className),
278
+ ...props,
279
+ children: [
280
+ /* @__PURE__ */ jsx2(ScrollAreaPrimitive.Viewport, {
281
+ "data-slot": "scroll-area-viewport",
282
+ className: "size-full min-h-0 flex-1 rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-1",
283
+ children
284
+ }),
285
+ scrollbars,
286
+ /* @__PURE__ */ jsx2(ScrollAreaPrimitive.Corner, {})
287
+ ]
288
+ });
289
+ }
290
+ function ScrollBar2({ density, className, orientation = "vertical", ...props }) {
291
+ return /* @__PURE__ */ jsx2(ScrollAreaPrimitive.Scrollbar, {
292
+ "data-density": density,
293
+ "data-slot": "scroll-area-scrollbar",
294
+ "data-orientation": orientation,
295
+ orientation,
296
+ className: (state) => cn2("flex touch-none p-px transition-colors select-none data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:border-t data-[orientation=horizontal]:border-t-transparent data-[orientation=vertical]:w-2.5 data-[orientation=vertical]:border-s data-[orientation=vertical]:border-s-transparent", typeof className === "function" ? className(state) : className),
297
+ ...props,
298
+ children: /* @__PURE__ */ jsx2(ScrollAreaPrimitive.Thumb, {
299
+ "data-slot": "scroll-area-thumb",
300
+ className: "relative flex-1 rounded-full bg-border"
301
+ })
302
+ });
303
+ }
304
+
305
+ // src/components/NumberField.tsx
306
+ import { NumberField as NumberFieldPrimitive } from "@base-ui/react/number-field";
307
+ import { MinusIcon, PlusIcon, MoveHorizontalIcon } from "lucide-react";
308
+ import { jsx as jsx3 } from "react/jsx-runtime";
309
+ function NumberField2({ density, className, ...props }) {
310
+ return /* @__PURE__ */ jsx3(NumberFieldPrimitive.Root, {
311
+ "data-density": density,
312
+ "data-slot": "number-field",
313
+ className: (state) => cn2("flex min-w-0 flex-col gap-field-gap", typeof className === "function" ? className(state) : className),
314
+ ...props
315
+ });
316
+ }
317
+ function NumberFieldGroup2({
318
+ density,
319
+ className,
320
+ ...props
321
+ }) {
322
+ return /* @__PURE__ */ jsx3(NumberFieldPrimitive.Group, {
323
+ "data-density": density,
324
+ "data-slot": "number-field-group",
325
+ className: (state) => cn2("flex h-control min-w-0 items-stretch rounded-sm border border-input bg-secondary text-foreground transition-colors focus-within:border-ring focus-within:ring-1 focus-within:ring-ring data-disabled:opacity-50 motion-reduce:transition-none", typeof className === "function" ? className(state) : className),
326
+ ...props
327
+ });
328
+ }
329
+ function NumberFieldInput2({
330
+ density,
331
+ className,
332
+ ...props
333
+ }) {
334
+ return /* @__PURE__ */ jsx3(NumberFieldPrimitive.Input, {
335
+ "data-density": density,
336
+ "data-slot": "number-field-input",
337
+ className: (state) => cn2("min-w-0 flex-1 bg-transparent px-control-x text-center text-sm tabular-nums outline-none disabled:cursor-not-allowed", typeof className === "function" ? className(state) : className),
338
+ ...props
339
+ });
340
+ }
341
+ function NumberFieldDecrement2({
342
+ density,
343
+ className,
344
+ children = /* @__PURE__ */ jsx3(MinusIcon, {}),
345
+ ...props
346
+ }) {
347
+ return /* @__PURE__ */ jsx3(NumberFieldPrimitive.Decrement, {
348
+ "data-density": density,
349
+ "data-slot": "number-field-decrement",
350
+ className: (state) => cn2("flex w-control shrink-0 items-center justify-center rounded-s-sm outline-none hover:bg-muted focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-3.5", typeof className === "function" ? className(state) : className),
351
+ ...props,
352
+ children
353
+ });
354
+ }
355
+ function NumberFieldIncrement2({
356
+ density,
357
+ className,
358
+ children = /* @__PURE__ */ jsx3(PlusIcon, {}),
359
+ ...props
360
+ }) {
361
+ return /* @__PURE__ */ jsx3(NumberFieldPrimitive.Increment, {
362
+ "data-density": density,
363
+ "data-slot": "number-field-increment",
364
+ className: (state) => cn2("flex w-control shrink-0 items-center justify-center rounded-e-sm outline-none hover:bg-muted focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-3.5", typeof className === "function" ? className(state) : className),
365
+ ...props,
366
+ children
367
+ });
368
+ }
369
+ function NumberFieldScrubArea2({
370
+ density,
371
+ className,
372
+ ...props
373
+ }) {
374
+ return /* @__PURE__ */ jsx3(NumberFieldPrimitive.ScrubArea, {
375
+ "data-density": density,
376
+ "data-slot": "number-field-scrub-area",
377
+ className: (state) => cn2("flex w-fit cursor-ew-resize items-center gap-control-gap text-sm font-medium", typeof className === "function" ? className(state) : className),
378
+ ...props
379
+ });
380
+ }
381
+ function NumberFieldScrubAreaCursor2({
382
+ density,
383
+ className,
384
+ children = /* @__PURE__ */ jsx3(MoveHorizontalIcon, {}),
385
+ ...props
386
+ }) {
387
+ const resolvedDensity = useDensity(density);
388
+ return /* @__PURE__ */ jsx3(NumberFieldPrimitive.ScrubAreaCursor, {
389
+ "data-density": resolvedDensity,
390
+ "data-slot": "number-field-scrub-area-cursor",
391
+ className: (state) => cn2("z-50 font-sans text-sm text-foreground [&_svg]:size-5", typeof className === "function" ? className(state) : className),
392
+ ...props,
393
+ children
394
+ });
395
+ }
396
+
397
+ export { Combobox2, ComboboxValue2, ComboboxTrigger2, ComboboxInput2, ComboboxContent2, ComboboxList2, ComboboxItem2, ComboboxGroup2, ComboboxLabel2, ComboboxCollection2, ComboboxEmpty2, ComboboxSeparator2, ComboboxChips2, ComboboxChip2, ComboboxChipsInput2, useComboboxAnchor2, ScrollArea2, ScrollBar2, NumberField2, NumberFieldGroup2, NumberFieldInput2, NumberFieldDecrement2, NumberFieldIncrement2, NumberFieldScrubArea2, NumberFieldScrubAreaCursor2 };