@colineapp/ui 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -0
- package/README.md +37 -0
- package/dist/index.d.ts +20 -6
- package/dist/index.js +105 -126
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -2
package/AGENTS.md
CHANGED
|
@@ -100,3 +100,15 @@ Keep state/conflict/sync logic in the SDK; React owns only subscriptions and
|
|
|
100
100
|
lifecycle. Inline serializable query objects must not restart the view on each
|
|
101
101
|
render. React Strict Mode cleanup/start must remain supported. Never infer record
|
|
102
102
|
permission from optimistic state or broadcast private fields to an install room.
|
|
103
|
+
|
|
104
|
+
## UI 0.4.1 defaults
|
|
105
|
+
|
|
106
|
+
Use `Tabs` / `TabsList` / `TabsTrigger` / `TabsContent` for app views. The raised
|
|
107
|
+
sliding selection and content transition are automatic. Do not recreate tab
|
|
108
|
+
buttons or choose the opt-in line variant for standard Coline navigation.
|
|
109
|
+
Use `FilterMenu` for value filters, and `DropdownMenu` for actions. Both use the
|
|
110
|
+
canonical Coline menu surface and highlight. `pnpm check:parity` enforces the
|
|
111
|
+
vendored dropdown implementation; `pnpm sync:platform` refreshes it.
|
|
112
|
+
Keep animation CSS in the package, respect reduced motion, and verify controls
|
|
113
|
+
in a portalled dialog as well as on the page. A form submit button needs explicit
|
|
114
|
+
`type="submit"`. Do not restyle shared controls with app-specific CSS.
|
package/README.md
CHANGED
|
@@ -111,3 +111,40 @@ routing, drag-and-drop, or persistence. `RecordTable` provides a first-cell butt
|
|
|
111
111
|
when `onOpen` is set (don't nest a second control there); secondary columns hide
|
|
112
112
|
at narrow widths. Split details stack on mobile; the app owns focus management.
|
|
113
113
|
See the scaffold's `examples/` for complete interactive references.
|
|
114
|
+
|
|
115
|
+
## Shared controls and motion (0.4.1)
|
|
116
|
+
|
|
117
|
+
`Tabs` uses the same raised selection as Coline and Upstream. Selection springs
|
|
118
|
+
and content transitions are automatic; no indicator or animation wrapper is
|
|
119
|
+
required. Each tabs group owns its indicator so multiple groups never collide.
|
|
120
|
+
`TabsIndicator` remains available for existing custom compositions.
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
<Tabs defaultValue="inbox">
|
|
124
|
+
<TabsList aria-label="Views">
|
|
125
|
+
<TabsTrigger value="inbox">Inbox</TabsTrigger>
|
|
126
|
+
<TabsTrigger value="roadmap">Roadmap</TabsTrigger>
|
|
127
|
+
</TabsList>
|
|
128
|
+
<TabsContent value="inbox">{/* Inbox */}</TabsContent>
|
|
129
|
+
<TabsContent value="roadmap">{/* Roadmap */}</TabsContent>
|
|
130
|
+
</Tabs>
|
|
131
|
+
<FilterMenu
|
|
132
|
+
aria-label="Filter by status"
|
|
133
|
+
value={status}
|
|
134
|
+
onValueChange={setStatus}
|
|
135
|
+
options={[{ value: "all", label: "All statuses" }, { value: "planned", label: "Planned" }]}
|
|
136
|
+
/>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`FilterMenu` composes the exact Coline `DropdownMenu` radio group, surface, and
|
|
140
|
+
sliding highlight. Use `DropdownMenu` directly for action menus. `PageToolbar`
|
|
141
|
+
is borderless. `RecordTable` uses separated, rounded selection/hover rows.
|
|
142
|
+
Dialogs and menus include their animation CSS; the provider respects reduced
|
|
143
|
+
motion, including portals. Buttons default to `type="button"`; use
|
|
144
|
+
`type="submit"` for a form's submit action.
|
|
145
|
+
|
|
146
|
+
Use component defaults rather than copying their CSS into the app. Custom CSS
|
|
147
|
+
variables scoped to `AppPage` do not reach portalled dialogs/menus. Keep decorative
|
|
148
|
+
app variables at `:root` when they must cross portals, and retain host theme tokens.
|
|
149
|
+
App bundles include their dependencies: upgrade, rebuild and push to adopt a UI
|
|
150
|
+
release. Updating npm does not rewrite already-published app bundles.
|
package/dist/index.d.ts
CHANGED
|
@@ -168,21 +168,21 @@ declare function TableHead({ className, ...props }: React$1.ComponentProps<"th">
|
|
|
168
168
|
declare function TableCell({ className, ...props }: React$1.ComponentProps<"td">): React$1.JSX.Element;
|
|
169
169
|
declare function TableCaption({ className, ...props }: React$1.ComponentProps<"caption">): React$1.JSX.Element;
|
|
170
170
|
|
|
171
|
-
/**
|
|
171
|
+
/** Same raised selection and spring as Coline and Upstream navigation. */
|
|
172
172
|
declare const TABS_LAYOUT_SPRING: {
|
|
173
173
|
type: "spring";
|
|
174
174
|
stiffness: number;
|
|
175
175
|
damping: number;
|
|
176
176
|
mass: number;
|
|
177
177
|
};
|
|
178
|
-
declare function Tabs({ className, orientation, ...props }: React$1.ComponentProps<typeof Tabs$1.Root>): React$1.JSX.Element;
|
|
178
|
+
declare function Tabs({ className, orientation, value, defaultValue, onValueChange, ...props }: React$1.ComponentProps<typeof Tabs$1.Root>): React$1.JSX.Element;
|
|
179
179
|
declare const tabsListVariants: (props?: ({
|
|
180
180
|
variant?: "default" | "line" | null | undefined;
|
|
181
181
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
182
182
|
declare function TabsList({ className, variant, ...props }: React$1.ComponentProps<typeof Tabs$1.List> & VariantProps<typeof tabsListVariants>): React$1.JSX.Element;
|
|
183
|
-
declare function TabsTrigger({ className, ...props }: React$1.ComponentProps<typeof Tabs$1.Trigger>): React$1.JSX.Element;
|
|
184
|
-
/**
|
|
185
|
-
declare function TabsIndicator({ className, layoutId
|
|
183
|
+
declare function TabsTrigger({ className, children, value, asChild, ...props }: React$1.ComponentProps<typeof Tabs$1.Trigger>): React$1.JSX.Element;
|
|
184
|
+
/** Optional customization; the raised indicator is included automatically. */
|
|
185
|
+
declare function TabsIndicator({ className, layoutId }: {
|
|
186
186
|
className?: string;
|
|
187
187
|
layoutId?: string;
|
|
188
188
|
}): React$1.JSX.Element;
|
|
@@ -296,4 +296,18 @@ declare function SettingsSection({ title, description, children, }: {
|
|
|
296
296
|
children: React$1.ReactNode;
|
|
297
297
|
}): React$1.JSX.Element;
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
/** A value picker using the same dropdown and sliding highlight as Coline. */
|
|
300
|
+
declare const FilterMenu: React$1.ForwardRefExoticComponent<{
|
|
301
|
+
value: string;
|
|
302
|
+
options: readonly {
|
|
303
|
+
value: string;
|
|
304
|
+
label: string;
|
|
305
|
+
disabled?: boolean;
|
|
306
|
+
}[];
|
|
307
|
+
onValueChange: (value: string) => void;
|
|
308
|
+
"aria-label": string;
|
|
309
|
+
disabled?: boolean;
|
|
310
|
+
className?: string;
|
|
311
|
+
} & React$1.RefAttributes<HTMLButtonElement>>;
|
|
312
|
+
|
|
313
|
+
export { AppErrorState, AppLoadingState, AppPage, Badge, Board, BoardCard, BoardColumn, Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, ColineAppProvider, type ColineQueryState, DetailPanel, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FilterMenu, Input, Label, PageToolbar, Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, type RecordColumn, RecordTable, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SettingsSection, Skeleton, Slider, SplitView, StatusBadge, Switch, TABS_LAYOUT_SPRING, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger, Textarea, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, cn, tabsListVariants, toggleVariants, useColine, useColineContext, useColineQuery, useColorScheme, useLiveCollection };
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ function cn(...inputs) {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
// src/provider.tsx
|
|
11
|
+
import { MotionConfig } from "framer-motion";
|
|
11
12
|
import * as React from "react";
|
|
12
13
|
import {
|
|
13
14
|
connectGuestBridge
|
|
@@ -67,7 +68,7 @@ function ColineAppProvider({ children }) {
|
|
|
67
68
|
if (!runtime) {
|
|
68
69
|
return /* @__PURE__ */ jsx("p", { role: connectionError ? "alert" : "status", children: connectionError ?? "Connecting to Coline\u2026" });
|
|
69
70
|
}
|
|
70
|
-
return /* @__PURE__ */ jsx(ColineRuntimeContext.Provider, { value: runtime, children });
|
|
71
|
+
return /* @__PURE__ */ jsx(ColineRuntimeContext.Provider, { value: runtime, children: /* @__PURE__ */ jsx(MotionConfig, { reducedMotion: "user", children }) });
|
|
71
72
|
}
|
|
72
73
|
function useColine() {
|
|
73
74
|
const runtime = React.useContext(ColineRuntimeContext);
|
|
@@ -165,7 +166,7 @@ import { cva as cva2 } from "class-variance-authority";
|
|
|
165
166
|
import { Slot as Slot2 } from "radix-ui";
|
|
166
167
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
167
168
|
var buttonVariants = cva2(
|
|
168
|
-
"group/button inline-flex shrink-0 items-center justify-center rounded-4xl border border-white/20 text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color] duration-
|
|
169
|
+
"coline-button group/button inline-flex shrink-0 items-center justify-center rounded-4xl border border-white/20 text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,transform,box-shadow] duration-150 ease-[cubic-bezier(0.23,1,0.32,1)] outline-none select-none focus-visible:border-ring disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20 dark:border-white/[0.06] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
169
170
|
{
|
|
170
171
|
variants: {
|
|
171
172
|
variant: {
|
|
@@ -198,6 +199,7 @@ var Button = React3.forwardRef(function Button2({
|
|
|
198
199
|
variant = "default",
|
|
199
200
|
size = "default",
|
|
200
201
|
asChild = false,
|
|
202
|
+
type,
|
|
201
203
|
...props
|
|
202
204
|
}, ref) {
|
|
203
205
|
const Comp = asChild ? Slot2.Root : "button";
|
|
@@ -205,6 +207,7 @@ var Button = React3.forwardRef(function Button2({
|
|
|
205
207
|
Comp,
|
|
206
208
|
{
|
|
207
209
|
ref,
|
|
210
|
+
...!asChild ? { type: type ?? "button" } : type ? { type } : {},
|
|
208
211
|
"data-slot": "button",
|
|
209
212
|
"data-variant": variant,
|
|
210
213
|
"data-size": size,
|
|
@@ -339,6 +342,11 @@ function Checkbox({
|
|
|
339
342
|
import "react";
|
|
340
343
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
341
344
|
import { IconX } from "@tabler/icons-react";
|
|
345
|
+
|
|
346
|
+
// src/components/liquid-menu-surface.ts
|
|
347
|
+
var liquidMenuSurfaceClasses = "rounded-2xl bg-popover/75 dark:bg-zinc-900/75 backdrop-blur-[3px] border border-black/[0.08] text-popover-foreground shadow-[0_4px_16px_-4px_rgba(0,0,0,0.08),0_16px_48px_-12px_rgba(0,0,0,0.28)] dark:border-white/[0.09] dark:bg-[#141417] dark:shadow-[0_4px_16px_-4px_rgba(0,0,0,0.4),0_16px_48px_-12px_rgba(0,0,0,0.7)]";
|
|
348
|
+
|
|
349
|
+
// src/components/dialog.tsx
|
|
342
350
|
import { jsx as jsx6, jsxs } from "react/jsx-runtime";
|
|
343
351
|
function Dialog({
|
|
344
352
|
...props
|
|
@@ -369,7 +377,7 @@ function DialogOverlay({
|
|
|
369
377
|
{
|
|
370
378
|
"data-slot": "dialog-overlay",
|
|
371
379
|
className: cn(
|
|
372
|
-
"fixed inset-0 isolate z-50 bg-black/30 supports-backdrop-filter:backdrop-blur-sm",
|
|
380
|
+
"coline-dialog-overlay fixed inset-0 isolate z-50 bg-black/30 supports-backdrop-filter:backdrop-blur-sm",
|
|
373
381
|
className
|
|
374
382
|
),
|
|
375
383
|
...props
|
|
@@ -390,15 +398,16 @@ function DialogContent({
|
|
|
390
398
|
"data-slot": "dialog-content",
|
|
391
399
|
className: cn(
|
|
392
400
|
// Mobile: bottom-sheet style, pinned to bottom with slide-up
|
|
393
|
-
"fixed z-50 grid w-full gap-4
|
|
394
|
-
|
|
401
|
+
"coline-dialog-content fixed z-50 grid w-full gap-4 p-4 text-sm outline-none",
|
|
402
|
+
liquidMenuSurfaceClasses,
|
|
403
|
+
"inset-x-0 bottom-0 max-h-[85dvh] overflow-y-auto rounded-b-none pb-[max(1rem,env(safe-area-inset-bottom))]",
|
|
395
404
|
// Desktop: centered modal
|
|
396
|
-
"sm:inset-x-auto sm:bottom-auto sm:top-1/2 sm:left-1/2 sm:max-w-md sm:max-h-[calc(100dvh-4rem)] sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-
|
|
405
|
+
"sm:inset-x-auto sm:bottom-auto sm:top-1/2 sm:left-1/2 sm:max-w-md sm:max-h-[calc(100dvh-4rem)] sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-2xl sm:p-6 sm:gap-6 sm:pb-6",
|
|
397
406
|
className
|
|
398
407
|
),
|
|
399
408
|
...props,
|
|
400
409
|
children: [
|
|
401
|
-
/* @__PURE__ */ jsx6("div", { className: "mx-auto h-1 w-10 shrink-0 rounded-full bg-muted-foreground/30 sm:hidden" }),
|
|
410
|
+
/* @__PURE__ */ jsx6("div", { className: "mx-auto h-1 w-10 shrink-0 rounded-full bg-muted-foreground/30 sm:hidden", "aria-hidden": "true" }),
|
|
402
411
|
children,
|
|
403
412
|
showCloseButton && /* @__PURE__ */ jsx6(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxs(
|
|
404
413
|
Button,
|
|
@@ -422,7 +431,7 @@ function DialogHeader({ className, ...props }) {
|
|
|
422
431
|
"div",
|
|
423
432
|
{
|
|
424
433
|
"data-slot": "dialog-header",
|
|
425
|
-
className: cn("flex flex-col gap-2", className),
|
|
434
|
+
className: cn("flex flex-col gap-2 pr-8", className),
|
|
426
435
|
...props
|
|
427
436
|
}
|
|
428
437
|
);
|
|
@@ -484,9 +493,6 @@ import * as React8 from "react";
|
|
|
484
493
|
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
485
494
|
import { IconCheck as IconCheck2, IconChevronRight } from "@tabler/icons-react";
|
|
486
495
|
|
|
487
|
-
// src/components/liquid-menu-surface.ts
|
|
488
|
-
var liquidMenuSurfaceClasses = "rounded-2xl bg-popover/75 dark:bg-zinc-900/75 backdrop-blur-[3px] border border-black/[0.08] text-popover-foreground shadow-[0_4px_16px_-4px_rgba(0,0,0,0.08),0_16px_48px_-12px_rgba(0,0,0,0.28)] dark:border-white/[0.09] dark:bg-[#141417] dark:shadow-[0_4px_16px_-4px_rgba(0,0,0,0.4),0_16px_48px_-12px_rgba(0,0,0,0.7)]";
|
|
489
|
-
|
|
490
496
|
// src/components/menu-highlight.tsx
|
|
491
497
|
import * as React7 from "react";
|
|
492
498
|
import { motion } from "framer-motion";
|
|
@@ -1646,115 +1652,73 @@ function TableCaption({
|
|
|
1646
1652
|
}
|
|
1647
1653
|
|
|
1648
1654
|
// src/components/tabs.tsx
|
|
1649
|
-
import "react";
|
|
1655
|
+
import * as React18 from "react";
|
|
1650
1656
|
import { cva as cva4 } from "class-variance-authority";
|
|
1651
1657
|
import { Tabs as TabsPrimitive } from "radix-ui";
|
|
1652
|
-
import { motion as motion2 } from "framer-motion";
|
|
1653
|
-
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1654
|
-
var TABS_LAYOUT_SPRING = {
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
...props
|
|
1664
|
-
}) {
|
|
1665
|
-
return /* @__PURE__ */ jsx20(
|
|
1658
|
+
import { motion as motion2, useReducedMotion } from "framer-motion";
|
|
1659
|
+
import { Fragment, jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1660
|
+
var TABS_LAYOUT_SPRING = { type: "spring", stiffness: 300, damping: 26, mass: 1 };
|
|
1661
|
+
var TabsContext = React18.createContext(null);
|
|
1662
|
+
var ListVariantContext = React18.createContext("default");
|
|
1663
|
+
function Tabs({ className, orientation = "horizontal", value, defaultValue, onValueChange, ...props }) {
|
|
1664
|
+
const [localValue, setLocalValue] = React18.useState(defaultValue);
|
|
1665
|
+
const id = React18.useId();
|
|
1666
|
+
const activeValue = value ?? localValue;
|
|
1667
|
+
const context = React18.useMemo(() => ({ value: activeValue, id }), [activeValue, id]);
|
|
1668
|
+
return /* @__PURE__ */ jsx20(TabsContext.Provider, { value: context, children: /* @__PURE__ */ jsx20(
|
|
1666
1669
|
TabsPrimitive.Root,
|
|
1667
1670
|
{
|
|
1671
|
+
...props,
|
|
1672
|
+
...activeValue === void 0 ? {} : { value: activeValue },
|
|
1673
|
+
orientation,
|
|
1674
|
+
onValueChange: (next) => {
|
|
1675
|
+
if (value === void 0) setLocalValue(next);
|
|
1676
|
+
onValueChange?.(next);
|
|
1677
|
+
},
|
|
1668
1678
|
"data-slot": "tabs",
|
|
1669
|
-
"
|
|
1670
|
-
className: cn(
|
|
1671
|
-
"group/tabs flex gap-2 data-horizontal:flex-col",
|
|
1672
|
-
className
|
|
1673
|
-
),
|
|
1674
|
-
...props
|
|
1675
|
-
}
|
|
1676
|
-
);
|
|
1677
|
-
}
|
|
1678
|
-
var tabsListVariants = cva4(
|
|
1679
|
-
"group/tabs-list relative inline-flex w-fit items-center justify-center rounded-4xl p-[3px] text-muted-foreground group-data-horizontal/tabs:h-9 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col group-data-vertical/tabs:rounded-2xl data-[variant=line]:rounded-none",
|
|
1680
|
-
{
|
|
1681
|
-
variants: {
|
|
1682
|
-
variant: {
|
|
1683
|
-
default: "bg-muted/70 border border-black/4 shadow-[inset_0_1px_2px_rgba(0,0,0,0.06)] dark:bg-white/4 dark:border-white/4 dark:shadow-[inset_0_1px_3px_rgba(0,0,0,0.3)]",
|
|
1684
|
-
line: "gap-1 bg-transparent"
|
|
1685
|
-
}
|
|
1686
|
-
},
|
|
1687
|
-
defaultVariants: {
|
|
1688
|
-
variant: "default"
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
);
|
|
1692
|
-
function TabsList({
|
|
1693
|
-
className,
|
|
1694
|
-
variant = "default",
|
|
1695
|
-
...props
|
|
1696
|
-
}) {
|
|
1697
|
-
return /* @__PURE__ */ jsx20(
|
|
1698
|
-
TabsPrimitive.List,
|
|
1699
|
-
{
|
|
1700
|
-
"data-slot": "tabs-list",
|
|
1701
|
-
"data-variant": variant,
|
|
1702
|
-
className: cn(tabsListVariants({ variant }), className),
|
|
1703
|
-
...props
|
|
1679
|
+
className: cn("coline-tabs", className)
|
|
1704
1680
|
}
|
|
1705
|
-
);
|
|
1681
|
+
) });
|
|
1706
1682
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
})
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
);
|
|
1683
|
+
var tabsListVariants = cva4("coline-tabs-list", {
|
|
1684
|
+
variants: { variant: { default: "coline-tabs-raised", line: "coline-tabs-line" } },
|
|
1685
|
+
defaultVariants: { variant: "default" }
|
|
1686
|
+
});
|
|
1687
|
+
function TabsList({ className, variant = "default", ...props }) {
|
|
1688
|
+
return /* @__PURE__ */ jsx20(ListVariantContext.Provider, { value: variant ?? "default", children: /* @__PURE__ */ jsx20(TabsPrimitive.List, { ...props, "data-slot": "tabs-list", "data-variant": variant, className: cn(tabsListVariants({ variant }), className) }) });
|
|
1689
|
+
}
|
|
1690
|
+
function hasIndicator(children) {
|
|
1691
|
+
return React18.Children.toArray(children).some((child) => React18.isValidElement(child) && (child.type === TabsIndicator || hasIndicator(child.props.children)));
|
|
1692
|
+
}
|
|
1693
|
+
function TabsTrigger({ className, children, value, asChild = false, ...props }) {
|
|
1694
|
+
const tabs = React18.useContext(TabsContext);
|
|
1695
|
+
const variant = React18.useContext(ListVariantContext);
|
|
1696
|
+
const indicator = tabs?.value === value && variant === "default" && !hasIndicator(children) ? /* @__PURE__ */ jsx20(TabsIndicator, {}) : null;
|
|
1697
|
+
const content = asChild && React18.isValidElement(children) ? React18.cloneElement(children, void 0, indicator, children.props.children) : /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
1698
|
+
indicator,
|
|
1699
|
+
children
|
|
1700
|
+
] });
|
|
1701
|
+
return /* @__PURE__ */ jsx20(TabsPrimitive.Trigger, { ...props, value, asChild, "data-slot": "tabs-trigger", className: cn("coline-tabs-trigger", className), children: content });
|
|
1725
1702
|
}
|
|
1726
|
-
function TabsIndicator({
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1703
|
+
function TabsIndicator({ className, layoutId = "selection" }) {
|
|
1704
|
+
const tabs = React18.useContext(TabsContext);
|
|
1705
|
+
const fallbackId = React18.useId();
|
|
1706
|
+
const reducedMotion = useReducedMotion();
|
|
1730
1707
|
return /* @__PURE__ */ jsx20(
|
|
1731
1708
|
motion2.div,
|
|
1732
1709
|
{
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
),
|
|
1739
|
-
transition: TABS_LAYOUT_SPRING
|
|
1710
|
+
"aria-hidden": "true",
|
|
1711
|
+
"data-slot": "tabs-indicator",
|
|
1712
|
+
layout: true,
|
|
1713
|
+
layoutId: `${tabs?.id ?? fallbackId}-${layoutId}`,
|
|
1714
|
+
initial: false,
|
|
1715
|
+
className: cn("coline-tabs-indicator", className),
|
|
1716
|
+
transition: reducedMotion ? { duration: 0 } : TABS_LAYOUT_SPRING
|
|
1740
1717
|
}
|
|
1741
1718
|
);
|
|
1742
1719
|
}
|
|
1743
|
-
function TabsContent({
|
|
1744
|
-
className,
|
|
1745
|
-
...props
|
|
1746
|
-
}) {
|
|
1747
|
-
return /* @__PURE__ */ jsx20(
|
|
1748
|
-
TabsPrimitive.Content,
|
|
1749
|
-
{
|
|
1750
|
-
"data-slot": "tabs-content",
|
|
1751
|
-
className: cn(
|
|
1752
|
-
"flex-1 text-sm outline-none animate-in fade-in-0 slide-in-from-bottom-0.5 duration-100 ease-out",
|
|
1753
|
-
className
|
|
1754
|
-
),
|
|
1755
|
-
...props
|
|
1756
|
-
}
|
|
1757
|
-
);
|
|
1720
|
+
function TabsContent({ className, ...props }) {
|
|
1721
|
+
return /* @__PURE__ */ jsx20(TabsPrimitive.Content, { ...props, "data-slot": "tabs-content", className: cn("coline-tabs-content", className) });
|
|
1758
1722
|
}
|
|
1759
1723
|
|
|
1760
1724
|
// src/components/textarea.tsx
|
|
@@ -1898,7 +1862,7 @@ function useLiveCollection(name, query, options) {
|
|
|
1898
1862
|
|
|
1899
1863
|
// src/patterns/workspace.tsx
|
|
1900
1864
|
import * as React23 from "react";
|
|
1901
|
-
import { Fragment, jsx as jsx24, jsxs as
|
|
1865
|
+
import { Fragment as Fragment2, jsx as jsx24, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1902
1866
|
function AppPage({
|
|
1903
1867
|
title,
|
|
1904
1868
|
description,
|
|
@@ -1908,9 +1872,9 @@ function AppPage({
|
|
|
1908
1872
|
width = "wide",
|
|
1909
1873
|
className
|
|
1910
1874
|
}) {
|
|
1911
|
-
return /* @__PURE__ */
|
|
1912
|
-
/* @__PURE__ */
|
|
1913
|
-
/* @__PURE__ */
|
|
1875
|
+
return /* @__PURE__ */ jsxs7("main", { className: cn("coline-page", className), "data-width": width, children: [
|
|
1876
|
+
/* @__PURE__ */ jsxs7("header", { className: "coline-page-header", children: [
|
|
1877
|
+
/* @__PURE__ */ jsxs7("div", { className: "coline-page-heading", children: [
|
|
1914
1878
|
eyebrow && /* @__PURE__ */ jsx24("div", { className: "coline-eyebrow", children: eyebrow }),
|
|
1915
1879
|
/* @__PURE__ */ jsx24("h1", { children: title }),
|
|
1916
1880
|
description && /* @__PURE__ */ jsx24("p", { className: "coline-page-description", children: description })
|
|
@@ -1933,7 +1897,7 @@ function EmptyState({
|
|
|
1933
1897
|
action,
|
|
1934
1898
|
icon
|
|
1935
1899
|
}) {
|
|
1936
|
-
return /* @__PURE__ */
|
|
1900
|
+
return /* @__PURE__ */ jsxs7("section", { className: "coline-empty", children: [
|
|
1937
1901
|
icon && /* @__PURE__ */ jsx24("div", { className: "coline-empty-icon", "aria-hidden": "true", children: icon }),
|
|
1938
1902
|
/* @__PURE__ */ jsx24("h2", { children: title }),
|
|
1939
1903
|
description && /* @__PURE__ */ jsx24("p", { children: description }),
|
|
@@ -1941,8 +1905,8 @@ function EmptyState({
|
|
|
1941
1905
|
] });
|
|
1942
1906
|
}
|
|
1943
1907
|
function AppErrorState({ message, onRetry }) {
|
|
1944
|
-
return /* @__PURE__ */
|
|
1945
|
-
/* @__PURE__ */
|
|
1908
|
+
return /* @__PURE__ */ jsxs7("section", { className: "coline-error", role: "alert", children: [
|
|
1909
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
1946
1910
|
/* @__PURE__ */ jsx24("h2", { children: "Something went wrong" }),
|
|
1947
1911
|
/* @__PURE__ */ jsx24("p", { children: message })
|
|
1948
1912
|
] }),
|
|
@@ -1953,7 +1917,7 @@ function AppLoadingState({
|
|
|
1953
1917
|
label = "Loading",
|
|
1954
1918
|
rows = 5
|
|
1955
1919
|
}) {
|
|
1956
|
-
return /* @__PURE__ */
|
|
1920
|
+
return /* @__PURE__ */ jsxs7("div", { className: "coline-loading", role: "status", "aria-label": label, children: [
|
|
1957
1921
|
Array.from({ length: Math.max(1, Math.min(rows, 12)) }, (_, i) => /* @__PURE__ */ jsx24("div", { style: { width: `${92 - i % 3 * 14}%` } }, i)),
|
|
1958
1922
|
/* @__PURE__ */ jsx24("span", { className: "coline-sr-only", children: label })
|
|
1959
1923
|
] });
|
|
@@ -1962,7 +1926,7 @@ function StatusBadge({
|
|
|
1962
1926
|
children,
|
|
1963
1927
|
tone = "neutral"
|
|
1964
1928
|
}) {
|
|
1965
|
-
return /* @__PURE__ */
|
|
1929
|
+
return /* @__PURE__ */ jsxs7("span", { className: "coline-status", "data-tone": tone, children: [
|
|
1966
1930
|
/* @__PURE__ */ jsx24("span", { "aria-hidden": "true" }),
|
|
1967
1931
|
children
|
|
1968
1932
|
] });
|
|
@@ -1972,7 +1936,7 @@ function SplitView({
|
|
|
1972
1936
|
detail,
|
|
1973
1937
|
label = "Details"
|
|
1974
1938
|
}) {
|
|
1975
|
-
return /* @__PURE__ */
|
|
1939
|
+
return /* @__PURE__ */ jsxs7("div", { className: "coline-split", "data-open": Boolean(detail), children: [
|
|
1976
1940
|
/* @__PURE__ */ jsx24("section", { className: "coline-split-list", children: list }),
|
|
1977
1941
|
detail && /* @__PURE__ */ jsx24("aside", { className: "coline-split-detail", "aria-label": label, children: detail })
|
|
1978
1942
|
] });
|
|
@@ -1984,9 +1948,9 @@ function DetailPanel({
|
|
|
1984
1948
|
children,
|
|
1985
1949
|
actions
|
|
1986
1950
|
}) {
|
|
1987
|
-
return /* @__PURE__ */
|
|
1988
|
-
/* @__PURE__ */
|
|
1989
|
-
/* @__PURE__ */
|
|
1951
|
+
return /* @__PURE__ */ jsxs7("section", { className: "coline-detail", children: [
|
|
1952
|
+
/* @__PURE__ */ jsxs7("header", { children: [
|
|
1953
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
1990
1954
|
subtitle && /* @__PURE__ */ jsx24("div", { className: "coline-eyebrow", children: subtitle }),
|
|
1991
1955
|
/* @__PURE__ */ jsx24("h2", { children: title })
|
|
1992
1956
|
] }),
|
|
@@ -2005,8 +1969,8 @@ function RecordTable({
|
|
|
2005
1969
|
empty
|
|
2006
1970
|
}) {
|
|
2007
1971
|
if (!records.length)
|
|
2008
|
-
return /* @__PURE__ */ jsx24(
|
|
2009
|
-
return /* @__PURE__ */ jsx24("div", { className: "coline-table-scroll", children: /* @__PURE__ */
|
|
1972
|
+
return /* @__PURE__ */ jsx24(Fragment2, { children: empty ?? /* @__PURE__ */ jsx24(EmptyState, { title: "No results", description: "Try changing your filters." }) });
|
|
1973
|
+
return /* @__PURE__ */ jsx24("div", { className: "coline-table-scroll", children: /* @__PURE__ */ jsxs7("table", { className: "coline-record-table", "aria-label": label, children: [
|
|
2010
1974
|
/* @__PURE__ */ jsx24("thead", { children: /* @__PURE__ */ jsx24("tr", { children: columns.map((column) => /* @__PURE__ */ jsx24(
|
|
2011
1975
|
"th",
|
|
2012
1976
|
{
|
|
@@ -2048,8 +2012,8 @@ function BoardColumn({
|
|
|
2048
2012
|
children,
|
|
2049
2013
|
action
|
|
2050
2014
|
}) {
|
|
2051
|
-
return /* @__PURE__ */
|
|
2052
|
-
/* @__PURE__ */
|
|
2015
|
+
return /* @__PURE__ */ jsxs7("section", { className: "coline-board-column", children: [
|
|
2016
|
+
/* @__PURE__ */ jsxs7("header", { children: [
|
|
2053
2017
|
/* @__PURE__ */ jsx24("h2", { children: title }),
|
|
2054
2018
|
count !== void 0 && /* @__PURE__ */ jsx24("span", { className: "coline-count", children: count }),
|
|
2055
2019
|
action
|
|
@@ -2063,7 +2027,7 @@ function BoardCard({
|
|
|
2063
2027
|
footer,
|
|
2064
2028
|
onOpen
|
|
2065
2029
|
}) {
|
|
2066
|
-
return /* @__PURE__ */
|
|
2030
|
+
return /* @__PURE__ */ jsxs7("article", { className: "coline-board-card", children: [
|
|
2067
2031
|
/* @__PURE__ */ jsx24("h3", { children: onOpen ? /* @__PURE__ */ jsx24("button", { type: "button", className: "coline-row-open", onClick: onOpen, children: title }) : title }),
|
|
2068
2032
|
children && /* @__PURE__ */ jsx24("div", { className: "coline-board-card-body", children }),
|
|
2069
2033
|
footer && /* @__PURE__ */ jsx24("footer", { children: footer })
|
|
@@ -2075,14 +2039,28 @@ function SettingsSection({
|
|
|
2075
2039
|
children
|
|
2076
2040
|
}) {
|
|
2077
2041
|
const id = React23.useId();
|
|
2078
|
-
return /* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2042
|
+
return /* @__PURE__ */ jsxs7("section", { className: "coline-settings-section", "aria-labelledby": id, children: [
|
|
2043
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
2080
2044
|
/* @__PURE__ */ jsx24("h2", { id, children: title }),
|
|
2081
2045
|
description && /* @__PURE__ */ jsx24("p", { children: description })
|
|
2082
2046
|
] }),
|
|
2083
2047
|
/* @__PURE__ */ jsx24("div", { className: "coline-settings-fields", children })
|
|
2084
2048
|
] });
|
|
2085
2049
|
}
|
|
2050
|
+
|
|
2051
|
+
// src/patterns/filter-menu.tsx
|
|
2052
|
+
import * as React24 from "react";
|
|
2053
|
+
import { IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
2054
|
+
import { jsx as jsx25, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2055
|
+
var FilterMenu = React24.forwardRef(function FilterMenu2({ value, options, onValueChange, className, disabled, "aria-label": label }, ref) {
|
|
2056
|
+
return /* @__PURE__ */ jsxs8(DropdownMenu, { children: [
|
|
2057
|
+
/* @__PURE__ */ jsx25(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs8(Button, { ref, variant: "outline", disabled, "aria-label": label, className: cn("coline-filter-menu", className), children: [
|
|
2058
|
+
/* @__PURE__ */ jsx25("span", { children: options.find((option) => option.value === value)?.label ?? label }),
|
|
2059
|
+
/* @__PURE__ */ jsx25(IconChevronDown2, { "aria-hidden": "true" })
|
|
2060
|
+
] }) }),
|
|
2061
|
+
/* @__PURE__ */ jsx25(DropdownMenuContent, { children: /* @__PURE__ */ jsx25(DropdownMenuRadioGroup, { "aria-label": label, value, onValueChange, children: options.map((option) => /* @__PURE__ */ jsx25(DropdownMenuRadioItem, { value: option.value, disabled: option.disabled ?? false, children: option.label }, option.value)) }) })
|
|
2062
|
+
] });
|
|
2063
|
+
});
|
|
2086
2064
|
export {
|
|
2087
2065
|
AppErrorState,
|
|
2088
2066
|
AppLoadingState,
|
|
@@ -2138,6 +2116,7 @@ export {
|
|
|
2138
2116
|
FieldSeparator,
|
|
2139
2117
|
FieldSet,
|
|
2140
2118
|
FieldTitle,
|
|
2119
|
+
FilterMenu,
|
|
2141
2120
|
Input,
|
|
2142
2121
|
Label,
|
|
2143
2122
|
PageToolbar,
|