@apotech-os/ui-sdk 0.3.0 → 0.6.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 +361 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +155 -1
- package/dist/index.d.ts +155 -1
- package/dist/index.js +351 -2
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
package/dist/index.d.cts
CHANGED
|
@@ -22,6 +22,12 @@ interface AppContextValue {
|
|
|
22
22
|
pagePath: string;
|
|
23
23
|
/** The active space id, when applicable. */
|
|
24
24
|
spaceId?: string;
|
|
25
|
+
/**
|
|
26
|
+
* The current user's grant role on this app context, when the shell knows it.
|
|
27
|
+
* Settings pages use it to render read-only fields below ADMIN instead of
|
|
28
|
+
* letting the user discover the 403 at save time.
|
|
29
|
+
*/
|
|
30
|
+
role?: 'VIEWER' | 'EDITOR' | 'ADMIN';
|
|
25
31
|
}
|
|
26
32
|
declare const AppContextProvider: React.Provider<AppContextValue | null>;
|
|
27
33
|
/** Returns context info for the current app page (appSlug, pagePath, spaceId). */
|
|
@@ -36,6 +42,10 @@ interface AppApiClient {
|
|
|
36
42
|
* Perform a POST request to a platform-data endpoint.
|
|
37
43
|
*/
|
|
38
44
|
post<T>(path: string, body?: unknown): Promise<T>;
|
|
45
|
+
/**
|
|
46
|
+
* Perform a PUT request to a platform-data endpoint (e.g. write app settings).
|
|
47
|
+
*/
|
|
48
|
+
put<T>(path: string, body?: unknown): Promise<T>;
|
|
39
49
|
/**
|
|
40
50
|
* Perform a PATCH request to a platform-data endpoint (e.g. update a record).
|
|
41
51
|
*/
|
|
@@ -44,6 +54,34 @@ interface AppApiClient {
|
|
|
44
54
|
* Perform a DELETE request to a platform-data endpoint (e.g. delete a record).
|
|
45
55
|
*/
|
|
46
56
|
delete<T>(path: string): Promise<T>;
|
|
57
|
+
/**
|
|
58
|
+
* Run one of this app's `uiInvoke` functions and get its return value back.
|
|
59
|
+
*
|
|
60
|
+
* This is the ONLY way a page can reach an integration: the action endpoint
|
|
61
|
+
* requires an app token and refuses a browser session. The platform mints the
|
|
62
|
+
* token server-side and runs the handler in-process.
|
|
63
|
+
*
|
|
64
|
+
* The function must be declared `trigger: { type: 'uiInvoke' }` in the
|
|
65
|
+
* manifest, and the caller must hold its `minRole` (default EDITOR).
|
|
66
|
+
*
|
|
67
|
+
* Pass `idempotencyKey` for anything that must not run twice on a double
|
|
68
|
+
* click — a concurrent duplicate is rejected with 409 INVOCATION_IN_FLIGHT.
|
|
69
|
+
*
|
|
70
|
+
* Throws AppInvokeError. `code === 'FUNCTION_REJECTED'` carries an app-authored
|
|
71
|
+
* message that is safe to show the user; every other failure is generic on
|
|
72
|
+
* purpose (raw provider errors can leak tokens or PII).
|
|
73
|
+
*/
|
|
74
|
+
invoke<TResult, TInput = Record<string, unknown>>(functionName: string, input?: TInput, opts?: {
|
|
75
|
+
idempotencyKey?: string;
|
|
76
|
+
signal?: AbortSignal;
|
|
77
|
+
}): Promise<TResult>;
|
|
78
|
+
}
|
|
79
|
+
/** Thrown by AppApiClient.invoke. */
|
|
80
|
+
declare class AppInvokeError extends Error {
|
|
81
|
+
readonly status: number;
|
|
82
|
+
readonly code?: string | undefined;
|
|
83
|
+
readonly invocationId?: string | undefined;
|
|
84
|
+
constructor(status: number, message: string, code?: string | undefined, invocationId?: string | undefined);
|
|
47
85
|
}
|
|
48
86
|
declare const AppApiProvider: React.Provider<AppApiClient | null>;
|
|
49
87
|
/**
|
|
@@ -51,6 +89,26 @@ declare const AppApiProvider: React.Provider<AppApiClient | null>;
|
|
|
51
89
|
* Requests go to /api/data/* with the session cookie (RBAC applies server-side).
|
|
52
90
|
*/
|
|
53
91
|
declare function useAppApi(): AppApiClient;
|
|
92
|
+
/**
|
|
93
|
+
* Reads and writes this app's settings (GET/PUT /data/apps/:appSlug/settings).
|
|
94
|
+
*
|
|
95
|
+
* The app slug comes from the surrounding AppContext, so a settings page only
|
|
96
|
+
* has to describe its form. Values are the ones the server merged with the
|
|
97
|
+
* `settings.fields` defaults declared in the manifest.
|
|
98
|
+
*
|
|
99
|
+
* Reading requires VIEWER, writing requires ADMIN. `save` never throws: it
|
|
100
|
+
* reports through `saveError`, which carries the raw failure (422
|
|
101
|
+
* SETTINGS_VALIDATION_FAILED with its per-key errors, or 403) so the page can
|
|
102
|
+
* map it back onto its fields. A failed save leaves `settings` untouched.
|
|
103
|
+
*/
|
|
104
|
+
declare function useAppSettings<T = Record<string, unknown>>(): {
|
|
105
|
+
settings: T | undefined;
|
|
106
|
+
isLoading: boolean;
|
|
107
|
+
error: unknown;
|
|
108
|
+
save: (patch: Partial<T>) => Promise<void>;
|
|
109
|
+
isSaving: boolean;
|
|
110
|
+
saveError: unknown;
|
|
111
|
+
};
|
|
54
112
|
|
|
55
113
|
declare const buttonVariants: (props?: ({
|
|
56
114
|
variant?: "default" | "secondary" | "outline" | "ghost" | "destructive" | null | undefined;
|
|
@@ -139,5 +197,101 @@ interface DateRangePickerProps {
|
|
|
139
197
|
}
|
|
140
198
|
/** Minimal controlled date-range picker using two native date inputs. */
|
|
141
199
|
declare function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps): React.JSX.Element;
|
|
200
|
+
type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
|
201
|
+
declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
|
|
202
|
+
interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {
|
|
203
|
+
checked?: boolean;
|
|
204
|
+
/** Preferred over onChange — receives the boolean directly. */
|
|
205
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
206
|
+
label?: React.ReactNode;
|
|
207
|
+
}
|
|
208
|
+
declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
|
|
209
|
+
interface SidePanelProps {
|
|
210
|
+
open: boolean;
|
|
211
|
+
onClose: () => void;
|
|
212
|
+
title?: React.ReactNode;
|
|
213
|
+
description?: React.ReactNode;
|
|
214
|
+
children: React.ReactNode;
|
|
215
|
+
className?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Blocking slide-over — reach for it when a task has more fields than a `Modal`
|
|
219
|
+
* can show without an inner scrollbar. Full height, so the body scrolls once and
|
|
220
|
+
* a footer can stay pinned; `Modal` centres a box and does no height management.
|
|
221
|
+
*
|
|
222
|
+
* Children are laid out in a flex column filling the panel: put the scrollable
|
|
223
|
+
* region in a `min-h-0 flex-1 overflow-y-auto` child and the footer after it.
|
|
224
|
+
*
|
|
225
|
+
* NOTE: no focus management. Autofocus the primary action yourself.
|
|
226
|
+
*/
|
|
227
|
+
declare function SidePanel({ open, onClose, title, description, children, className, }: SidePanelProps): React.JSX.Element | null;
|
|
228
|
+
interface CopyButtonProps {
|
|
229
|
+
value: string;
|
|
230
|
+
label?: string;
|
|
231
|
+
copiedLabel?: string;
|
|
232
|
+
variant?: ButtonProps['variant'];
|
|
233
|
+
size?: ButtonProps['size'];
|
|
234
|
+
className?: string;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Copy-to-clipboard button with inline feedback. On failure it says so rather
|
|
238
|
+
* than silently doing nothing — keep the copyable text selectable so manual
|
|
239
|
+
* copy stays the fallback.
|
|
240
|
+
*/
|
|
241
|
+
declare function CopyButton({ value, label, copiedLabel, variant, size, className, }: CopyButtonProps): React.JSX.Element;
|
|
242
|
+
interface PopoverProps {
|
|
243
|
+
open: boolean;
|
|
244
|
+
onOpenChange: (open: boolean) => void;
|
|
245
|
+
trigger: React.ReactNode;
|
|
246
|
+
children: React.ReactNode;
|
|
247
|
+
align?: 'start' | 'end';
|
|
248
|
+
className?: string;
|
|
249
|
+
}
|
|
250
|
+
/** Anchored panel. Controlled — the caller owns `open`. Closes on outside click
|
|
251
|
+
* and Escape, which is what a filter pill needs and a Modal is too heavy for. */
|
|
252
|
+
declare function Popover({ open, onOpenChange, trigger, children, align, className, }: PopoverProps): React.JSX.Element;
|
|
253
|
+
interface DropdownMenuItem {
|
|
254
|
+
label: React.ReactNode;
|
|
255
|
+
onSelect: () => void;
|
|
256
|
+
disabled?: boolean;
|
|
257
|
+
destructive?: boolean;
|
|
258
|
+
}
|
|
259
|
+
interface DropdownMenuProps {
|
|
260
|
+
trigger: React.ReactNode;
|
|
261
|
+
items: DropdownMenuItem[];
|
|
262
|
+
align?: 'start' | 'end';
|
|
263
|
+
className?: string;
|
|
264
|
+
}
|
|
265
|
+
/** Uncontrolled menu built on Popover. Selecting an item closes it. */
|
|
266
|
+
declare function DropdownMenu({ trigger, items, align, className }: DropdownMenuProps): React.JSX.Element;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Browser helpers for app pages.
|
|
270
|
+
*
|
|
271
|
+
* App bundles get react, react-dom and this SDK from the shell's import map and
|
|
272
|
+
* bundle everything else themselves — so without these here, every app would
|
|
273
|
+
* reimplement clipboard handling and CSV escaping, and get the edge cases wrong
|
|
274
|
+
* in its own way.
|
|
275
|
+
*/
|
|
276
|
+
/**
|
|
277
|
+
* Copy text to the clipboard.
|
|
278
|
+
*
|
|
279
|
+
* Returns `false` instead of throwing when the clipboard is unavailable (non
|
|
280
|
+
* secure context, permission refused) so the caller can render inline feedback.
|
|
281
|
+
* No `document.execCommand('copy')` fallback: it is deprecated, and the shell
|
|
282
|
+
* only ever runs on https or localhost, both secure contexts.
|
|
283
|
+
*/
|
|
284
|
+
declare function copyToClipboard(text: string): Promise<boolean>;
|
|
285
|
+
/** Trigger a browser download of a Blob via a throwaway object URL + `<a>` click. */
|
|
286
|
+
declare function downloadBlob(blob: Blob, filename: string): void;
|
|
287
|
+
/** Serialize rows (header included) into an RFC 4180 CSV string. */
|
|
288
|
+
declare function toCsv(rows: string[][]): string;
|
|
289
|
+
/**
|
|
290
|
+
* Serialize + download in one call.
|
|
291
|
+
*
|
|
292
|
+
* The BOM is the whole reason this helper exists: without it Excel on Windows
|
|
293
|
+
* reads the file as latin-1 and mangles every accented character.
|
|
294
|
+
*/
|
|
295
|
+
declare function downloadCsv(rows: string[][], filename: string): void;
|
|
142
296
|
|
|
143
|
-
export { type AppApiClient, AppApiProvider, AppContextProvider, type AppContextValue, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type DateRange, DateRangePicker, type DateRangePickerProps, Input, Link, type LinkProps, Modal, type ModalProps, Select, type SelectProps, Spinner, type SpinnerProps, Switch, type SwitchProps, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, type TabsProps, TabsTrigger, cn, useAppApi, useAppContext };
|
|
297
|
+
export { type AppApiClient, AppApiProvider, AppContextProvider, type AppContextValue, AppInvokeError, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, Checkbox, type CheckboxProps, CopyButton, type CopyButtonProps, type DateRange, DateRangePicker, type DateRangePickerProps, DropdownMenu, type DropdownMenuItem, type DropdownMenuProps, Input, Link, type LinkProps, Modal, type ModalProps, Popover, type PopoverProps, Select, type SelectProps, SidePanel, type SidePanelProps, Spinner, type SpinnerProps, Switch, type SwitchProps, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, type TabsProps, TabsTrigger, Textarea, type TextareaProps, cn, copyToClipboard, downloadBlob, downloadCsv, toCsv, useAppApi, useAppContext, useAppSettings };
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,12 @@ interface AppContextValue {
|
|
|
22
22
|
pagePath: string;
|
|
23
23
|
/** The active space id, when applicable. */
|
|
24
24
|
spaceId?: string;
|
|
25
|
+
/**
|
|
26
|
+
* The current user's grant role on this app context, when the shell knows it.
|
|
27
|
+
* Settings pages use it to render read-only fields below ADMIN instead of
|
|
28
|
+
* letting the user discover the 403 at save time.
|
|
29
|
+
*/
|
|
30
|
+
role?: 'VIEWER' | 'EDITOR' | 'ADMIN';
|
|
25
31
|
}
|
|
26
32
|
declare const AppContextProvider: React.Provider<AppContextValue | null>;
|
|
27
33
|
/** Returns context info for the current app page (appSlug, pagePath, spaceId). */
|
|
@@ -36,6 +42,10 @@ interface AppApiClient {
|
|
|
36
42
|
* Perform a POST request to a platform-data endpoint.
|
|
37
43
|
*/
|
|
38
44
|
post<T>(path: string, body?: unknown): Promise<T>;
|
|
45
|
+
/**
|
|
46
|
+
* Perform a PUT request to a platform-data endpoint (e.g. write app settings).
|
|
47
|
+
*/
|
|
48
|
+
put<T>(path: string, body?: unknown): Promise<T>;
|
|
39
49
|
/**
|
|
40
50
|
* Perform a PATCH request to a platform-data endpoint (e.g. update a record).
|
|
41
51
|
*/
|
|
@@ -44,6 +54,34 @@ interface AppApiClient {
|
|
|
44
54
|
* Perform a DELETE request to a platform-data endpoint (e.g. delete a record).
|
|
45
55
|
*/
|
|
46
56
|
delete<T>(path: string): Promise<T>;
|
|
57
|
+
/**
|
|
58
|
+
* Run one of this app's `uiInvoke` functions and get its return value back.
|
|
59
|
+
*
|
|
60
|
+
* This is the ONLY way a page can reach an integration: the action endpoint
|
|
61
|
+
* requires an app token and refuses a browser session. The platform mints the
|
|
62
|
+
* token server-side and runs the handler in-process.
|
|
63
|
+
*
|
|
64
|
+
* The function must be declared `trigger: { type: 'uiInvoke' }` in the
|
|
65
|
+
* manifest, and the caller must hold its `minRole` (default EDITOR).
|
|
66
|
+
*
|
|
67
|
+
* Pass `idempotencyKey` for anything that must not run twice on a double
|
|
68
|
+
* click — a concurrent duplicate is rejected with 409 INVOCATION_IN_FLIGHT.
|
|
69
|
+
*
|
|
70
|
+
* Throws AppInvokeError. `code === 'FUNCTION_REJECTED'` carries an app-authored
|
|
71
|
+
* message that is safe to show the user; every other failure is generic on
|
|
72
|
+
* purpose (raw provider errors can leak tokens or PII).
|
|
73
|
+
*/
|
|
74
|
+
invoke<TResult, TInput = Record<string, unknown>>(functionName: string, input?: TInput, opts?: {
|
|
75
|
+
idempotencyKey?: string;
|
|
76
|
+
signal?: AbortSignal;
|
|
77
|
+
}): Promise<TResult>;
|
|
78
|
+
}
|
|
79
|
+
/** Thrown by AppApiClient.invoke. */
|
|
80
|
+
declare class AppInvokeError extends Error {
|
|
81
|
+
readonly status: number;
|
|
82
|
+
readonly code?: string | undefined;
|
|
83
|
+
readonly invocationId?: string | undefined;
|
|
84
|
+
constructor(status: number, message: string, code?: string | undefined, invocationId?: string | undefined);
|
|
47
85
|
}
|
|
48
86
|
declare const AppApiProvider: React.Provider<AppApiClient | null>;
|
|
49
87
|
/**
|
|
@@ -51,6 +89,26 @@ declare const AppApiProvider: React.Provider<AppApiClient | null>;
|
|
|
51
89
|
* Requests go to /api/data/* with the session cookie (RBAC applies server-side).
|
|
52
90
|
*/
|
|
53
91
|
declare function useAppApi(): AppApiClient;
|
|
92
|
+
/**
|
|
93
|
+
* Reads and writes this app's settings (GET/PUT /data/apps/:appSlug/settings).
|
|
94
|
+
*
|
|
95
|
+
* The app slug comes from the surrounding AppContext, so a settings page only
|
|
96
|
+
* has to describe its form. Values are the ones the server merged with the
|
|
97
|
+
* `settings.fields` defaults declared in the manifest.
|
|
98
|
+
*
|
|
99
|
+
* Reading requires VIEWER, writing requires ADMIN. `save` never throws: it
|
|
100
|
+
* reports through `saveError`, which carries the raw failure (422
|
|
101
|
+
* SETTINGS_VALIDATION_FAILED with its per-key errors, or 403) so the page can
|
|
102
|
+
* map it back onto its fields. A failed save leaves `settings` untouched.
|
|
103
|
+
*/
|
|
104
|
+
declare function useAppSettings<T = Record<string, unknown>>(): {
|
|
105
|
+
settings: T | undefined;
|
|
106
|
+
isLoading: boolean;
|
|
107
|
+
error: unknown;
|
|
108
|
+
save: (patch: Partial<T>) => Promise<void>;
|
|
109
|
+
isSaving: boolean;
|
|
110
|
+
saveError: unknown;
|
|
111
|
+
};
|
|
54
112
|
|
|
55
113
|
declare const buttonVariants: (props?: ({
|
|
56
114
|
variant?: "default" | "secondary" | "outline" | "ghost" | "destructive" | null | undefined;
|
|
@@ -139,5 +197,101 @@ interface DateRangePickerProps {
|
|
|
139
197
|
}
|
|
140
198
|
/** Minimal controlled date-range picker using two native date inputs. */
|
|
141
199
|
declare function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps): React.JSX.Element;
|
|
200
|
+
type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
|
201
|
+
declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
|
|
202
|
+
interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {
|
|
203
|
+
checked?: boolean;
|
|
204
|
+
/** Preferred over onChange — receives the boolean directly. */
|
|
205
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
206
|
+
label?: React.ReactNode;
|
|
207
|
+
}
|
|
208
|
+
declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
|
|
209
|
+
interface SidePanelProps {
|
|
210
|
+
open: boolean;
|
|
211
|
+
onClose: () => void;
|
|
212
|
+
title?: React.ReactNode;
|
|
213
|
+
description?: React.ReactNode;
|
|
214
|
+
children: React.ReactNode;
|
|
215
|
+
className?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Blocking slide-over — reach for it when a task has more fields than a `Modal`
|
|
219
|
+
* can show without an inner scrollbar. Full height, so the body scrolls once and
|
|
220
|
+
* a footer can stay pinned; `Modal` centres a box and does no height management.
|
|
221
|
+
*
|
|
222
|
+
* Children are laid out in a flex column filling the panel: put the scrollable
|
|
223
|
+
* region in a `min-h-0 flex-1 overflow-y-auto` child and the footer after it.
|
|
224
|
+
*
|
|
225
|
+
* NOTE: no focus management. Autofocus the primary action yourself.
|
|
226
|
+
*/
|
|
227
|
+
declare function SidePanel({ open, onClose, title, description, children, className, }: SidePanelProps): React.JSX.Element | null;
|
|
228
|
+
interface CopyButtonProps {
|
|
229
|
+
value: string;
|
|
230
|
+
label?: string;
|
|
231
|
+
copiedLabel?: string;
|
|
232
|
+
variant?: ButtonProps['variant'];
|
|
233
|
+
size?: ButtonProps['size'];
|
|
234
|
+
className?: string;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Copy-to-clipboard button with inline feedback. On failure it says so rather
|
|
238
|
+
* than silently doing nothing — keep the copyable text selectable so manual
|
|
239
|
+
* copy stays the fallback.
|
|
240
|
+
*/
|
|
241
|
+
declare function CopyButton({ value, label, copiedLabel, variant, size, className, }: CopyButtonProps): React.JSX.Element;
|
|
242
|
+
interface PopoverProps {
|
|
243
|
+
open: boolean;
|
|
244
|
+
onOpenChange: (open: boolean) => void;
|
|
245
|
+
trigger: React.ReactNode;
|
|
246
|
+
children: React.ReactNode;
|
|
247
|
+
align?: 'start' | 'end';
|
|
248
|
+
className?: string;
|
|
249
|
+
}
|
|
250
|
+
/** Anchored panel. Controlled — the caller owns `open`. Closes on outside click
|
|
251
|
+
* and Escape, which is what a filter pill needs and a Modal is too heavy for. */
|
|
252
|
+
declare function Popover({ open, onOpenChange, trigger, children, align, className, }: PopoverProps): React.JSX.Element;
|
|
253
|
+
interface DropdownMenuItem {
|
|
254
|
+
label: React.ReactNode;
|
|
255
|
+
onSelect: () => void;
|
|
256
|
+
disabled?: boolean;
|
|
257
|
+
destructive?: boolean;
|
|
258
|
+
}
|
|
259
|
+
interface DropdownMenuProps {
|
|
260
|
+
trigger: React.ReactNode;
|
|
261
|
+
items: DropdownMenuItem[];
|
|
262
|
+
align?: 'start' | 'end';
|
|
263
|
+
className?: string;
|
|
264
|
+
}
|
|
265
|
+
/** Uncontrolled menu built on Popover. Selecting an item closes it. */
|
|
266
|
+
declare function DropdownMenu({ trigger, items, align, className }: DropdownMenuProps): React.JSX.Element;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Browser helpers for app pages.
|
|
270
|
+
*
|
|
271
|
+
* App bundles get react, react-dom and this SDK from the shell's import map and
|
|
272
|
+
* bundle everything else themselves — so without these here, every app would
|
|
273
|
+
* reimplement clipboard handling and CSV escaping, and get the edge cases wrong
|
|
274
|
+
* in its own way.
|
|
275
|
+
*/
|
|
276
|
+
/**
|
|
277
|
+
* Copy text to the clipboard.
|
|
278
|
+
*
|
|
279
|
+
* Returns `false` instead of throwing when the clipboard is unavailable (non
|
|
280
|
+
* secure context, permission refused) so the caller can render inline feedback.
|
|
281
|
+
* No `document.execCommand('copy')` fallback: it is deprecated, and the shell
|
|
282
|
+
* only ever runs on https or localhost, both secure contexts.
|
|
283
|
+
*/
|
|
284
|
+
declare function copyToClipboard(text: string): Promise<boolean>;
|
|
285
|
+
/** Trigger a browser download of a Blob via a throwaway object URL + `<a>` click. */
|
|
286
|
+
declare function downloadBlob(blob: Blob, filename: string): void;
|
|
287
|
+
/** Serialize rows (header included) into an RFC 4180 CSV string. */
|
|
288
|
+
declare function toCsv(rows: string[][]): string;
|
|
289
|
+
/**
|
|
290
|
+
* Serialize + download in one call.
|
|
291
|
+
*
|
|
292
|
+
* The BOM is the whole reason this helper exists: without it Excel on Windows
|
|
293
|
+
* reads the file as latin-1 and mangles every accented character.
|
|
294
|
+
*/
|
|
295
|
+
declare function downloadCsv(rows: string[][], filename: string): void;
|
|
142
296
|
|
|
143
|
-
export { type AppApiClient, AppApiProvider, AppContextProvider, type AppContextValue, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type DateRange, DateRangePicker, type DateRangePickerProps, Input, Link, type LinkProps, Modal, type ModalProps, Select, type SelectProps, Spinner, type SpinnerProps, Switch, type SwitchProps, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, type TabsProps, TabsTrigger, cn, useAppApi, useAppContext };
|
|
297
|
+
export { type AppApiClient, AppApiProvider, AppContextProvider, type AppContextValue, AppInvokeError, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, Checkbox, type CheckboxProps, CopyButton, type CopyButtonProps, type DateRange, DateRangePicker, type DateRangePickerProps, DropdownMenu, type DropdownMenuItem, type DropdownMenuProps, Input, Link, type LinkProps, Modal, type ModalProps, Popover, type PopoverProps, Select, type SelectProps, SidePanel, type SidePanelProps, Spinner, type SpinnerProps, Switch, type SwitchProps, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, type TabsProps, TabsTrigger, Textarea, type TextareaProps, cn, copyToClipboard, downloadBlob, downloadCsv, toCsv, useAppApi, useAppContext, useAppSettings };
|