@devalok/shilp-sutra 0.52.0 → 0.54.0
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/AGENTS.md +7 -1
- package/BREAKING.json +29 -0
- package/MIGRATION.md +61 -0
- package/dist/_chunks/motion-provider.js +7 -6
- package/dist/_chunks/motion-provider.js.map +1 -1
- package/dist/_chunks/success.js +53 -53
- package/dist/ai/command-bar.js +158 -158
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js +5 -5
- package/dist/composed/avatar-group.d.ts +11 -9
- package/dist/composed/avatar-group.d.ts.map +1 -1
- package/dist/composed/avatar-group.js +108 -140
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/bulk-action-bar.d.ts +19 -11
- package/dist/composed/bulk-action-bar.d.ts.map +1 -1
- package/dist/composed/bulk-action-bar.js +81 -110
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.js +17 -17
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/error-boundary.d.ts +15 -3
- package/dist/composed/error-boundary.d.ts.map +1 -1
- package/dist/composed/error-boundary.js +43 -26
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/loading-skeleton.d.ts +2 -0
- package/dist/composed/loading-skeleton.d.ts.map +1 -1
- package/dist/composed/loading-skeleton.js +79 -56
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/master-detail.d.ts +21 -8
- package/dist/composed/master-detail.d.ts.map +1 -1
- package/dist/composed/master-detail.js +91 -77
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/page-skeletons.d.ts +6 -0
- package/dist/composed/page-skeletons.d.ts.map +1 -1
- package/dist/composed/page-skeletons.js +93 -71
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/priority-indicator.d.ts +15 -6
- package/dist/composed/priority-indicator.d.ts.map +1 -1
- package/dist/composed/priority-indicator.js +37 -88
- package/dist/composed/priority-indicator.js.map +1 -1
- package/dist/composed/schedule-view.d.ts +17 -2
- package/dist/composed/schedule-view.d.ts.map +1 -1
- package/dist/composed/schedule-view.js +163 -64
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/motion/motion-provider.d.ts.map +1 -1
- package/dist/shell/bottom-navbar.d.ts +32 -6
- package/dist/shell/bottom-navbar.d.ts.map +1 -1
- package/dist/shell/bottom-navbar.js +156 -129
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/index.d.ts +5 -3
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +2 -3
- package/dist/shell/notification-preferences.d.ts.map +1 -1
- package/dist/shell/notification-preferences.js +2 -0
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/tokens/primitives.css +6 -2
- package/dist/tokens/utilities.css +6 -0
- package/dist/ui/autocomplete.d.ts +34 -32
- package/dist/ui/autocomplete.d.ts.map +1 -1
- package/dist/ui/autocomplete.js +115 -110
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/combobox.d.ts +1 -1
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +133 -128
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/file-upload.d.ts.map +1 -1
- package/dist/ui/file-upload.js +124 -138
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/form.d.ts +7 -0
- package/dist/ui/form.d.ts.map +1 -1
- package/dist/ui/form.js +4 -2
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/icon-button.d.ts +2 -1
- package/dist/ui/icon-button.d.ts.map +1 -1
- package/dist/ui/icon-button.js +1 -1
- package/dist/ui/icon-button.js.map +1 -1
- package/dist/ui/index.js +30 -30
- package/dist/ui/label.d.ts.map +1 -1
- package/dist/ui/label.js +7 -6
- package/dist/ui/label.js.map +1 -1
- package/dist/ui/search-input.js +4 -4
- package/dist/ui/sidebar.js +7 -7
- package/dist/ui/spinner.d.ts.map +1 -1
- package/dist/ui/spinner.js +50 -44
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/switch.d.ts.map +1 -1
- package/dist/ui/switch.js +24 -24
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/table.js +1 -1
- package/dist/ui/table.js.map +1 -1
- package/docs/components/composed/bulk-action-bar.md +9 -3
- package/docs/components/composed/error-boundary.md +18 -2
- package/docs/components/composed/master-detail.md +12 -2
- package/docs/components/composed/page-skeletons.md +2 -2
- package/docs/components/composed/priority-indicator.md +22 -11
- package/docs/components/composed/rich-chat-input.md +18 -6
- package/docs/components/composed/schedule-view.md +20 -5
- package/docs/components/composed/simple-tooltip.md +1 -1
- package/docs/components/shell/app-command-palette.md +2 -1
- package/docs/components/shell/bottom-navbar.md +28 -9
- package/docs/components/shell/command-registry.md +2 -2
- package/docs/components/shell/link-context.md +2 -2
- package/docs/components/shell/top-bar.md +1 -1
- package/docs/components/ui/autocomplete.md +26 -10
- package/docs/components/ui/search-input.md +2 -2
- package/docs/components/ui/slider.md +2 -2
- package/docs/components/ui/split-button.md +3 -3
- package/llms.txt +2 -2
- package/make-kit/Guidelines.md +1 -1
- package/make-kit/components/overview.md +2 -2
- package/make-kit/foundations/surfaces.md +1 -1
- package/mcp-manifest.json +581 -172
- package/package.json +1 -6
- package/skill/SKILL.md +1 -1
- package/skill/chat-skill/README.md +18 -0
- package/skill/chat-skill/SKILL.md +78 -0
- package/skill/chat-skill/chatgpt-instructions.md +26 -0
- package/skill/chat-skill/gemini-instructions.md +25 -0
- package/skill/references/components.md +2 -2
- package/dist/shell/sidebar.d.ts +0 -113
- package/dist/shell/sidebar.d.ts.map +0 -1
- package/dist/shell/sidebar.js +0 -293
- package/dist/shell/sidebar.js.map +0 -1
- package/docs/components/shell/sidebar.md +0 -103
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loading-skeleton.js","names":[],"sources":["../../src/composed/loading-skeleton.tsx"],"sourcesContent":["// @server-safe\nimport * as React from 'react'\n\nimport { cn } from '../ui/lib/utils'\nimport { Skeleton } from '../ui/skeleton'\n\nexport interface CardSkeletonProps extends React.ComponentPropsWithoutRef<'div'> {\n className?: string\n}\n\nconst CardSkeleton = React.forwardRef<HTMLDivElement, CardSkeletonProps>(\n function CardSkeleton({ className, ...props }, ref) {\n return (\n <div\n ref={ref}\n {...props}\n className={cn(\n 'rounded-surface border border-card-strong bg-surface-raised p-ds-05b',\n className,\n )}\n >\n <div className=\"flex items-center justify-between pb-ds-05\">\n <Skeleton className=\"h-ds-05 w-[128px] bg-surface-raised-hover\" />\n <Skeleton className=\"h-ico-sm w-ico-sm rounded bg-surface-raised-hover\" />\n </div>\n <div className=\"space-y-ds-04\">\n <Skeleton className=\"h-ds-04 w-full bg-surface-raised-hover\" />\n <Skeleton className=\"h-ds-04 w-4/5 bg-surface-raised-hover\" />\n <Skeleton className=\"h-ds-04 w-3/5 bg-surface-raised-hover\" />\n </div>\n <div className=\"flex items-center gap-ds-03 pt-ds-05\">\n <Skeleton className=\"h-ds-xs w-ds-xs rounded-pill bg-surface-raised-hover\" />\n <Skeleton className=\"h-ds-04 w-ds-11 bg-surface-raised-hover\" />\n </div>\n </div>\n )\n},\n)\n\nCardSkeleton.displayName = 'CardSkeleton'\n\nexport interface TableSkeletonProps extends CardSkeletonProps {\n rows?: number\n columns?: number\n}\n\nconst TableSkeleton = React.forwardRef<HTMLDivElement, TableSkeletonProps>(\n function TableSkeleton({\n rows = 5,\n columns = 4,\n className,\n ...props\n}, ref) {\n return (\n <div\n ref={ref}\n {...props}\n className={cn(\n 'overflow-hidden rounded-surface border border-card-strong',\n className,\n )}\n >\n {/* Header */}\n <div className=\"flex items-center gap-ds-05 border-b border-surface-border-strong bg-surface-raised px-ds-05 py-ds-04\">\n {Array.from({ length: columns }).map((_, i) => (\n <Skeleton\n key={`head-${i}`}\n className={cn(\n 'h-ds-04 bg-surface-raised-hover',\n i === 0 ? 'w-ds-13' : 'flex-1',\n )}\n />\n ))}\n </div>\n\n {/* Rows */}\n {Array.from({ length: rows }).map((_, rowIndex) => (\n <div\n key={`row-${rowIndex}`}\n className={cn(\n 'flex items-center gap-ds-05 px-ds-05 py-ds-04',\n rowIndex < rows - 1 && 'border-b border-surface-border-strong',\n )}\n style={{ animationDelay: `${rowIndex * 50}ms` }}\n >\n {Array.from({ length: columns }).map((_, colIndex) => (\n <Skeleton\n key={`cell-${rowIndex}-${colIndex}`}\n className={cn(\n 'h-ds-04 bg-surface-raised-hover',\n colIndex === 0 ? 'w-ds-13' : 'flex-1',\n )}\n />\n ))}\n </div>\n ))}\n </div>\n )\n},\n)\n\nTableSkeleton.displayName = 'TableSkeleton'\n\nexport interface BoardSkeletonProps extends CardSkeletonProps {\n columns?: number\n cardsPerColumn?: number\n}\n\nconst BoardSkeleton = React.forwardRef<HTMLDivElement, BoardSkeletonProps>(\n function BoardSkeleton({\n columns = 4,\n cardsPerColumn = 3,\n className,\n ...props\n}, ref) {\n return (\n <div ref={ref} {...props} className={cn('flex gap-ds-05 overflow-x-auto', className)}>\n {Array.from({ length: columns }).map((_, colIndex) => (\n <div\n key={`col-${colIndex}`}\n className=\"flex w-[272px] shrink-0 flex-col gap-ds-03\"\n >\n {/* Column header */}\n <div className=\"flex items-center justify-between px-ds-02 py-ds-03\">\n <div className=\"flex items-center gap-ds-03\">\n <Skeleton className=\"h-ds-04 w-ds-04 rounded bg-surface-raised-hover\" />\n <Skeleton className=\"h-ds-04 w-ds-11 bg-surface-raised-hover\" />\n <Skeleton className=\"h-ds-05 w-ds-05b rounded-pill bg-surface-raised-hover\" />\n </div>\n <Skeleton className=\"h-ico-sm w-ico-sm rounded bg-surface-raised-hover\" />\n </div>\n\n {/* Column cards */}\n {Array.from({ length: cardsPerColumn }).map((_, cardIndex) => (\n <div\n key={`card-${colIndex}-${cardIndex}`}\n className=\"rounded-surface border border-card-strong bg-surface-raised p-ds-04\"\n style={{ animationDelay: `${(colIndex * cardsPerColumn + cardIndex) * 50}ms` }}\n >\n <div className=\"space-y-ds-03\">\n <Skeleton className=\"h-ds-04 w-4/5 bg-surface-raised-hover\" />\n <Skeleton className=\"h-ds-04 w-3/5 bg-surface-raised-hover\" />\n </div>\n <div className=\"flex items-center justify-between pt-ds-04\">\n <div className=\"flex items-center gap-ds-02b\">\n <Skeleton className=\"h-ico-md w-ico-md rounded-pill bg-surface-raised-hover\" />\n <Skeleton className=\"h-ds-03 w-ds-10 bg-surface-raised-hover\" />\n </div>\n <Skeleton className=\"h-ds-05 w-ds-lg rounded-pill bg-surface-raised-hover\" />\n </div>\n </div>\n ))}\n </div>\n ))}\n </div>\n )\n},\n)\n\nBoardSkeleton.displayName = 'BoardSkeleton'\n\nexport interface ListSkeletonProps extends CardSkeletonProps {\n rows?: number\n showAvatar?: boolean\n}\n\nconst ListSkeleton = React.forwardRef<HTMLDivElement, ListSkeletonProps>(\n function ListSkeleton({\n rows = 6,\n showAvatar = true,\n className,\n ...props\n}, ref) {\n return (\n <div ref={ref} {...props} className={cn('flex flex-col', className)}>\n {Array.from({ length: rows }).map((_, i) => (\n <div\n key={`list-${i}`}\n className={cn(\n 'flex items-center gap-ds-04 py-ds-04',\n i < rows - 1 && 'border-b border-surface-border-strong',\n )}\n style={{ animationDelay: `${i * 50}ms` }}\n >\n {showAvatar && (\n <Skeleton className=\"h-ds-sm w-ds-sm shrink-0 rounded-pill bg-surface-raised-hover\" />\n )}\n <div className=\"flex flex-1 flex-col gap-ds-02b\">\n <Skeleton className=\"h-ds-04 w-2/5 bg-surface-raised-hover\" />\n <Skeleton className=\"h-ds-03 w-3/5 bg-surface-raised-hover\" />\n </div>\n <Skeleton className=\"h-ds-05b w-[56px] rounded-pill bg-surface-raised-hover\" />\n </div>\n ))}\n </div>\n )\n},\n)\n\nListSkeleton.displayName = 'ListSkeleton'\n\nexport { BoardSkeleton, CardSkeleton, ListSkeleton,TableSkeleton }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loading-skeleton.js","names":[],"sources":["../../src/composed/loading-skeleton.tsx"],"sourcesContent":["// @server-safe\nimport * as React from 'react'\n\nimport { cn } from '../ui/lib/utils'\nimport { Skeleton } from '../ui/skeleton'\n\n// Non-negative integer count (guards Array.from against NaN / negatives → RangeError).\nconst clamp = (n: number | undefined, fallback: number) =>\n Math.max(0, Math.floor(typeof n === 'number' && !Number.isNaN(n) ? n : fallback))\n\n// role=status + aria-busy so AT announces the loading region (child Skeletons are\n// aria-hidden). sr-only label gives the announcement text.\nfunction statusProps(label?: string) {\n return { role: 'status' as const, 'aria-busy': true, 'aria-label': label ?? 'Loading' }\n}\nfunction SrLabel({ label }: { label?: string }) {\n return <span className=\"sr-only\">{label ?? 'Loading'}…</span>\n}\n\nexport interface CardSkeletonProps extends React.ComponentPropsWithoutRef<'div'> {\n className?: string\n /** Accessible label for the loading region. @default 'Loading' */\n label?: string\n}\n\nconst CardSkeleton = React.forwardRef<HTMLDivElement, CardSkeletonProps>(\n function CardSkeleton({ className, label, ...props }, ref) {\n return (\n <div\n ref={ref}\n {...statusProps(label)}\n {...props}\n className={cn('rounded-surface border border-card bg-surface-raised p-ds-05b', className)}\n >\n <SrLabel label={label} />\n <div className=\"flex items-center justify-between pb-ds-05\">\n <Skeleton className=\"h-ds-05 w-ds-13\" />\n <Skeleton className=\"h-ico-sm w-ico-sm rounded\" />\n </div>\n <div className=\"space-y-ds-04\">\n <Skeleton className=\"h-ds-04 w-full\" />\n <Skeleton className=\"h-ds-04 w-4/5\" />\n <Skeleton className=\"h-ds-04 w-3/5\" />\n </div>\n <div className=\"flex items-center gap-ds-03 pt-ds-05\">\n <Skeleton className=\"h-ds-xs w-ds-xs rounded-pill\" />\n <Skeleton className=\"h-ds-04 w-ds-11\" />\n </div>\n </div>\n )\n },\n)\nCardSkeleton.displayName = 'CardSkeleton'\n\nexport interface TableSkeletonProps extends CardSkeletonProps {\n rows?: number\n columns?: number\n}\n\nconst TableSkeleton = React.forwardRef<HTMLDivElement, TableSkeletonProps>(\n function TableSkeleton({ rows = 5, columns = 4, className, label, ...props }, ref) {\n const r = clamp(rows, 5)\n const c = Math.max(1, clamp(columns, 4))\n return (\n <div\n ref={ref}\n {...statusProps(label)}\n {...props}\n className={cn('overflow-hidden rounded-surface border border-card', className)}\n >\n <SrLabel label={label} />\n {/* Header */}\n <div className=\"flex items-center gap-ds-05 border-b border-surface-border-strong bg-surface-raised px-ds-05 py-ds-04\">\n {Array.from({ length: c }).map((_, i) => (\n <Skeleton key={`head-${i}`} className={cn('h-ds-04', i === 0 ? 'w-ds-13' : 'flex-1')} />\n ))}\n </div>\n {/* Rows */}\n {Array.from({ length: r }).map((_, rowIndex) => (\n <div\n key={`row-${rowIndex}`}\n className={cn(\n 'flex items-center gap-ds-05 px-ds-05 py-ds-04',\n rowIndex < r - 1 && 'border-b border-surface-border-strong',\n )}\n >\n {Array.from({ length: c }).map((_, colIndex) => (\n <Skeleton\n key={`cell-${rowIndex}-${colIndex}`}\n className={cn('h-ds-04', colIndex === 0 ? 'w-ds-13' : 'flex-1')}\n />\n ))}\n </div>\n ))}\n </div>\n )\n },\n)\nTableSkeleton.displayName = 'TableSkeleton'\n\nexport interface BoardSkeletonProps extends CardSkeletonProps {\n columns?: number\n cardsPerColumn?: number\n}\n\nconst BoardSkeleton = React.forwardRef<HTMLDivElement, BoardSkeletonProps>(\n function BoardSkeleton({ columns = 4, cardsPerColumn = 3, className, label, ...props }, ref) {\n const c = clamp(columns, 4)\n const cards = clamp(cardsPerColumn, 3)\n return (\n <div ref={ref} {...statusProps(label)} {...props} className={cn('flex gap-ds-05 overflow-x-auto', className)}>\n <SrLabel label={label} />\n {Array.from({ length: c }).map((_, colIndex) => (\n <div key={`col-${colIndex}`} className=\"flex w-[272px] shrink-0 flex-col gap-ds-03\">\n {/* Column header */}\n <div className=\"flex items-center justify-between px-ds-02 py-ds-03\">\n <div className=\"flex items-center gap-ds-03\">\n <Skeleton className=\"h-ds-04 w-ds-04 rounded\" />\n <Skeleton className=\"h-ds-04 w-ds-11\" />\n <Skeleton className=\"h-ds-05 w-ds-05b rounded-pill\" />\n </div>\n <Skeleton className=\"h-ico-sm w-ico-sm rounded\" />\n </div>\n {/* Column cards */}\n {Array.from({ length: cards }).map((_, cardIndex) => (\n <div\n key={`card-${colIndex}-${cardIndex}`}\n className=\"rounded-surface border border-card bg-surface-raised p-ds-04\"\n >\n <div className=\"space-y-ds-03\">\n <Skeleton className=\"h-ds-04 w-4/5\" />\n <Skeleton className=\"h-ds-04 w-3/5\" />\n </div>\n <div className=\"flex items-center justify-between pt-ds-04\">\n <div className=\"flex items-center gap-ds-02b\">\n <Skeleton className=\"h-ico-md w-ico-md rounded-pill\" />\n <Skeleton className=\"h-ds-03 w-ds-10\" />\n </div>\n <Skeleton className=\"h-ds-05 w-ds-lg rounded-pill\" />\n </div>\n </div>\n ))}\n </div>\n ))}\n </div>\n )\n },\n)\nBoardSkeleton.displayName = 'BoardSkeleton'\n\nexport interface ListSkeletonProps extends CardSkeletonProps {\n rows?: number\n showAvatar?: boolean\n}\n\nconst ListSkeleton = React.forwardRef<HTMLDivElement, ListSkeletonProps>(\n function ListSkeleton({ rows = 6, showAvatar = true, className, label, ...props }, ref) {\n const r = clamp(rows, 6)\n return (\n <div ref={ref} {...statusProps(label)} {...props} className={cn('flex flex-col', className)}>\n <SrLabel label={label} />\n {Array.from({ length: r }).map((_, i) => (\n <div\n key={`list-${i}`}\n className={cn(\n 'flex items-center gap-ds-04 py-ds-04',\n i < r - 1 && 'border-b border-surface-border-strong',\n )}\n >\n {showAvatar && <Skeleton className=\"h-ds-sm w-ds-sm shrink-0 rounded-pill\" />}\n <div className=\"flex flex-1 flex-col gap-ds-02b\">\n <Skeleton className=\"h-ds-04 w-2/5\" />\n <Skeleton className=\"h-ds-03 w-3/5\" />\n </div>\n <Skeleton className=\"h-ds-05b w-ds-09 rounded-pill\" />\n </div>\n ))}\n </div>\n )\n },\n)\nListSkeleton.displayName = 'ListSkeleton'\n\nexport { BoardSkeleton, CardSkeleton, ListSkeleton, TableSkeleton }\n"],"mappings":"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"}
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
/**
|
|
4
|
-
* A responsive master-detail layout.
|
|
5
|
-
*
|
|
6
|
-
* with
|
|
4
|
+
* A responsive master-detail layout. Desktop: fixed-width list panel + detail
|
|
5
|
+
* panel. Below the breakpoint: stacked view with a back button. The list is an
|
|
6
|
+
* ARIA `listbox` with roving keyboard nav (Arrow/Home/End + Enter/Space).
|
|
7
|
+
*
|
|
8
|
+
* Selection can be **controlled** (`selected`) or **owned** by the component
|
|
9
|
+
* (`defaultSelected` + `onSelect`, deriving each row's active state from its
|
|
10
|
+
* `value` — no hand-wiring `active` + `onClick` per row).
|
|
7
11
|
*/
|
|
8
|
-
export interface MasterDetailProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
9
|
-
/**
|
|
12
|
+
export interface MasterDetailProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {
|
|
13
|
+
/** Controlled selected item id. `null` = no selection. Omit for uncontrolled. */
|
|
10
14
|
selected?: string | null;
|
|
15
|
+
/** Uncontrolled initial selection. */
|
|
16
|
+
defaultSelected?: string | null;
|
|
17
|
+
/** Called with a row's `value` when it's chosen (click or Enter/Space). */
|
|
18
|
+
onSelect?: (value: string) => void;
|
|
19
|
+
/** Accessible name for the list (the `listbox`). @default 'Items' */
|
|
20
|
+
label?: string;
|
|
11
21
|
/** Called when mobile back button is pressed. */
|
|
12
22
|
onBack?: () => void;
|
|
13
23
|
/** Master panel width on desktop. @default '280px' */
|
|
@@ -16,7 +26,7 @@ export interface MasterDetailProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
16
26
|
breakpoint?: 'sm' | 'md' | 'lg';
|
|
17
27
|
/** Content to show in the detail pane when nothing is selected. */
|
|
18
28
|
emptyState?: React.ReactNode;
|
|
19
|
-
/** Called when user presses ArrowUp/ArrowDown while the list has focus. */
|
|
29
|
+
/** Called when the user presses ArrowUp/ArrowDown while the list has focus. */
|
|
20
30
|
onNavigate?: (direction: 'up' | 'down') => void;
|
|
21
31
|
}
|
|
22
32
|
interface MasterDetailListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
@@ -24,11 +34,14 @@ interface MasterDetailListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
24
34
|
interface MasterDetailDetailProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
25
35
|
}
|
|
26
36
|
interface MasterDetailListItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
37
|
+
/** Explicit active state. Omit to derive from `value` === the selected id. */
|
|
27
38
|
active?: boolean;
|
|
39
|
+
/** Row id — enables derived selection + auto-fires `onSelect` on activate. */
|
|
40
|
+
value?: string;
|
|
28
41
|
}
|
|
29
|
-
declare function MasterDetailList({ children, className, ...props }: MasterDetailListProps): React.JSX.Element | null;
|
|
42
|
+
declare function MasterDetailList({ children, className, 'aria-label': ariaLabel, ...props }: MasterDetailListProps): React.JSX.Element | null;
|
|
30
43
|
declare function MasterDetailDetail({ children, className, ...props }: MasterDetailDetailProps): React.JSX.Element | null;
|
|
31
|
-
declare function MasterDetailRoot({ selected, onBack, masterWidth, breakpoint, emptyState, onNavigate, children, className, style, ...props }: MasterDetailProps): React.JSX.Element;
|
|
44
|
+
declare function MasterDetailRoot({ selected, defaultSelected, onSelect, label, onBack, masterWidth, breakpoint, emptyState, onNavigate, children, className, style, ...props }: MasterDetailProps): React.JSX.Element;
|
|
32
45
|
declare const MasterDetail: typeof MasterDetailRoot & {
|
|
33
46
|
List: typeof MasterDetailList;
|
|
34
47
|
Detail: typeof MasterDetailDetail;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-detail.d.ts","sourceRoot":"","sources":["../../src/composed/master-detail.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"master-detail.d.ts","sourceRoot":"","sources":["../../src/composed/master-detail.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAEf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC9D,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,sCAAsC;IACtC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mEAAmE;IACnE,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IAC/B,mEAAmE;IACnE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAA;CAChD;AAED,UAAU,qBAAsB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAC/E,UAAU,uBAAwB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AACjF,UAAU,yBAA0B,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACvF,8EAA8E;IAC9E,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AA6CD,iBAAS,gBAAgB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,qBAAqB,4BA2D1G;AAED,iBAAS,kBAAkB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,uBAAuB,4BA4BrF;AA4CD,iBAAS,gBAAgB,CAAC,EACxB,QAAQ,EACR,eAAsB,EACtB,QAAQ,EACR,KAAe,EACf,MAAM,EACN,WAAqB,EACrB,UAAiB,EACjB,UAAU,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,iBAAiB,qBAmCnB;AAED,QAAA,MAAM,YAAY;;;;CAIhB,CAAA;AAEF,OAAO,EAAE,YAAY,EAAE,CAAA;AACvB,YAAY,EAAE,yBAAyB,EAAE,CAAA"}
|
|
@@ -6,14 +6,14 @@ import { Button as r } from "../ui/button.js";
|
|
|
6
6
|
import * as i from "react";
|
|
7
7
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
8
8
|
import { IconArrowLeft as s } from "@tabler/icons-react";
|
|
9
|
-
import { AnimatePresence as c, motion as l } from "framer-motion";
|
|
9
|
+
import { AnimatePresence as c, motion as l, useReducedMotion as u } from "framer-motion";
|
|
10
10
|
//#region src/composed/master-detail.tsx
|
|
11
|
-
var
|
|
11
|
+
var d = {
|
|
12
12
|
sm: "640px",
|
|
13
13
|
md: "768px",
|
|
14
14
|
lg: "1024px"
|
|
15
15
|
};
|
|
16
|
-
function
|
|
16
|
+
function f(e) {
|
|
17
17
|
let [t, n] = i.useState(!1);
|
|
18
18
|
return i.useEffect(() => {
|
|
19
19
|
if (typeof window > "u") return;
|
|
@@ -23,77 +23,84 @@ function d(e) {
|
|
|
23
23
|
return t.addEventListener("change", r), () => t.removeEventListener("change", r);
|
|
24
24
|
}, [e]), t;
|
|
25
25
|
}
|
|
26
|
-
var
|
|
26
|
+
var p = i.createContext({
|
|
27
27
|
selected: null,
|
|
28
|
+
label: "Items",
|
|
28
29
|
isMobile: !1,
|
|
29
30
|
activeIndex: 0,
|
|
30
31
|
setActiveIndex: () => {},
|
|
31
|
-
registerItemRef: () => {}
|
|
32
|
-
itemCount: 0,
|
|
33
|
-
setItemCount: () => {}
|
|
32
|
+
registerItemRef: () => {}
|
|
34
33
|
});
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
function m(e, t) {
|
|
35
|
+
if (!i.isValidElement(e)) return !1;
|
|
36
|
+
let n = e.props;
|
|
37
|
+
return n.active ?? (n.value != null && n.value === t);
|
|
38
|
+
}
|
|
39
|
+
function h({ children: e, className: n, "aria-label": r, ...o }) {
|
|
40
|
+
let { selected: s, label: c, isMobile: l, onNavigate: u, activeIndex: d, setActiveIndex: f, registerItemRef: h } = i.useContext(p), g = i.useRef([]), _ = i.Children.count(e), v = i.useMemo(() => {
|
|
41
41
|
let t = -1;
|
|
42
42
|
return i.Children.forEach(e, (e, n) => {
|
|
43
|
-
|
|
43
|
+
m(e, s) && (t = n);
|
|
44
44
|
}), t;
|
|
45
|
-
}, [e]);
|
|
45
|
+
}, [e, s]);
|
|
46
46
|
if (i.useEffect(() => {
|
|
47
|
-
|
|
48
|
-
}, [
|
|
49
|
-
function
|
|
47
|
+
v >= 0 && f(v);
|
|
48
|
+
}, [v, f]), l && s) return null;
|
|
49
|
+
function y(e) {
|
|
50
50
|
if (e.key === "ArrowDown") {
|
|
51
51
|
e.preventDefault();
|
|
52
|
-
let t = Math.min(
|
|
53
|
-
|
|
52
|
+
let t = Math.min(d + 1, _ - 1);
|
|
53
|
+
f(t), g.current[t]?.focus(), u?.("down");
|
|
54
54
|
} else if (e.key === "ArrowUp") {
|
|
55
55
|
e.preventDefault();
|
|
56
|
-
let t = Math.max(
|
|
57
|
-
|
|
58
|
-
} else if (e.key === "Home") e.preventDefault(),
|
|
56
|
+
let t = Math.max(d - 1, 0);
|
|
57
|
+
f(t), g.current[t]?.focus(), u?.("up");
|
|
58
|
+
} else if (e.key === "Home") e.preventDefault(), f(0), g.current[0]?.focus();
|
|
59
59
|
else if (e.key === "End") {
|
|
60
60
|
e.preventDefault();
|
|
61
|
-
let t =
|
|
62
|
-
|
|
61
|
+
let t = _ - 1;
|
|
62
|
+
f(t), g.current[t]?.focus();
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
return /* @__PURE__ */ a("div", {
|
|
66
66
|
role: "listbox",
|
|
67
|
+
"aria-label": r ?? c,
|
|
67
68
|
tabIndex: -1,
|
|
68
|
-
className: t("overflow-y-auto focus-visible:outline-hidden", !
|
|
69
|
-
onKeyDown:
|
|
70
|
-
...
|
|
69
|
+
className: t("overflow-y-auto focus-visible:outline-hidden", !l && "border-e border-surface-border", n),
|
|
70
|
+
onKeyDown: y,
|
|
71
|
+
...o,
|
|
71
72
|
children: i.Children.map(e, (e, t) => i.isValidElement(e) ? i.cloneElement(e, {
|
|
72
73
|
ref: (e) => {
|
|
73
|
-
|
|
74
|
+
g.current[t] = e, h(t, e);
|
|
74
75
|
},
|
|
75
|
-
tabIndex: t ===
|
|
76
|
+
tabIndex: t === d ? 0 : -1
|
|
76
77
|
}) : e)
|
|
77
78
|
});
|
|
78
79
|
}
|
|
79
|
-
function
|
|
80
|
-
let { selected:
|
|
81
|
-
return
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
function g({ children: d, className: f, ...m }) {
|
|
81
|
+
let { selected: h, isMobile: g, onBack: _, emptyState: v } = i.useContext(p), y = u();
|
|
82
|
+
return g && !h ? null : /* @__PURE__ */ o("div", {
|
|
83
|
+
role: "region",
|
|
84
|
+
"aria-label": "Detail",
|
|
85
|
+
"aria-live": "polite",
|
|
86
|
+
className: t("flex-1 overflow-y-auto", f),
|
|
87
|
+
...m,
|
|
88
|
+
children: [g && _ && /* @__PURE__ */ a("div", {
|
|
85
89
|
className: "border-b border-surface-border px-ds-04 py-ds-03",
|
|
86
90
|
children: /* @__PURE__ */ a(r, {
|
|
87
91
|
variant: "ghost",
|
|
88
92
|
size: "xs",
|
|
89
|
-
onClick:
|
|
90
|
-
startIcon: /* @__PURE__ */ a(n, {
|
|
93
|
+
onClick: _,
|
|
94
|
+
startIcon: /* @__PURE__ */ a(n, {
|
|
95
|
+
icon: s,
|
|
96
|
+
className: "rtl:-scale-x-100"
|
|
97
|
+
}),
|
|
91
98
|
children: "Back"
|
|
92
99
|
})
|
|
93
100
|
}), /* @__PURE__ */ a(c, {
|
|
94
101
|
mode: "wait",
|
|
95
102
|
children: /* @__PURE__ */ a(l.div, {
|
|
96
|
-
initial:
|
|
103
|
+
initial: g && !y ? {
|
|
97
104
|
x: 20,
|
|
98
105
|
opacity: 0
|
|
99
106
|
} : !1,
|
|
@@ -101,64 +108,71 @@ function m({ children: u, className: d, ...p }) {
|
|
|
101
108
|
x: 0,
|
|
102
109
|
opacity: 1
|
|
103
110
|
},
|
|
104
|
-
exit:
|
|
111
|
+
exit: g && !y ? {
|
|
105
112
|
x: -20,
|
|
106
113
|
opacity: 0
|
|
107
114
|
} : void 0,
|
|
108
|
-
transition: e.snappy,
|
|
109
|
-
children:
|
|
110
|
-
},
|
|
115
|
+
transition: y ? { duration: 0 } : e.snappy,
|
|
116
|
+
children: h ? d : v ?? d
|
|
117
|
+
}, h ?? "empty")
|
|
111
118
|
})]
|
|
112
119
|
});
|
|
113
120
|
}
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
var _ = i.forwardRef(function({ active: e, value: n, children: r, className: o, onKeyDown: s, onClick: c, ...l }, u) {
|
|
122
|
+
let { selected: d, onSelect: f } = i.useContext(p), m = e ?? (n != null && n === d);
|
|
123
|
+
function h(e) {
|
|
124
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), e.currentTarget.click()), s?.(e);
|
|
125
|
+
}
|
|
126
|
+
function g(e) {
|
|
127
|
+
n != null && f?.(n), c?.(e);
|
|
117
128
|
}
|
|
118
129
|
return /* @__PURE__ */ a("button", {
|
|
119
|
-
ref:
|
|
130
|
+
ref: u,
|
|
120
131
|
type: "button",
|
|
121
132
|
role: "option",
|
|
122
|
-
"aria-selected":
|
|
123
|
-
"data-active":
|
|
124
|
-
onKeyDown:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
"aria-selected": m,
|
|
134
|
+
"data-active": m || void 0,
|
|
135
|
+
onKeyDown: h,
|
|
136
|
+
onClick: g,
|
|
137
|
+
className: t("flex w-full items-center px-ds-04 py-ds-03 text-left text-body-md font-sans text-surface-fg", "transition-colors duration-fast-01 ease-productive-standard", "hover:bg-surface-raised-hover", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-7 focus-visible:ring-inset", m && "bg-accent-2 text-accent-11 font-medium", o),
|
|
138
|
+
...l,
|
|
139
|
+
children: r
|
|
128
140
|
});
|
|
129
141
|
});
|
|
130
|
-
function
|
|
131
|
-
let
|
|
132
|
-
|
|
142
|
+
function v({ selected: e, defaultSelected: n = null, onSelect: r, label: o = "Items", onBack: s, masterWidth: c = "280px", breakpoint: l = "md", emptyState: u, onNavigate: m, children: h, className: g, style: _, ...v }) {
|
|
143
|
+
let y = f(`(max-width: ${d[l]})`), [b, x] = i.useState(0), S = i.useRef([]), C = e !== void 0, [w, T] = i.useState(n), E = C ? e ?? null : w, D = i.useCallback((e) => {
|
|
144
|
+
C || T(e), r?.(e);
|
|
145
|
+
}, [C, r]), O = i.useCallback((e, t) => {
|
|
146
|
+
S.current[e] = t;
|
|
133
147
|
}, []);
|
|
134
|
-
return /* @__PURE__ */ a(
|
|
148
|
+
return /* @__PURE__ */ a(p.Provider, {
|
|
135
149
|
value: {
|
|
136
|
-
selected:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
selected: E,
|
|
151
|
+
onSelect: D,
|
|
152
|
+
label: o,
|
|
153
|
+
isMobile: y,
|
|
154
|
+
onBack: s,
|
|
155
|
+
emptyState: u,
|
|
156
|
+
onNavigate: m,
|
|
157
|
+
activeIndex: b,
|
|
158
|
+
setActiveIndex: x,
|
|
159
|
+
registerItemRef: O
|
|
146
160
|
},
|
|
147
161
|
children: /* @__PURE__ */ a("div", {
|
|
148
|
-
className: t("flex h-full", !
|
|
162
|
+
className: t("flex h-full", !y && "grid", g),
|
|
149
163
|
style: {
|
|
150
|
-
...
|
|
151
|
-
...
|
|
164
|
+
..._,
|
|
165
|
+
...y ? {} : { gridTemplateColumns: `${c} 1fr` }
|
|
152
166
|
},
|
|
153
|
-
...
|
|
154
|
-
children:
|
|
167
|
+
...v,
|
|
168
|
+
children: h
|
|
155
169
|
})
|
|
156
170
|
});
|
|
157
171
|
}
|
|
158
|
-
var
|
|
159
|
-
List:
|
|
160
|
-
Detail:
|
|
161
|
-
ListItem:
|
|
172
|
+
var y = Object.assign(v, {
|
|
173
|
+
List: h,
|
|
174
|
+
Detail: g,
|
|
175
|
+
ListItem: _
|
|
162
176
|
});
|
|
163
177
|
//#endregion
|
|
164
|
-
export {
|
|
178
|
+
export { y as MasterDetail };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-detail.js","names":[],"sources":["../../src/composed/master-detail.tsx"],"sourcesContent":["'use client'\n\nimport { IconArrowLeft } from '@tabler/icons-react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { springs } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\n\n// ============================================================\n// Types\n// ============================================================\n\n/**\n * A responsive master-detail layout. On desktop, shows a fixed-width list panel\n * alongside a detail panel. Below the breakpoint, switches to a stacked view\n * with animated transitions and a back button.\n */\nexport interface MasterDetailProps extends React.HTMLAttributes<HTMLDivElement> {\n /** ID of currently selected item. null = no selection (show list on mobile). */\n selected?: string | null\n /** Called when mobile back button is pressed. */\n onBack?: () => void\n /** Master panel width on desktop. @default '280px' */\n masterWidth?: string\n /** Breakpoint below which stacked mode activates. @default 'md' */\n breakpoint?: 'sm' | 'md' | 'lg'\n /** Content to show in the detail pane when nothing is selected. */\n emptyState?: React.ReactNode\n /** Called when user presses ArrowUp/ArrowDown while the list has focus. */\n onNavigate?: (direction: 'up' | 'down') => void\n}\n\ninterface MasterDetailListProps extends React.HTMLAttributes<HTMLDivElement> {}\n\ninterface MasterDetailDetailProps extends React.HTMLAttributes<HTMLDivElement> {}\n\ninterface MasterDetailListItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n active?: boolean\n}\n\n// ============================================================\n// Breakpoint values\n// ============================================================\n\nconst breakpoints: Record<string, string> = {\n sm: '640px',\n md: '768px',\n lg: '1024px',\n}\n\nfunction useMediaQuery(query: string): boolean {\n const [matches, setMatches] = React.useState(false)\n\n React.useEffect(() => {\n if (typeof window === 'undefined') return\n const mql = window.matchMedia(query)\n setMatches(mql.matches)\n const handler = (e: MediaQueryListEvent) => setMatches(e.matches)\n mql.addEventListener('change', handler)\n return () => mql.removeEventListener('change', handler)\n }, [query])\n\n return matches\n}\n\n// ============================================================\n// Context\n// ============================================================\n\ninterface MasterDetailContextValue {\n selected: string | null\n isMobile: boolean\n onBack?: () => void\n emptyState?: React.ReactNode\n onNavigate?: (direction: 'up' | 'down') => void\n activeIndex: number\n setActiveIndex: (index: number) => void\n registerItemRef: (index: number, el: HTMLButtonElement | null) => void\n itemCount: number\n setItemCount: (count: number) => void\n}\n\nconst MasterDetailContext = React.createContext<MasterDetailContextValue>({\n selected: null,\n isMobile: false,\n activeIndex: 0,\n setActiveIndex: () => {},\n registerItemRef: () => {},\n itemCount: 0,\n setItemCount: () => {},\n})\n\n// ============================================================\n// Compound Components\n// ============================================================\n\nfunction MasterDetailList({ children, className, ...props }: MasterDetailListProps) {\n const { selected, isMobile, onNavigate, activeIndex, setActiveIndex, registerItemRef, setItemCount } = React.useContext(MasterDetailContext)\n const itemRefsLocal = React.useRef<(HTMLButtonElement | null)[]>([])\n\n // Count children and register with context\n const childCount = React.Children.count(children)\n React.useEffect(() => {\n setItemCount(childCount)\n }, [childCount, setItemCount])\n\n // Keep roving focus in sync with the active/selected item, so keyboard nav\n // starts on the current selection instead of always the first row.\n const activeChildIndex = React.useMemo(() => {\n let idx = -1\n React.Children.forEach(children, (child, i) => {\n if (\n React.isValidElement(child) &&\n (child.props as { active?: boolean }).active\n ) {\n idx = i\n }\n })\n return idx\n }, [children])\n React.useEffect(() => {\n if (activeChildIndex >= 0) setActiveIndex(activeChildIndex)\n }, [activeChildIndex, setActiveIndex])\n\n // On mobile, hide list when something is selected\n if (isMobile && selected) return null\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n const next = Math.min(activeIndex + 1, childCount - 1)\n setActiveIndex(next)\n itemRefsLocal.current[next]?.focus()\n onNavigate?.('down')\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n const prev = Math.max(activeIndex - 1, 0)\n setActiveIndex(prev)\n itemRefsLocal.current[prev]?.focus()\n onNavigate?.('up')\n } else if (e.key === 'Home') {\n e.preventDefault()\n setActiveIndex(0)\n itemRefsLocal.current[0]?.focus()\n } else if (e.key === 'End') {\n e.preventDefault()\n const last = childCount - 1\n setActiveIndex(last)\n itemRefsLocal.current[last]?.focus()\n }\n }\n\n return (\n <div\n role=\"listbox\"\n tabIndex={-1}\n className={cn(\n 'overflow-y-auto focus-visible:outline-hidden',\n !isMobile && 'border-r border-surface-border',\n className,\n )}\n onKeyDown={handleKeyDown}\n {...props}\n >\n {React.Children.map(children, (child, i) => {\n if (!React.isValidElement(child)) return child\n return React.cloneElement(child as React.ReactElement<any>, {\n ref: (el: HTMLButtonElement | null) => {\n itemRefsLocal.current[i] = el\n registerItemRef(i, el)\n },\n tabIndex: i === activeIndex ? 0 : -1,\n })\n })}\n </div>\n )\n}\n\nfunction MasterDetailDetail({ children, className, ...props }: MasterDetailDetailProps) {\n const { selected, isMobile, onBack, emptyState } = React.useContext(MasterDetailContext)\n\n // On mobile, hide detail when nothing selected\n if (isMobile && !selected) return null\n\n return (\n <div className={cn('flex-1 overflow-y-auto', className)} {...props}>\n {isMobile && onBack && (\n <div className=\"border-b border-surface-border px-ds-04 py-ds-03\">\n <Button variant=\"ghost\" size=\"xs\" onClick={onBack} startIcon={<Icon icon={IconArrowLeft} />}>\n Back\n </Button>\n </div>\n )}\n <AnimatePresence mode=\"wait\">\n <motion.div\n key={selected ?? 'empty'}\n initial={isMobile ? { x: 20, opacity: 0 } : false}\n animate={{ x: 0, opacity: 1 }}\n exit={isMobile ? { x: -20, opacity: 0 } : undefined}\n transition={springs.snappy}\n >\n {selected ? children : (emptyState ?? children)}\n </motion.div>\n </AnimatePresence>\n </div>\n )\n}\n\nconst MasterDetailListItem = React.forwardRef<HTMLButtonElement, MasterDetailListItemProps>(\n function MasterDetailListItem({ active = false, children, className, onKeyDown, ...props }, ref) {\n function handleKeyDown(e: React.KeyboardEvent<HTMLButtonElement>) {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n ;(e.target as HTMLButtonElement).click()\n }\n onKeyDown?.(e)\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n data-active={active || undefined}\n onKeyDown={handleKeyDown}\n className={cn(\n 'flex w-full items-center px-ds-04 py-ds-03 text-left text-body-md font-sans text-surface-fg',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-7 focus-visible:ring-inset',\n active && 'bg-accent-2 text-accent-11 font-medium',\n className,\n )}\n {...props}\n >\n {children}\n </button>\n )\n },\n)\n\n// ============================================================\n// MasterDetail Root\n// ============================================================\n\nfunction MasterDetailRoot({\n selected = null,\n onBack,\n masterWidth = '280px',\n breakpoint = 'md',\n emptyState,\n onNavigate,\n children,\n className,\n style,\n ...props\n}: MasterDetailProps) {\n const isMobile = useMediaQuery(`(max-width: ${breakpoints[breakpoint]})`)\n const [activeIndex, setActiveIndex] = React.useState(0)\n const [itemCount, setItemCount] = React.useState(0)\n const itemRefs = React.useRef<(HTMLButtonElement | null)[]>([])\n\n const registerItemRef = React.useCallback((index: number, el: HTMLButtonElement | null) => {\n itemRefs.current[index] = el\n }, [])\n\n return (\n <MasterDetailContext.Provider value={{ selected, isMobile, onBack, emptyState, onNavigate, activeIndex, setActiveIndex, registerItemRef, itemCount, setItemCount }}>\n <div\n className={cn(\n 'flex h-full',\n !isMobile && 'grid',\n className,\n )}\n style={{\n ...style,\n ...(isMobile ? {} : { gridTemplateColumns: `${masterWidth} 1fr` }),\n }}\n {...props}\n >\n {children}\n </div>\n </MasterDetailContext.Provider>\n )\n}\n\nconst MasterDetail = Object.assign(MasterDetailRoot, {\n List: MasterDetailList,\n Detail: MasterDetailDetail,\n ListItem: MasterDetailListItem,\n})\n\nexport { MasterDetail }\nexport type { MasterDetailListItemProps }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"master-detail.js","names":[],"sources":["../../src/composed/master-detail.tsx"],"sourcesContent":["'use client'\n\nimport { IconArrowLeft } from '@tabler/icons-react'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { springs } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\n\n/**\n * A responsive master-detail layout. Desktop: fixed-width list panel + detail\n * panel. Below the breakpoint: stacked view with a back button. The list is an\n * ARIA `listbox` with roving keyboard nav (Arrow/Home/End + Enter/Space).\n *\n * Selection can be **controlled** (`selected`) or **owned** by the component\n * (`defaultSelected` + `onSelect`, deriving each row's active state from its\n * `value` — no hand-wiring `active` + `onClick` per row).\n */\nexport interface MasterDetailProps\n // Replaces the rarely-used native text-selection `onSelect` with our row-select callback.\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {\n /** Controlled selected item id. `null` = no selection. Omit for uncontrolled. */\n selected?: string | null\n /** Uncontrolled initial selection. */\n defaultSelected?: string | null\n /** Called with a row's `value` when it's chosen (click or Enter/Space). */\n onSelect?: (value: string) => void\n /** Accessible name for the list (the `listbox`). @default 'Items' */\n label?: string\n /** Called when mobile back button is pressed. */\n onBack?: () => void\n /** Master panel width on desktop. @default '280px' */\n masterWidth?: string\n /** Breakpoint below which stacked mode activates. @default 'md' */\n breakpoint?: 'sm' | 'md' | 'lg'\n /** Content to show in the detail pane when nothing is selected. */\n emptyState?: React.ReactNode\n /** Called when the user presses ArrowUp/ArrowDown while the list has focus. */\n onNavigate?: (direction: 'up' | 'down') => void\n}\n\ninterface MasterDetailListProps extends React.HTMLAttributes<HTMLDivElement> {}\ninterface MasterDetailDetailProps extends React.HTMLAttributes<HTMLDivElement> {}\ninterface MasterDetailListItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Explicit active state. Omit to derive from `value` === the selected id. */\n active?: boolean\n /** Row id — enables derived selection + auto-fires `onSelect` on activate. */\n value?: string\n}\n\nconst breakpoints: Record<string, string> = { sm: '640px', md: '768px', lg: '1024px' }\n\nfunction useMediaQuery(query: string): boolean {\n const [matches, setMatches] = React.useState(false)\n React.useEffect(() => {\n if (typeof window === 'undefined') return\n const mql = window.matchMedia(query)\n setMatches(mql.matches)\n const handler = (e: MediaQueryListEvent) => setMatches(e.matches)\n mql.addEventListener('change', handler)\n return () => mql.removeEventListener('change', handler)\n }, [query])\n return matches\n}\n\ninterface MasterDetailContextValue {\n selected: string | null\n onSelect?: (value: string) => void\n label: string\n isMobile: boolean\n onBack?: () => void\n emptyState?: React.ReactNode\n onNavigate?: (direction: 'up' | 'down') => void\n activeIndex: number\n setActiveIndex: (index: number) => void\n registerItemRef: (index: number, el: HTMLButtonElement | null) => void\n}\n\nconst MasterDetailContext = React.createContext<MasterDetailContextValue>({\n selected: null,\n label: 'Items',\n isMobile: false,\n activeIndex: 0,\n setActiveIndex: () => {},\n registerItemRef: () => {},\n})\n\nfunction itemIsActive(child: React.ReactNode, selected: string | null): boolean {\n if (!React.isValidElement(child)) return false\n const p = child.props as { active?: boolean; value?: string }\n return p.active ?? (p.value != null && p.value === selected)\n}\n\nfunction MasterDetailList({ children, className, 'aria-label': ariaLabel, ...props }: MasterDetailListProps) {\n const { selected, label, isMobile, onNavigate, activeIndex, setActiveIndex, registerItemRef } =\n React.useContext(MasterDetailContext)\n const itemRefsLocal = React.useRef<(HTMLButtonElement | null)[]>([])\n const childCount = React.Children.count(children)\n\n // Roving focus starts on the active/selected row (derived from `active` or `value`).\n const activeChildIndex = React.useMemo(() => {\n let idx = -1\n React.Children.forEach(children, (child, i) => {\n if (itemIsActive(child, selected)) idx = i\n })\n return idx\n }, [children, selected])\n React.useEffect(() => {\n if (activeChildIndex >= 0) setActiveIndex(activeChildIndex)\n }, [activeChildIndex, setActiveIndex])\n\n if (isMobile && selected) return null\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n const next = Math.min(activeIndex + 1, childCount - 1)\n setActiveIndex(next); itemRefsLocal.current[next]?.focus(); onNavigate?.('down')\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n const prev = Math.max(activeIndex - 1, 0)\n setActiveIndex(prev); itemRefsLocal.current[prev]?.focus(); onNavigate?.('up')\n } else if (e.key === 'Home') {\n e.preventDefault(); setActiveIndex(0); itemRefsLocal.current[0]?.focus()\n } else if (e.key === 'End') {\n e.preventDefault()\n const last = childCount - 1\n setActiveIndex(last); itemRefsLocal.current[last]?.focus()\n }\n }\n\n return (\n <div\n role=\"listbox\"\n aria-label={ariaLabel ?? label}\n tabIndex={-1}\n className={cn('overflow-y-auto focus-visible:outline-hidden', !isMobile && 'border-e border-surface-border', className)}\n onKeyDown={handleKeyDown}\n {...props}\n >\n {React.Children.map(children, (child, i) => {\n if (!React.isValidElement(child)) return child\n return React.cloneElement(child as React.ReactElement<any>, {\n ref: (el: HTMLButtonElement | null) => {\n itemRefsLocal.current[i] = el\n registerItemRef(i, el)\n },\n tabIndex: i === activeIndex ? 0 : -1,\n })\n })}\n </div>\n )\n}\n\nfunction MasterDetailDetail({ children, className, ...props }: MasterDetailDetailProps) {\n const { selected, isMobile, onBack, emptyState } = React.useContext(MasterDetailContext)\n const reduced = useReducedMotion()\n if (isMobile && !selected) return null\n\n return (\n // aria-live so AT users are told the detail changed when the selection swaps.\n <div role=\"region\" aria-label=\"Detail\" aria-live=\"polite\" className={cn('flex-1 overflow-y-auto', className)} {...props}>\n {isMobile && onBack && (\n <div className=\"border-b border-surface-border px-ds-04 py-ds-03\">\n <Button variant=\"ghost\" size=\"xs\" onClick={onBack} startIcon={<Icon icon={IconArrowLeft} className=\"rtl:-scale-x-100\" />}>\n Back\n </Button>\n </div>\n )}\n <AnimatePresence mode=\"wait\">\n <motion.div\n key={selected ?? 'empty'}\n initial={isMobile && !reduced ? { x: 20, opacity: 0 } : false}\n animate={{ x: 0, opacity: 1 }}\n exit={isMobile && !reduced ? { x: -20, opacity: 0 } : undefined}\n transition={reduced ? { duration: 0 } : springs.snappy}\n >\n {selected ? children : (emptyState ?? children)}\n </motion.div>\n </AnimatePresence>\n </div>\n )\n}\n\nconst MasterDetailListItem = React.forwardRef<HTMLButtonElement, MasterDetailListItemProps>(\n function MasterDetailListItem({ active, value, children, className, onKeyDown, onClick, ...props }, ref) {\n const { selected, onSelect } = React.useContext(MasterDetailContext)\n const isActive = active ?? (value != null && value === selected)\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLButtonElement>) {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n ;(e.currentTarget as HTMLButtonElement).click()\n }\n onKeyDown?.(e)\n }\n function handleClick(e: React.MouseEvent<HTMLButtonElement>) {\n if (value != null) onSelect?.(value)\n onClick?.(e)\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"option\"\n aria-selected={isActive}\n data-active={isActive || undefined}\n onKeyDown={handleKeyDown}\n onClick={handleClick}\n className={cn(\n 'flex w-full items-center px-ds-04 py-ds-03 text-left text-body-md font-sans text-surface-fg',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-7 focus-visible:ring-inset',\n isActive && 'bg-accent-2 text-accent-11 font-medium',\n className,\n )}\n {...props}\n >\n {children}\n </button>\n )\n },\n)\n\nfunction MasterDetailRoot({\n selected,\n defaultSelected = null,\n onSelect,\n label = 'Items',\n onBack,\n masterWidth = '280px',\n breakpoint = 'md',\n emptyState,\n onNavigate,\n children,\n className,\n style,\n ...props\n}: MasterDetailProps) {\n const isMobile = useMediaQuery(`(max-width: ${breakpoints[breakpoint]})`)\n const [activeIndex, setActiveIndex] = React.useState(0)\n const itemRefs = React.useRef<(HTMLButtonElement | null)[]>([])\n\n // Controlled when `selected` is provided; otherwise own the selection.\n const isControlled = selected !== undefined\n const [internalSelected, setInternalSelected] = React.useState<string | null>(defaultSelected)\n const resolvedSelected = isControlled ? selected ?? null : internalSelected\n\n const handleSelect = React.useCallback(\n (value: string) => {\n if (!isControlled) setInternalSelected(value)\n onSelect?.(value)\n },\n [isControlled, onSelect],\n )\n\n const registerItemRef = React.useCallback((index: number, el: HTMLButtonElement | null) => {\n itemRefs.current[index] = el\n }, [])\n\n return (\n <MasterDetailContext.Provider\n value={{ selected: resolvedSelected, onSelect: handleSelect, label, isMobile, onBack, emptyState, onNavigate, activeIndex, setActiveIndex, registerItemRef }}\n >\n <div\n className={cn('flex h-full', !isMobile && 'grid', className)}\n style={{ ...style, ...(isMobile ? {} : { gridTemplateColumns: `${masterWidth} 1fr` }) }}\n {...props}\n >\n {children}\n </div>\n </MasterDetailContext.Provider>\n )\n}\n\nconst MasterDetail = Object.assign(MasterDetailRoot, {\n List: MasterDetailList,\n Detail: MasterDetailDetail,\n ListItem: MasterDetailListItem,\n})\n\nexport { MasterDetail }\nexport type { MasterDetailListItemProps }\n"],"mappings":"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"}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
export interface DashboardSkeletonProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
3
|
+
/** Accessible label for the loading region. @default 'Loading' */
|
|
4
|
+
label?: string;
|
|
3
5
|
}
|
|
4
6
|
declare const DashboardSkeleton: React.ForwardRefExoticComponent<DashboardSkeletonProps & React.RefAttributes<HTMLDivElement>>;
|
|
5
7
|
export interface ProjectListSkeletonProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
8
|
+
/** Accessible label for the loading region. @default 'Loading' */
|
|
9
|
+
label?: string;
|
|
6
10
|
}
|
|
7
11
|
declare const ProjectListSkeleton: React.ForwardRefExoticComponent<ProjectListSkeletonProps & React.RefAttributes<HTMLDivElement>>;
|
|
8
12
|
export interface TaskDetailSkeletonProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
13
|
+
/** Accessible label for the loading region. @default 'Loading' */
|
|
14
|
+
label?: string;
|
|
9
15
|
}
|
|
10
16
|
declare const TaskDetailSkeleton: React.ForwardRefExoticComponent<TaskDetailSkeletonProps & React.RefAttributes<HTMLDivElement>>;
|
|
11
17
|
export { DashboardSkeleton, ProjectListSkeleton, TaskDetailSkeleton, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-skeletons.d.ts","sourceRoot":"","sources":["../../src/composed/page-skeletons.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"page-skeletons.d.ts","sourceRoot":"","sources":["../../src/composed/page-skeletons.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgB9B,MAAM,WAAW,sBAAuB,SAAQ,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC;IACnF,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,QAAA,MAAM,iBAAiB,+FAmDtB,CAAA;AAMD,MAAM,WAAW,wBAAyB,SAAQ,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC;IACrF,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,QAAA,MAAM,mBAAmB,iGA4DxB,CAAA;AAMD,MAAM,WAAW,uBAAwB,SAAQ,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC;IACpF,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,QAAA,MAAM,kBAAkB,gGA+CvB,CAAA;AAID,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GACnB,CAAA"}
|