@refraction-ui/react 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +558 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +547 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/kanban-board/index.d.ts +98 -0
- package/dist/internal/react-kanban-board/index.d.ts +71 -0
- package/dist/internal/react-slot-picker/index.d.ts +31 -0
- package/dist/internal/react-sortable-list/index.d.ts +35 -0
- package/dist/internal/slot-picker/index.d.ts +77 -0
- package/package.json +4 -1
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** A single column definition for the Kanban board. */
|
|
2
|
+
type KanbanColumnDef = {
|
|
3
|
+
/** Unique identifier for this column (matches cards' column id). */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Display title of the column (e.g. stage name). */
|
|
6
|
+
title: string;
|
|
7
|
+
/** Optional accent color applied via CSS var `--kanban-accent`. */
|
|
8
|
+
accent?: string;
|
|
9
|
+
/** Optional note or gate description shown below the column header. */
|
|
10
|
+
note?: string;
|
|
11
|
+
};
|
|
12
|
+
interface KanbanBoardAPI {
|
|
13
|
+
/** ARIA attributes to spread on the board container. */
|
|
14
|
+
ariaProps: {
|
|
15
|
+
role: 'group';
|
|
16
|
+
'aria-label': string;
|
|
17
|
+
};
|
|
18
|
+
/** Data attributes for styling hooks. */
|
|
19
|
+
dataAttributes: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build the framework-agnostic board props.
|
|
23
|
+
*
|
|
24
|
+
* Returns `role="group"` with a fixed accessible label and data attributes
|
|
25
|
+
* so adapters can style based on state without inlining logic.
|
|
26
|
+
*/
|
|
27
|
+
declare function createKanbanBoard(): KanbanBoardAPI;
|
|
28
|
+
/**
|
|
29
|
+
* Bucket cards into a Map keyed by column id, preserving column order.
|
|
30
|
+
* Columns that have no cards get an empty array entry so callers can always
|
|
31
|
+
* iterate `columns` and look up their bucket safely.
|
|
32
|
+
*
|
|
33
|
+
* @param cards - All cards to distribute.
|
|
34
|
+
* @param getColumnId - Selector that reads the column id from a card.
|
|
35
|
+
* @param columns - Column definitions (determines output order).
|
|
36
|
+
*/
|
|
37
|
+
declare function cardsByColumn<T>(cards: T[], getColumnId: (c: T) => string, columns: KanbanColumnDef[]): Map<string, T[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Split a card list into a visible slice and an overflow count.
|
|
40
|
+
*
|
|
41
|
+
* @param cards - Full list of cards in the column.
|
|
42
|
+
* @param cap - Maximum visible cards. Defaults to 5.
|
|
43
|
+
*/
|
|
44
|
+
declare function visibleAndOverflow<T>(cards: T[], cap?: number): {
|
|
45
|
+
visible: T[];
|
|
46
|
+
overflow: number;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/** The outer board: horizontal scroll, flex row, gap between columns. */
|
|
50
|
+
declare const kanbanBoardVariants: (props?: ({} & {
|
|
51
|
+
className?: string;
|
|
52
|
+
}) | undefined) => string;
|
|
53
|
+
/** A single column: muted background, rounded, fixed minimum width. */
|
|
54
|
+
declare const kanbanColumnVariants: (props?: ({} & {
|
|
55
|
+
className?: string;
|
|
56
|
+
}) | undefined) => string;
|
|
57
|
+
/** Column header row: icon slot + title + count badge. */
|
|
58
|
+
declare const kanbanColumnHeaderClass = "flex items-center gap-2 px-4 pt-4 pb-2";
|
|
59
|
+
/** Column title text. */
|
|
60
|
+
declare const kanbanColumnTitleClass = "flex-1 text-sm font-semibold text-foreground truncate";
|
|
61
|
+
/**
|
|
62
|
+
* Column count badge: a compact pill to the right of the title.
|
|
63
|
+
* Uses muted tokens so it sits quietly against any column accent.
|
|
64
|
+
*/
|
|
65
|
+
declare const kanbanColumnCountClass = "ml-auto inline-flex items-center justify-center rounded-full bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground";
|
|
66
|
+
/**
|
|
67
|
+
* Thin accent bar directly below the header.
|
|
68
|
+
* Callers apply `style={{ '--kanban-accent': def.accent }}` on the column
|
|
69
|
+
* element; this bar reads `var(--kanban-accent)` via an inline style.
|
|
70
|
+
* When no accent is supplied the bar is invisible (transparent).
|
|
71
|
+
*/
|
|
72
|
+
declare const kanbanAccentBarClass = "h-0.5 w-full";
|
|
73
|
+
/**
|
|
74
|
+
* Note/gate bar shown beneath the accent bar.
|
|
75
|
+
* Displays brief stage notes (e.g. "Technical screen required").
|
|
76
|
+
*/
|
|
77
|
+
declare const kanbanNoteBarClass = "mx-4 mb-2 rounded-md bg-muted px-3 py-1.5 text-xs text-muted-foreground";
|
|
78
|
+
/** Column body: card stack with gap, padded sides and bottom. */
|
|
79
|
+
declare const kanbanColumnBodyClass = "flex flex-col gap-2 px-3 pb-3";
|
|
80
|
+
/**
|
|
81
|
+
* "+N more" overflow button.
|
|
82
|
+
* Styled as a subtle full-width ghost button inside the column.
|
|
83
|
+
*/
|
|
84
|
+
declare const kanbanOverflowButtonClass: string;
|
|
85
|
+
/**
|
|
86
|
+
* Default card surface.
|
|
87
|
+
*
|
|
88
|
+
* Variants:
|
|
89
|
+
* - `clickable: 'true'` — adds hover treatment for interactive cards.
|
|
90
|
+
* - `clickable: 'false'` — static (default).
|
|
91
|
+
*/
|
|
92
|
+
declare const kanbanCardVariants: (props?: ({
|
|
93
|
+
clickable?: "true" | "false" | undefined;
|
|
94
|
+
} & {
|
|
95
|
+
className?: string;
|
|
96
|
+
}) | undefined) => string;
|
|
97
|
+
|
|
98
|
+
export { type KanbanBoardAPI, type KanbanColumnDef, cardsByColumn, createKanbanBoard, kanbanAccentBarClass, kanbanBoardVariants, kanbanCardVariants, kanbanColumnBodyClass, kanbanColumnCountClass, kanbanColumnHeaderClass, kanbanColumnTitleClass, kanbanColumnVariants, kanbanNoteBarClass, kanbanOverflowButtonClass, visibleAndOverflow };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { KanbanColumnDef } from '../kanban-board/index.js';
|
|
3
|
+
export { KanbanColumnDef } from '../kanban-board/index.js';
|
|
4
|
+
|
|
5
|
+
interface KanbanCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'content'> {
|
|
6
|
+
/** Optional accent color for a top border treatment (CSS color value). */
|
|
7
|
+
accent?: string;
|
|
8
|
+
/** Whether the card should show hover/click affordance. */
|
|
9
|
+
clickable?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* KanbanCard — the card surface inside a column.
|
|
13
|
+
*
|
|
14
|
+
* Renders a bordered `bg-card` block. Pass `clickable` for hover treatment and
|
|
15
|
+
* an `onClick` handler for interaction. Children define the card content.
|
|
16
|
+
*/
|
|
17
|
+
declare const KanbanCard: React.ForwardRefExoticComponent<KanbanCardProps & React.RefAttributes<HTMLDivElement>>;
|
|
18
|
+
interface KanbanColumnProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'content'> {
|
|
19
|
+
/** Column definition (id, title, accent, note). */
|
|
20
|
+
def: KanbanColumnDef;
|
|
21
|
+
/** Card count shown in the header badge. If omitted, derived from children. */
|
|
22
|
+
count?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* KanbanColumn — a single stage column with a header and optional note bar.
|
|
26
|
+
*
|
|
27
|
+
* Place `<KanbanCard>` elements as children. The count badge is derived from
|
|
28
|
+
* `React.Children.count(children)` when `count` is not provided.
|
|
29
|
+
*/
|
|
30
|
+
declare const KanbanColumn: React.ForwardRefExoticComponent<KanbanColumnProps & React.RefAttributes<HTMLDivElement>>;
|
|
31
|
+
interface KanbanBoardProps<T> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'content' | 'onSelect' | 'results'> {
|
|
32
|
+
/** Column definitions (order determines left-to-right render order). */
|
|
33
|
+
columns: KanbanColumnDef[];
|
|
34
|
+
/** All cards to distribute into columns. */
|
|
35
|
+
cards: T[];
|
|
36
|
+
/** Selector returning the column id for a card. */
|
|
37
|
+
getCardColumnId: (card: T) => string;
|
|
38
|
+
/** Selector returning a unique React key for a card. */
|
|
39
|
+
getCardKey: (card: T) => string;
|
|
40
|
+
/** Render a single card inside a column. */
|
|
41
|
+
renderCard: (card: T, columnDef: KanbanColumnDef) => React.ReactNode;
|
|
42
|
+
/** Max visible cards per column before showing "+N more". Defaults to 5. */
|
|
43
|
+
cardCap?: number;
|
|
44
|
+
/** Called when the user clicks a card (passed through to renderCard context). */
|
|
45
|
+
onCardClick?: (card: T) => void;
|
|
46
|
+
/** Override the column header render. Receives the def and card count. */
|
|
47
|
+
columnHeader?: (def: KanbanColumnDef, count: number) => React.ReactNode;
|
|
48
|
+
/** Called when the user taps "+N more" for a column. */
|
|
49
|
+
onShowMore?: (columnId: string) => void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* KanbanBoard — a generic multi-column stage board.
|
|
53
|
+
*
|
|
54
|
+
* Distributes `cards` into columns defined by `columns` using `getCardColumnId`.
|
|
55
|
+
* Each column caps at `cardCap` (default 5) visible cards and shows a
|
|
56
|
+
* "+N more" button for the overflow.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* <KanbanBoard
|
|
61
|
+
* columns={stages}
|
|
62
|
+
* cards={candidates}
|
|
63
|
+
* getCardColumnId={(c) => c.stageId}
|
|
64
|
+
* getCardKey={(c) => c.id}
|
|
65
|
+
* renderCard={(c) => <KanbanCard clickable>{c.name}</KanbanCard>}
|
|
66
|
+
* />
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function KanbanBoard<T>({ columns, cards, getCardColumnId, getCardKey, renderCard, cardCap, onCardClick: _onCardClick, columnHeader, onShowMore, className, ...props }: KanbanBoardProps<T>): React.ReactElement;
|
|
70
|
+
|
|
71
|
+
export { KanbanBoard, type KanbanBoardProps, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { SlotDay, SlotSelection } from '../slot-picker/index.js';
|
|
3
|
+
export { SlotDay, SlotSelection } from '../slot-picker/index.js';
|
|
4
|
+
|
|
5
|
+
interface SlotPickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'results' | 'color' | 'content' | 'defaultValue' | 'onChange'> {
|
|
6
|
+
/** The list of days to show as chips. */
|
|
7
|
+
days: SlotDay[];
|
|
8
|
+
/** Map of dayId → available time slot strings. */
|
|
9
|
+
slotsByDay: Record<string, string[]>;
|
|
10
|
+
/** Controlled selection value. */
|
|
11
|
+
value?: SlotSelection;
|
|
12
|
+
/** Initial selection for uncontrolled usage. */
|
|
13
|
+
defaultValue?: SlotSelection;
|
|
14
|
+
/** Called when the user picks a day + slot. */
|
|
15
|
+
onChange?: (selection: SlotSelection) => void;
|
|
16
|
+
/** Label shown beside the "Pick a time" heading (e.g. "Eastern Time"). */
|
|
17
|
+
timezoneLabel?: string;
|
|
18
|
+
/** Slot strings that should be rendered as disabled. */
|
|
19
|
+
disabledSlots?: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* SlotPicker — a Calendly-style day + time-slot booking picker.
|
|
23
|
+
*
|
|
24
|
+
* Renders a row of day chips (radiogroup) and a grid of time-slot buttons
|
|
25
|
+
* (radiogroup) for the currently-selected day. Supports controlled (`value`)
|
|
26
|
+
* and uncontrolled (`defaultValue`) usage. Selecting a day clears the slot
|
|
27
|
+
* when the previously-chosen slot is not available on the new day.
|
|
28
|
+
*/
|
|
29
|
+
declare const SlotPicker: React.ForwardRefExoticComponent<SlotPickerProps & React.RefAttributes<HTMLDivElement>>;
|
|
30
|
+
|
|
31
|
+
export { SlotPicker, type SlotPickerProps };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/** Props injected into each rendered row via renderItem. */
|
|
4
|
+
interface DragHandleProps {
|
|
5
|
+
/** Must be spread onto the grip element (button). */
|
|
6
|
+
'aria-label': string;
|
|
7
|
+
/** Role is already set inside the component; exposed for convenience. */
|
|
8
|
+
role: 'button';
|
|
9
|
+
tabIndex: number;
|
|
10
|
+
onKeyDown: (event: React.KeyboardEvent<HTMLButtonElement>) => void;
|
|
11
|
+
onDragStart: (event: React.DragEvent<HTMLButtonElement>) => void;
|
|
12
|
+
}
|
|
13
|
+
interface SortableListProps<T> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'results' | 'color' | 'content' | 'children'> {
|
|
14
|
+
/** The ordered list of items to render. */
|
|
15
|
+
items: T[];
|
|
16
|
+
/** Return a stable key for each item. */
|
|
17
|
+
getKey: (item: T, index: number) => string | number;
|
|
18
|
+
/**
|
|
19
|
+
* Render the content of a single row.
|
|
20
|
+
* Spread `dragHandleProps` onto your grip button so keyboard + DnD work.
|
|
21
|
+
*/
|
|
22
|
+
renderItem: (item: T, meta: {
|
|
23
|
+
index: number;
|
|
24
|
+
dragHandleProps: DragHandleProps;
|
|
25
|
+
}) => React.ReactNode;
|
|
26
|
+
/** Called when the user reorders an item. Receives the new items array. */
|
|
27
|
+
onReorder?: (items: T[]) => void;
|
|
28
|
+
/** Disables all drag and keyboard reordering. */
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
}
|
|
31
|
+
declare const SortableList: <T>(props: SortableListProps<T> & {
|
|
32
|
+
ref?: React.ForwardedRef<HTMLDivElement>;
|
|
33
|
+
}) => React.ReactElement | null;
|
|
34
|
+
|
|
35
|
+
export { type DragHandleProps, SortableList, type SortableListProps };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** A single day chip shown in the day-selector row. */
|
|
2
|
+
type SlotDay = {
|
|
3
|
+
/** Unique identifier for the day (e.g. "2024-06-14"). */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Short weekday label (e.g. "Fri"). */
|
|
6
|
+
weekday: string;
|
|
7
|
+
/** Day-of-month label (e.g. "14" or 14). */
|
|
8
|
+
dayNum: string | number;
|
|
9
|
+
};
|
|
10
|
+
/** The currently-selected day + time slot pair. */
|
|
11
|
+
type SlotSelection = {
|
|
12
|
+
/** The `id` of the selected day. */
|
|
13
|
+
dayId: string;
|
|
14
|
+
/** The selected time slot string (e.g. "10:00 AM"). */
|
|
15
|
+
slot: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Return the list of available time slots for a given day.
|
|
19
|
+
* Returns an empty array when `dayId` has no entry in `slotsByDay`.
|
|
20
|
+
*/
|
|
21
|
+
declare function slotsForDay(slotsByDay: Record<string, string[]>, dayId: string): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Check whether a specific slot in a specific day is currently selected.
|
|
24
|
+
*/
|
|
25
|
+
declare function isSlotSelected(value: SlotSelection | undefined, dayId: string, slot: string): boolean;
|
|
26
|
+
interface SlotPickerAPI {
|
|
27
|
+
/** ARIA attributes to spread on the root group element. */
|
|
28
|
+
ariaProps: {
|
|
29
|
+
role: 'group';
|
|
30
|
+
'aria-label': string;
|
|
31
|
+
};
|
|
32
|
+
/** Data attributes for styling hooks. */
|
|
33
|
+
dataAttributes: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build the framework-agnostic root props for a slot picker.
|
|
37
|
+
*
|
|
38
|
+
* Returns `role="group"` with an accessible label and data attributes.
|
|
39
|
+
* Adapters spread these onto their container element.
|
|
40
|
+
*/
|
|
41
|
+
declare function createSlotPicker(): SlotPickerAPI;
|
|
42
|
+
|
|
43
|
+
/** Root wrapper for the entire slot picker (day row + slots grid). */
|
|
44
|
+
declare const slotPickerVariants: (props?: ({} & {
|
|
45
|
+
className?: string;
|
|
46
|
+
}) | undefined) => string;
|
|
47
|
+
/** Scrollable row of day chips. */
|
|
48
|
+
declare const slotPickerDayRowClass = "flex items-center gap-2 overflow-x-auto pb-1";
|
|
49
|
+
/**
|
|
50
|
+
* Individual day chip.
|
|
51
|
+
*
|
|
52
|
+
* `selected` → primary treatment; `unselected` → card with border.
|
|
53
|
+
*/
|
|
54
|
+
declare const slotPickerDayVariants: (props?: ({
|
|
55
|
+
selected?: "true" | "false" | undefined;
|
|
56
|
+
} & {
|
|
57
|
+
className?: string;
|
|
58
|
+
}) | undefined) => string;
|
|
59
|
+
/** Grid that holds the time-slot buttons. */
|
|
60
|
+
declare const slotPickerGridClass = "grid grid-cols-3 gap-2 sm:grid-cols-4";
|
|
61
|
+
/**
|
|
62
|
+
* Individual time-slot button.
|
|
63
|
+
*
|
|
64
|
+
* `selected` → primary; `disabled` → dimmed regardless of selection.
|
|
65
|
+
*/
|
|
66
|
+
declare const slotPickerSlotVariants: (props?: ({
|
|
67
|
+
selected?: "true" | "false" | undefined;
|
|
68
|
+
disabled?: "true" | "false" | undefined;
|
|
69
|
+
} & {
|
|
70
|
+
className?: string;
|
|
71
|
+
}) | undefined) => string;
|
|
72
|
+
/** Section label above the day row or slot grid (e.g. "Pick a day"). */
|
|
73
|
+
declare const slotPickerSectionLabelClass = "text-sm font-semibold text-foreground";
|
|
74
|
+
/** Timezone label rendered beside the "Pick a time" heading. */
|
|
75
|
+
declare const slotPickerTimezoneClass = "text-xs text-muted-foreground ml-2";
|
|
76
|
+
|
|
77
|
+
export { type SlotDay, type SlotPickerAPI, type SlotSelection, createSlotPicker, isSlotSelected, slotPickerDayRowClass, slotPickerDayVariants, slotPickerGridClass, slotPickerSectionLabelClass, slotPickerSlotVariants, slotPickerTimezoneClass, slotPickerVariants, slotsForDay };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@refraction-ui/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "All Refraction UI React components in one package — headless, accessible, zero-dependency",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
"@refraction-ui/react-input": "workspace:*",
|
|
108
108
|
"@refraction-ui/react-input-group": "workspace:*",
|
|
109
109
|
"@refraction-ui/react-install-prompt": "workspace:*",
|
|
110
|
+
"@refraction-ui/react-kanban-board": "workspace:*",
|
|
110
111
|
"@refraction-ui/react-keyboard-shortcut": "workspace:*",
|
|
111
112
|
"@refraction-ui/react-language-selector": "workspace:*",
|
|
112
113
|
"@refraction-ui/react-link-card": "workspace:*",
|
|
@@ -147,7 +148,9 @@
|
|
|
147
148
|
"@refraction-ui/react-skip-to-content": "workspace:*",
|
|
148
149
|
"@refraction-ui/react-slide-viewer": "workspace:*",
|
|
149
150
|
"@refraction-ui/react-slider": "workspace:*",
|
|
151
|
+
"@refraction-ui/react-slot-picker": "workspace:*",
|
|
150
152
|
"@refraction-ui/react-social-auth-button": "workspace:*",
|
|
153
|
+
"@refraction-ui/react-sortable-list": "workspace:*",
|
|
151
154
|
"@refraction-ui/react-stat-grid": "workspace:*",
|
|
152
155
|
"@refraction-ui/react-status-indicator": "workspace:*",
|
|
153
156
|
"@refraction-ui/react-steps": "workspace:*",
|