torch-glare 2.1.4 → 2.1.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.
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Fragment, useMemo, useState } from "react";
3
+ import { useMemo, useState } from "react";
4
4
  import {
5
5
  X,
6
6
  Settings as SettingsIcon,
@@ -7,6 +7,7 @@ import {
7
7
  useMemo,
8
8
  useRef,
9
9
  useState,
10
+ type ElementType,
10
11
  type ReactNode,
11
12
  } from "react";
12
13
  import { List, LayoutGrid, Inbox as InboxIcon, Network } from "lucide-react";
@@ -61,6 +62,12 @@ export type DataViewsLayoutProps = {
61
62
  addNewLabel?: string;
62
63
 
63
64
  inboxItemHref?: (item: DynamicRecord, id: any) => string;
65
+ /**
66
+ * Component used to render inbox item links when `inboxItemHref` is set.
67
+ * Defaults to a plain `<a>` (full-page navigation). Pass your router's link
68
+ * (e.g. Next.js `Link`, React Router `Link`) for client-side navigation.
69
+ */
70
+ inboxLinkComponent?: ElementType;
64
71
  inboxSelectedId?: any;
65
72
  inboxRenderDetail?: (item: DynamicRecord | null) => ReactNode;
66
73
 
@@ -108,6 +115,7 @@ export const DataViewsLayout = forwardRef<HTMLDivElement, DataViewsLayoutProps>(
108
115
  onAddNew,
109
116
  addNewLabel,
110
117
  inboxItemHref,
118
+ inboxLinkComponent,
111
119
  inboxSelectedId,
112
120
  inboxRenderDetail,
113
121
  searchValue,
@@ -276,6 +284,7 @@ export const DataViewsLayout = forwardRef<HTMLDivElement, DataViewsLayoutProps>(
276
284
  onFilterChange={setFilterState}
277
285
  showFilters={false}
278
286
  itemHref={inboxItemHref}
287
+ linkComponent={inboxLinkComponent}
279
288
  selectedItemId={inboxSelectedId}
280
289
  renderDetail={inboxRenderDetail}
281
290
  />
@@ -222,7 +222,8 @@ export function FilterPanel({
222
222
  <Badge
223
223
  {...countBadge}
224
224
  label={String(totalFilters)}
225
- className="h-5 min-w-[20px] rounded-full p-0 text-xs"
225
+ showIcon={false}
226
+ className="h-5 w-5 min-w-0 justify-center rounded-full p-0 text-xs"
226
227
  size="XS"
227
228
  />
228
229
  )}
@@ -270,9 +271,9 @@ export function FilterPanel({
270
271
  <Badge
271
272
  {...countBadge}
272
273
  label={String(totalFilters)}
273
- className="h-5 min-w-[20px] rounded-full p-0 text-xs"
274
+ showIcon={false}
275
+ className="h-5 w-5 min-w-0 justify-center rounded-full p-0 text-xs"
274
276
  size="XS"
275
-
276
277
  />
277
278
  )}
278
279
  </div>
@@ -1,6 +1,12 @@
1
1
  "use client";
2
2
 
3
- import { useEffect, useMemo, useState, type ReactNode } from "react";
3
+ import {
4
+ useEffect,
5
+ useMemo,
6
+ useState,
7
+ type ElementType,
8
+ type ReactNode,
9
+ } from "react";
4
10
  import { Badge } from "../Badge";
5
11
  import { FilterPanel } from "./FilterPanel";
6
12
  import {
@@ -57,6 +63,12 @@ export type InboxViewProps = {
57
63
  onFilterChange?: (filters: FilterState) => void;
58
64
  showFilters?: boolean;
59
65
  itemHref?: (item: DynamicRecord, id: any) => string;
66
+ /**
67
+ * Component used to render each item's link when `itemHref` is set. Defaults
68
+ * to a plain `<a>` (full-page navigation). Pass your router's link
69
+ * (e.g. Next.js `Link`, React Router `Link`) for client-side navigation.
70
+ */
71
+ linkComponent?: ElementType;
60
72
  selectedItemId?: any;
61
73
  renderDetail?: (item: DynamicRecord | null) => ReactNode;
62
74
  };
@@ -100,6 +112,7 @@ export function InboxView({
100
112
  onFilterChange,
101
113
  showFilters = true,
102
114
  itemHref,
115
+ linkComponent,
103
116
  selectedItemId,
104
117
  renderDetail,
105
118
  }: InboxViewProps) {
@@ -350,6 +363,7 @@ export function InboxView({
350
363
  selected={selected}
351
364
  onSelect={() => handleSelectItem(item)}
352
365
  href={itemHref?.(item, itemId)}
366
+ linkComponent={linkComponent}
353
367
  />
354
368
  );
355
369
  })}
@@ -114,6 +114,12 @@ const DrawerContent = React.forwardRef<
114
114
  )}
115
115
  >
116
116
  <div
117
+ // The content surface is always light (#F0F0F0) regardless of the
118
+ // page theme, so pin a light theme here. This makes theme-aware
119
+ // content tokens (DrawerTitle/Description and any consumer content)
120
+ // resolve to their dark-on-light values instead of following a dark
121
+ // page theme (which would render white-on-light = invisible).
122
+ data-theme="light"
117
123
  className={cn(
118
124
  "flex flex-1 flex-col gap-2 rounded-t-[16px] p-1.5 bg-[#F0F0F0] min-h-0",
119
125
  framed && "border border-[#D4D4D4] shadow-[inset_0_-4px_16px_rgba(0,0,0,0.1)]",
@@ -148,14 +154,18 @@ const DrawerHeader = ({
148
154
  DrawerHeader.displayName = "DrawerHeader";
149
155
 
150
156
  const drawerHeaderPane = cva(
151
- "flex items-center gap-2 rounded-[14px] border p-2 bg-[#131415] border-[#2C2D2E] shadow-[0_0_32px_2px_rgba(0,0,0,0.05)]",
157
+ // Dark pill. Force any DrawerTitle/Description inside it back to light text
158
+ // (their defaults are dark for the light content surface).
159
+ "flex items-center gap-2 rounded-[14px] border p-2 bg-[#131415] border-[#2C2D2E] shadow-[0_0_32px_2px_rgba(0,0,0,0.05)] [&_[data-slot=drawer-title]]:text-white [&_[data-slot=drawer-description]]:text-[#9FA0A1]",
152
160
  );
153
161
 
154
162
  const DrawerHeaderTitle = ({
155
163
  className,
156
164
  ...props
157
165
  }: React.HTMLAttributes<HTMLDivElement>) => (
158
- <div className={cn(drawerHeaderPane(), className)} {...props} />
166
+ // Dark surface pin a dark theme so any buttons/content inside resolve their
167
+ // theme tokens for dark (the surrounding content surface is data-theme=light).
168
+ <div data-theme="dark" className={cn(drawerHeaderPane(), className)} {...props} />
159
169
  );
160
170
  DrawerHeaderTitle.displayName = "DrawerHeaderTitle";
161
171
 
@@ -164,6 +174,7 @@ const DrawerHeaderActions = ({
164
174
  ...props
165
175
  }: React.HTMLAttributes<HTMLDivElement>) => (
166
176
  <div
177
+ data-theme="dark"
167
178
  className={cn(drawerHeaderPane(), "justify-end", className)}
168
179
  {...props}
169
180
  />
@@ -358,8 +369,12 @@ const DrawerTitle = React.forwardRef<
358
369
  >(({ className, ...props }, ref) => (
359
370
  <DrawerPrimitive.Title
360
371
  ref={ref}
372
+ data-slot="drawer-title"
373
+ // Dark text by default — the title usually sits on the light content
374
+ // surface. Inside the dark DrawerHeaderTitle pill it is flipped back to
375
+ // white via a descendant selector on `drawerHeaderPane`.
361
376
  className={cn(
362
- "typography-display-medium-medium uppercase text-white leading-none",
377
+ "typography-display-medium-medium uppercase text-content-presentation-global-primary leading-none",
363
378
  className,
364
379
  )}
365
380
  {...props}
@@ -373,7 +388,11 @@ const DrawerDescription = React.forwardRef<
373
388
  >(({ className, ...props }, ref) => (
374
389
  <DrawerPrimitive.Description
375
390
  ref={ref}
376
- className={cn("typography-body-small-regular text-[#9FA0A1]", className)}
391
+ data-slot="drawer-description"
392
+ className={cn(
393
+ "typography-body-small-regular text-content-presentation-action-light-secondary",
394
+ className,
395
+ )}
377
396
  {...props}
378
397
  />
379
398
  ));
package/dist/bin/index.js CHANGED
@@ -20,7 +20,8 @@ program
20
20
  program
21
21
  .command("add [component]")
22
22
  .description("Add a component interactively or install a specified one")
23
- .action((component) => add(component));
23
+ .option("-f, --force", "Overwrite the component if it already exists")
24
+ .action((component, options) => add(component, !!options.force));
24
25
  program
25
26
  .command("hook [hook]")
26
27
  .description("Add a hook interactively or install a specified one")
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../cli/bin/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;AAE9B,OAAO;KACJ,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,0DAA0D,CAAC;KACvE,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAEzC,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,qDAAqD,CAAC;KAClE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;AAEhD,OAAO;KACJ,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,CAAC,CAAC;AAE5D,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,sDAAsD,CAAC;KACnE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAEnC,OAAO;KACJ,OAAO,CAAC,qBAAqB,CAAC;KAC9B,WAAW,CAAC,yDAAyD,CAAC;KACtE,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,IAAI,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;AAEhE,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,GAAG,EAAE,CAAC,yBAAyB,EAAE,CAAC,CAAC;AAE7C,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;AAE5B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../cli/bin/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;AAE9B,OAAO;KACJ,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,0DAA0D,CAAC;KACvE,MAAM,CAAC,aAAa,EAAE,8CAA8C,CAAC;KACrE,MAAM,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAEnE,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,qDAAqD,CAAC;KAClE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;AAEhD,OAAO;KACJ,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,CAAC,CAAC;AAE5D,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,sDAAsD,CAAC;KACnE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAEnC,OAAO;KACJ,OAAO,CAAC,qBAAqB,CAAC;KAC9B,WAAW,CAAC,yDAAyD,CAAC;KACtE,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,IAAI,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;AAEhE,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,GAAG,EAAE,CAAC,yBAAyB,EAAE,CAAC,CAAC;AAE7C,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;AAE5B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -11,7 +11,22 @@ keywords: [data-views, layout, table, kanban, inbox, tree, multi-view, filter, s
11
11
 
12
12
  ## Installation
13
13
 
14
- The component is part of `torch-glare`. It depends on `@radix-ui/react-slider`, `react-day-picker`, `lucide-react`, and `vaul` (all already vendored by the library). No extra install needed.
14
+ ```bash
15
+ npx torch-glare@latest add DataViews
16
+ ```
17
+
18
+ The CLI transitively installs everything DataViews imports — the sibling views,
19
+ the `DataViewCard` layout, the `useDataViewsState` hook, the `dataViews` utils,
20
+ and the `TreeFolder` component — plus the 3rd-party deps it uses
21
+ (`@radix-ui/react-slider`, `react-day-picker`, `lucide-react`, `vaul`).
22
+
23
+ > **Badge version:** DataViews uses the current Badge API
24
+ > (`color` / `badgeStyle` / `showIcon`). If your project vendored an older
25
+ > `Badge.tsx` (with `variant` / `isSelected`), refresh it with
26
+ > `npx torch-glare@latest add Badge --force` and migrate call sites
27
+ > (`variant=` → `color=`, `isSelected`+`onUnselect` → `isClosable`+`onClose`).
28
+ > The Badge also needs `mapping-color-system-v4` tokens
29
+ > (`--background-presentation-badge-{color}-{subtle|solid}`) in your CSS.
15
30
 
16
31
  ## Import
17
32
 
@@ -140,6 +155,8 @@ Inbox auto-detects `isRead`, `isStarred`, `hasAttachment`, `priority`. Override
140
155
  | `views` | `ViewVisibility` | all on (tree auto) | Per-view toggle: `{ table?, kanban?, inbox?, tree? }`. Omitted keys default to `true` (Tree auto-hides without hierarchy). |
141
156
  | `kanbanGroupBy` | `string` | `"status"` | Dot-path to the field used for Kanban columns. |
142
157
  | `inboxConfig` | `InboxConfig` | auto-detected | Map of starred/read/attachment/priority field paths for Inbox. |
158
+ | `inboxItemHref` | `(item, id) => string` | — | When set, each Inbox row becomes a link to the returned href. |
159
+ | `inboxLinkComponent` | `ElementType` | `"a"` | Component used to render Inbox item links when `inboxItemHref` is set. Pass your router's link (Next.js `Link`, React Router `Link`) for client-side navigation; defaults to a plain `<a>` (full-page nav). |
143
160
  | `treeConfig` | `TreeConfig` | auto-detected | `childrenField`, `parentField`, `idField`, `nodeLabel`, `defaultExpanded`. |
144
161
  | `filterState` | `FilterState` | uncontrolled | Controlled filter state. Pair with `onFilterChange`. |
145
162
  | `onFilterChange` | `(state: FilterState) => void` | — | Fires when any filter changes. When provided, the layout is controlled. |