@refraction-ui/react 0.23.1 → 0.23.3
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/dist/index.cjs +82 -223
- package/dist/index.cjs.map +1 -1
- package/dist/internal/page-header/index.d.ts +2 -2
- package/dist/internal/react-data-table/index.d.cts +2 -1
- package/dist/internal/react-data-table/index.d.ts +2 -1
- package/dist/internal/react-stat-grid/index.d.ts +2 -1
- package/dist/internal/shared/index.d.cts +10 -1
- package/dist/internal/shared/index.d.ts +10 -1
- package/dist/react-avatar.js +17 -3
- package/dist/react-avatar.js.map +2 -2
- package/dist/react-data-table.js.map +2 -2
- package/dist/react-dialog.js +53 -31
- package/dist/react-dialog.js.map +2 -2
- package/dist/react-dropdown-menu.js +4 -93
- package/dist/react-dropdown-menu.js.map +2 -2
- package/dist/react-page-header.js +1 -1
- package/dist/react-page-header.js.map +1 -1
- package/dist/react-stat-grid.js.map +1 -1
- package/dist/react-tabs.js +4 -96
- package/dist/react-tabs.js.map +2 -2
- package/package.json +1 -1
|
@@ -21,8 +21,8 @@ declare function createPageHeader(props?: PageHeaderProps): PageHeaderAPI;
|
|
|
21
21
|
* on narrow screens. Carries no outer margin — the page layout spaces it.
|
|
22
22
|
*/
|
|
23
23
|
declare const pageHeaderClass = "flex flex-wrap items-start justify-between gap-4";
|
|
24
|
-
/**
|
|
25
|
-
declare const pageHeaderTextClass = "flex min-w-0
|
|
24
|
+
/** Give text a preferred width so actions wrap before squeezing the heading. */
|
|
25
|
+
declare const pageHeaderTextClass = "flex min-w-0 basis-64 grow flex-col gap-1";
|
|
26
26
|
/** Small uppercase eyebrow above the title. */
|
|
27
27
|
declare const pageHeaderKickerClass = "break-words text-[11px] uppercase tracking-wider text-muted-foreground";
|
|
28
28
|
/** Title — app-sized, not a marketing display size. */
|
|
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { ColumnDef, SortDirection } from '../data-table/index.cjs';
|
|
4
4
|
export { ColumnDef, DataTableProps as CoreDataTableProps, DataTableAPI, DataTableAlign, DataTableState, SortDirection, cellVariants, headerVariants, rowVariants, tableVariants } from '../data-table/index.cjs';
|
|
5
|
+
import { DataAttributes } from '../shared/index.cjs';
|
|
5
6
|
|
|
6
7
|
interface DataTableColumn<T = Record<string, unknown>> extends Omit<ColumnDef<T>, 'header' | 'cell'> {
|
|
7
8
|
/** Header content. A string is also used for the filter input's label. */
|
|
@@ -20,7 +21,7 @@ interface DataTableProps<T = Record<string, unknown>> extends Omit<React.TableHT
|
|
|
20
21
|
/** Stable key per row. Defaults to the row index — pass one when rows can reorder. */
|
|
21
22
|
getRowKey?: (row: T, index: number) => string | number;
|
|
22
23
|
/** Extra attributes for a row (`data-*`, `aria-*`, className, handlers). */
|
|
23
|
-
getRowProps?: (row: T, index: number) => React.HTMLAttributes<HTMLTableRowElement
|
|
24
|
+
getRowProps?: (row: T, index: number) => React.HTMLAttributes<HTMLTableRowElement> & DataAttributes;
|
|
24
25
|
/**
|
|
25
26
|
* Row action. Makes each row focusable (Tab) and activatable with click,
|
|
26
27
|
* Enter or Space. Keep a real link/button in the row too when the action
|
|
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { ColumnDef, SortDirection } from '../data-table/index.js';
|
|
4
4
|
export { ColumnDef, DataTableProps as CoreDataTableProps, DataTableAPI, DataTableAlign, DataTableState, SortDirection, cellVariants, headerVariants, rowVariants, tableVariants } from '../data-table/index.js';
|
|
5
|
+
import { DataAttributes } from '../shared/index.js';
|
|
5
6
|
|
|
6
7
|
interface DataTableColumn<T = Record<string, unknown>> extends Omit<ColumnDef<T>, 'header' | 'cell'> {
|
|
7
8
|
/** Header content. A string is also used for the filter input's label. */
|
|
@@ -20,7 +21,7 @@ interface DataTableProps<T = Record<string, unknown>> extends Omit<React.TableHT
|
|
|
20
21
|
/** Stable key per row. Defaults to the row index — pass one when rows can reorder. */
|
|
21
22
|
getRowKey?: (row: T, index: number) => string | number;
|
|
22
23
|
/** Extra attributes for a row (`data-*`, `aria-*`, className, handlers). */
|
|
23
|
-
getRowProps?: (row: T, index: number) => React.HTMLAttributes<HTMLTableRowElement
|
|
24
|
+
getRowProps?: (row: T, index: number) => React.HTMLAttributes<HTMLTableRowElement> & DataAttributes;
|
|
24
25
|
/**
|
|
25
26
|
* Row action. Makes each row focusable (Tab) and activatable with click,
|
|
26
27
|
* Enter or Space. Keep a real link/button in the row too when the action
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { StatTone, StatGridColumns, StatGridVariant, StatGridLayout } from '../stat-grid/index.js';
|
|
3
3
|
export { StatGridColumns, StatGridLayout, StatGridVariant, StatItem, StatTone, statColumns } from '../stat-grid/index.js';
|
|
4
|
+
import { DataAttributes } from '../shared/index.js';
|
|
4
5
|
|
|
5
6
|
interface StatGridItem {
|
|
6
7
|
/** The primary value displayed prominently. Allows rich content in React. */
|
|
@@ -14,7 +15,7 @@ interface StatGridItem {
|
|
|
14
15
|
/** Colour of the value. Defaults to `default`. */
|
|
15
16
|
tone?: StatTone;
|
|
16
17
|
/** Extra attributes for this item's element (`data-*`, `aria-*`, `title`, className). */
|
|
17
|
-
props?: React.HTMLAttributes<HTMLDivElement
|
|
18
|
+
props?: React.HTMLAttributes<HTMLDivElement> & DataAttributes;
|
|
18
19
|
}
|
|
19
20
|
interface StatGridProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'content'> {
|
|
20
21
|
/** The stat items to display in the grid. */
|
|
@@ -10,6 +10,15 @@ interface BaseProps {
|
|
|
10
10
|
style?: Record<string, string | number>;
|
|
11
11
|
[dataAttr: `data-${string}`]: string | undefined;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* `data-*` attributes, for props that take element attributes as an object
|
|
15
|
+
* (e.g. DataTable `getRowProps`, StatGrid item `props`). React's
|
|
16
|
+
* HTMLAttributes declares no `data-*` key, so without this an object of only
|
|
17
|
+
* data attributes fails TypeScript's weak-type check.
|
|
18
|
+
*/
|
|
19
|
+
type DataAttributes = {
|
|
20
|
+
[dataAttr: `data-${string}`]: string | number | boolean | undefined;
|
|
21
|
+
};
|
|
13
22
|
/** Accessibility props */
|
|
14
23
|
interface AccessibilityProps {
|
|
15
24
|
role?: string;
|
|
@@ -419,4 +428,4 @@ declare function prefersReducedMotion(): boolean;
|
|
|
419
428
|
/** Get animation duration — returns '0ms' if reduced motion preferred */
|
|
420
429
|
declare function getAnimationDuration(normalDuration: string): string;
|
|
421
430
|
|
|
422
|
-
export { type AccessibilityProps, type Align, type BaseProps, type CompositionProps, type DataState, type DevFeedbackRecord, type DevFeedbackSink, type EngineAdapter, FOCUSABLE_SELECTOR, type FocusTrap, type FocusTrapConfig, type KeyboardHandlerMap, type KeyboardKey, Keys, type LibraryFramework, type LibraryOriginEnvelope, type LibraryOriginErrorInput, type LibraryOriginIdentity, type LiveRegion, type LiveRegionConfig, type Machine, type MachineConfig, type Orientation, type Side, type Size, type SkipLinkProps, type ThemeProps, type TokenContract, type TokenDefinition, type Variant, captureLibraryOriginError, cn, createFocusTrap, createKeyboardHandler, createLiveRegion, createMachine, createSkipLink, cva, devError, devWarn, generateId, getAnimationDuration, getFocusableElements, isLibraryOriginError, libraryOriginEnvelope, libraryOriginError, mergeAriaProps, prefersReducedMotion, resetDevFeedback, resetIdCounter, setDevFeedbackSink, stackFingerprint };
|
|
431
|
+
export { type AccessibilityProps, type Align, type BaseProps, type CompositionProps, type DataAttributes, type DataState, type DevFeedbackRecord, type DevFeedbackSink, type EngineAdapter, FOCUSABLE_SELECTOR, type FocusTrap, type FocusTrapConfig, type KeyboardHandlerMap, type KeyboardKey, Keys, type LibraryFramework, type LibraryOriginEnvelope, type LibraryOriginErrorInput, type LibraryOriginIdentity, type LiveRegion, type LiveRegionConfig, type Machine, type MachineConfig, type Orientation, type Side, type Size, type SkipLinkProps, type ThemeProps, type TokenContract, type TokenDefinition, type Variant, captureLibraryOriginError, cn, createFocusTrap, createKeyboardHandler, createLiveRegion, createMachine, createSkipLink, cva, devError, devWarn, generateId, getAnimationDuration, getFocusableElements, isLibraryOriginError, libraryOriginEnvelope, libraryOriginError, mergeAriaProps, prefersReducedMotion, resetDevFeedback, resetIdCounter, setDevFeedbackSink, stackFingerprint };
|
|
@@ -10,6 +10,15 @@ interface BaseProps {
|
|
|
10
10
|
style?: Record<string, string | number>;
|
|
11
11
|
[dataAttr: `data-${string}`]: string | undefined;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* `data-*` attributes, for props that take element attributes as an object
|
|
15
|
+
* (e.g. DataTable `getRowProps`, StatGrid item `props`). React's
|
|
16
|
+
* HTMLAttributes declares no `data-*` key, so without this an object of only
|
|
17
|
+
* data attributes fails TypeScript's weak-type check.
|
|
18
|
+
*/
|
|
19
|
+
type DataAttributes = {
|
|
20
|
+
[dataAttr: `data-${string}`]: string | number | boolean | undefined;
|
|
21
|
+
};
|
|
13
22
|
/** Accessibility props */
|
|
14
23
|
interface AccessibilityProps {
|
|
15
24
|
role?: string;
|
|
@@ -419,4 +428,4 @@ declare function prefersReducedMotion(): boolean;
|
|
|
419
428
|
/** Get animation duration — returns '0ms' if reduced motion preferred */
|
|
420
429
|
declare function getAnimationDuration(normalDuration: string): string;
|
|
421
430
|
|
|
422
|
-
export { type AccessibilityProps, type Align, type BaseProps, type CompositionProps, type DataState, type DevFeedbackRecord, type DevFeedbackSink, type EngineAdapter, FOCUSABLE_SELECTOR, type FocusTrap, type FocusTrapConfig, type KeyboardHandlerMap, type KeyboardKey, Keys, type LibraryFramework, type LibraryOriginEnvelope, type LibraryOriginErrorInput, type LibraryOriginIdentity, type LiveRegion, type LiveRegionConfig, type Machine, type MachineConfig, type Orientation, type Side, type Size, type SkipLinkProps, type ThemeProps, type TokenContract, type TokenDefinition, type Variant, captureLibraryOriginError, cn, createFocusTrap, createKeyboardHandler, createLiveRegion, createMachine, createSkipLink, cva, devError, devWarn, generateId, getAnimationDuration, getFocusableElements, isLibraryOriginError, libraryOriginEnvelope, libraryOriginError, mergeAriaProps, prefersReducedMotion, resetDevFeedback, resetIdCounter, setDevFeedbackSink, stackFingerprint };
|
|
431
|
+
export { type AccessibilityProps, type Align, type BaseProps, type CompositionProps, type DataAttributes, type DataState, type DevFeedbackRecord, type DevFeedbackSink, type EngineAdapter, FOCUSABLE_SELECTOR, type FocusTrap, type FocusTrapConfig, type KeyboardHandlerMap, type KeyboardKey, Keys, type LibraryFramework, type LibraryOriginEnvelope, type LibraryOriginErrorInput, type LibraryOriginIdentity, type LiveRegion, type LiveRegionConfig, type Machine, type MachineConfig, type Orientation, type Side, type Size, type SkipLinkProps, type ThemeProps, type TokenContract, type TokenDefinition, type Variant, captureLibraryOriginError, cn, createFocusTrap, createKeyboardHandler, createLiveRegion, createMachine, createSkipLink, cva, devError, devWarn, generateId, getAnimationDuration, getFocusableElements, isLibraryOriginError, libraryOriginEnvelope, libraryOriginError, mergeAriaProps, prefersReducedMotion, resetDevFeedback, resetIdCounter, setDevFeedbackSink, stackFingerprint };
|
package/dist/react-avatar.js
CHANGED
|
@@ -117,9 +117,23 @@ var Avatar = React.forwardRef(
|
|
|
117
117
|
var AvatarImage = React.forwardRef(
|
|
118
118
|
function AvatarImage2({ className, src, alt = "", onLoad, onError, ...props }, ref) {
|
|
119
119
|
const { imageError, setImageLoaded, setImageError } = React.useContext(AvatarContext);
|
|
120
|
+
const imageRef = React.useRef(null);
|
|
121
|
+
const mergedRef = React.useCallback((node) => {
|
|
122
|
+
imageRef.current = node;
|
|
123
|
+
if (typeof ref === "function") {
|
|
124
|
+
const cleanup = ref(node);
|
|
125
|
+
if (typeof cleanup === "function") {
|
|
126
|
+
return () => {
|
|
127
|
+
imageRef.current = null;
|
|
128
|
+
cleanup();
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
} else if (ref) ref.current = node;
|
|
132
|
+
}, [ref]);
|
|
120
133
|
React.useEffect(() => {
|
|
121
|
-
|
|
122
|
-
|
|
134
|
+
const image = imageRef.current;
|
|
135
|
+
setImageLoaded(!!image?.complete && image.naturalWidth > 0);
|
|
136
|
+
setImageError(!!image?.complete && image.naturalWidth === 0);
|
|
123
137
|
}, [src, setImageLoaded, setImageError]);
|
|
124
138
|
const handleLoad = (e) => {
|
|
125
139
|
setImageLoaded(true);
|
|
@@ -133,7 +147,7 @@ var AvatarImage = React.forwardRef(
|
|
|
133
147
|
return /* @__PURE__ */ jsx(
|
|
134
148
|
"img",
|
|
135
149
|
{
|
|
136
|
-
ref,
|
|
150
|
+
ref: mergedRef,
|
|
137
151
|
className: cn(avatarImageVariants(), className),
|
|
138
152
|
src,
|
|
139
153
|
alt,
|
package/dist/react-avatar.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../avatar/src/avatar.ts", "../../avatar/src/avatar.styles.ts", "../../react-avatar/src/avatar.tsx"],
|
|
4
|
-
"sourcesContent": ["import type { AccessibilityProps } from '@refraction-ui/shared'\n\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/** Outline of the avatar. */\nexport type AvatarShape = 'circle' | 'square'\n\nexport type AvatarLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'\n\nexport interface AvatarProps {\n src?: string\n alt?: string\n fallback?: string\n size?: AvatarSize\n}\n\nexport interface AvatarAPI {\n /** ARIA attributes to spread on the root element */\n ariaProps: Partial<AccessibilityProps>\n /** Data attributes for CSS styling hooks */\n dataAttributes: Record<string, string>\n /** Image ARIA props */\n imageProps: {\n alt: string\n role: string\n }\n /** Fallback text (initials) */\n fallbackText: string\n /** Current state */\n state: {\n size: AvatarSize\n hasSrc: boolean\n }\n}\n\n/**\n * Extract initials from a name or fallback string.\n * Takes first letter of first two words, uppercased.\n */\nexport function getInitials(name: string): string {\n const parts = name.trim().split(/\\s+/)\n if (parts.length === 0 || parts[0] === '') return ''\n if (parts.length === 1) return parts[0].charAt(0).toUpperCase()\n return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase()\n}\n\nexport function createAvatar(props: AvatarProps = {}): AvatarAPI {\n const { src, alt = '', fallback = '', size = 'md' } = props\n\n // role=\"img\" makes its children presentational, so it is only applied when\n // the avatar itself has a name; otherwise the inner <img alt> / fallback\n // text stays exposed.\n const ariaProps: Partial<AccessibilityProps> = {}\n if (alt) {\n ariaProps.role = 'img'\n ariaProps['aria-label'] = alt\n }\n\n const fallbackText = fallback ? getInitials(fallback) : (alt ? getInitials(alt) : '')\n\n const dataAttributes: Record<string, string> = {\n 'data-slot': 'avatar',\n }\n\n return {\n ariaProps,\n dataAttributes,\n imageProps: {\n alt,\n role: 'img',\n },\n fallbackText,\n state: {\n size,\n hasSrc: !!src,\n },\n }\n}\n", "import { cva } from '@refraction-ui/shared'\nimport type { TokenContract } from '@refraction-ui/shared'\n\nexport const avatarTokens: TokenContract = {\n name: 'avatar',\n tokens: {\n bg: { variable: '--rfr-avatar-bg', fallback: 'hsl(var(--muted))' },\n fg: { variable: '--rfr-avatar-fg', fallback: 'hsl(var(--muted-foreground))' },\n border: { variable: '--rfr-avatar-border', fallback: 'hsl(var(--border))' },\n },\n}\n\nexport const avatarVariants = cva({\n base: 'relative flex shrink-0 overflow-hidden',\n variants: {\n shape: {\n circle: 'rounded-full',\n square: 'rounded-md',\n },\n size: {\n xs: 'h-6 w-6',\n sm: 'h-8 w-8',\n md: 'h-10 w-10',\n lg: 'h-12 w-12',\n xl: 'h-16 w-16',\n },\n },\n defaultVariants: {\n shape: 'circle',\n size: 'md',\n },\n})\n\nexport const avatarImageVariants = cva({\n base: 'aspect-square h-full w-full object-cover',\n})\n\nexport const avatarFallbackVariants = cva({\n base: 'flex h-full w-full items-center justify-center rounded-[inherit] bg-muted text-muted-foreground',\n variants: {\n size: {\n xs: 'text-xs',\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n xl: 'text-lg',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n})\n", "import * as React from 'react'\nimport {\n createAvatar,\n avatarVariants,\n avatarImageVariants,\n avatarFallbackVariants,\n type AvatarSize,\n type AvatarShape,\n} from '@refraction-ui/avatar'\nimport { cn } from '@refraction-ui/shared'\n\n/* ─── Context ──────────────────────────────────────────────────── */\ninterface AvatarContextValue {\n size: AvatarSize\n imageLoaded: boolean\n imageError: boolean\n setImageLoaded: (loaded: boolean) => void\n setImageError: (error: boolean) => void\n}\n\nconst AvatarContext = React.createContext<AvatarContextValue>({\n size: 'md',\n imageLoaded: false,\n imageError: false,\n setImageLoaded: () => {},\n setImageError: () => {},\n})\n\n/* ─── Avatar (root) ────────────────────────────────────────────── */\nexport interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {\n size?: AvatarSize\n /** `circle` (default) or `square` (rounded corners) — e.g. for teams and organisations. */\n shape?: AvatarShape\n}\n\n/**\n * Avatar -- circular image with fallback support.\n * Compound component: use Avatar > AvatarImage + AvatarFallback.\n */\nexport const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>(\n function Avatar({ size = 'md', shape = 'circle', className, children, ...props }, ref) {\n const [imageLoaded, setImageLoaded] = React.useState(false)\n const [imageError, setImageError] = React.useState(false)\n\n const api = createAvatar({ size, alt: props['aria-label'] })\n\n return (\n <AvatarContext.Provider value={{ size, imageLoaded, imageError, setImageLoaded, setImageError }}>\n <span\n ref={ref}\n className={cn(avatarVariants({ size, shape }), className)}\n {...api.ariaProps}\n {...api.dataAttributes}\n {...props}\n >\n {children}\n </span>\n </AvatarContext.Provider>\n )\n },\n)\n\n/* ─── AvatarImage ──────────────────────────────────────────────── */\nexport interface AvatarImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {}\n\nexport const AvatarImage = React.forwardRef<HTMLImageElement, AvatarImageProps>(\n function AvatarImage({ className, src, alt = '', onLoad, onError, ...props }, ref) {\n const { imageError, setImageLoaded, setImageError } = React.useContext(AvatarContext)\n\n React.useEffect(() => {\n setImageLoaded(
|
|
5
|
-
"mappings": ";;;;;;;;;AAuCO,SAAS,YAAY,MAAsB;AAChD,QAAM,QAAQ,KAAK,KAAA,EAAO,MAAM,KAAK;AACrC,MAAI,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM,GAAI,QAAO;AAClD,MAAI,MAAM,WAAW,EAAG,QAAO,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,YAAA;AAClD,UAAQ,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,MAAM,MAAM,SAAS,CAAC,EAAE,OAAO,CAAC,GAAG,YAAA;AAClE;AAEO,SAAS,aAAa,QAAqB,CAAA,GAAe;AAC/D,QAAM,EAAE,KAAK,MAAM,IAAI,WAAW,IAAI,OAAO,KAAA,IAAS;AAKtD,QAAM,YAAyC,CAAA;AAC/C,MAAI,KAAK;AACP,cAAU,OAAO;AACjB,cAAU,YAAY,IAAI;EAC5B;AAEA,QAAM,eAAe,WAAW,YAAY,QAAQ,IAAK,MAAM,YAAY,GAAG,IAAI;AAElF,QAAM,iBAAyC;IAC7C,aAAa;EAAA;AAGf,SAAO;IACL;IACA;IACA,YAAY;MACV;MACA,MAAM;IAAA;IAER;IACA,OAAO;MACL;MACA,QAAQ,CAAC,CAAC;IAAA;EACZ;AAEJ;AC1EO,IAAM,eAA8B;EACzC,MAAM;EACN,QAAQ;IACN,IAAI,EAAE,UAAU,mBAAmB,UAAU,oBAAA;IAC7C,IAAI,EAAE,UAAU,mBAAmB,UAAU,+BAAA;IAC7C,QAAQ,EAAE,UAAU,uBAAuB,UAAU,qBAAA;EAAqB;AAE9E;AAEO,IAAM,iBAAiB,IAAI;EAChC,MAAM;EACN,UAAU;IACR,OAAO;MACL,QAAQ;MACR,QAAQ;IAAA;IAEV,MAAM;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;IAAA;EACN;EAEF,iBAAiB;IACf,OAAO;IACP,MAAM;EAAA;AAEV,CAAC;AAEM,IAAM,sBAAsB,IAAI;EACrC,MAAM;AACR,CAAC;AAEM,IAAM,yBAAyB,IAAI;EACxC,MAAM;EACN,UAAU;IACR,MAAM;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;IAAA;EACN;EAEF,iBAAiB;IACf,MAAM;EAAA;AAEV,CAAC;;;;AC/BD,IAAM,gBAAsB,oBAAkC;EAC5D,MAAM;EACN,aAAa;EACb,YAAY;EACZ,gBAAgB,MAAM;EAAC;EACvB,eAAe,MAAM;EAAC;AACxB,CAAC;AAaM,IAAM,SAAe;EAC1B,SAASA,QAAO,EAAE,OAAO,MAAM,QAAQ,UAAU,WAAW,UAAU,GAAG,MAAA,GAAS,KAAK;AACrF,UAAM,CAAC,aAAa,cAAc,IAAU,eAAS,KAAK;AAC1D,UAAM,CAAC,YAAY,aAAa,IAAU,eAAS,KAAK;AAExD,UAAM,MAAM,aAAa,EAAE,MAAM,KAAK,MAAM,YAAY,EAAA,CAAG;AAE3D,WACE,oBAAC,cAAc,UAAd,EAAuB,OAAO,EAAE,MAAM,aAAa,YAAY,gBAAgB,cAAA,GAC9E,UAAA;MAAC;MAAA;QACC;QACA,WAAW,GAAG,eAAe,EAAE,MAAM,MAAA,CAAO,GAAG,SAAS;QACvD,GAAG,IAAI;QACP,GAAG,IAAI;QACP,GAAG;QAEH;MAAA;IAAA,EACH,CACF;EAEJ;AACF;AAKO,IAAM,cAAoB;EAC/B,SAASC,aAAY,EAAE,WAAW,KAAK,MAAM,IAAI,QAAQ,SAAS,GAAG,MAAA,GAAS,KAAK;AACjF,UAAM,EAAE,YAAY,gBAAgB,cAAA,IAAwB,iBAAW,aAAa;
|
|
4
|
+
"sourcesContent": ["import type { AccessibilityProps } from '@refraction-ui/shared'\n\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/** Outline of the avatar. */\nexport type AvatarShape = 'circle' | 'square'\n\nexport type AvatarLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'\n\nexport interface AvatarProps {\n src?: string\n alt?: string\n fallback?: string\n size?: AvatarSize\n}\n\nexport interface AvatarAPI {\n /** ARIA attributes to spread on the root element */\n ariaProps: Partial<AccessibilityProps>\n /** Data attributes for CSS styling hooks */\n dataAttributes: Record<string, string>\n /** Image ARIA props */\n imageProps: {\n alt: string\n role: string\n }\n /** Fallback text (initials) */\n fallbackText: string\n /** Current state */\n state: {\n size: AvatarSize\n hasSrc: boolean\n }\n}\n\n/**\n * Extract initials from a name or fallback string.\n * Takes first letter of first two words, uppercased.\n */\nexport function getInitials(name: string): string {\n const parts = name.trim().split(/\\s+/)\n if (parts.length === 0 || parts[0] === '') return ''\n if (parts.length === 1) return parts[0].charAt(0).toUpperCase()\n return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase()\n}\n\nexport function createAvatar(props: AvatarProps = {}): AvatarAPI {\n const { src, alt = '', fallback = '', size = 'md' } = props\n\n // role=\"img\" makes its children presentational, so it is only applied when\n // the avatar itself has a name; otherwise the inner <img alt> / fallback\n // text stays exposed.\n const ariaProps: Partial<AccessibilityProps> = {}\n if (alt) {\n ariaProps.role = 'img'\n ariaProps['aria-label'] = alt\n }\n\n const fallbackText = fallback ? getInitials(fallback) : (alt ? getInitials(alt) : '')\n\n const dataAttributes: Record<string, string> = {\n 'data-slot': 'avatar',\n }\n\n return {\n ariaProps,\n dataAttributes,\n imageProps: {\n alt,\n role: 'img',\n },\n fallbackText,\n state: {\n size,\n hasSrc: !!src,\n },\n }\n}\n", "import { cva } from '@refraction-ui/shared'\nimport type { TokenContract } from '@refraction-ui/shared'\n\nexport const avatarTokens: TokenContract = {\n name: 'avatar',\n tokens: {\n bg: { variable: '--rfr-avatar-bg', fallback: 'hsl(var(--muted))' },\n fg: { variable: '--rfr-avatar-fg', fallback: 'hsl(var(--muted-foreground))' },\n border: { variable: '--rfr-avatar-border', fallback: 'hsl(var(--border))' },\n },\n}\n\nexport const avatarVariants = cva({\n base: 'relative flex shrink-0 overflow-hidden',\n variants: {\n shape: {\n circle: 'rounded-full',\n square: 'rounded-md',\n },\n size: {\n xs: 'h-6 w-6',\n sm: 'h-8 w-8',\n md: 'h-10 w-10',\n lg: 'h-12 w-12',\n xl: 'h-16 w-16',\n },\n },\n defaultVariants: {\n shape: 'circle',\n size: 'md',\n },\n})\n\nexport const avatarImageVariants = cva({\n base: 'aspect-square h-full w-full object-cover',\n})\n\nexport const avatarFallbackVariants = cva({\n base: 'flex h-full w-full items-center justify-center rounded-[inherit] bg-muted text-muted-foreground',\n variants: {\n size: {\n xs: 'text-xs',\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n xl: 'text-lg',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n})\n", "import * as React from 'react'\nimport {\n createAvatar,\n avatarVariants,\n avatarImageVariants,\n avatarFallbackVariants,\n type AvatarSize,\n type AvatarShape,\n} from '@refraction-ui/avatar'\nimport { cn } from '@refraction-ui/shared'\n\n/* ─── Context ──────────────────────────────────────────────────── */\ninterface AvatarContextValue {\n size: AvatarSize\n imageLoaded: boolean\n imageError: boolean\n setImageLoaded: (loaded: boolean) => void\n setImageError: (error: boolean) => void\n}\n\nconst AvatarContext = React.createContext<AvatarContextValue>({\n size: 'md',\n imageLoaded: false,\n imageError: false,\n setImageLoaded: () => {},\n setImageError: () => {},\n})\n\n/* ─── Avatar (root) ────────────────────────────────────────────── */\nexport interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {\n size?: AvatarSize\n /** `circle` (default) or `square` (rounded corners) — e.g. for teams and organisations. */\n shape?: AvatarShape\n}\n\n/**\n * Avatar -- circular image with fallback support.\n * Compound component: use Avatar > AvatarImage + AvatarFallback.\n */\nexport const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>(\n function Avatar({ size = 'md', shape = 'circle', className, children, ...props }, ref) {\n const [imageLoaded, setImageLoaded] = React.useState(false)\n const [imageError, setImageError] = React.useState(false)\n\n const api = createAvatar({ size, alt: props['aria-label'] })\n\n return (\n <AvatarContext.Provider value={{ size, imageLoaded, imageError, setImageLoaded, setImageError }}>\n <span\n ref={ref}\n className={cn(avatarVariants({ size, shape }), className)}\n {...api.ariaProps}\n {...api.dataAttributes}\n {...props}\n >\n {children}\n </span>\n </AvatarContext.Provider>\n )\n },\n)\n\n/* ─── AvatarImage ──────────────────────────────────────────────── */\nexport interface AvatarImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {}\n\nexport const AvatarImage = React.forwardRef<HTMLImageElement, AvatarImageProps>(\n function AvatarImage({ className, src, alt = '', onLoad, onError, ...props }, ref) {\n const { imageError, setImageLoaded, setImageError } = React.useContext(AvatarContext)\n\n const imageRef = React.useRef<HTMLImageElement | null>(null)\n const mergedRef = React.useCallback((node: HTMLImageElement | null) => {\n imageRef.current = node\n if (typeof ref === 'function') {\n const cleanup: unknown = ref(node)\n if (typeof cleanup === 'function') {\n return () => {\n imageRef.current = null\n cleanup()\n }\n }\n } else if (ref) ref.current = node\n }, [ref])\n\n React.useEffect(() => {\n // SSR images may finish before hydration installs event handlers. Read\n // the native result instead of erasing a cached success or failure.\n const image = imageRef.current\n setImageLoaded(!!image?.complete && image.naturalWidth > 0)\n setImageError(!!image?.complete && image.naturalWidth === 0)\n }, [src, setImageLoaded, setImageError])\n\n const handleLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n setImageLoaded(true)\n onLoad?.(e)\n }\n\n const handleError = (e: React.SyntheticEvent<HTMLImageElement>) => {\n setImageError(true)\n onError?.(e)\n }\n\n if (imageError) return null\n\n return (\n <img\n ref={mergedRef}\n className={cn(avatarImageVariants(), className)}\n src={src}\n alt={alt}\n onLoad={handleLoad}\n onError={handleError}\n {...props}\n />\n )\n },\n)\n\n/* ─── AvatarFallback ───────────────────────────────────────────── */\nexport interface AvatarFallbackProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport const AvatarFallback = React.forwardRef<HTMLSpanElement, AvatarFallbackProps>(\n function AvatarFallback({ className, children, ...props }, ref) {\n const { size, imageLoaded, imageError } = React.useContext(AvatarContext)\n\n if (imageLoaded && !imageError) return null\n\n return (\n <span\n ref={ref}\n className={cn(avatarFallbackVariants({ size }), className)}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;AAuCO,SAAS,YAAY,MAAsB;AAChD,QAAM,QAAQ,KAAK,KAAA,EAAO,MAAM,KAAK;AACrC,MAAI,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM,GAAI,QAAO;AAClD,MAAI,MAAM,WAAW,EAAG,QAAO,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,YAAA;AAClD,UAAQ,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,MAAM,MAAM,SAAS,CAAC,EAAE,OAAO,CAAC,GAAG,YAAA;AAClE;AAEO,SAAS,aAAa,QAAqB,CAAA,GAAe;AAC/D,QAAM,EAAE,KAAK,MAAM,IAAI,WAAW,IAAI,OAAO,KAAA,IAAS;AAKtD,QAAM,YAAyC,CAAA;AAC/C,MAAI,KAAK;AACP,cAAU,OAAO;AACjB,cAAU,YAAY,IAAI;EAC5B;AAEA,QAAM,eAAe,WAAW,YAAY,QAAQ,IAAK,MAAM,YAAY,GAAG,IAAI;AAElF,QAAM,iBAAyC;IAC7C,aAAa;EAAA;AAGf,SAAO;IACL;IACA;IACA,YAAY;MACV;MACA,MAAM;IAAA;IAER;IACA,OAAO;MACL;MACA,QAAQ,CAAC,CAAC;IAAA;EACZ;AAEJ;AC1EO,IAAM,eAA8B;EACzC,MAAM;EACN,QAAQ;IACN,IAAI,EAAE,UAAU,mBAAmB,UAAU,oBAAA;IAC7C,IAAI,EAAE,UAAU,mBAAmB,UAAU,+BAAA;IAC7C,QAAQ,EAAE,UAAU,uBAAuB,UAAU,qBAAA;EAAqB;AAE9E;AAEO,IAAM,iBAAiB,IAAI;EAChC,MAAM;EACN,UAAU;IACR,OAAO;MACL,QAAQ;MACR,QAAQ;IAAA;IAEV,MAAM;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;IAAA;EACN;EAEF,iBAAiB;IACf,OAAO;IACP,MAAM;EAAA;AAEV,CAAC;AAEM,IAAM,sBAAsB,IAAI;EACrC,MAAM;AACR,CAAC;AAEM,IAAM,yBAAyB,IAAI;EACxC,MAAM;EACN,UAAU;IACR,MAAM;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;IAAA;EACN;EAEF,iBAAiB;IACf,MAAM;EAAA;AAEV,CAAC;;;;AC/BD,IAAM,gBAAsB,oBAAkC;EAC5D,MAAM;EACN,aAAa;EACb,YAAY;EACZ,gBAAgB,MAAM;EAAC;EACvB,eAAe,MAAM;EAAC;AACxB,CAAC;AAaM,IAAM,SAAe;EAC1B,SAASA,QAAO,EAAE,OAAO,MAAM,QAAQ,UAAU,WAAW,UAAU,GAAG,MAAA,GAAS,KAAK;AACrF,UAAM,CAAC,aAAa,cAAc,IAAU,eAAS,KAAK;AAC1D,UAAM,CAAC,YAAY,aAAa,IAAU,eAAS,KAAK;AAExD,UAAM,MAAM,aAAa,EAAE,MAAM,KAAK,MAAM,YAAY,EAAA,CAAG;AAE3D,WACE,oBAAC,cAAc,UAAd,EAAuB,OAAO,EAAE,MAAM,aAAa,YAAY,gBAAgB,cAAA,GAC9E,UAAA;MAAC;MAAA;QACC;QACA,WAAW,GAAG,eAAe,EAAE,MAAM,MAAA,CAAO,GAAG,SAAS;QACvD,GAAG,IAAI;QACP,GAAG,IAAI;QACP,GAAG;QAEH;MAAA;IAAA,EACH,CACF;EAEJ;AACF;AAKO,IAAM,cAAoB;EAC/B,SAASC,aAAY,EAAE,WAAW,KAAK,MAAM,IAAI,QAAQ,SAAS,GAAG,MAAA,GAAS,KAAK;AACjF,UAAM,EAAE,YAAY,gBAAgB,cAAA,IAAwB,iBAAW,aAAa;AAEpF,UAAM,WAAiB,aAAgC,IAAI;AAC3D,UAAM,YAAkB,kBAAY,CAAC,SAAkC;AACrE,eAAS,UAAU;AACnB,UAAI,OAAO,QAAQ,YAAY;AAC7B,cAAM,UAAmB,IAAI,IAAI;AACjC,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,MAAM;AACX,qBAAS,UAAU;AACnB,oBAAA;UACF;QACF;MACF,WAAW,IAAK,KAAI,UAAU;IAChC,GAAG,CAAC,GAAG,CAAC;AAEF,IAAA,gBAAU,MAAM;AAGpB,YAAM,QAAQ,SAAS;AACvB,qBAAe,CAAC,CAAC,OAAO,YAAY,MAAM,eAAe,CAAC;AAC1D,oBAAc,CAAC,CAAC,OAAO,YAAY,MAAM,iBAAiB,CAAC;IAC7D,GAAG,CAAC,KAAK,gBAAgB,aAAa,CAAC;AAEvC,UAAM,aAAa,CAAC,MAA8C;AAChE,qBAAe,IAAI;AACnB,eAAS,CAAC;IACZ;AAEA,UAAM,cAAc,CAAC,MAA8C;AACjE,oBAAc,IAAI;AAClB,gBAAU,CAAC;IACb;AAEA,QAAI,WAAY,QAAO;AAEvB,WACE;MAAC;MAAA;QACC,KAAK;QACL,WAAW,GAAG,oBAAA,GAAuB,SAAS;QAC9C;QACA;QACA,QAAQ;QACR,SAAS;QACR,GAAG;MAAA;IAAA;EAGV;AACF;AAKO,IAAM,iBAAuB;EAClC,SAASC,gBAAe,EAAE,WAAW,UAAU,GAAG,MAAA,GAAS,KAAK;AAC9D,UAAM,EAAE,MAAM,aAAa,WAAA,IAAqB,iBAAW,aAAa;AAExE,QAAI,eAAe,CAAC,WAAY,QAAO;AAEvC,WACE;MAAC;MAAA;QACC;QACA,WAAW,GAAG,uBAAuB,EAAE,KAAA,CAAM,GAAG,SAAS;QACxD,GAAG;QAEH;MAAA;IAAA;EAGP;AACF;",
|
|
6
6
|
"names": ["Avatar", "AvatarImage", "AvatarFallback"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../data-table/src/data-table.ts", "../../data-table/src/data-table.styles.ts", "../../react-data-table/src/DataTable.tsx"],
|
|
4
|
-
"sourcesContent": ["import type { AccessibilityProps } from '@refraction-ui/shared'\n\nexport interface ColumnDef<T = Record<string, unknown>> {\n /** Unique column identifier */\n id: string\n /** Column header text */\n header: string\n /**\n * Value of this column for a row. Drives sorting, filtering and — when no\n * `cell` renderer is given — the rendered text. Optional for display-only\n * columns that set `cell`.\n */\n accessor?: (row: T) => unknown\n /**\n * Custom cell renderer. Framework adapters narrow the return type (React:\n * `ReactNode`). When omitted the cell renders `String(accessor(row))`.\n */\n cell?: (row: T, index: number) => unknown\n /** Horizontal alignment of header and cells. Defaults to `start`. */\n align?: DataTableAlign\n /** Numeric column: tabular figures, no wrapping, aligned to `end` unless `align` says otherwise. */\n numeric?: boolean\n /** Extra class for this column's data cells. */\n className?: string\n /** Extra class for this column's header cell. */\n headerClassName?: string\n /** Whether this column is sortable */\n sortable?: boolean\n /** Whether this column is filterable */\n filterable?: boolean\n}\n\nexport type SortDirection = 'asc' | 'desc'\n\n/** Horizontal alignment of a column (logical, RTL-safe). */\nexport type DataTableAlign = 'start' | 'center' | 'end'\n\n/** A column's effective alignment: explicit `align`, else `end` for numeric columns. */\nexport function resolveColumnAlign(col: { align?: DataTableAlign; numeric?: boolean }): DataTableAlign {\n return col.align ?? (col.numeric ? 'end' : 'start')\n}\n\n/** The raw value of a column for a row (`undefined` without an accessor). */\nexport function getColumnValue<T>(col: { accessor?: (row: T) => unknown }, row: T): unknown {\n return col.accessor ? col.accessor(row) : undefined\n}\n\n/**\n * Stable React/DOM key for a row: `getRowKey` when given, else the row's\n * index. Prefer a `getRowKey` — index keys break row state on sort/filter.\n */\nexport function resolveRowKey<T>(\n row: T,\n index: number,\n getRowKey?: (row: T, index: number) => string | number,\n): string | number {\n return getRowKey ? getRowKey(row, index) : index\n}\n\nexport interface DataTableProps<T = Record<string, unknown>> {\n /** Column definitions */\n columns: ColumnDef<T>[]\n /** Data rows */\n data: T[]\n /** Current sort column */\n sortBy?: string\n /** Current sort direction */\n sortDir?: SortDirection\n /** Callback when sort changes */\n onSort?: (columnId: string, direction: SortDirection) => void\n /** Active filters: columnId -> filter value */\n filters?: Record<string, string>\n}\n\nexport interface DataTableState<T = Record<string, unknown>> {\n sortedData: T[]\n sortBy: string | null\n sortDir: SortDirection\n filters: Record<string, string>\n}\n\nexport interface DataTableAPI<T = Record<string, unknown>> {\n /** Current table state */\n state: DataTableState<T>\n /** Toggle sort for a column */\n sort(columnId: string): void\n /** Set a filter value for a column */\n setFilter(columnId: string, value: string): void\n /** Get ARIA and role props for a header cell */\n getHeaderProps(col: ColumnDef<T>): Partial<AccessibilityProps> & Record<string, unknown>\n /** Get props for a data cell */\n getCellProps(col: ColumnDef<T>, row: T): Record<string, unknown>\n /** Get props for a data row */\n getRowProps(row: T, index: number): Record<string, unknown>\n}\n\nexport function createDataTable<T = Record<string, unknown>>(\n props: DataTableProps<T>,\n): DataTableAPI<T> {\n const {\n columns,\n data,\n sortBy: initialSortBy,\n sortDir: initialSortDir = 'asc',\n onSort,\n filters: initialFilters,\n } = props\n\n let sortBy: string | null = initialSortBy ?? null\n let sortDir: SortDirection = initialSortDir\n let filters: Record<string, string> = { ...(initialFilters ?? {}) }\n\n function getFilteredData(): T[] {\n let result = [...data]\n\n for (const [columnId, filterValue] of Object.entries(filters)) {\n if (!filterValue) continue\n const col = columns.find((c) => c.id === columnId)\n if (!col?.accessor) continue\n const lowerFilter = filterValue.toLowerCase()\n result = result.filter((row) => {\n const cellValue = getColumnValue(col, row)\n return String(cellValue ?? '').toLowerCase().includes(lowerFilter)\n })\n }\n\n return result\n }\n\n function getSortedData(): T[] {\n const filtered = getFilteredData()\n\n if (!sortBy) return filtered\n\n const col = columns.find((c) => c.id === sortBy)\n if (!col?.accessor) return filtered\n\n return [...filtered].sort((a, b) => {\n const aVal = getColumnValue(col, a)\n const bVal = getColumnValue(col, b)\n const aStr = String(aVal ?? '')\n const bStr = String(bVal ?? '')\n\n const cmp = aStr.localeCompare(bStr, undefined, { numeric: true })\n return sortDir === 'asc' ? cmp : -cmp\n })\n }\n\n function sort(columnId: string): void {\n const col = columns.find((c) => c.id === columnId)\n if (!col?.sortable) return\n\n if (sortBy === columnId) {\n sortDir = sortDir === 'asc' ? 'desc' : 'asc'\n } else {\n sortBy = columnId\n sortDir = 'asc'\n }\n\n onSort?.(sortBy, sortDir)\n }\n\n function setFilter(columnId: string, value: string): void {\n filters = { ...filters, [columnId]: value }\n }\n\n function getHeaderProps(\n col: ColumnDef<T>,\n ): Partial<AccessibilityProps> & Record<string, unknown> {\n const props: Partial<AccessibilityProps> & Record<string, unknown> = {\n role: 'columnheader',\n }\n\n if (col.sortable) {\n if (sortBy === col.id) {\n props['aria-sort'] = sortDir === 'asc' ? 'ascending' : 'descending'\n } else {\n props['aria-sort'] = 'none'\n }\n }\n\n return props\n }\n\n function getCellProps(\n col: ColumnDef<T>,\n _row: T,\n ): Record<string, unknown> {\n return {\n role: 'cell',\n 'data-column': col.id,\n }\n }\n\n function getRowProps(_row: T, index: number): Record<string, unknown> {\n return {\n role: 'row',\n 'data-row-index': index,\n }\n }\n\n return {\n get state(): DataTableState<T> {\n return {\n get sortedData() {\n return getSortedData()\n },\n get sortBy() {\n return sortBy\n },\n get sortDir() {\n return sortDir\n },\n get filters() {\n return { ...filters }\n },\n }\n },\n sort,\n setFilter,\n getHeaderProps,\n getCellProps,\n getRowProps,\n }\n}\n", "import { cva } from '@refraction-ui/shared'\n\nexport const tableVariants = cva({\n base: 'w-full caption-bottom text-sm border-collapse',\n variants: {\n size: {\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n})\n\nexport const headerVariants = cva({\n base: 'h-10 px-2 text-left align-middle font-medium text-muted-foreground border-b',\n variants: {\n sortable: {\n true: 'cursor-pointer select-none hover:text-foreground',\n false: '',\n },\n },\n defaultVariants: {\n sortable: 'false',\n },\n})\n\nexport const cellVariants = cva({\n base: 'p-2 align-middle border-b',\n variants: {\n size: {\n sm: 'p-1',\n md: 'p-2',\n lg: 'p-3',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n})\n\nexport const rowVariants = cva({\n base: 'border-b transition-colors hover:bg-muted/50',\n variants: {\n selected: {\n true: 'bg-muted',\n false: '',\n },\n },\n defaultVariants: {\n selected: 'false',\n },\n})\n\n/** Logical text alignment per column alignment. */\nexport const dataTableAlignClass = {\n start: 'text-start',\n center: 'text-center',\n end: 'text-end',\n} as const\n\n/** Numeric cells: tabular figures, no wrapping. */\nexport const dataTableNumericClass = 'tabular-nums whitespace-nowrap'\n\n/** Button inside a sortable header: the keyboard-reachable sort control. */\nexport const dataTableSortButtonClass =\n 'inline-flex items-center gap-1 rounded-sm font-inherit text-inherit focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n\n/** Rows with a row action: pointer + keyboard focus ring. */\nexport const dataTableActionRowClass =\n 'cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring'\n", "import * as React from 'react'\nimport {\n createDataTable,\n tableVariants,\n headerVariants,\n cellVariants,\n rowVariants,\n resolveColumnAlign,\n getColumnValue,\n resolveRowKey,\n dataTableAlignClass,\n dataTableNumericClass,\n dataTableSortButtonClass,\n dataTableActionRowClass,\n type ColumnDef,\n type SortDirection,\n} from '@refraction-ui/data-table'\nimport { cn } from '@refraction-ui/shared'\n\n// ---------------------------------------------------------------------------\n// Column definition (React): header and cell may be any ReactNode\n// ---------------------------------------------------------------------------\n\nexport interface DataTableColumn<T = Record<string, unknown>>\n extends Omit<ColumnDef<T>, 'header' | 'cell'> {\n /** Header content. A string is also used for the filter input's label. */\n header: React.ReactNode\n /** Render the cell. Defaults to `String(accessor(row))`. */\n cell?: (row: T, index: number) => React.ReactNode\n}\n\n// ---------------------------------------------------------------------------\n// DataTable\n// ---------------------------------------------------------------------------\n\nexport interface DataTableProps<T = Record<string, unknown>>\n extends Omit<React.TableHTMLAttributes<HTMLTableElement>, 'children'> {\n columns: DataTableColumn<T>[]\n data: T[]\n sortBy?: string\n sortDir?: SortDirection\n onSort?: (columnId: string, direction: SortDirection) => void\n filters?: Record<string, string>\n emptyMessage?: React.ReactNode\n /** Stable key per row. Defaults to the row index — pass one when rows can reorder. */\n getRowKey?: (row: T, index: number) => string | number\n /** Extra attributes for a row (`data-*`, `aria-*`, className, handlers). */\n getRowProps?: (row: T, index: number) => React.HTMLAttributes<HTMLTableRowElement>\n /**\n * Row action. Makes each row focusable (Tab) and activatable with click,\n * Enter or Space. Keep a real link/button in the row too when the action\n * needs an accessible name beyond the row's text.\n */\n onRowClick?: (row: T, index: number) => void\n /** Table caption (rendered as `<caption>`). */\n caption?: React.ReactNode\n /** Class for the horizontal scroll wrapper. */\n wrapperClassName?: string\n}\n\nconst ACTIVATION_KEYS = new Set(['Enter', ' '])\n\nfunction filterLabel(header: React.ReactNode, id: string): string {\n return typeof header === 'string' || typeof header === 'number' ? String(header) : id\n}\n\nexport function DataTable<T = Record<string, unknown>>({\n columns,\n data,\n sortBy: controlledSortBy,\n sortDir: controlledSortDir = 'asc',\n onSort,\n filters: controlledFilters,\n className,\n emptyMessage = 'No data available',\n getRowKey,\n getRowProps,\n onRowClick,\n caption,\n wrapperClassName,\n ...tableProps\n}: DataTableProps<T>) {\n const [sortBy, setSortBy] = React.useState<string | null>(controlledSortBy ?? null)\n const [sortDir, setSortDir] = React.useState<SortDirection>(controlledSortDir)\n const [filters, setFilters] = React.useState<Record<string, string>>(controlledFilters ?? {})\n\n const api = React.useMemo(\n () =>\n createDataTable<T>({\n // The core only reads id/accessor/sortable/filterable; header and cell\n // are rendered here.\n columns: columns as unknown as ColumnDef<T>[],\n data,\n sortBy: sortBy ?? undefined,\n sortDir,\n onSort,\n filters,\n }),\n [columns, data, sortBy, sortDir, onSort, filters],\n )\n\n const handleSort = (columnId: string) => {\n const col = columns.find((c) => c.id === columnId)\n if (!col?.sortable) return\n const newDir: SortDirection = sortBy === columnId && sortDir === 'asc' ? 'desc' : 'asc'\n setSortBy(columnId)\n setSortDir(newDir)\n onSort?.(columnId, newDir)\n }\n\n const handleFilter = (columnId: string, value: string) => {\n setFilters((prev) => ({ ...prev, [columnId]: value }))\n }\n\n const rows = api.state.sortedData\n const hasFilterable = columns.some((c) => c.filterable)\n\n const rowElementProps = (row: T, index: number): React.HTMLAttributes<HTMLTableRowElement> => {\n const extra = getRowProps?.(row, index) ?? {}\n if (!onRowClick) return extra\n return {\n tabIndex: 0,\n ...extra,\n className: cn(dataTableActionRowClass, extra.className),\n onClick: (e) => {\n extra.onClick?.(e)\n if (!e.defaultPrevented) onRowClick(row, index)\n },\n onKeyDown: (e) => {\n extra.onKeyDown?.(e)\n // Only when the row itself is focused — not a control inside it.\n if (e.defaultPrevented || e.target !== e.currentTarget || !ACTIVATION_KEYS.has(e.key)) return\n e.preventDefault()\n onRowClick(row, index)\n },\n }\n }\n\n return (\n <div className={cn('relative w-full overflow-auto', wrapperClassName)}>\n <table className={cn(tableVariants(), className)} role=\"table\" {...tableProps}>\n {caption != null && <caption className=\"mt-2 caption-bottom text-xs text-muted-foreground\">{caption}</caption>}\n <thead>\n <tr role=\"row\">\n {columns.map((col) => {\n const headerProps = api.getHeaderProps(col as unknown as ColumnDef<T>)\n const align = resolveColumnAlign(col)\n const indicator =\n col.sortable && sortBy === col.id ? (\n <span aria-hidden=\"true\">{sortDir === 'asc' ? '↑' : '↓'}</span>\n ) : null\n return (\n <th\n key={col.id}\n {...headerProps}\n className={cn(\n headerVariants({ sortable: col.sortable ? 'true' : 'false' }),\n dataTableAlignClass[align],\n col.headerClassName,\n )}\n >\n {col.sortable ? (\n <button type=\"button\" className={dataTableSortButtonClass} onClick={() => handleSort(col.id)}>\n {col.header}\n {indicator}\n </button>\n ) : (\n col.header\n )}\n </th>\n )\n })}\n </tr>\n {hasFilterable && (\n <tr role=\"row\" data-filter-row=\"true\">\n {columns.map((col) => (\n <th key={`filter-${col.id}`}>\n {col.filterable ? (\n <input\n type=\"text\"\n aria-label={`Filter ${filterLabel(col.header, col.id)}`}\n value={filters[col.id] ?? ''}\n onChange={(e) => handleFilter(col.id, e.target.value)}\n placeholder=\"Filter...\"\n />\n ) : null}\n </th>\n ))}\n </tr>\n )}\n </thead>\n <tbody>\n {rows.length === 0 ? (\n <tr role=\"row\">\n <td colSpan={columns.length} className=\"text-center p-4 text-muted-foreground\" role=\"cell\">\n {emptyMessage}\n </td>\n </tr>\n ) : (\n rows.map((row, rowIndex) => {\n const rowProps = rowElementProps(row, rowIndex)\n return (\n <tr\n key={resolveRowKey(row, rowIndex, getRowKey)}\n {...api.getRowProps(row, rowIndex)}\n {...rowProps}\n className={cn(rowVariants(), rowProps.className)}\n >\n {columns.map((col) => (\n <td\n key={col.id}\n {...api.getCellProps(col as unknown as ColumnDef<T>, row)}\n className={cn(\n cellVariants(),\n dataTableAlignClass[resolveColumnAlign(col)],\n col.numeric && dataTableNumericClass,\n col.className,\n )}\n >\n {col.cell ? col.cell(row, rowIndex) : String(getColumnValue(col, row) ?? '')}\n </td>\n ))}\n </tr>\n )\n })\n )}\n </tbody>\n </table>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { AccessibilityProps } from '@refraction-ui/shared'\n\nexport interface ColumnDef<T = Record<string, unknown>> {\n /** Unique column identifier */\n id: string\n /** Column header text */\n header: string\n /**\n * Value of this column for a row. Drives sorting, filtering and — when no\n * `cell` renderer is given — the rendered text. Optional for display-only\n * columns that set `cell`.\n */\n accessor?: (row: T) => unknown\n /**\n * Custom cell renderer. Framework adapters narrow the return type (React:\n * `ReactNode`). When omitted the cell renders `String(accessor(row))`.\n */\n cell?: (row: T, index: number) => unknown\n /** Horizontal alignment of header and cells. Defaults to `start`. */\n align?: DataTableAlign\n /** Numeric column: tabular figures, no wrapping, aligned to `end` unless `align` says otherwise. */\n numeric?: boolean\n /** Extra class for this column's data cells. */\n className?: string\n /** Extra class for this column's header cell. */\n headerClassName?: string\n /** Whether this column is sortable */\n sortable?: boolean\n /** Whether this column is filterable */\n filterable?: boolean\n}\n\nexport type SortDirection = 'asc' | 'desc'\n\n/** Horizontal alignment of a column (logical, RTL-safe). */\nexport type DataTableAlign = 'start' | 'center' | 'end'\n\n/** A column's effective alignment: explicit `align`, else `end` for numeric columns. */\nexport function resolveColumnAlign(col: { align?: DataTableAlign; numeric?: boolean }): DataTableAlign {\n return col.align ?? (col.numeric ? 'end' : 'start')\n}\n\n/** The raw value of a column for a row (`undefined` without an accessor). */\nexport function getColumnValue<T>(col: { accessor?: (row: T) => unknown }, row: T): unknown {\n return col.accessor ? col.accessor(row) : undefined\n}\n\n/**\n * Stable React/DOM key for a row: `getRowKey` when given, else the row's\n * index. Prefer a `getRowKey` — index keys break row state on sort/filter.\n */\nexport function resolveRowKey<T>(\n row: T,\n index: number,\n getRowKey?: (row: T, index: number) => string | number,\n): string | number {\n return getRowKey ? getRowKey(row, index) : index\n}\n\nexport interface DataTableProps<T = Record<string, unknown>> {\n /** Column definitions */\n columns: ColumnDef<T>[]\n /** Data rows */\n data: T[]\n /** Current sort column */\n sortBy?: string\n /** Current sort direction */\n sortDir?: SortDirection\n /** Callback when sort changes */\n onSort?: (columnId: string, direction: SortDirection) => void\n /** Active filters: columnId -> filter value */\n filters?: Record<string, string>\n}\n\nexport interface DataTableState<T = Record<string, unknown>> {\n sortedData: T[]\n sortBy: string | null\n sortDir: SortDirection\n filters: Record<string, string>\n}\n\nexport interface DataTableAPI<T = Record<string, unknown>> {\n /** Current table state */\n state: DataTableState<T>\n /** Toggle sort for a column */\n sort(columnId: string): void\n /** Set a filter value for a column */\n setFilter(columnId: string, value: string): void\n /** Get ARIA and role props for a header cell */\n getHeaderProps(col: ColumnDef<T>): Partial<AccessibilityProps> & Record<string, unknown>\n /** Get props for a data cell */\n getCellProps(col: ColumnDef<T>, row: T): Record<string, unknown>\n /** Get props for a data row */\n getRowProps(row: T, index: number): Record<string, unknown>\n}\n\nexport function createDataTable<T = Record<string, unknown>>(\n props: DataTableProps<T>,\n): DataTableAPI<T> {\n const {\n columns,\n data,\n sortBy: initialSortBy,\n sortDir: initialSortDir = 'asc',\n onSort,\n filters: initialFilters,\n } = props\n\n let sortBy: string | null = initialSortBy ?? null\n let sortDir: SortDirection = initialSortDir\n let filters: Record<string, string> = { ...(initialFilters ?? {}) }\n\n function getFilteredData(): T[] {\n let result = [...data]\n\n for (const [columnId, filterValue] of Object.entries(filters)) {\n if (!filterValue) continue\n const col = columns.find((c) => c.id === columnId)\n if (!col?.accessor) continue\n const lowerFilter = filterValue.toLowerCase()\n result = result.filter((row) => {\n const cellValue = getColumnValue(col, row)\n return String(cellValue ?? '').toLowerCase().includes(lowerFilter)\n })\n }\n\n return result\n }\n\n function getSortedData(): T[] {\n const filtered = getFilteredData()\n\n if (!sortBy) return filtered\n\n const col = columns.find((c) => c.id === sortBy)\n if (!col?.accessor) return filtered\n\n return [...filtered].sort((a, b) => {\n const aVal = getColumnValue(col, a)\n const bVal = getColumnValue(col, b)\n const aStr = String(aVal ?? '')\n const bStr = String(bVal ?? '')\n\n const cmp = aStr.localeCompare(bStr, undefined, { numeric: true })\n return sortDir === 'asc' ? cmp : -cmp\n })\n }\n\n function sort(columnId: string): void {\n const col = columns.find((c) => c.id === columnId)\n if (!col?.sortable) return\n\n if (sortBy === columnId) {\n sortDir = sortDir === 'asc' ? 'desc' : 'asc'\n } else {\n sortBy = columnId\n sortDir = 'asc'\n }\n\n onSort?.(sortBy, sortDir)\n }\n\n function setFilter(columnId: string, value: string): void {\n filters = { ...filters, [columnId]: value }\n }\n\n function getHeaderProps(\n col: ColumnDef<T>,\n ): Partial<AccessibilityProps> & Record<string, unknown> {\n const props: Partial<AccessibilityProps> & Record<string, unknown> = {\n role: 'columnheader',\n }\n\n if (col.sortable) {\n if (sortBy === col.id) {\n props['aria-sort'] = sortDir === 'asc' ? 'ascending' : 'descending'\n } else {\n props['aria-sort'] = 'none'\n }\n }\n\n return props\n }\n\n function getCellProps(\n col: ColumnDef<T>,\n _row: T,\n ): Record<string, unknown> {\n return {\n role: 'cell',\n 'data-column': col.id,\n }\n }\n\n function getRowProps(_row: T, index: number): Record<string, unknown> {\n return {\n role: 'row',\n 'data-row-index': index,\n }\n }\n\n return {\n get state(): DataTableState<T> {\n return {\n get sortedData() {\n return getSortedData()\n },\n get sortBy() {\n return sortBy\n },\n get sortDir() {\n return sortDir\n },\n get filters() {\n return { ...filters }\n },\n }\n },\n sort,\n setFilter,\n getHeaderProps,\n getCellProps,\n getRowProps,\n }\n}\n", "import { cva } from '@refraction-ui/shared'\n\nexport const tableVariants = cva({\n base: 'w-full caption-bottom text-sm border-collapse',\n variants: {\n size: {\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n})\n\nexport const headerVariants = cva({\n base: 'h-10 px-2 text-left align-middle font-medium text-muted-foreground border-b',\n variants: {\n sortable: {\n true: 'cursor-pointer select-none hover:text-foreground',\n false: '',\n },\n },\n defaultVariants: {\n sortable: 'false',\n },\n})\n\nexport const cellVariants = cva({\n base: 'p-2 align-middle border-b',\n variants: {\n size: {\n sm: 'p-1',\n md: 'p-2',\n lg: 'p-3',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n})\n\nexport const rowVariants = cva({\n base: 'border-b transition-colors hover:bg-muted/50',\n variants: {\n selected: {\n true: 'bg-muted',\n false: '',\n },\n },\n defaultVariants: {\n selected: 'false',\n },\n})\n\n/** Logical text alignment per column alignment. */\nexport const dataTableAlignClass = {\n start: 'text-start',\n center: 'text-center',\n end: 'text-end',\n} as const\n\n/** Numeric cells: tabular figures, no wrapping. */\nexport const dataTableNumericClass = 'tabular-nums whitespace-nowrap'\n\n/** Button inside a sortable header: the keyboard-reachable sort control. */\nexport const dataTableSortButtonClass =\n 'inline-flex items-center gap-1 rounded-sm font-inherit text-inherit focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n\n/** Rows with a row action: pointer + keyboard focus ring. */\nexport const dataTableActionRowClass =\n 'cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring'\n", "import * as React from 'react'\nimport {\n createDataTable,\n tableVariants,\n headerVariants,\n cellVariants,\n rowVariants,\n resolveColumnAlign,\n getColumnValue,\n resolveRowKey,\n dataTableAlignClass,\n dataTableNumericClass,\n dataTableSortButtonClass,\n dataTableActionRowClass,\n type ColumnDef,\n type SortDirection,\n} from '@refraction-ui/data-table'\nimport { cn, type DataAttributes } from '@refraction-ui/shared'\n\n// ---------------------------------------------------------------------------\n// Column definition (React): header and cell may be any ReactNode\n// ---------------------------------------------------------------------------\n\nexport interface DataTableColumn<T = Record<string, unknown>>\n extends Omit<ColumnDef<T>, 'header' | 'cell'> {\n /** Header content. A string is also used for the filter input's label. */\n header: React.ReactNode\n /** Render the cell. Defaults to `String(accessor(row))`. */\n cell?: (row: T, index: number) => React.ReactNode\n}\n\n// ---------------------------------------------------------------------------\n// DataTable\n// ---------------------------------------------------------------------------\n\nexport interface DataTableProps<T = Record<string, unknown>>\n extends Omit<React.TableHTMLAttributes<HTMLTableElement>, 'children'> {\n columns: DataTableColumn<T>[]\n data: T[]\n sortBy?: string\n sortDir?: SortDirection\n onSort?: (columnId: string, direction: SortDirection) => void\n filters?: Record<string, string>\n emptyMessage?: React.ReactNode\n /** Stable key per row. Defaults to the row index — pass one when rows can reorder. */\n getRowKey?: (row: T, index: number) => string | number\n /** Extra attributes for a row (`data-*`, `aria-*`, className, handlers). */\n getRowProps?: (row: T, index: number) => React.HTMLAttributes<HTMLTableRowElement> & DataAttributes\n /**\n * Row action. Makes each row focusable (Tab) and activatable with click,\n * Enter or Space. Keep a real link/button in the row too when the action\n * needs an accessible name beyond the row's text.\n */\n onRowClick?: (row: T, index: number) => void\n /** Table caption (rendered as `<caption>`). */\n caption?: React.ReactNode\n /** Class for the horizontal scroll wrapper. */\n wrapperClassName?: string\n}\n\nconst ACTIVATION_KEYS = new Set(['Enter', ' '])\n\nfunction filterLabel(header: React.ReactNode, id: string): string {\n return typeof header === 'string' || typeof header === 'number' ? String(header) : id\n}\n\nexport function DataTable<T = Record<string, unknown>>({\n columns,\n data,\n sortBy: controlledSortBy,\n sortDir: controlledSortDir = 'asc',\n onSort,\n filters: controlledFilters,\n className,\n emptyMessage = 'No data available',\n getRowKey,\n getRowProps,\n onRowClick,\n caption,\n wrapperClassName,\n ...tableProps\n}: DataTableProps<T>) {\n const [sortBy, setSortBy] = React.useState<string | null>(controlledSortBy ?? null)\n const [sortDir, setSortDir] = React.useState<SortDirection>(controlledSortDir)\n const [filters, setFilters] = React.useState<Record<string, string>>(controlledFilters ?? {})\n\n const api = React.useMemo(\n () =>\n createDataTable<T>({\n // The core only reads id/accessor/sortable/filterable; header and cell\n // are rendered here.\n columns: columns as unknown as ColumnDef<T>[],\n data,\n sortBy: sortBy ?? undefined,\n sortDir,\n onSort,\n filters,\n }),\n [columns, data, sortBy, sortDir, onSort, filters],\n )\n\n const handleSort = (columnId: string) => {\n const col = columns.find((c) => c.id === columnId)\n if (!col?.sortable) return\n const newDir: SortDirection = sortBy === columnId && sortDir === 'asc' ? 'desc' : 'asc'\n setSortBy(columnId)\n setSortDir(newDir)\n onSort?.(columnId, newDir)\n }\n\n const handleFilter = (columnId: string, value: string) => {\n setFilters((prev) => ({ ...prev, [columnId]: value }))\n }\n\n const rows = api.state.sortedData\n const hasFilterable = columns.some((c) => c.filterable)\n\n const rowElementProps = (\n row: T,\n index: number,\n ): React.HTMLAttributes<HTMLTableRowElement> & DataAttributes => {\n const extra = getRowProps?.(row, index) ?? {}\n if (!onRowClick) return extra\n return {\n tabIndex: 0,\n ...extra,\n className: cn(dataTableActionRowClass, extra.className),\n onClick: (e) => {\n extra.onClick?.(e)\n if (!e.defaultPrevented) onRowClick(row, index)\n },\n onKeyDown: (e) => {\n extra.onKeyDown?.(e)\n // Only when the row itself is focused — not a control inside it.\n if (e.defaultPrevented || e.target !== e.currentTarget || !ACTIVATION_KEYS.has(e.key)) return\n e.preventDefault()\n onRowClick(row, index)\n },\n }\n }\n\n return (\n <div className={cn('relative w-full overflow-auto', wrapperClassName)}>\n <table className={cn(tableVariants(), className)} role=\"table\" {...tableProps}>\n {caption != null && <caption className=\"mt-2 caption-bottom text-xs text-muted-foreground\">{caption}</caption>}\n <thead>\n <tr role=\"row\">\n {columns.map((col) => {\n const headerProps = api.getHeaderProps(col as unknown as ColumnDef<T>)\n const align = resolveColumnAlign(col)\n const indicator =\n col.sortable && sortBy === col.id ? (\n <span aria-hidden=\"true\">{sortDir === 'asc' ? '↑' : '↓'}</span>\n ) : null\n return (\n <th\n key={col.id}\n {...headerProps}\n className={cn(\n headerVariants({ sortable: col.sortable ? 'true' : 'false' }),\n dataTableAlignClass[align],\n col.headerClassName,\n )}\n >\n {col.sortable ? (\n <button type=\"button\" className={dataTableSortButtonClass} onClick={() => handleSort(col.id)}>\n {col.header}\n {indicator}\n </button>\n ) : (\n col.header\n )}\n </th>\n )\n })}\n </tr>\n {hasFilterable && (\n <tr role=\"row\" data-filter-row=\"true\">\n {columns.map((col) => (\n <th key={`filter-${col.id}`}>\n {col.filterable ? (\n <input\n type=\"text\"\n aria-label={`Filter ${filterLabel(col.header, col.id)}`}\n value={filters[col.id] ?? ''}\n onChange={(e) => handleFilter(col.id, e.target.value)}\n placeholder=\"Filter...\"\n />\n ) : null}\n </th>\n ))}\n </tr>\n )}\n </thead>\n <tbody>\n {rows.length === 0 ? (\n <tr role=\"row\">\n <td colSpan={columns.length} className=\"text-center p-4 text-muted-foreground\" role=\"cell\">\n {emptyMessage}\n </td>\n </tr>\n ) : (\n rows.map((row, rowIndex) => {\n const rowProps = rowElementProps(row, rowIndex)\n return (\n <tr\n key={resolveRowKey(row, rowIndex, getRowKey)}\n {...api.getRowProps(row, rowIndex)}\n {...rowProps}\n className={cn(rowVariants(), rowProps.className)}\n >\n {columns.map((col) => (\n <td\n key={col.id}\n {...api.getCellProps(col as unknown as ColumnDef<T>, row)}\n className={cn(\n cellVariants(),\n dataTableAlignClass[resolveColumnAlign(col)],\n col.numeric && dataTableNumericClass,\n col.className,\n )}\n >\n {col.cell ? col.cell(row, rowIndex) : String(getColumnValue(col, row) ?? '')}\n </td>\n ))}\n </tr>\n )\n })\n )}\n </tbody>\n </table>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;AAsCO,SAAS,mBAAmB,KAAoE;AACrG,SAAO,IAAI,UAAU,IAAI,UAAU,QAAQ;AAC7C;AAGO,SAAS,eAAkB,KAAyC,KAAiB;AAC1F,SAAO,IAAI,WAAW,IAAI,SAAS,GAAG,IAAI;AAC5C;AAMO,SAAS,cACd,KACA,OACA,WACiB;AACjB,SAAO,YAAY,UAAU,KAAK,KAAK,IAAI;AAC7C;AAuCO,SAAS,gBACd,OACiB;AACjB,QAAM;IACJ;IACA;IACA,QAAQ;IACR,SAAS,iBAAiB;IAC1B;IACA,SAAS;EAAA,IACP;AAEJ,MAAI,SAAwB,iBAAiB;AAC7C,MAAI,UAAyB;AAC7B,MAAI,UAAkC,EAAE,GAAI,kBAAkB,CAAA,EAAC;AAE/D,WAAS,kBAAuB;AAC9B,QAAI,SAAS,CAAC,GAAG,IAAI;AAErB,eAAW,CAAC,UAAU,WAAW,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC7D,UAAI,CAAC,YAAa;AAClB,YAAM,MAAM,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AACjD,UAAI,CAAC,KAAK,SAAU;AACpB,YAAM,cAAc,YAAY,YAAA;AAChC,eAAS,OAAO,OAAO,CAAC,QAAQ;AAC9B,cAAM,YAAY,eAAe,KAAK,GAAG;AACzC,eAAO,OAAO,aAAa,EAAE,EAAE,YAAA,EAAc,SAAS,WAAW;MACnE,CAAC;IACH;AAEA,WAAO;EACT;AAEA,WAAS,gBAAqB;AAC5B,UAAM,WAAW,gBAAA;AAEjB,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,MAAM,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM;AAC/C,QAAI,CAAC,KAAK,SAAU,QAAO;AAE3B,WAAO,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM;AAClC,YAAM,OAAO,eAAe,KAAK,CAAC;AAClC,YAAM,OAAO,eAAe,KAAK,CAAC;AAClC,YAAM,OAAO,OAAO,QAAQ,EAAE;AAC9B,YAAM,OAAO,OAAO,QAAQ,EAAE;AAE9B,YAAM,MAAM,KAAK,cAAc,MAAM,QAAW,EAAE,SAAS,KAAA,CAAM;AACjE,aAAO,YAAY,QAAQ,MAAM,CAAC;IACpC,CAAC;EACH;AAEA,WAAS,KAAK,UAAwB;AACpC,UAAM,MAAM,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AACjD,QAAI,CAAC,KAAK,SAAU;AAEpB,QAAI,WAAW,UAAU;AACvB,gBAAU,YAAY,QAAQ,SAAS;IACzC,OAAO;AACL,eAAS;AACT,gBAAU;IACZ;AAEA,aAAS,QAAQ,OAAO;EAC1B;AAEA,WAAS,UAAU,UAAkB,OAAqB;AACxD,cAAU,EAAE,GAAG,SAAS,CAAC,QAAQ,GAAG,MAAA;EACtC;AAEA,WAAS,eACP,KACuD;AACvD,UAAMA,SAA+D;MACnE,MAAM;IAAA;AAGR,QAAI,IAAI,UAAU;AAChB,UAAI,WAAW,IAAI,IAAI;AACrBA,eAAM,WAAW,IAAI,YAAY,QAAQ,cAAc;MACzD,OAAO;AACLA,eAAM,WAAW,IAAI;MACvB;IACF;AAEA,WAAOA;EACT;AAEA,WAAS,aACP,KACA,MACyB;AACzB,WAAO;MACL,MAAM;MACN,eAAe,IAAI;IAAA;EAEvB;AAEA,WAAS,YAAY,MAAS,OAAwC;AACpE,WAAO;MACL,MAAM;MACN,kBAAkB;IAAA;EAEtB;AAEA,SAAO;IACL,IAAI,QAA2B;AAC7B,aAAO;QACL,IAAI,aAAa;AACf,iBAAO,cAAA;QACT;QACA,IAAI,SAAS;AACX,iBAAO;QACT;QACA,IAAI,UAAU;AACZ,iBAAO;QACT;QACA,IAAI,UAAU;AACZ,iBAAO,EAAE,GAAG,QAAA;QACd;MAAA;IAEJ;IACA;IACA;IACA;IACA;IACA;EAAA;AAEJ;AC9NO,IAAM,gBAAgB,IAAI;EAC/B,MAAM;EACN,UAAU;IACR,MAAM;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;IAAA;EACN;EAEF,iBAAiB;IACf,MAAM;EAAA;AAEV,CAAC;AAEM,IAAM,iBAAiB,IAAI;EAChC,MAAM;EACN,UAAU;IACR,UAAU;MACR,MAAM;MACN,OAAO;IAAA;EACT;EAEF,iBAAiB;IACf,UAAU;EAAA;AAEd,CAAC;AAEM,IAAM,eAAe,IAAI;EAC9B,MAAM;EACN,UAAU;IACR,MAAM;MACJ,IAAI;MACJ,IAAI;MACJ,IAAI;IAAA;EACN;EAEF,iBAAiB;IACf,MAAM;EAAA;AAEV,CAAC;AAEM,IAAM,cAAc,IAAI;EAC7B,MAAM;EACN,UAAU;IACR,UAAU;MACR,MAAM;MACN,OAAO;IAAA;EACT;EAEF,iBAAiB;IACf,UAAU;EAAA;AAEd,CAAC;AAGM,IAAM,sBAAsB;EACjC,OAAO;EACP,QAAQ;EACR,KAAK;AACP;AAGO,IAAM,wBAAwB;AAG9B,IAAM,2BACX;AAGK,IAAM,0BACX;;;;ACZF,IAAM,kBAAkB,oBAAI,IAAI,CAAC,SAAS,GAAG,CAAC;AAE9C,SAAS,YAAY,QAAyB,IAAoB;AAChE,SAAO,OAAO,WAAW,YAAY,OAAO,WAAW,WAAW,OAAO,MAAM,IAAI;AACrF;AAEO,SAAS,UAAuC;EACrD;EACA;EACA,QAAQ;EACR,SAAS,oBAAoB;EAC7B;EACA,SAAS;EACT;EACA,eAAe;EACf;EACA;EACA;EACA;EACA;EACA,GAAG;AACL,GAAsB;AACpB,QAAM,CAAC,QAAQ,SAAS,IAAU,eAAwB,oBAAoB,IAAI;AAClF,QAAM,CAAC,SAAS,UAAU,IAAU,eAAwB,iBAAiB;AAC7E,QAAM,CAAC,SAAS,UAAU,IAAU,eAAiC,qBAAqB,CAAA,CAAE;AAE5F,QAAM,MAAY;IAChB,MACE,gBAAmB;;;MAGjB;MACA;MACA,QAAQ,UAAU;MAClB;MACA;MACA;IAAA,CACD;IACH,CAAC,SAAS,MAAM,QAAQ,SAAS,QAAQ,OAAO;EAAA;AAGlD,QAAM,aAAa,CAAC,aAAqB;AACvC,UAAM,MAAM,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AACjD,QAAI,CAAC,KAAK,SAAU;AACpB,UAAM,SAAwB,WAAW,YAAY,YAAY,QAAQ,SAAS;AAClF,cAAU,QAAQ;AAClB,eAAW,MAAM;AACjB,aAAS,UAAU,MAAM;EAC3B;AAEA,QAAM,eAAe,CAAC,UAAkB,UAAkB;AACxD,eAAW,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,QAAQ,GAAG,MAAA,EAAQ;EACvD;AAEA,QAAM,OAAO,IAAI,MAAM;AACvB,QAAM,gBAAgB,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU;AAEtD,QAAM,kBAAkB,CACtB,KACA,UAC+D;AAC/D,UAAM,QAAQ,cAAc,KAAK,KAAK,KAAK,CAAA;AAC3C,QAAI,CAAC,WAAY,QAAO;AACxB,WAAO;MACL,UAAU;MACV,GAAG;MACH,WAAW,GAAG,yBAAyB,MAAM,SAAS;MACtD,SAAS,CAAC,MAAM;AACd,cAAM,UAAU,CAAC;AACjB,YAAI,CAAC,EAAE,iBAAkB,YAAW,KAAK,KAAK;MAChD;MACA,WAAW,CAAC,MAAM;AAChB,cAAM,YAAY,CAAC;AAEnB,YAAI,EAAE,oBAAoB,EAAE,WAAW,EAAE,iBAAiB,CAAC,gBAAgB,IAAI,EAAE,GAAG,EAAG;AACvF,UAAE,eAAA;AACF,mBAAW,KAAK,KAAK;MACvB;IAAA;EAEJ;AAEA,SAAA,oBACG,OAAA,EAAI,WAAW,GAAG,iCAAiC,gBAAgB,GAClE,UAAA,qBAAC,SAAA,EAAM,WAAW,GAAG,cAAA,GAAiB,SAAS,GAAG,MAAK,SAAS,GAAG,YAChE,UAAA;IAAA,WAAW,QAAQ,oBAAC,WAAA,EAAQ,WAAU,qDAAqD,UAAA,QAAA,CAAQ;IAAA,qBACnG,SAAA,EACC,UAAA;MAAA,oBAAC,MAAA,EAAG,MAAK,OACN,UAAA,QAAQ,IAAI,CAAC,QAAQ;AACpB,cAAM,cAAc,IAAI,eAAe,GAA8B;AACrE,cAAM,QAAQ,mBAAmB,GAAG;AACpC,cAAM,YACJ,IAAI,YAAY,WAAW,IAAI,KAC7B,oBAAC,QAAA,EAAK,eAAY,QAAQ,UAAA,YAAY,QAAQ,WAAM,SAAA,CAAI,IACtD;AACN,eACE;UAAC;UAAA;YAEE,GAAG;YACJ,WAAW;cACT,eAAe,EAAE,UAAU,IAAI,WAAW,SAAS,QAAA,CAAS;cAC5D,oBAAoB,KAAK;cACzB,IAAI;YAAA;YAGL,UAAA,IAAI,WACH,qBAAC,UAAA,EAAO,MAAK,UAAS,WAAW,0BAA0B,SAAS,MAAM,WAAW,IAAI,EAAE,GACxF,UAAA;cAAA,IAAI;cACJ;YAAA,EAAA,CACH,IAEA,IAAI;UAAA;UAdD,IAAI;QAAA;MAkBf,CAAC,EAAA,CACH;MACC,iBACC,oBAAC,MAAA,EAAG,MAAK,OAAM,mBAAgB,QAC5B,UAAA,QAAQ,IAAI,CAAC,QACZ,oBAAC,MAAA,EACE,UAAA,IAAI,aACH;QAAC;QAAA;UACC,MAAK;UACL,cAAY,UAAU,YAAY,IAAI,QAAQ,IAAI,EAAE,CAAC;UACrD,OAAO,QAAQ,IAAI,EAAE,KAAK;UAC1B,UAAU,CAAC,MAAM,aAAa,IAAI,IAAI,EAAE,OAAO,KAAK;UACpD,aAAY;QAAA;MAAA,IAEZ,KAAA,GATG,UAAU,IAAI,EAAE,EAUzB,CACD,EAAA,CACH;IAAA,EAAA,CAEJ;IACA,oBAAC,SAAA,EACE,UAAA,KAAK,WAAW,IAAA,oBACd,MAAA,EAAG,MAAK,OACP,UAAA,oBAAC,MAAA,EAAG,SAAS,QAAQ,QAAQ,WAAU,yCAAwC,MAAK,QACjF,UAAA,aAAA,CACH,EAAA,CACF,IAEA,KAAK,IAAI,CAAC,KAAK,aAAa;AAC1B,YAAM,WAAW,gBAAgB,KAAK,QAAQ;AAC9C,aACA;QAAC;QAAA;UAEE,GAAG,IAAI,YAAY,KAAK,QAAQ;UAChC,GAAG;UACJ,WAAW,GAAG,YAAA,GAAe,SAAS,SAAS;UAE9C,UAAA,QAAQ,IAAI,CAAC,QACZ;YAAC;YAAA;cAEE,GAAG,IAAI,aAAa,KAAgC,GAAG;cACxD,WAAW;gBACT,aAAA;gBACA,oBAAoB,mBAAmB,GAAG,CAAC;gBAC3C,IAAI,WAAW;gBACf,IAAI;cAAA;cAGL,UAAA,IAAI,OAAO,IAAI,KAAK,KAAK,QAAQ,IAAI,OAAO,eAAe,KAAK,GAAG,KAAK,EAAE;YAAA;YATtE,IAAI;UAAA,CAWZ;QAAA;QAlBI,cAAc,KAAK,UAAU,SAAS;MAAA;IAqB/C,CAAC,EAAA,CAEL;EAAA,EAAA,CACF,EAAA,CACF;AAEJ;",
|
|
6
6
|
"names": ["props"]
|
|
7
7
|
}
|
package/dist/react-dialog.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createDialog,
|
|
3
2
|
dialogContentVariants,
|
|
4
3
|
overlayStyles
|
|
5
4
|
} from "./chunk-4ACSHPCM.js";
|
|
@@ -43,11 +42,10 @@ function Dialog({
|
|
|
43
42
|
},
|
|
44
43
|
[isControlled, onOpenChange]
|
|
45
44
|
);
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
const api = apiRef.current;
|
|
45
|
+
const id = React.useId();
|
|
46
|
+
const contentId = `rfr-dialog-content-${id}`;
|
|
47
|
+
const titleId = `rfr-dialog-title-${id}`;
|
|
48
|
+
const descriptionId = `rfr-dialog-desc-${id}`;
|
|
51
49
|
const [hasTitle, setHasTitle] = React.useState(false);
|
|
52
50
|
const [hasDescription, setHasDescription] = React.useState(false);
|
|
53
51
|
const ctx = React.useMemo(
|
|
@@ -55,38 +53,66 @@ function Dialog({
|
|
|
55
53
|
open,
|
|
56
54
|
onOpenChange: handleOpenChange,
|
|
57
55
|
modal,
|
|
58
|
-
contentId
|
|
59
|
-
titleId
|
|
60
|
-
descriptionId
|
|
56
|
+
contentId,
|
|
57
|
+
titleId,
|
|
58
|
+
descriptionId,
|
|
61
59
|
hasTitle,
|
|
62
60
|
hasDescription,
|
|
63
61
|
setHasTitle,
|
|
64
62
|
setHasDescription
|
|
65
63
|
}),
|
|
66
|
-
[open, handleOpenChange, modal,
|
|
64
|
+
[open, handleOpenChange, modal, contentId, titleId, descriptionId, hasTitle, hasDescription]
|
|
67
65
|
);
|
|
68
66
|
return React.createElement(DialogContext.Provider, { value: ctx }, children);
|
|
69
67
|
}
|
|
70
68
|
var DialogTrigger = React.forwardRef(
|
|
71
|
-
function DialogTrigger2({ onClick, children, ...props }, ref) {
|
|
69
|
+
function DialogTrigger2({ asChild = false, onClick, children, ...props }, ref) {
|
|
72
70
|
const { open, onOpenChange, contentId } = useDialogContext();
|
|
73
|
-
const handleClick = (
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
const handleClick = (event) => {
|
|
72
|
+
onClick?.(event);
|
|
73
|
+
if (!event.defaultPrevented) onOpenChange(!open);
|
|
76
74
|
};
|
|
77
|
-
|
|
78
|
-
"button",
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
75
|
+
const triggerProps = {
|
|
76
|
+
type: "button",
|
|
77
|
+
"aria-expanded": open,
|
|
78
|
+
"aria-controls": contentId,
|
|
79
|
+
"aria-haspopup": "dialog",
|
|
80
|
+
...props,
|
|
81
|
+
onClick: handleClick
|
|
82
|
+
};
|
|
83
|
+
if (asChild) {
|
|
84
|
+
if (!React.isValidElement(children)) {
|
|
85
|
+
devWarn("dialog-trigger-asChild-child", "DialogTrigger: `asChild` expects a single React element child; rendering nothing.");
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const child = children;
|
|
89
|
+
const childRef = React.version.startsWith("18.") ? child.ref : child.props.ref;
|
|
90
|
+
return React.cloneElement(child, {
|
|
91
|
+
...triggerProps,
|
|
92
|
+
className: cn(props.className, child.props.className),
|
|
93
|
+
onClick: (event) => {
|
|
94
|
+
child.props.onClick?.(event);
|
|
95
|
+
if (!event.defaultPrevented) handleClick(event);
|
|
96
|
+
},
|
|
97
|
+
ref: (node) => {
|
|
98
|
+
const outerCleanup = typeof ref === "function" ? ref(node) : void 0;
|
|
99
|
+
if (ref && typeof ref !== "function") ref.current = node;
|
|
100
|
+
const childCleanup = typeof childRef === "function" ? childRef(node) : void 0;
|
|
101
|
+
if (childRef && typeof childRef !== "function") childRef.current = node;
|
|
102
|
+
if (typeof outerCleanup === "function" || typeof childCleanup === "function") {
|
|
103
|
+
return () => {
|
|
104
|
+
if (typeof outerCleanup === "function") outerCleanup();
|
|
105
|
+
else if (typeof ref === "function") ref(null);
|
|
106
|
+
else if (ref) ref.current = null;
|
|
107
|
+
if (typeof childCleanup === "function") childCleanup();
|
|
108
|
+
else if (typeof childRef === "function") childRef(null);
|
|
109
|
+
else if (childRef) childRef.current = null;
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return React.createElement("button", { ref, ...triggerProps }, children);
|
|
90
116
|
}
|
|
91
117
|
);
|
|
92
118
|
var DialogOverlay = React.forwardRef(
|
|
@@ -119,10 +145,6 @@ function containsElement(node, type) {
|
|
|
119
145
|
var DialogContent = React.forwardRef(
|
|
120
146
|
function DialogContent2({ className, children, onKeyDown, ...props }, ref) {
|
|
121
147
|
const { open, onOpenChange, modal, contentId, titleId, descriptionId, hasTitle, hasDescription } = useDialogContext();
|
|
122
|
-
React.useMemo(
|
|
123
|
-
() => createDialog({ open, modal }),
|
|
124
|
-
[open, modal]
|
|
125
|
-
);
|
|
126
148
|
const handleKeyDown = (e) => {
|
|
127
149
|
const handler = createKeyboardHandler({
|
|
128
150
|
Escape: (ev) => {
|
package/dist/react-dialog.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../react-dialog/src/dialog.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport * as ReactDOM from 'react-dom'\nimport {\n createDialog,\n overlayStyles,\n dialogContentVariants,\n type DialogProps as CoreDialogProps,\n} from '@refraction-ui/dialog'\nimport { cn, createKeyboardHandler, devWarn } from '@refraction-ui/shared'\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ninterface DialogContextValue {\n open: boolean\n onOpenChange: (open: boolean) => void\n modal: boolean\n contentId: string\n titleId: string\n descriptionId: string\n /** Whether a DialogTitle / DialogDescription is mounted — only then is it referenced. */\n hasTitle: boolean\n hasDescription: boolean\n setHasTitle: (present: boolean) => void\n setHasDescription: (present: boolean) => void\n}\n\nconst DialogContext = React.createContext<DialogContextValue | null>(null)\n\nfunction useDialogContext(): DialogContextValue {\n const ctx = React.useContext(DialogContext)\n if (!ctx) {\n devWarn(\n 'react-dialog/context-outside-provider',\n 'Dialog compound components (DialogTrigger/DialogContent/DialogTitle/etc.) must be rendered inside a <Dialog>. The missing DialogContext makes this throw.',\n )\n throw new Error('Dialog compound components must be used within <Dialog>')\n }\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// Dialog (root provider)\n// ---------------------------------------------------------------------------\n\nexport interface DialogProps {\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n modal?: boolean\n children?: React.ReactNode\n}\n\nexport function Dialog({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n modal = true,\n children,\n}: DialogProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (next: boolean) => {\n if (!isControlled) {\n setUncontrolledOpen(next)\n }\n onOpenChange?.(next)\n },\n [isControlled, onOpenChange],\n )\n\n // Use the headless core to get stable IDs\n const apiRef = React.useRef<ReturnType<typeof createDialog> | null>(null)\n if (apiRef.current === null) {\n apiRef.current = createDialog({ open, modal })\n }\n const api = apiRef.current\n const [hasTitle, setHasTitle] = React.useState(false)\n const [hasDescription, setHasDescription] = React.useState(false)\n\n const ctx = React.useMemo<DialogContextValue>(\n () => ({\n open,\n onOpenChange: handleOpenChange,\n modal,\n contentId: api.ids.content,\n titleId: api.ids.title,\n descriptionId: api.ids.description,\n hasTitle,\n hasDescription,\n setHasTitle,\n setHasDescription,\n }),\n [open, handleOpenChange, modal, api.ids.content, api.ids.title, api.ids.description, hasTitle, hasDescription],\n )\n\n return React.createElement(DialogContext.Provider, { value: ctx }, children)\n}\n\n// ---------------------------------------------------------------------------\n// DialogTrigger\n// ---------------------------------------------------------------------------\n\nexport interface DialogTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n asChild?: boolean\n}\n\nexport const DialogTrigger = React.forwardRef<HTMLButtonElement, DialogTriggerProps>(\n function DialogTrigger({ onClick, children, ...props }, ref) {\n const { open, onOpenChange, contentId } = useDialogContext()\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n onOpenChange(!open)\n onClick?.(e)\n }\n\n return React.createElement(\n 'button',\n {\n ref,\n type: 'button',\n 'aria-expanded': open,\n 'aria-controls': contentId,\n 'aria-haspopup': 'dialog',\n onClick: handleClick,\n ...props,\n },\n children,\n )\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogOverlay\n// ---------------------------------------------------------------------------\n\nexport interface DialogOverlayProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const DialogOverlay = React.forwardRef<HTMLDivElement, DialogOverlayProps>(\n function DialogOverlay({ className, onClick, ...props }, ref) {\n const { open, onOpenChange } = useDialogContext()\n\n if (!open) return null\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n // Only close if clicking the overlay itself, not children\n if (e.target === e.currentTarget) {\n onOpenChange(false)\n }\n onClick?.(e)\n }\n\n return React.createElement('div', {\n ref,\n className: cn(overlayStyles, className),\n 'data-state': open ? 'open' : 'closed',\n onClick: handleClick,\n ...props,\n })\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogContent\n// ---------------------------------------------------------------------------\n\nexport interface DialogContentProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Whether `type` appears in the element tree — covers the first and server\n * render, before a mounted DialogTitle/DialogDescription has registered.\n * Parts nested inside custom components are found once they mount.\n */\nfunction containsElement(node: React.ReactNode, type: React.ElementType): boolean {\n let found = false\n React.Children.forEach(node, (child) => {\n if (found || !React.isValidElement<{ children?: React.ReactNode }>(child)) return\n found = child.type === type || containsElement(child.props.children, type)\n })\n return found\n}\n\nexport const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps>(\n function DialogContent({ className, children, onKeyDown, ...props }, ref) {\n const { open, onOpenChange, modal, contentId, titleId, descriptionId, hasTitle, hasDescription } =\n useDialogContext()\n\n const api = React.useMemo(\n () => createDialog({ open, modal }),\n [open, modal],\n )\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const handler = createKeyboardHandler({\n Escape: (ev) => {\n ev.preventDefault()\n onOpenChange(false)\n },\n })\n handler(e.nativeEvent)\n onKeyDown?.(e)\n }\n\n if (!open) return null\n\n const content = React.createElement(\n 'div',\n {\n ref,\n role: 'dialog',\n 'aria-modal': modal,\n // Reference only parts that exist: an id pointing at nothing leaves the\n // dialog unnamed while looking labelled.\n 'aria-labelledby': hasTitle || containsElement(children, DialogTitle) ? titleId : undefined,\n 'aria-describedby':\n hasDescription || containsElement(children, DialogDescription) ? descriptionId : undefined,\n id: contentId,\n className: cn(dialogContentVariants(), className),\n onKeyDown: handleKeyDown,\n tabIndex: -1,\n ...props,\n },\n children,\n )\n\n // Render via portal if document is available (client-side)\n if (typeof document !== 'undefined') {\n return ReactDOM.createPortal(content, document.body)\n }\n\n // SSR fallback: render inline\n return content\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogHeader\n// ---------------------------------------------------------------------------\n\nexport interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(\n function DialogHeader({ className, ...props }, ref) {\n return React.createElement('div', {\n ref,\n className: cn('flex flex-col space-y-1.5 text-center sm:text-left', className),\n ...props,\n })\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogFooter\n// ---------------------------------------------------------------------------\n\nexport interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(\n function DialogFooter({ className, ...props }, ref) {\n return React.createElement('div', {\n ref,\n className: cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',\n className,\n ),\n ...props,\n })\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogTitle\n// ---------------------------------------------------------------------------\n\nexport interface DialogTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {}\n\nexport const DialogTitle = React.forwardRef<HTMLHeadingElement, DialogTitleProps>(\n function DialogTitle({ className, ...props }, ref) {\n const { titleId, setHasTitle } = useDialogContext()\n React.useEffect(() => {\n setHasTitle(true)\n return () => setHasTitle(false)\n }, [setHasTitle])\n\n return React.createElement('h2', {\n ref,\n id: titleId,\n className: cn('text-lg font-semibold leading-none tracking-tight', className),\n ...props,\n })\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogDescription\n// ---------------------------------------------------------------------------\n\nexport interface DialogDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {}\n\nexport const DialogDescription = React.forwardRef<\n HTMLParagraphElement,\n DialogDescriptionProps\n>(function DialogDescription({ className, ...props }, ref) {\n const { descriptionId, setHasDescription } = useDialogContext()\n React.useEffect(() => {\n setHasDescription(true)\n return () => setHasDescription(false)\n }, [setHasDescription])\n\n return React.createElement('p', {\n ref,\n id: descriptionId,\n className: cn('text-sm text-muted-foreground', className),\n ...props,\n })\n})\n\n// ---------------------------------------------------------------------------\n// DialogClose\n// ---------------------------------------------------------------------------\n\nexport interface DialogCloseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}\n\nexport const DialogClose = React.forwardRef<HTMLButtonElement, DialogCloseProps>(\n function DialogClose({ onClick, children, ...props }, ref) {\n const { onOpenChange } = useDialogContext()\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n onOpenChange(false)\n onClick?.(e)\n }\n\n return React.createElement(\n 'button',\n {\n ref,\n type: 'button',\n onClick: handleClick,\n ...props,\n },\n children,\n )\n },\n)\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport * as ReactDOM from 'react-dom'\nimport {\n overlayStyles,\n dialogContentVariants,\n} from '@refraction-ui/dialog'\nimport { cn, createKeyboardHandler, devWarn } from '@refraction-ui/shared'\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ninterface DialogContextValue {\n open: boolean\n onOpenChange: (open: boolean) => void\n modal: boolean\n contentId: string\n titleId: string\n descriptionId: string\n /** Whether a DialogTitle / DialogDescription is mounted — only then is it referenced. */\n hasTitle: boolean\n hasDescription: boolean\n setHasTitle: (present: boolean) => void\n setHasDescription: (present: boolean) => void\n}\n\nconst DialogContext = React.createContext<DialogContextValue | null>(null)\n\nfunction useDialogContext(): DialogContextValue {\n const ctx = React.useContext(DialogContext)\n if (!ctx) {\n devWarn(\n 'react-dialog/context-outside-provider',\n 'Dialog compound components (DialogTrigger/DialogContent/DialogTitle/etc.) must be rendered inside a <Dialog>. The missing DialogContext makes this throw.',\n )\n throw new Error('Dialog compound components must be used within <Dialog>')\n }\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// Dialog (root provider)\n// ---------------------------------------------------------------------------\n\nexport interface DialogProps {\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n modal?: boolean\n children?: React.ReactNode\n}\n\nexport function Dialog({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n modal = true,\n children,\n}: DialogProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (next: boolean) => {\n if (!isControlled) {\n setUncontrolledOpen(next)\n }\n onOpenChange?.(next)\n },\n [isControlled, onOpenChange],\n )\n\n // React's tree-derived IDs survive SSR requests and client hydration.\n const id = React.useId()\n const contentId = `rfr-dialog-content-${id}`\n const titleId = `rfr-dialog-title-${id}`\n const descriptionId = `rfr-dialog-desc-${id}`\n const [hasTitle, setHasTitle] = React.useState(false)\n const [hasDescription, setHasDescription] = React.useState(false)\n\n const ctx = React.useMemo<DialogContextValue>(\n () => ({\n open,\n onOpenChange: handleOpenChange,\n modal,\n contentId,\n titleId,\n descriptionId,\n hasTitle,\n hasDescription,\n setHasTitle,\n setHasDescription,\n }),\n [open, handleOpenChange, modal, contentId, titleId, descriptionId, hasTitle, hasDescription],\n )\n\n return React.createElement(DialogContext.Provider, { value: ctx }, children)\n}\n\n// ---------------------------------------------------------------------------\n// DialogTrigger\n// ---------------------------------------------------------------------------\n\nexport interface DialogTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n asChild?: boolean\n}\n\nexport const DialogTrigger = React.forwardRef<HTMLButtonElement, DialogTriggerProps>(\n function DialogTrigger({ asChild = false, onClick, children, ...props }, ref) {\n const { open, onOpenChange, contentId } = useDialogContext()\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event)\n if (!event.defaultPrevented) onOpenChange(!open)\n }\n const triggerProps = {\n type: 'button' as const,\n 'aria-expanded': open,\n 'aria-controls': contentId,\n 'aria-haspopup': 'dialog' as const,\n ...props,\n onClick: handleClick,\n }\n\n if (asChild) {\n if (!React.isValidElement(children)) {\n devWarn('dialog-trigger-asChild-child', 'DialogTrigger: `asChild` expects a single React element child; rendering nothing.')\n return null\n }\n const child = children as React.ReactElement<React.ButtonHTMLAttributes<HTMLButtonElement> & {\n ref?: React.Ref<HTMLButtonElement>\n }> & { ref?: React.Ref<HTMLButtonElement> }\n // React 19 moved ref into props; reading element.ref there emits a warning.\n const childRef = React.version.startsWith('18.') ? child.ref : child.props.ref\n return React.cloneElement(child, {\n ...triggerProps,\n className: cn(props.className, child.props.className),\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n child.props.onClick?.(event)\n if (!event.defaultPrevented) handleClick(event)\n },\n ref: (node: HTMLButtonElement | null) => {\n const outerCleanup: unknown = typeof ref === 'function' ? ref(node) : undefined\n if (ref && typeof ref !== 'function') ref.current = node\n const childCleanup: unknown = typeof childRef === 'function' ? childRef(node) : undefined\n if (childRef && typeof childRef !== 'function') childRef.current = node\n if (typeof outerCleanup === 'function' || typeof childCleanup === 'function') {\n return () => {\n if (typeof outerCleanup === 'function') outerCleanup()\n else if (typeof ref === 'function') ref(null)\n else if (ref) ref.current = null\n if (typeof childCleanup === 'function') childCleanup()\n else if (typeof childRef === 'function') childRef(null)\n else if (childRef) childRef.current = null\n }\n }\n },\n })\n }\n\n return React.createElement('button', { ref, ...triggerProps }, children)\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogOverlay\n// ---------------------------------------------------------------------------\n\nexport interface DialogOverlayProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const DialogOverlay = React.forwardRef<HTMLDivElement, DialogOverlayProps>(\n function DialogOverlay({ className, onClick, ...props }, ref) {\n const { open, onOpenChange } = useDialogContext()\n\n if (!open) return null\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n // Only close if clicking the overlay itself, not children\n if (e.target === e.currentTarget) {\n onOpenChange(false)\n }\n onClick?.(e)\n }\n\n return React.createElement('div', {\n ref,\n className: cn(overlayStyles, className),\n 'data-state': open ? 'open' : 'closed',\n onClick: handleClick,\n ...props,\n })\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogContent\n// ---------------------------------------------------------------------------\n\nexport interface DialogContentProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Whether `type` appears in the element tree — covers the first and server\n * render, before a mounted DialogTitle/DialogDescription has registered.\n * Parts nested inside custom components are found once they mount.\n */\nfunction containsElement(node: React.ReactNode, type: React.ElementType): boolean {\n let found = false\n React.Children.forEach(node, (child) => {\n if (found || !React.isValidElement<{ children?: React.ReactNode }>(child)) return\n found = child.type === type || containsElement(child.props.children, type)\n })\n return found\n}\n\nexport const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps>(\n function DialogContent({ className, children, onKeyDown, ...props }, ref) {\n const { open, onOpenChange, modal, contentId, titleId, descriptionId, hasTitle, hasDescription } =\n useDialogContext()\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const handler = createKeyboardHandler({\n Escape: (ev) => {\n ev.preventDefault()\n onOpenChange(false)\n },\n })\n handler(e.nativeEvent)\n onKeyDown?.(e)\n }\n\n if (!open) return null\n\n const content = React.createElement(\n 'div',\n {\n ref,\n role: 'dialog',\n 'aria-modal': modal,\n // Reference only parts that exist: an id pointing at nothing leaves the\n // dialog unnamed while looking labelled.\n 'aria-labelledby': hasTitle || containsElement(children, DialogTitle) ? titleId : undefined,\n 'aria-describedby':\n hasDescription || containsElement(children, DialogDescription) ? descriptionId : undefined,\n id: contentId,\n className: cn(dialogContentVariants(), className),\n onKeyDown: handleKeyDown,\n tabIndex: -1,\n ...props,\n },\n children,\n )\n\n // Render via portal if document is available (client-side)\n if (typeof document !== 'undefined') {\n return ReactDOM.createPortal(content, document.body)\n }\n\n // SSR fallback: render inline\n return content\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogHeader\n// ---------------------------------------------------------------------------\n\nexport interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(\n function DialogHeader({ className, ...props }, ref) {\n return React.createElement('div', {\n ref,\n className: cn('flex flex-col space-y-1.5 text-center sm:text-left', className),\n ...props,\n })\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogFooter\n// ---------------------------------------------------------------------------\n\nexport interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(\n function DialogFooter({ className, ...props }, ref) {\n return React.createElement('div', {\n ref,\n className: cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',\n className,\n ),\n ...props,\n })\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogTitle\n// ---------------------------------------------------------------------------\n\nexport interface DialogTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {}\n\nexport const DialogTitle = React.forwardRef<HTMLHeadingElement, DialogTitleProps>(\n function DialogTitle({ className, ...props }, ref) {\n const { titleId, setHasTitle } = useDialogContext()\n React.useEffect(() => {\n setHasTitle(true)\n return () => setHasTitle(false)\n }, [setHasTitle])\n\n return React.createElement('h2', {\n ref,\n id: titleId,\n className: cn('text-lg font-semibold leading-none tracking-tight', className),\n ...props,\n })\n },\n)\n\n// ---------------------------------------------------------------------------\n// DialogDescription\n// ---------------------------------------------------------------------------\n\nexport interface DialogDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {}\n\nexport const DialogDescription = React.forwardRef<\n HTMLParagraphElement,\n DialogDescriptionProps\n>(function DialogDescription({ className, ...props }, ref) {\n const { descriptionId, setHasDescription } = useDialogContext()\n React.useEffect(() => {\n setHasDescription(true)\n return () => setHasDescription(false)\n }, [setHasDescription])\n\n return React.createElement('p', {\n ref,\n id: descriptionId,\n className: cn('text-sm text-muted-foreground', className),\n ...props,\n })\n})\n\n// ---------------------------------------------------------------------------\n// DialogClose\n// ---------------------------------------------------------------------------\n\nexport interface DialogCloseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}\n\nexport const DialogClose = React.forwardRef<HTMLButtonElement, DialogCloseProps>(\n function DialogClose({ onClick, children, ...props }, ref) {\n const { onOpenChange } = useDialogContext()\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n onOpenChange(false)\n onClick?.(e)\n }\n\n return React.createElement(\n 'button',\n {\n ref,\n type: 'button',\n onClick: handleClick,\n ...props,\n },\n children,\n )\n },\n)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["DialogTrigger", "DialogOverlay", "DialogContent", "DialogHeader", "DialogFooter", "DialogTitle", "DialogDescription", "DialogClose"]
|
|
7
7
|
}
|