@vvedantb/ui 0.16.0 → 0.16.2

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
@@ -642,6 +642,8 @@ The root `cn` knows these are radius classes, so `cn("rounded-lg", "rounded-menu
642
642
  | `DropdownMenu` and `ContextMenu` item, sub-trigger, checkbox item and radio item | `rounded-md`, `calc(var(--radius) - 2px)` (14px) | `rounded-menu-item` (8px) |
643
643
  | Menu surface | `rounded-lg` (16px) | unchanged |
644
644
 
645
+ From 0.16.2, `Select` and `RadixSelect` items (`rounded-lg`, 16px), `CommandItem` (`rounded-md`, 14px) and `ComposerSlashMenu` rows (`rounded-lg`, 16px) also use `rounded-menu-item` (8px).
646
+
645
647
  ### Sidebar panel nav rows
646
648
 
647
649
  Rows in the panel beside the rail. Rail tiles are unchanged.
@@ -1002,7 +1004,7 @@ import { DatePicker, DateTimePicker, MonthPicker } from "@vvedantb/ui";
1002
1004
  - `MonthPicker`: `value` "YYYY-MM" or "", with year navigation and a month grid. `min` and `max` are "YYYY-MM".
1003
1005
  - `Calendar`: the styled `DayPicker` for custom layouts (every `DayPicker` prop). `parseDateValue` and `formatDateValue` convert between "YYYY-MM-DD" and a local `Date`.
1004
1006
 
1005
- ## Slider (0.16.0)
1007
+ ## Slider (0.16.0, dark contrast and className props 0.16.1)
1006
1008
 
1007
1009
  shadcn's slider on `@radix-ui/react-slider` (a peer dependency), with package tokens.
1008
1010
 
@@ -1014,7 +1016,7 @@ import { LabeledSliderRow, Slider } from "@vvedantb/ui";
1014
1016
  <LabeledSliderRow id="temperature" label="Temperature" value={temp} onValueChange={setTemp} max={2} step={0.1} formatValue={(v) => v.map((n) => n.toFixed(1)).join("–")} minLabel="Precise" maxLabel="Creative" />
1015
1017
  ```
1016
1018
 
1017
- - `Slider`: every Radix `Root` prop (`value`, `defaultValue`, `min`, `max`, `step`, `orientation`, `disabled`, `onValueChange`, `onValueCommit`, and so on). It renders one thumb per value, so `[n]` gives one thumb and `[a, b]` a range. The track is `bg-default`, the range `bg-primary`, and the thumb a `size-4` circle on `bg-background` with the `Switch` focus ring. Disabled dims to 50%. A vertical slider needs a height from its parent or `className` (default `min-h-40`). The ref goes to `Root`.
1019
+ - `Slider`: every Radix `Root` prop (`value`, `defaultValue`, `min`, `max`, `step`, `orientation`, `disabled`, `onValueChange`, `onValueCommit`, and so on). It renders one thumb per value, so `[n]` gives one thumb and `[a, b]` a range. The track is `bg-default` (`dark:bg-muted/40`), the range `bg-primary`, and the thumb a `size-4` circle on `bg-background` with `border-border` (`dark:bg-foreground dark:border-muted`, a light thumb in dark mode) and the `Switch` focus ring. `trackClassName`, `rangeClassName` and `thumbClassName` merge after the defaults, so caller classes win; override a `dark:` default with a `dark:` class. Disabled dims to 50%. A vertical slider needs a height from its parent or `className` (default `min-h-40`). The ref goes to `Root`.
1018
1020
  - Names: `id`, `aria-label`, `aria-labelledby` and `aria-valuetext` go to the first thumb, the focusable `role="slider"` element, not `Root`. `thumbLabels` sets `aria-label` per thumb and wins over `aria-label` on the first. Without a name, Radix labels a two-thumb range "Minimum" and "Maximum". The thumb is a `<span>`, so `<Label htmlFor>` does not name it; pass `aria-labelledby` with the label's `id`.
