@colineapp/ui 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -58,10 +58,9 @@ as `Button`, `Card`, `Input`, `Textarea`, `Badge`, `Dialog`, `Select`,
58
58
  `Checkbox`, `Switch`, `Tabs`, `Table`, `Skeleton`, and `Tooltip`. Check the
59
59
  component source and declaration output before documenting a new prop.
60
60
 
61
- The client bundle is built by Coline. The app submits `main.tsx` and its
62
- source files; it does not submit `node_modules` or install packages in the
63
- sandbox. Keep client imports limited to the scaffold dependencies and app
64
- source.
61
+ The CLI bundles `main.tsx`, installed client dependencies, and imported CSS.
62
+ Coline rebuilds the uploaded artifact; the sandbox does not install packages.
63
+ Browser-compatible npm dependencies can be added to the app package.
65
64
 
66
65
  ## Verification and release
67
66
 
@@ -71,3 +70,33 @@ source.
71
70
  - Update README examples and the scaffold skill when an app-facing contract
72
71
  changes. The generated app must be able to use the documented API after a
73
72
  clean `npm install`.
73
+
74
+ ## SDK 0.4 / CLI 2.4 workflow
75
+
76
+ Run `coline-app check` before pushing: it checks types, the manifest, hosted logic,
77
+ and the React bundle without uploading. `dev --internal` updates one development
78
+ version; install it in the workspace and reload after changes. The CLI bundles
79
+ from the app's installed dependencies and preserves imported CSS and inline assets.
80
+ CLI 2.5 compiles app-specific Tailwind v4 and ordinary CSS automatically.
81
+ Import UI styles, then app.css; use complete class names. Local `preview` uses
82
+ the public test workspace and sandbox bridge, requires no credentials, and can
83
+ capture light/dark/mobile/error states with `--screenshots <directory>`.
84
+
85
+ The starter includes a React home and editor, tree mobile fallback, and a tool.
86
+ Use `coline.tools.invoke` or `actions.invokeTool` to run the same declared tool
87
+ from UI that Kairo runs. Save with `expectedVersion` to detect concurrent edits.
88
+ Homes/editors can write within grants; previews and server render handlers cannot.
89
+ `createTestWorkspace(app).client()` tests the interactive contract and
90
+ `grantedPermissions` simulates revoked consent.
91
+
92
+ New `tasks`, `calendar`, `messages`, and `references` capabilities require their
93
+ explicit manifest permissions and retain the invoking user's workspace access.
94
+ Use `files.list({ scope: "workspace" })` for shared files; document writes stay
95
+ with the owning app. Collections are install-private. Code integration and a
96
+ native mobile React runtime are separate work.
97
+
98
+ `src/live-collection.ts` wraps the SDK's canonical live-record implementation.
99
+ Keep state/conflict/sync logic in the SDK; React owns only subscriptions and
100
+ lifecycle. Inline serializable query objects must not restart the view on each
101
+ render. React Strict Mode cleanup/start must remain supported. Never infer record
102
+ permission from optimistic state or broadcast private fields to an install room.
package/README.md CHANGED
@@ -64,3 +64,50 @@ Used inside a Coline App's react-tier surface (`{ tier: "react", entry:
64
64
  Full guides at [coline.app/developers/docs](https://coline.app/developers/docs).
65
65
 
66
66
  MIT © Coline
67
+
68
+ ## SDK 0.4 / CLI 2.5 workflow
69
+
70
+ Run `coline-app check` before pushing: it checks types, the manifest, hosted logic,
71
+ and the React bundle without uploading. `dev --internal` updates one development
72
+ version; install it in the workspace and reload after changes. The CLI bundles
73
+ from the app's installed dependencies and preserves imported CSS and inline assets.
74
+ App-specific Tailwind v4 utilities compile automatically with CLI 2.5. Import
75
+ `@colineapp/ui/styles.css` and then `./app.css`; use complete class names.
76
+
77
+ The starter includes a React home and editor, tree mobile fallback, and a tool.
78
+ Use `coline.tools.invoke` or `actions.invokeTool` to run the same declared tool
79
+ from UI that Kairo runs. Save with `expectedVersion` to detect concurrent edits.
80
+ Homes/editors can write within grants; previews and server render handlers cannot.
81
+ `createTestWorkspace(app).client()` tests the interactive contract and
82
+ `grantedPermissions` simulates revoked consent.
83
+
84
+ New `tasks`, `calendar`, `messages`, and `references` capabilities require their
85
+ explicit manifest permissions and retain the invoking user's workspace access.
86
+ Use `files.list({ scope: "workspace" })` for shared files; document writes stay
87
+ with the owning app. Collections are install-private. Code integration and a
88
+ native mobile React runtime are separate work.
89
+
90
+ ### Live data
91
+
92
+ `useLiveCollection<RecordType>("collection", { where, orderBy, limit })` returns
93
+ `records`, `pending`, `status`, `error`, `nextCursor`, `insert`, `update`, `delete`,
94
+ `setAccess`, and `refresh`. Inline query objects are supported. Mutations update
95
+ local UI immediately and reject on conflicts or permission failures; catch their
96
+ promises to present the error. The hook owns subscription cleanup and reconnect
97
+ recovery. Use filtered/paged views (at most 200 records), not an entire workspace
98
+ in one hook. Structured-record sync does not imply CRDT text editing or offline
99
+ write persistence.
100
+
101
+ ## Screen patterns
102
+
103
+ Use `AppPage` and `PageToolbar` for consistent hierarchy, `RecordTable` with
104
+ `SplitView`/`DetailPanel` for queues, `Board`/`BoardColumn`/`BoardCard` for stages,
105
+ and `SettingsSection` for configuration. `EmptyState`, `AppErrorState`,
106
+ `AppLoadingState`, and `StatusBadge` cover common states. Their CSS ships in
107
+ `@colineapp/ui/styles.css`; they require no app-side utility generation.
108
+
109
+ Patterns compose around your domain and capabilities. They do not supply data,
110
+ routing, drag-and-drop, or persistence. `RecordTable` provides a first-cell button
111
+ when `onOpen` is set (don't nest a second control there); secondary columns hide
112
+ at narrow widths. Split details stack on mobile; the app owns focus management.
113
+ See the scaffold's `examples/` for complete interactive references.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { ClassValue } from 'clsx';
2
2
  import * as React$1 from 'react';
3
3
  import { SandboxContext } from '@colineapp/app-runtime';
4
- import { ColineCapabilities } from '@colineapp/sdk/v2';
4
+ import * as _colineapp_sdk_v2 from '@colineapp/sdk/v2';
5
+ import { ColineCapabilities, ColineRecordQuery, LiveCollectionOptions } from '@colineapp/sdk/v2';
5
6
  import * as class_variance_authority_types from 'class-variance-authority/types';
6
7
  import { VariantProps } from 'class-variance-authority';
7
8
  import { Checkbox as Checkbox$1, Dialog as Dialog$1, DropdownMenu as DropdownMenu$1, Label as Label$1, Popover as Popover$1, Progress as Progress$1, Select as Select$1, Separator as Separator$1, Slider as Slider$1, Switch as Switch$1, Tabs as Tabs$1, Toggle as Toggle$1, Tooltip as Tooltip$1 } from 'radix-ui';
@@ -10,7 +11,7 @@ declare function cn(...inputs: ClassValue[]): string;
10
11
 
11
12
  declare function ColineAppProvider({ children }: {
12
13
  children: React$1.ReactNode;
13
- }): React$1.JSX.Element | null;
14
+ }): React$1.JSX.Element;
14
15
  declare function useColine(): ColineCapabilities;
