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.
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +1 -1
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +9 -0
- package/apps/lib/components/DataViews/FilterPanel.tsx +4 -3
- package/apps/lib/components/DataViews/InboxView.tsx +15 -1
- package/apps/lib/components/Drawer.tsx +23 -4
- package/dist/bin/index.js +2 -1
- package/dist/bin/index.js.map +1 -1
- package/docs/components/data-views-layout.md +18 -1
- package/docs/components/drawer.md +527 -668
- package/docs/components/inbox-view.md +159 -0
- package/docs/components/kanban-view.md +125 -0
- package/docs/components/table-view.md +131 -0
- package/docs/components/tree-view.md +136 -0
- package/docs/how-to/data-views-from-backend-response.md +191 -0
- package/package.json +3 -2
- package/apps/lib/components/DataViews/ARCHITECTURE.md +0 -439
|
@@ -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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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
|
-
.
|
|
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")
|
package/dist/bin/index.js.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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. |
|