1019
1021
  - `LabeledSliderRow`: the `LabeledSwitchRow` layout with the slider below. `id`, `label`, `description`, `icon`, `value`, `onValueChange`, `onValueCommit`, `min`, `max`, `step`, `disabled`, `thumbLabels`, `className`. `formatValue` sets the right-aligned value (default: values joined by an en dash). `minLabel` and `maxLabel` add captions under the ends. The label names the first thumb through `aria-labelledby`, unless `thumbLabels` is set.
1020
1022
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vvedantb/ui",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "license": "MIT",
5
5
  "description": "Shared React 19 UI for web apps: one JavaScript entry (primitives, shell pieces, app helpers including the Convex and Clerk provider, VITE env parsing and ensure-user, artifact viewers over the @vvedantb/server artifacts core, native tokens), design-token CSS, shared Tailwind v4 CSS and a Tailwind preset.",
6
6
  "type": "module",
@@ -108,7 +108,7 @@ export function ComposerSlashMenu({
108
108
  onSelectItem(item);
109
109
  }}
110
110
  className={
111
- "mx-1 flex w-[calc(100%-0.5rem)] min-w-0 items-center rounded-lg px-2 py-1.5 text-left text-sm max-sm:py-2.5 " +
111
+ "mx-1 flex w-[calc(100%-0.5rem)] min-w-0 items-center rounded-menu-item px-2 py-1.5 text-left text-sm max-sm:py-2.5 " +
112
112
  "transition-[background-color] active:scale-[0.99] active:duration-100 active:ease-out " +
113
113
  (isSelected
114
114
  ? "bg-primary/15 font-medium text-foreground dark:bg-primary/25"
@@ -28,7 +28,7 @@ Command.displayName = CommandPrimitive.displayName;
28
28
  // The list is pinned rather than `max-h`: a palette that resizes on every
29
29
  // keystroke shifts the whole dialog under the cursor.
30
30
  const commandDialogPinnedClass =
31
- "[&_[cmdk-list]]:h-80 [&_[cmdk-list]]:max-h-[60dvh] [&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-widest [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-1.5 [&_[cmdk-input-wrapper]_svg]:h-4 [&_[cmdk-input-wrapper]_svg]:w-4 [&_[cmdk-input]]:h-11 [&_[cmdk-item]]:rounded-md [&_[cmdk-item]]:px-2.5 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4";
31
+ "[&_[cmdk-list]]:h-80 [&_[cmdk-list]]:max-h-[60dvh] [&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-widest [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-1.5 [&_[cmdk-input-wrapper]_svg]:h-4 [&_[cmdk-input-wrapper]_svg]:w-4 [&_[cmdk-input]]:h-11 [&_[cmdk-item]]:rounded-menu-item [&_[cmdk-item]]:px-2.5 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4";
32
32
 
33
33
  // The list sizes itself and items keep the caller's styling.
34
34
  const commandDialogAutoClass =
@@ -155,7 +155,7 @@ const CommandItem = React.forwardRef<
155
155
  <CommandPrimitive.Item
156
156
  ref={ref}
157
157
  className={cn(
158
- "relative flex cursor-default gap-2 select-none items-center rounded-md px-2.5 py-2 text-sm outline-none transition-colors data-[disabled=true]:pointer-events-none data-[selected=true]:bg-surface-tertiary/80 data-[selected=true]:text-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
158
+ "relative flex cursor-default gap-2 select-none items-center rounded-menu-item px-2.5 py-2 text-sm outline-none transition-colors data-[disabled=true]:pointer-events-none data-[selected=true]:bg-surface-tertiary/80 data-[selected=true]:text-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
159
159
  className,
160
160
  )}
161
161
  {...props}
@@ -117,7 +117,7 @@ function SelectItem({
117
117
  <SelectPrimitive.Item
118
118
  data-slot="select-item"
119
119
  className={cn(
120
- "[&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-pointer select-none items-center gap-2 rounded-lg py-2 pl-2.5 pr-8 text-sm outline-hidden [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 last:[span]:*:flex last:[span]:*:items-center last:[span]:*:gap-2",
120
+ "[&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-pointer select-none items-center gap-2 rounded-menu-item py-2 pl-2.5 pr-8 text-sm outline-hidden [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 last:[span]:*:flex last:[span]:*:items-center last:[span]:*:gap-2",
121
121
  menuItemClass,
122
122
  className,
123
123
  )}
package/src/ui/select.tsx CHANGED
@@ -122,7 +122,7 @@ const SelectItem = React.forwardRef<
122
122
  <SelectPrimitive.Item
123
123
  ref={ref}
124
124
  className={cn(
125
- "relative flex w-full cursor-pointer select-none items-center rounded-lg py-2 pl-2.5 pr-8 text-sm outline-none transition-[background-color,color] focus:bg-default focus:text-foreground data-[highlighted]:bg-default data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
125
+ "relative flex w-full cursor-pointer select-none items-center rounded-menu-item py-2 max-sm:min-h-10 pl-2.5 pr-8 text-sm outline-none transition-[background-color,color] focus:bg-default focus:text-foreground data-[highlighted]:bg-default data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
126
126
  className,
127
127
  )}
128
128
  {...props}
package/src/ui/slider.tsx CHANGED
@@ -5,6 +5,12 @@ import { cn } from "../utils/cn";
5
5
  type SliderProps = React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> & {
6
6
  /** Accessible name per thumb, by index. Wins over `aria-label` on the first thumb. */
7
7
  thumbLabels?: string[];
8
+ /** Classes for the track, merged after the defaults so they win (`bg-default dark:bg-muted/40`). */
9
+ trackClassName?: string;
10
+ /** Classes for the filled range, merged after the defaults so they win (`bg-primary`). */
11
+ rangeClassName?: string;
12
+ /** Classes for every thumb, merged after the defaults so they win (`bg-background dark:bg-foreground dark:border-muted`). */
13
+ thumbClassName?: string;
8
14
  };
9
15
 
10
16
  // `id`, `aria-label`, `aria-labelledby` and `aria-valuetext` go to the first
@@ -19,6 +25,9 @@ const Slider = React.forwardRef<React.ComponentRef<typeof SliderPrimitive.Root>,
19
25
  "aria-labelledby": ariaLabelledBy,
20
26
  "aria-valuetext": ariaValueText,
21
27
  thumbLabels,
28
+ trackClassName,
29
+ rangeClassName,
30
+ thumbClassName,
22
31
  ...props
23
32
  },
24
33
  ref,
@@ -33,8 +42,18 @@ const Slider = React.forwardRef<React.ComponentRef<typeof SliderPrimitive.Root>,
33
42
  {...props}
34
43
  ref={ref}
35
44
  >
36
- <SliderPrimitive.Track className="relative grow overflow-hidden rounded-full bg-default data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5">
37
- <SliderPrimitive.Range className="absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full" />
45
+ <SliderPrimitive.Track
46
+ className={cn(
47
+ "relative grow overflow-hidden rounded-full bg-default dark:bg-muted/40 data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5",
48
+ trackClassName,
49
+ )}
50
+ >
51
+ <SliderPrimitive.Range
52
+ className={cn(
53
+ "absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full",
54
+ rangeClassName,
55
+ )}
56
+ />
38
57
  </SliderPrimitive.Track>
39
58
  {Array.from({ length: count }, (_, i) => (
40
59
  <SliderPrimitive.Thumb
@@ -43,7 +62,10 @@ const Slider = React.forwardRef<React.ComponentRef<typeof SliderPrimitive.Root>,
43
62
  aria-label={thumbLabels?.[i] ?? (i === 0 ? ariaLabel : undefined)}
44
63
  aria-labelledby={i === 0 ? ariaLabelledBy : undefined}
45
64
  aria-valuetext={i === 0 ? ariaValueText : undefined}
46
- className="block size-4 shrink-0 rounded-full border border-border bg-background shadow-sm transition-[box-shadow] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring data-[disabled]:cursor-not-allowed"
65
+ className={cn(
66
+ "block size-4 shrink-0 rounded-full border border-border bg-background shadow-sm transition-[box-shadow] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring data-[disabled]:cursor-not-allowed dark:border-muted dark:bg-foreground",
67
+ thumbClassName,
68
+ )}
47
69
  />
48
70
  ))}
49
71
  </SliderPrimitive.Root>