15
16
  declare function useColineContext(): SandboxContext;
16
17
  declare function useColorScheme(): "light" | "dark";
@@ -200,4 +201,99 @@ declare function Tooltip({ ...props }: React$1.ComponentProps<typeof Tooltip$1.R
200
201
  declare function TooltipTrigger({ ...props }: React$1.ComponentProps<typeof Tooltip$1.Trigger>): React$1.JSX.Element;
201
202
  declare function TooltipContent({ className, sideOffset, children, ...props }: React$1.ComponentProps<typeof Tooltip$1.Content>): React$1.JSX.Element;
202
203
 
203
- export { Badge, Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, ColineAppProvider, type ColineQueryState, 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, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Input, Label, Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Skeleton, Slider, 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 };
204
+ /** Inline query objects are safe: equivalent inputs retain the same live view. */
205
+ declare function useLiveCollection<T extends Record<string, unknown>>(name: string, query?: ColineRecordQuery<T>, options?: LiveCollectionOptions): {
206
+ insert: (data: T, access?: _colineapp_sdk_v2.ColineRecordAccess) => Promise<_colineapp_sdk_v2.ColineRecordEnvelope<T> | null>;
207
+ update: (id: string, patch: Partial<T>) => Promise<_colineapp_sdk_v2.ColineRecordEnvelope<T> | null>;
208
+ delete: (id: string) => Promise<_colineapp_sdk_v2.ColineRecordEnvelope<T> | null>;
209
+ setAccess: (id: string, access: _colineapp_sdk_v2.ColineRecordAccess) => Promise<_colineapp_sdk_v2.ColineRecordEnvelope<T> | null>;
210
+ refresh: () => Promise<void>;
211
+ records: readonly _colineapp_sdk_v2.ColineRecordEnvelope<T>[];
212
+ nextCursor: string | null;
213
+ status: "loading" | "ready" | "syncing" | "error";
214
+ pending: number;
215
+ error: Error | null;
216
+ };
217
+
218
+ declare function AppPage({ title, description, eyebrow, actions, children, width, className, }: {
219
+ title: string;
220
+ description?: React$1.ReactNode;
221
+ eyebrow?: React$1.ReactNode;
222
+ actions?: React$1.ReactNode;
223
+ children: React$1.ReactNode;
224
+ width?: "wide" | "reading";
225
+ className?: string;
226
+ }): React$1.JSX.Element;
227
+ declare function PageToolbar({ children, label, className, }: {
228
+ children: React$1.ReactNode;
229
+ label?: string;
230
+ className?: string;
231
+ }): React$1.JSX.Element;
232
+ declare function EmptyState({ title, description, action, icon, }: {
233
+ title: string;
234
+ description?: React$1.ReactNode;
235
+ action?: React$1.ReactNode;
236
+ icon?: React$1.ReactNode;
237
+ }): React$1.JSX.Element;
238
+ declare function AppErrorState({ message, onRetry }: {
239
+ message: string;
240
+ onRetry?: () => void;
241
+ }): React$1.JSX.Element;
242
+ declare function AppLoadingState({ label, rows, }: {
243
+ label?: string;
244
+ rows?: number;
245
+ }): React$1.JSX.Element;
246
+ declare function StatusBadge({ children, tone, }: {
247
+ children: React$1.ReactNode;
248
+ tone?: "neutral" | "info" | "success" | "warning" | "danger";
249
+ }): React$1.JSX.Element;
250
+ declare function SplitView({ list, detail, label, }: {
251
+ list: React$1.ReactNode;
252
+ detail?: React$1.ReactNode;
253
+ label?: string;
254
+ }): React$1.JSX.Element;
255
+ declare function DetailPanel({ title, subtitle, onClose, children, actions, }: {
256
+ title: string;
257
+ subtitle?: React$1.ReactNode;
258
+ onClose?: () => void;
259
+ children: React$1.ReactNode;
260
+ actions?: React$1.ReactNode;
261
+ }): React$1.JSX.Element;
262
+ interface RecordColumn<T> {
263
+ key: string;
264
+ label: string;
265
+ render: (record: T) => React$1.ReactNode;
266
+ secondary?: boolean;
267
+ align?: "start" | "end";
268
+ }
269
+ declare function RecordTable<T>({ records, columns, rowKey, onOpen, label, empty, }: {
270
+ records: readonly T[];
271
+ columns: readonly RecordColumn<T>[];
272
+ rowKey: (record: T) => string;
273
+ onOpen?: (record: T) => void;
274
+ label?: string;
275
+ empty?: React$1.ReactNode;
276
+ }): React$1.JSX.Element;
277
+ declare function Board({ children, label, }: {
278
+ children: React$1.ReactNode;
279
+ label?: string;
280
+ }): React$1.JSX.Element;
281
+ declare function BoardColumn({ title, count, children, action, }: {
282
+ title: string;
283
+ count?: number;
284
+ children: React$1.ReactNode;
285
+ action?: React$1.ReactNode;
286
+ }): React$1.JSX.Element;
287
+ declare function BoardCard({ title, children, footer, onOpen, }: {
288
+ title: string;
289
+ children?: React$1.ReactNode;
290
+ footer?: React$1.ReactNode;
291
+ onOpen?: () => void;
292
+ }): React$1.JSX.Element;
293
+ declare function SettingsSection({ title, description, children, }: {
294
+ title: string;
295
+ description?: string;
296
+ children: React$1.ReactNode;
297
+ }): React$1.JSX.Element;
298
+
299
+ 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, 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
@@ -24,18 +24,22 @@ function applyTheme(theme, colorScheme) {
24
24
  root.classList.toggle("dark", colorScheme === "dark");
25
25
  }
26
26
  function ColineAppProvider({ children }) {
27
+ const [connectionError, setConnectionError] = React.useState(null);
27
28
  const [runtime, setRuntime] = React.useState(null);
28
29
  React.useEffect(() => {
29
30
  let disposed = false;
31
+ let activeBridge = null;
30
32
  let removeThemeListener = null;
31
33
  void connectGuestBridge().then((bridge) => {
32
- if (disposed) return;
34
+ if (disposed) {
35
+ bridge.dispose();
36
+ return;
37
+ }
38
+ activeBridge = bridge;
33
39
  applyTheme(bridge.theme, bridge.colorScheme);
34
40
  removeThemeListener = bridge.onThemeChange((theme, colorScheme) => {
35
41
  applyTheme(theme, colorScheme);
36
- setRuntime(
37
- (current) => current ? { ...current, colorScheme } : current
38
- );
42
+ setRuntime((current) => current ? { ...current, colorScheme } : current);
39
43
  });
40
44
  setRuntime({
41
45
  bridge,
@@ -43,9 +47,12 @@ function ColineAppProvider({ children }) {
43
47
  context: bridge.context,
44
48
  colorScheme: bridge.colorScheme
45
49
  });
50
+ }).catch((error) => {
51
+ if (!disposed) setConnectionError(error instanceof Error ? error.message : String(error));
46
52
  });
47
53
  return () => {
48
54
  disposed = true;
55
+ activeBridge?.dispose();
49
56
  removeThemeListener?.();
50
57
  };
51
58
  }, []);
@@ -58,7 +65,7 @@ function ColineAppProvider({ children }) {
58
65
  return () => observer.disconnect();
59
66
  }, [runtime]);
60
67
  if (!runtime) {
61
- return null;
68
+ return /* @__PURE__ */ jsx("p", { role: connectionError ? "alert" : "status", children: connectionError ?? "Connecting to Coline\u2026" });
62
69
  }
63
70
  return /* @__PURE__ */ jsx(ColineRuntimeContext.Provider, { value: runtime, children });
64
71
  }
@@ -1857,8 +1864,233 @@ function TooltipContent({
1857
1864
  }
1858
1865
  ) });
