@apotech-os/ui-sdk 0.10.0 → 2.0.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.d.ts CHANGED
@@ -170,9 +170,34 @@ declare function TableBody({ className, ...props }: React.HTMLAttributes<HTMLTab
170
170
  declare function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>): React.JSX.Element;
171
171
  declare function TableHead({ className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>): React.JSX.Element;
172
172
  declare function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>): React.JSX.Element;
173
- interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {
173
+ interface SelectOption {
174
+ value: string;
175
+ label: React.ReactNode;
176
+ disabled?: boolean;
174
177
  }
175
- declare const Select: React.ForwardRefExoticComponent<SelectProps & React.RefAttributes<HTMLSelectElement>>;
178
+ interface SelectProps {
179
+ /** Controlled value. Pair with `onValueChange`. */
180
+ value?: string;
181
+ defaultValue?: string;
182
+ onValueChange?: (value: string) => void;
183
+ items: SelectOption[];
184
+ /** Shown when nothing is chosen. */
185
+ placeholder?: React.ReactNode;
186
+ disabled?: boolean;
187
+ /** Submitted with a surrounding form, through a hidden native input. */
188
+ name?: string;
189
+ className?: string;
190
+ 'aria-label'?: string;
191
+ }
192
+ /**
193
+ * Listbox select.
194
+ *
195
+ * Contract 2: this used to be a native `<select>` taking `<option>` children.
196
+ * The popup is ours now — themed, positioned and keyboard-driven like every
197
+ * other floating surface — which a native select cannot be. `items` replaces the
198
+ * children, and the ref is gone: there is no `HTMLSelectElement` behind it.
199
+ */
200
+ declare function Select({ value, defaultValue, onValueChange, items, placeholder, disabled, name, className, ...props }: SelectProps): React.JSX.Element;
176
201
  interface TabsProps {
177
202
  defaultValue?: string;
178
203
  value?: string;
@@ -225,27 +250,29 @@ interface SwitchProps {
225
250
  'aria-label'?: string;
226
251
  }
227
252
  declare function Switch({ checked, onCheckedChange, disabled, className, ...props }: SwitchProps): React.JSX.Element;
228
- interface DateRange {
229
- from: string;
230
- to: string;
231
- }
232
- interface DateRangePickerProps {
233
- value: DateRange;
234
- onChange: (range: DateRange) => void;
235
- className?: string;
236
- disabled?: boolean;
237
- }
238
- /** Minimal controlled date-range picker using two native date inputs. */
239
- declare function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps): React.JSX.Element;
240
253
  type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
241
254
  declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
242
- interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {
255
+ interface CheckboxProps {
243
256
  checked?: boolean;
244
- /** Preferred over onChange — receives the boolean directly. */
257
+ defaultChecked?: boolean;
258
+ /** Receives the boolean directly. */
245
259
  onCheckedChange?: (checked: boolean) => void;
260
+ disabled?: boolean;
246
261
  label?: React.ReactNode;
262
+ /** Submitted with a surrounding form, through a hidden native input. */
263
+ name?: string;
264
+ className?: string;
265
+ 'aria-label'?: string;
247
266
  }
248
- declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
267
+ /**
268
+ * Checkbox.
269
+ *
270
+ * Contract 2: this used to be a native `<input type="checkbox">` forwarding an
271
+ * `HTMLInputElement` ref and taking every input attribute. Base UI renders a
272
+ * button with the role and a hidden input for form submission, so neither could
273
+ * survive — `onChange` and the ref are gone, `onCheckedChange` is the way in.
274
+ */
275
+ declare function Checkbox({ checked, defaultChecked, onCheckedChange, disabled, label, name, className, ...props }: CheckboxProps): React.JSX.Element;
249
276
  interface SidePanelProps {
250
277
  open: boolean;
251
278
  onClose: () => void;
@@ -306,6 +333,263 @@ interface DropdownMenuProps {
306
333
  /** Uncontrolled menu. Selecting an item closes it; arrow keys move between them. */
307
334
  declare function DropdownMenu({ trigger, items, align, className }: DropdownMenuProps): React.JSX.Element;
308
335
 
336
+ interface DataTableColumn<Row> {
337
+ /** Stable identifier — also the key used for sorting and hiding. */
338
+ key: string;
339
+ header: React.ReactNode;
340
+ /** Defaults to `String(row[key])`. */
341
+ cell?: (row: Row) => React.ReactNode;
342
+ /** Raw value used for client-side sorting and faceting. */
343
+ value?: (row: Row) => unknown;
344
+ sortable?: boolean;
345
+ align?: 'left' | 'right';
346
+ /** Starting width in pixels; the user can drag from there. */
347
+ width?: number;
348
+ }
349
+ /**
350
+ * The operators a filter can use — the same ten names the app manifest declares
351
+ * and the records endpoint implements.
352
+ *
353
+ * The names match; the edges do not, so do not assume a filter composed here and
354
+ * a `views[]` filter agree on every row. Two known differences: `neq` keeps rows
355
+ * whose value is absent here and drops them server-side, and the server compares
356
+ * `gt`/`lt`/`gte`/`lte` on the raw JSON text where this compares numbers and
357
+ * dates as such. And the endpoint's operator map takes one value per operator
358
+ * with no `in`, so a server-side facet should offer single-value operators —
359
+ * multi-select is a client-side affordance.
360
+ */
361
+ type DataTableFilterOperator = 'eq' | 'neq' | 'contains' | 'ncontains' | 'gt' | 'lt' | 'gte' | 'lte' | 'empty' | 'nempty';
362
+ interface DataTableFacet {
363
+ key: string;
364
+ label: string;
365
+ /** Values to choose from. Without them the facet takes a typed value instead. */
366
+ options?: Array<{
367
+ value: string;
368
+ label?: string;
369
+ }>;
370
+ /** Offered operators, first one default. Equality alone if omitted. */
371
+ operators?: DataTableFilterOperator[];
372
+ }
373
+ interface DataTableFilter {
374
+ operator: DataTableFilterOperator;
375
+ /** Empty for `empty`/`nempty`; one entry for a comparison; several for a set. */
376
+ values: string[];
377
+ }
378
+ interface DataTableSort {
379
+ key: string;
380
+ direction: 'asc' | 'desc';
381
+ }
382
+ interface DataTableState {
383
+ search: string;
384
+ sort: DataTableSort | null;
385
+ /** Faceted filters, by facet key. An absent key means "no constraint". */
386
+ filters: Record<string, DataTableFilter>;
387
+ hidden: string[];
388
+ selected: string[];
389
+ }
390
+ interface DataTablePagination {
391
+ hasNext: boolean;
392
+ hasPrevious: boolean;
393
+ onNext: () => void;
394
+ onPrevious: () => void;
395
+ }
396
+ interface DataTableProps<Row> {
397
+ columns: Array<DataTableColumn<Row>>;
398
+ rows: Row[];
399
+ rowId: (row: Row) => string;
400
+ /** Controlled state. Anything left out falls back to `defaultState`. */
401
+ state?: Partial<DataTableState>;
402
+ defaultState?: Partial<DataTableState>;
403
+ onStateChange?: (state: DataTableState) => void;
404
+ facets?: DataTableFacet[];
405
+ searchPlaceholder?: string;
406
+ selectable?: boolean;
407
+ onRowClick?: (row: Row) => void;
408
+ pagination?: DataTablePagination;
409
+ /** Server does the sorting, filtering and searching; render `rows` as given. */
410
+ manual?: boolean;
411
+ loading?: boolean;
412
+ error?: React.ReactNode;
413
+ empty?: React.ReactNode;
414
+ /** Beyond this many rows the body is virtualised. */
415
+ virtualizeFrom?: number;
416
+ className?: string;
417
+ }
418
+ declare function DataTable<Row>({ columns, rows, rowId, state: controlled, defaultState, onStateChange, facets, searchPlaceholder, selectable, onRowClick, pagination, manual, loading, error, empty, virtualizeFrom, className, }: DataTableProps<Row>): React.JSX.Element;
419
+
420
+ type PeriodPresetKey = 'today' | 'yesterday' | 'last7' | 'last30' | 'last90' | 'thisMonth' | 'lastMonth' | 'thisQuarter' | 'last12Months' | 'thisYear' | 'all' | 'custom';
421
+ interface PeriodRange {
422
+ /**
423
+ * Absent means unbounded — only the `all` preset produces it. The spec's
424
+ * `PeriodValue` sketch types `from` as required, which cannot express the
425
+ * "all time" entry its own preset rail asks for; a filter with no lower bound
426
+ * is a different query, so the type says so rather than encoding it as a
427
+ * sentinel date the caller would have to recognise.
428
+ */
429
+ from?: string;
430
+ to: string;
431
+ }
432
+ type PeriodCompareMode = 'none' | 'previous_period' | 'previous_year' | 'custom';
433
+ interface PeriodValue {
434
+ preset: PeriodPresetKey;
435
+ range: PeriodRange;
436
+ compare: PeriodCompareMode;
437
+ /** The window `compare` resolves to. Absent when comparing to nothing. */
438
+ compareRange?: PeriodRange;
439
+ }
440
+ interface PeriodPreset {
441
+ key: PeriodPresetKey;
442
+ label: string;
443
+ }
444
+ /** The rail, in the order it is offered. `custom` is reached by picking days. */
445
+ declare const PERIOD_PRESETS: readonly PeriodPreset[];
446
+ declare const COMPARE_LABELS: Record<PeriodCompareMode, string>;
447
+ /**
448
+ * The window a comparison mode resolves to, or undefined when there is nothing
449
+ * to compare against — `none`, an unbounded period, or `custom`, whose range the
450
+ * user picks and which therefore cannot be derived.
451
+ */
452
+ declare function comparisonRange(preset: PeriodPresetKey, range: PeriodRange, compare: PeriodCompareMode): PeriodRange | undefined;
453
+ /** A period with its comparison window resolved — the only way to build one. */
454
+ declare function makePeriod(preset: PeriodPresetKey, range: PeriodRange, compare: PeriodCompareMode, customCompareRange?: PeriodRange): PeriodValue;
455
+ /** The period a preset resolves to, relative to `today`. */
456
+ declare function periodFromPreset(preset: PeriodPresetKey, today: Date, compare?: PeriodCompareMode): PeriodValue;
457
+ /** A range as a person reads it, collapsing the parts both ends share. */
458
+ declare function formatRange(range: PeriodRange): string;
459
+ /**
460
+ * What the trigger shows: the preset's name, or the days a custom range spans.
461
+ *
462
+ * A range can arrive incomplete — the picker it replaced accepted `{from: '',
463
+ * to: ''}` as "nothing chosen yet" — and formatting one would print an Invalid
464
+ * Date rather than say there is nothing to show.
465
+ */
466
+ declare function formatPeriod(value: PeriodValue): string;
467
+
468
+ interface DateRangeCompareProps {
469
+ value: PeriodValue;
470
+ onChange: (value: PeriodValue) => void;
471
+ /** Offer the comparison section. */
472
+ comparable?: boolean;
473
+ /** Override the rail — a subset, or presets in another order. */
474
+ presets?: readonly PeriodPreset[];
475
+ align?: 'start' | 'end';
476
+ disabled?: boolean;
477
+ className?: string;
478
+ }
479
+ declare function DateRangeCompare({ value, onChange, comparable, presets, align, disabled, className, }: DateRangeCompareProps): React.JSX.Element;
480
+ /** A day range with both ends — what the pre-contract-2 picker spoke. */
481
+ interface DateRange {
482
+ from: string;
483
+ to: string;
484
+ }
485
+ interface DateRangePickerProps {
486
+ value: DateRange;
487
+ onChange: (range: DateRange) => void;
488
+ className?: string;
489
+ disabled?: boolean;
490
+ }
491
+ /**
492
+ * The plain range picker, now a view of `DateRangeCompare` with the preset rail
493
+ * and the comparison section it does not need.
494
+ *
495
+ * It stays because removing an export breaks the contract, and its signature is
496
+ * unchanged: a caller that only ever wanted two days keeps passing two days.
497
+ */
498
+ declare function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps): React.JSX.Element;
499
+
500
+ /**
501
+ * The pieces every chart in the kit is built from — the shadcn/chart blocks,
502
+ * adapted to this SDK.
503
+ *
504
+ * Two deliberate departures from the upstream blocks:
505
+ *
506
+ * Upstream lets a series carry any CSS colour and injects a per-chart `<style>`
507
+ * to declare it. Here a series names a `--chart-*` token instead, so there is
508
+ * nothing to inject: the theme already defines those variables for both colour
509
+ * schemes, and a chart cannot end up holding a colour the theme does not know.
510
+ *
511
+ * Nothing in this file is exported from the package. Recharts is an
512
+ * implementation detail, and these compose only with Recharts elements, so
513
+ * exporting them would put the engine in the public API through the back door.
514
+ */
515
+
516
+ interface ChartSeries {
517
+ /** The key this series reads from each row. */
518
+ key: string;
519
+ label: string;
520
+ /** Palette slot. Defaults to the series' position. */
521
+ colorIndex?: number;
522
+ }
523
+ type ValueFormatter = (value: number) => string;
524
+
525
+ /**
526
+ * ChartKit — the charts an app is allowed to draw.
527
+ *
528
+ * Each one is a finished block with a narrow, typed surface: rows, the field on
529
+ * the category axis, and the series to plot. Recharts is never re-exported and
530
+ * none of its elements appear in a prop type, so the engine stays replaceable
531
+ * and an app cannot assemble a chart that steps outside the design system.
532
+ *
533
+ * Colours come only from the `--chart-*` tokens, which the theme defines for
534
+ * both colour schemes. That is the whole reason charts belong in the SDK: a
535
+ * hand-drawn SVG with a hex literal is invisible in dark mode, and every app
536
+ * that drew its own got that wrong.
537
+ */
538
+
539
+ /** A row is whatever an app has; the chart only reads the keys it was given. */
540
+ type ChartRow = Record<string, string | number | null | undefined>;
541
+ interface CartesianChartProps {
542
+ data: ChartRow[];
543
+ /** The field on the category axis. */
544
+ x: string;
545
+ series: ChartSeries[];
546
+ /** The same measure over an earlier period, drawn dashed and faded. */
547
+ compareSeries?: ChartSeries;
548
+ formatValue?: ValueFormatter;
549
+ height?: number;
550
+ /** Read out in place of the graphic. Defaults to the series names. */
551
+ label?: string;
552
+ hideLegend?: boolean;
553
+ className?: string;
554
+ }
555
+ declare function BarChart(props: CartesianChartProps): React.JSX.Element;
556
+ declare function StackedBarChart(props: CartesianChartProps): React.JSX.Element;
557
+ declare function LineChart(props: CartesianChartProps): React.JSX.Element;
558
+ declare function AreaChart(props: CartesianChartProps): React.JSX.Element;
559
+ interface FunnelStep {
560
+ label: string;
561
+ value: number;
562
+ }
563
+ interface FunnelChartProps {
564
+ data: FunnelStep[];
565
+ formatValue?: ValueFormatter;
566
+ height?: number;
567
+ label?: string;
568
+ className?: string;
569
+ }
570
+ /**
571
+ * The one chart with no shadcn block, so it is assembled from Recharts' own
572
+ * funnel elements. Steps keep their palette slot in the order they are given —
573
+ * a funnel is read top to bottom, and a colour that moved between renders would
574
+ * read as a different step.
575
+ */
576
+ declare function FunnelChart({ data, formatValue, height, label, className, }: FunnelChartProps): React.JSX.Element;
577
+ interface KpiCardProps {
578
+ label: string;
579
+ value: number;
580
+ /** The same measure over the compared period. Drives the delta. */
581
+ compareValue?: number;
582
+ formatValue?: ValueFormatter;
583
+ /** For measures that are better when lower — cost, churn, delay. */
584
+ lowerIsBetter?: boolean;
585
+ /** A bare trend line under the figure. */
586
+ sparkline?: number[];
587
+ className?: string;
588
+ }
589
+ /** The signed change, or null when there is no baseline to divide by. */
590
+ declare function relativeDelta(value: number, compareValue: number | undefined): number | null;
591
+ declare function KpiCard({ label, value, compareValue, formatValue, lowerIsBetter, sparkline, className, }: KpiCardProps): React.JSX.Element;
592
+
309
593
  interface ToastInput {
310
594
  title: string;
311
595
  description?: string;
@@ -371,4 +655,4 @@ declare function toCsv(rows: string[][]): string;
371
655
  */
372
656
  declare function downloadCsv(rows: string[][], filename: string): void;
373
657
 
374
- export { type AppApiClient, AppApiProvider, AppContextProvider, type AppContextValue, AppInvokeError, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardDescription, CardFooter, 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, type ToastInput, ToastProvider, Tooltip, type TooltipProps, badgeVariants, buttonVariants, cn, copyToClipboard, downloadBlob, downloadCsv, toCsv, useAppApi, useAppContext, useAppRun, useAppRuns, useAppSettings, useToast };
658
+ export { type AppApiClient, AppApiProvider, AppContextProvider, type AppContextValue, AppInvokeError, AreaChart, Badge, type BadgeProps, BarChart, Button, type ButtonProps, COMPARE_LABELS, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CartesianChartProps, type ChartRow, type ChartSeries, Checkbox, type CheckboxProps, CopyButton, type CopyButtonProps, DataTable, type DataTableColumn, type DataTableFacet, type DataTableFilter, type DataTableFilterOperator, type DataTablePagination, type DataTableProps, type DataTableSort, type DataTableState, type DateRange, DateRangeCompare, type DateRangeCompareProps, DateRangePicker, type DateRangePickerProps, DropdownMenu, type DropdownMenuItem, type DropdownMenuProps, FunnelChart, type FunnelChartProps, type FunnelStep, Input, KpiCard, type KpiCardProps, LineChart, Link, type LinkProps, Modal, type ModalProps, PERIOD_PRESETS, type PeriodCompareMode, type PeriodPreset, type PeriodPresetKey, type PeriodRange, type PeriodValue, Popover, type PopoverProps, Select, type SelectOption, type SelectProps, SidePanel, type SidePanelProps, Spinner, type SpinnerProps, StackedBarChart, Switch, type SwitchProps, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, type TabsProps, TabsTrigger, Textarea, type TextareaProps, type ToastInput, ToastProvider, Tooltip, type TooltipProps, type ValueFormatter, badgeVariants, buttonVariants, cn, comparisonRange, copyToClipboard, downloadBlob, downloadCsv, formatPeriod, formatRange, makePeriod, periodFromPreset, relativeDelta, toCsv, useAppApi, useAppContext, useAppRun, useAppRuns, useAppSettings, useToast };