1859
1866
  }
1867
+
1868
+ // src/live-collection.ts
1869
+ import * as React22 from "react";
1870
+ import {
1871
+ createLiveCollection
1872
+ } from "@colineapp/sdk/v2";
1873
+ function useLiveCollection(name, query, options) {
1874
+ const coline = useColine();
1875
+ const context = useColineContext();
1876
+ const key = JSON.stringify({
1877
+ query,
1878
+ options: { actorUserId: context.actor?.userId, installId: context.app.installId, ...options }
1879
+ });
1880
+ const live = React22.useMemo(() => {
1881
+ const input = JSON.parse(key);
1882
+ return createLiveCollection(coline, name, input.query, input.options);
1883
+ }, [coline, name, key]);
1884
+ React22.useEffect(() => {
1885
+ void live.start();
1886
+ return () => live.stop();
1887
+ }, [live]);
1888
+ const snapshot = React22.useSyncExternalStore(live.subscribe, live.getSnapshot, live.getSnapshot);
1889
+ return {
1890
+ ...snapshot,
1891
+ insert: live.insert,
1892
+ update: live.update,
1893
+ delete: live.delete,
1894
+ setAccess: live.setAccess,
1895
+ refresh: live.refresh
1896
+ };
1897
+ }
1898
+
1899
+ // src/patterns/workspace.tsx
1900
+ import * as React23 from "react";
1901
+ import { Fragment, jsx as jsx24, jsxs as jsxs6 } from "react/jsx-runtime";
1902
+ function AppPage({
1903
+ title,
1904
+ description,
1905
+ eyebrow,
1906
+ actions,
1907
+ children,
1908
+ width = "wide",
1909
+ className
1910
+ }) {
1911
+ return /* @__PURE__ */ jsxs6("main", { className: cn("coline-page", className), "data-width": width, children: [
1912
+ /* @__PURE__ */ jsxs6("header", { className: "coline-page-header", children: [
1913
+ /* @__PURE__ */ jsxs6("div", { className: "coline-page-heading", children: [
1914
+ eyebrow && /* @__PURE__ */ jsx24("div", { className: "coline-eyebrow", children: eyebrow }),
1915
+ /* @__PURE__ */ jsx24("h1", { children: title }),
1916
+ description && /* @__PURE__ */ jsx24("p", { className: "coline-page-description", children: description })
1917
+ ] }),
1918
+ actions && /* @__PURE__ */ jsx24("div", { className: "coline-page-actions", children: actions })
1919
+ ] }),
1920
+ children
1921
+ ] });
1922
+ }
1923
+ function PageToolbar({
1924
+ children,
1925
+ label = "View controls",
1926
+ className
1927
+ }) {
1928
+ return /* @__PURE__ */ jsx24("div", { className: cn("coline-toolbar", className), role: "group", "aria-label": label, children });
1929
+ }
1930
+ function EmptyState({
1931
+ title,
1932
+ description,
1933
+ action,
1934
+ icon
1935
+ }) {
1936
+ return /* @__PURE__ */ jsxs6("section", { className: "coline-empty", children: [
1937
+ icon && /* @__PURE__ */ jsx24("div", { className: "coline-empty-icon", "aria-hidden": "true", children: icon }),
1938
+ /* @__PURE__ */ jsx24("h2", { children: title }),
1939
+ description && /* @__PURE__ */ jsx24("p", { children: description }),
1940
+ action && /* @__PURE__ */ jsx24("div", { children: action })
1941
+ ] });
1942
+ }
1943
+ function AppErrorState({ message, onRetry }) {
1944
+ return /* @__PURE__ */ jsxs6("section", { className: "coline-error", role: "alert", children: [
1945
+ /* @__PURE__ */ jsxs6("div", { children: [
1946
+ /* @__PURE__ */ jsx24("h2", { children: "Something went wrong" }),
1947
+ /* @__PURE__ */ jsx24("p", { children: message })
1948
+ ] }),
1949
+ onRetry && /* @__PURE__ */ jsx24(Button, { variant: "outline", onClick: onRetry, children: "Try again" })
1950
+ ] });
1951
+ }
1952
+ function AppLoadingState({
1953
+ label = "Loading",
1954
+ rows = 5
1955
+ }) {
1956
+ return /* @__PURE__ */ jsxs6("div", { className: "coline-loading", role: "status", "aria-label": label, children: [
1957
+ Array.from({ length: Math.max(1, Math.min(rows, 12)) }, (_, i) => /* @__PURE__ */ jsx24("div", { style: { width: `${92 - i % 3 * 14}%` } }, i)),
1958
+ /* @__PURE__ */ jsx24("span", { className: "coline-sr-only", children: label })
1959
+ ] });
1960
+ }
1961
+ function StatusBadge({
1962
+ children,
1963
+ tone = "neutral"
1964
+ }) {
1965
+ return /* @__PURE__ */ jsxs6("span", { className: "coline-status", "data-tone": tone, children: [
1966
+ /* @__PURE__ */ jsx24("span", { "aria-hidden": "true" }),
1967
+ children
1968
+ ] });
1969
+ }
1970
+ function SplitView({
1971
+ list,
1972
+ detail,
1973
+ label = "Details"
1974
+ }) {
1975
+ return /* @__PURE__ */ jsxs6("div", { className: "coline-split", "data-open": Boolean(detail), children: [
1976
+ /* @__PURE__ */ jsx24("section", { className: "coline-split-list", children: list }),
1977
+ detail && /* @__PURE__ */ jsx24("aside", { className: "coline-split-detail", "aria-label": label, children: detail })
1978
+ ] });
1979
+ }
1980
+ function DetailPanel({
1981
+ title,
1982
+ subtitle,
1983
+ onClose,
1984
+ children,
1985
+ actions
1986
+ }) {
1987
+ return /* @__PURE__ */ jsxs6("section", { className: "coline-detail", children: [
1988
+ /* @__PURE__ */ jsxs6("header", { children: [
1989
+ /* @__PURE__ */ jsxs6("div", { children: [
1990
+ subtitle && /* @__PURE__ */ jsx24("div", { className: "coline-eyebrow", children: subtitle }),
1991
+ /* @__PURE__ */ jsx24("h2", { children: title })
1992
+ ] }),
1993
+ onClose && /* @__PURE__ */ jsx24(Button, { variant: "ghost", size: "sm", onClick: onClose, "aria-label": "Close details", children: "Close" })
1994
+ ] }),
1995
+ /* @__PURE__ */ jsx24("div", { className: "coline-detail-body", children }),
1996
+ actions && /* @__PURE__ */ jsx24("footer", { children: actions })
1997
+ ] });
1998
+ }
1999
+ function RecordTable({
2000
+ records,
2001
+ columns,
2002
+ rowKey,
2003
+ onOpen,
2004
+ label = "Records",
2005
+ empty
2006
+ }) {
2007
+ if (!records.length)
2008
+ return /* @__PURE__ */ jsx24(Fragment, { children: empty ?? /* @__PURE__ */ jsx24(EmptyState, { title: "No results", description: "Try changing your filters." }) });
2009
+ return /* @__PURE__ */ jsx24("div", { className: "coline-table-scroll", children: /* @__PURE__ */ jsxs6("table", { className: "coline-record-table", "aria-label": label, children: [
2010
+ /* @__PURE__ */ jsx24("thead", { children: /* @__PURE__ */ jsx24("tr", { children: columns.map((column) => /* @__PURE__ */ jsx24(
2011
+ "th",
2012
+ {
2013
+ scope: "col",
2014
+ "data-secondary": column.secondary || void 0,
2015
+ "data-align": column.align,
2016
+ children: column.label
2017
+ },
2018
+ column.key
2019
+ )) }) }),
2020
+ /* @__PURE__ */ jsx24("tbody", { children: records.map((record) => /* @__PURE__ */ jsx24("tr", { children: columns.map((column, i) => /* @__PURE__ */ jsx24(
2021
+ "td",
2022
+ {
2023
+ "data-secondary": column.secondary || void 0,
2024
+ "data-align": column.align,
2025
+ children: i === 0 && onOpen ? /* @__PURE__ */ jsx24(
2026
+ "button",
2027
+ {
2028
+ type: "button",
2029
+ className: "coline-row-open",
2030
+ onClick: () => onOpen(record),
2031
+ children: column.render(record)
2032
+ }
2033
+ ) : column.render(record)
2034
+ },
2035
+ column.key
2036
+ )) }, rowKey(record))) })
2037
+ ] }) });
2038
+ }
2039
+ function Board({
2040
+ children,
2041
+ label = "Board"
2042
+ }) {
2043
+ return /* @__PURE__ */ jsx24("div", { className: "coline-board", role: "region", "aria-label": label, tabIndex: 0, children });
2044
+ }
2045
+ function BoardColumn({
2046
+ title,
2047
+ count,
2048
+ children,
2049
+ action
2050
+ }) {
2051
+ return /* @__PURE__ */ jsxs6("section", { className: "coline-board-column", children: [
2052
+ /* @__PURE__ */ jsxs6("header", { children: [
2053
+ /* @__PURE__ */ jsx24("h2", { children: title }),
2054
+ count !== void 0 && /* @__PURE__ */ jsx24("span", { className: "coline-count", children: count }),
2055
+ action
2056
+ ] }),
2057
+ /* @__PURE__ */ jsx24("div", { className: "coline-board-items", children })
2058
+ ] });
2059
+ }
2060
+ function BoardCard({
2061
+ title,
2062
+ children,
2063
+ footer,
2064
+ onOpen
2065
+ }) {
2066
+ return /* @__PURE__ */ jsxs6("article", { className: "coline-board-card", children: [
2067
+ /* @__PURE__ */ jsx24("h3", { children: onOpen ? /* @__PURE__ */ jsx24("button", { type: "button", className: "coline-row-open", onClick: onOpen, children: title }) : title }),
2068
+ children && /* @__PURE__ */ jsx24("div", { className: "coline-board-card-body", children }),
2069
+ footer && /* @__PURE__ */ jsx24("footer", { children: footer })
2070
+ ] });
2071
+ }
2072
+ function SettingsSection({
2073
+ title,
2074
+ description,
2075
+ children
2076
+ }) {
2077
+ const id = React23.useId();
2078
+ return /* @__PURE__ */ jsxs6("section", { className: "coline-settings-section", "aria-labelledby": id, children: [
2079
+ /* @__PURE__ */ jsxs6("div", { children: [
2080
+ /* @__PURE__ */ jsx24("h2", { id, children: title }),
2081
+ description && /* @__PURE__ */ jsx24("p", { children: description })
2082
+ ] }),
2083
+ /* @__PURE__ */ jsx24("div", { className: "coline-settings-fields", children })
2084
+ ] });
2085
+ }
1860
2086
  export {
2087
+ AppErrorState,
2088
+ AppLoadingState,
2089
+ AppPage,
1861
2090
  Badge,
2091
+ Board,
2092
+ BoardCard,
2093
+ BoardColumn,
1862
2094
  Button,
1863
2095
  Card,
1864
2096
  CardAction,
@@ -1869,6 +2101,7 @@ export {
1869
2101
  CardTitle,
1870
2102
  Checkbox,
1871
2103
  ColineAppProvider,
2104
+ DetailPanel,
1872
2105
  Dialog,
1873
2106
  DialogClose,
1874
2107
  DialogContent,
@@ -1894,6 +2127,7 @@ export {
1894
2127
  DropdownMenuSubContent,
1895
2128
  DropdownMenuSubTrigger,
1896
2129
  DropdownMenuTrigger,
2130
+ EmptyState,
1897
2131
  Field,
1898
2132
  FieldContent,
1899
2133
  FieldDescription,
@@ -1906,6 +2140,7 @@ export {
1906
2140
  FieldTitle,
1907
2141
  Input,
1908
2142
  Label,
2143
+ PageToolbar,
1909
2144
  Popover,
1910
2145
  PopoverAnchor,
1911
2146
  PopoverContent,
@@ -1914,6 +2149,7 @@ export {
1914
2149
  PopoverTitle,
1915
2150
  PopoverTrigger,
1916
2151
  Progress,
2152
+ RecordTable,
1917
2153
  Select,
1918
2154
  SelectContent,
1919
2155
  SelectGroup,
@@ -1925,8 +2161,11 @@ export {
1925
2161
  SelectTrigger,
1926
2162
  SelectValue,
1927
2163
  Separator,
2164
+ SettingsSection,
1928
2165
  Skeleton,
1929
2166
  Slider,
2167
+ SplitView,
2168
+ StatusBadge,
1930
2169
  Switch,
1931
2170
  TABS_LAYOUT_SPRING,
1932
2171
  Table,
@@ -1956,6 +2195,7 @@ export {
1956
2195
  useColine,
1957
2196
  useColineContext,
1958
2197
  useColineQuery,
1959
- useColorScheme
2198
+ useColorScheme,
2199
+ useLiveCollection
1960
2200
  };
1961
2201
  //# sourceMappingURL=index.js.map