@a4ui/core 0.34.0 → 0.35.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.
@@ -0,0 +1,49 @@
1
+ import { JSX } from 'solid-js';
2
+ /** A single audit-trail entry rendered by {@link ActivityFeed}. */
3
+ export interface ActivityItem {
4
+ id: string;
5
+ /** Name of the user/system that performed the action. */
6
+ actor: string;
7
+ /** What happened, rendered right after `actor` (e.g. `"commented on Invoice #42"`). */
8
+ action: JSX.Element;
9
+ /** Leading icon shown when `avatar` is omitted. Defaults to a generic activity icon. */
10
+ icon?: JSX.Element;
11
+ /** ISO 8601 timestamp of the event. */
12
+ timestamp: string;
13
+ avatar?: string;
14
+ }
15
+ export interface ActivityFeedProps {
16
+ items: ActivityItem[];
17
+ class?: string;
18
+ }
19
+ /**
20
+ * Chronological audit-trail list (newest first), grouped under subtle day
21
+ * headers (`"Today"` / `"Yesterday"` / a locale date) with a continuous
22
+ * connector line down the left, in the same spirit as {@link Timeline}. Each
23
+ * row shows an avatar (or a fallback icon), `"{actor} {action}"`, and a
24
+ * relative timestamp whose `title` carries the absolute time. Distinct from
25
+ * {@link TransactionFeed}: this is generic activity/audit history, not a
26
+ * financial ledger.
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * <ActivityFeed
31
+ * items={[
32
+ * {
33
+ * id: '1',
34
+ * actor: 'Ada Lovelace',
35
+ * action: <>commented on <strong>Invoice #42</strong></>,
36
+ * timestamp: '2026-07-21T09:15:00Z',
37
+ * avatar: ada.avatarUrl,
38
+ * },
39
+ * {
40
+ * id: '2',
41
+ * actor: 'System',
42
+ * action: 'archived the project',
43
+ * timestamp: '2026-07-20T18:02:00Z',
44
+ * },
45
+ * ]}
46
+ * />
47
+ * ```
48
+ */
49
+ export declare function ActivityFeed(props: ActivityFeedProps): JSX.Element;
@@ -0,0 +1,35 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface AvailabilityPickerProps {
3
+ /** Open slots per date, keyed by local ISO 'YYYY-MM-DD'; each value is a list of 'HH:mm' times. */
4
+ slotsByDate: Record<string, string[]>;
5
+ /** Controlled selection; omit to manage selection internally. */
6
+ value?: {
7
+ date: string;
8
+ time: string;
9
+ };
10
+ onChange?: (selection: {
11
+ date: string;
12
+ time: string;
13
+ }) => void;
14
+ /** Label shown near the slots. @default the browser's Intl timezone */
15
+ timezone?: string;
16
+ class?: string;
17
+ }
18
+ /**
19
+ * Booking-style availability picker: a scrollable list of bookable dates on the
20
+ * left (built from the keys of `slotsByDate`) and a scrollable grid of open
21
+ * 'HH:mm' slots for the selected date on the right, with a timezone label.
22
+ * Controlled via `value`/`onChange`, or self-managed when `value` is omitted.
23
+ * Fully keyboard accessible (native buttons, `aria-pressed` on the current pick).
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * const [selection, setSelection] = createSignal<{ date: string; time: string }>()
28
+ * <AvailabilityPicker
29
+ * slotsByDate={{ '2026-07-22': ['09:00', '09:30', '14:00'], '2026-07-23': ['10:00'] }}
30
+ * value={selection()}
31
+ * onChange={setSelection}
32
+ * />
33
+ * ```
34
+ */
35
+ export declare function AvailabilityPicker(props: AvailabilityPickerProps): JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface CodeEditorProps {
3
+ value: string;
4
+ /** Called with the new source string on every input event. */
5
+ onInput?: (v: string) => void;
6
+ /** Language used to pick the keyword set for highlighting. Default `'ts'`. */
7
+ language?: 'ts' | 'js' | 'json' | 'html' | 'css';
8
+ /** Hides the caret and blocks editing; the overlay still highlights. */
9
+ readOnly?: boolean;
10
+ class?: string;
11
+ }
12
+ /**
13
+ * A minimal code editor: line numbers in a gutter, a transparent textarea for
14
+ * input, and a `<pre>` overlay underneath it that renders approximate syntax
15
+ * highlighting from simple regexes (keywords, strings, numbers, comments).
16
+ * Not a full parser — good for READMEs, config editors, and demo panes, not
17
+ * a replacement for a real editor component (CodeMirror/Monaco).
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * const [src, setSrc] = createSignal('const x: number = 1\n')
22
+ * <CodeEditor value={src()} onInput={setSrc} language="ts" />
23
+ * ```
24
+ */
25
+ export declare function CodeEditor(props: CodeEditorProps): JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface EmojiPickerProps {
3
+ /** Called with the emoji character whenever the user picks one. */
4
+ onSelect: (emoji: string) => void;
5
+ class?: string;
6
+ }
7
+ /**
8
+ * A searchable emoji grid with an inline curated dataset (no network fetch),
9
+ * category tabs that scroll to their section, and a session-only "Recents"
10
+ * row. Type in the search box to filter by keyword, or click a category icon
11
+ * to jump the grid to that section.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <EmojiPicker onSelect={(emoji) => insertAtCursor(emoji)} />
16
+ * ```
17
+ */
18
+ export declare function EmojiPicker(props: EmojiPickerProps): JSX.Element;
@@ -0,0 +1,41 @@
1
+ import { JSX } from 'solid-js';
2
+ /** A single scheduled event; `start`/`end` are local ISO datetimes ('YYYY-MM-DDTHH:mm'). */
3
+ export interface SchedulerEvent {
4
+ id: string;
5
+ title: string;
6
+ start: string;
7
+ end: string;
8
+ tone?: 'primary' | 'accent';
9
+ }
10
+ export interface EventSchedulerProps {
11
+ events: SchedulerEvent[];
12
+ /** Day to show (day view) or the week containing it (week view). ISO 'YYYY-MM-DD'. @default today */
13
+ date?: string;
14
+ /** @default 'day' */
15
+ view?: 'day' | 'week';
16
+ /** First hour band shown (0–23). @default 7 */
17
+ startHour?: number;
18
+ /** Last hour band shown, exclusive (0–23). @default 21 */
19
+ endHour?: number;
20
+ class?: string;
21
+ }
22
+ /**
23
+ * Time-grid calendar: one column per visible day, hour bands from `startHour` to
24
+ * `endHour`, events absolutely positioned by their start/end minutes and split
25
+ * side-by-side when they overlap. Draws a "now" line through today's column
26
+ * when it's in view. Read-only positioning (drag-to-create/resize is out of
27
+ * scope). Scrolls vertically when the hour range is tall.
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * <EventScheduler
32
+ * view="week"
33
+ * date="2026-07-21"
34
+ * events={[
35
+ * { id: '1', title: 'Standup', start: '2026-07-21T09:00', end: '2026-07-21T09:30', tone: 'primary' },
36
+ * { id: '2', title: 'Design review', start: '2026-07-21T09:15', end: '2026-07-21T10:00', tone: 'accent' },
37
+ * ]}
38
+ * />
39
+ * ```
40
+ */
41
+ export declare function EventScheduler(props: EventSchedulerProps): JSX.Element;
@@ -0,0 +1,50 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface MapMarker {
3
+ lat: number;
4
+ lng: number;
5
+ label?: string;
6
+ id?: string;
7
+ }
8
+ export interface InteractiveMapProps {
9
+ /** Initial view center. Also acts as a recenter trigger: passing a new
10
+ * `{ lat, lng }` after mount pans the view there (e.g. a "use my
11
+ * location" button) without fighting the user's own drag/zoom in between.
12
+ * @default { lat: 0, lng: 0 } */
13
+ center?: {
14
+ lat: number;
15
+ lng: number;
16
+ };
17
+ /** Initial integer zoom level, clamped to `[2, 18]`. Synced the same way
18
+ * as `center` when it changes after mount. @default 3 */
19
+ zoom?: number;
20
+ /** Pins rendered on top of the tiles, projected to their pixel position. */
21
+ markers?: MapMarker[];
22
+ /** Tile URL template with `{z}`/`{x}`/`{y}` placeholders.
23
+ * @default 'https://tile.openstreetmap.org/{z}/{x}/{y}.png' */
24
+ tileUrl?: string;
25
+ /** Height of the map, in px. @default 400 */
26
+ height?: number;
27
+ /** Fires with the lat/lng under the pointer on a click (drags don't count). */
28
+ onClick?: (coord: {
29
+ lat: number;
30
+ lng: number;
31
+ }) => void;
32
+ class?: string;
33
+ }
34
+ /**
35
+ * A slippy tile map built directly on Web Mercator math — no map SDK. Pan by
36
+ * dragging, zoom with the +/- buttons or the wheel (zoom keeps the point
37
+ * under the cursor fixed), place `markers`, and get the lat/lng of a click
38
+ * via `onClick`. Recomputes its tile grid on resize (`ResizeObserver`).
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * <InteractiveMap
43
+ * center={{ lat: 48.8584, lng: 2.2945 }}
44
+ * zoom={13}
45
+ * markers={[{ lat: 48.8584, lng: 2.2945, label: 'Eiffel Tower' }]}
46
+ * onClick={(coord) => console.log('clicked', coord)}
47
+ * />
48
+ * ```
49
+ */
50
+ export declare function InteractiveMap(props: InteractiveMapProps): JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface JsonViewerProps {
3
+ /** The value to render — object, array, or a primitive at the root. */
4
+ data: unknown;
5
+ /** Expand every object/array node on first render. Defaults to `false`. */
6
+ defaultExpanded?: boolean;
7
+ class?: string;
8
+ }
9
+ /**
10
+ * Collapsible, indented JSON tree. Objects/arrays are expandable nodes (chevron
11
+ * + key + a `{…}` / `[…]` summary with child count); primitives render as
12
+ * `key: value` with the value tinted by type. Expanded state is tracked
13
+ * internally by path, seeded fully-open when `defaultExpanded` is set. An
14
+ * optional search box highlights keys/values that match.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <JsonViewer
19
+ * defaultExpanded
20
+ * data={{ user: { id: 1, name: 'Ada', active: true, tags: ['admin', 'core'] } }}
21
+ * />
22
+ * ```
23
+ */
24
+ export declare function JsonViewer(props: JsonViewerProps): JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface LocationValue {
3
+ lat: number;
4
+ lng: number;
5
+ label?: string;
6
+ }
7
+ export interface LocationPickerProps {
8
+ /** Controlled value. Omit to let the component manage its own state. */
9
+ value?: LocationValue;
10
+ /** Fires with the full value whenever the label, the pin, or geolocation changes it. */
11
+ onChange?: (v: LocationValue) => void;
12
+ class?: string;
13
+ }
14
+ /**
15
+ * Text label + compact map field for picking a location: click or drag the
16
+ * map to drop the pin (no geocoding — the label is a free-text tag the caller
17
+ * attaches to the coordinates), or use the "use my location" button.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * const [place, setPlace] = createSignal<LocationValue>({ lat: 48.8584, lng: 2.2945, label: 'Eiffel Tower' })
22
+ * <LocationPicker value={place()} onChange={setPlace} />
23
+ * ```
24
+ */
25
+ export declare function LocationPicker(props: LocationPickerProps): JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface MaskedInputProps {
3
+ /** `#` = digit slot, `A` = letter slot, any other char is a literal, e.g. `'(###) ###-####'`. */
4
+ mask: string;
5
+ /** Controlled raw value (just the entered #/A characters, no literals). */
6
+ value?: string;
7
+ /** Called with `(raw, formatted)` on every accepted keystroke or paste. */
8
+ onInput?: (raw: string, formatted: string) => void;
9
+ placeholder?: string;
10
+ class?: string;
11
+ 'aria-label'?: string;
12
+ }
13
+ /**
14
+ * Format-as-you-type input over a real `<input>`. `mask` uses `#` for a digit
15
+ * slot and `A` for a letter slot; any other character is a literal inserted
16
+ * automatically as the user reaches it. Characters that don't fit the next
17
+ * slot are rejected, and pasted text is normalized by re-extracting only its
18
+ * valid #/A characters. Controlled (`value`) or uncontrolled.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * const [phone, setPhone] = createSignal('')
23
+ * <MaskedInput mask="(###) ###-####" value={phone()} onInput={setPhone} placeholder="(555) 123-4567" />
24
+ * ```
25
+ */
26
+ export declare function MaskedInput(props: MaskedInputProps): JSX.Element;
@@ -0,0 +1,29 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface OtpInputProps {
3
+ /** Number of single-character boxes. @default 6 */
4
+ length?: number;
5
+ /** Controlled value; when provided, the group renders it and the parent owns state. */
6
+ value?: string;
7
+ /** Called with the full joined value on every box change (both typing and deletion). */
8
+ onInput?: (value: string) => void;
9
+ /** Called once with the full value when every box is filled. */
10
+ onComplete?: (value: string) => void;
11
+ /** Restrict input to digits and switch the mobile keyboard to numeric. */
12
+ numeric?: boolean;
13
+ class?: string;
14
+ 'aria-label'?: string;
15
+ }
16
+ /**
17
+ * Segmented one-time-passcode input: one `<input maxlength=1>` per character.
18
+ * Typing advances focus to the next box, Backspace on an empty box moves back
19
+ * and clears the previous one, arrow keys move focus, and pasting a string
20
+ * distributes its characters across boxes starting at the focused index.
21
+ * Works controlled (pass `value`) or uncontrolled.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * const [code, setCode] = createSignal('')
26
+ * <OtpInput length={6} value={code()} onInput={setCode} numeric onComplete={verify} />
27
+ * ```
28
+ */
29
+ export declare function OtpInput(props: OtpInputProps): JSX.Element;
@@ -0,0 +1,54 @@
1
+ import { JSX } from 'solid-js';
2
+ /** A user currently present/active in a collaborative session. */
3
+ export interface PresenceUser {
4
+ id: string;
5
+ name: string;
6
+ avatar?: string;
7
+ /** Accent for this user's remote cursor label. Falls back to the primary token. */
8
+ color?: string;
9
+ }
10
+ /** A remote user's pointer position, as fractions of the shared canvas. */
11
+ export interface RemoteCursor {
12
+ userId: string;
13
+ /** 0..1 fraction of the container's width. */
14
+ x: number;
15
+ /** 0..1 fraction of the container's height. */
16
+ y: number;
17
+ }
18
+ export interface PresenceAvatarsProps {
19
+ users: PresenceUser[];
20
+ /** Max avatars shown before collapsing the rest into `+N`. @default 4 */
21
+ max?: number;
22
+ /**
23
+ * Remote cursors to render. Positioned absolutely against the nearest
24
+ * `relative` ancestor, so the caller wraps its canvas/surface with
25
+ * `class="relative"` for the cursors to anchor to — this component itself
26
+ * does not create that positioning context.
27
+ */
28
+ cursors?: RemoteCursor[];
29
+ class?: string;
30
+ }
31
+ /**
32
+ * Stacked avatar group of users active in a collaborative session, each with
33
+ * a small online dot and a name tooltip; overflow past `max` (default 4)
34
+ * collapses into a trailing `+N` chip, mirroring {@link AvatarGroup}. When
35
+ * `cursors` is given, also renders labeled remote cursors — a small arrow
36
+ * plus a name chip tinted with the user's `color` — positioned at `x`/`y`
37
+ * fractions of the nearest `relative` ancestor and animated smoothly as
38
+ * positions update.
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * <div class="relative h-64 w-full overflow-hidden rounded-lg border">
43
+ * <PresenceAvatars
44
+ * class="absolute right-3 top-3"
45
+ * users={[
46
+ * { id: 'u1', name: 'Ada Lovelace' },
47
+ * { id: 'u2', name: 'Grace Hopper', color: 'hsl(280 80% 60%)' },
48
+ * ]}
49
+ * cursors={[{ userId: 'u2', x: 0.42, y: 0.6 }]}
50
+ * />
51
+ * </div>
52
+ * ```
53
+ */
54
+ export declare function PresenceAvatars(props: PresenceAvatarsProps): JSX.Element;
@@ -0,0 +1,56 @@
1
+ import { JSX } from 'solid-js';
2
+ /** A field the query builder can filter on. */
3
+ export interface QueryField {
4
+ /** Value stored in a rule's `field`; must be unique across `fields`. */
5
+ name: string;
6
+ /** Label shown in the field `<Select>`. */
7
+ label: string;
8
+ /** Determines which operators are offered and how the value is entered. Defaults to `'text'`. */
9
+ type?: 'text' | 'number' | 'select';
10
+ /** Options for the value `<Select>` when `type` is `'select'`. */
11
+ options?: string[];
12
+ }
13
+ /** A single leaf condition: `field operator value`. */
14
+ export type QueryRule = {
15
+ field: string;
16
+ operator: string;
17
+ value: string;
18
+ };
19
+ /** A group of rules and/or nested groups, combined with `and`/`or`. */
20
+ export type QueryGroup = {
21
+ combinator: 'and' | 'or';
22
+ rules: (QueryRule | QueryGroup)[];
23
+ };
24
+ export interface QueryBuilderProps {
25
+ /** Fields available to filter on; drives the per-field operator and value-input set. */
26
+ fields: QueryField[];
27
+ /** Controlled tree. Omit to manage state internally, seeded with one empty rule. */
28
+ value?: QueryGroup;
29
+ /** Called with the full, updated tree on every edit. */
30
+ onChange?: (group: QueryGroup) => void;
31
+ class?: string;
32
+ }
33
+ /**
34
+ * Nested AND/OR rule builder: each group has a combinator toggle plus "+ Rule"
35
+ * / "+ Group" buttons, and rules/groups can be removed individually. Groups
36
+ * nest recursively, indented with a left border. Controlled via `value` +
37
+ * `onChange`, or uncontrolled (seeded with one empty rule) when `value` is
38
+ * omitted.
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * const [query, setQuery] = createSignal<QueryGroup>({
43
+ * combinator: 'and',
44
+ * rules: [{ field: 'status', operator: 'is', value: 'open' }],
45
+ * })
46
+ * <QueryBuilder
47
+ * fields={[
48
+ * { name: 'status', label: 'Status', type: 'select', options: ['open', 'closed'] },
49
+ * { name: 'age', label: 'Age', type: 'number' },
50
+ * ]}
51
+ * value={query()}
52
+ * onChange={setQuery}
53
+ * />
54
+ * ```
55
+ */
56
+ export declare function QueryBuilder(props: QueryBuilderProps): JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface SignaturePadProps {
3
+ /** Called with a PNG data URL after each completed stroke, or `null` once the pad is empty (cleared/undone to nothing). */
4
+ onChange?: (dataUrl: string | null) => void;
5
+ /** Canvas height in CSS pixels. @default 200 */
6
+ height?: number;
7
+ class?: string;
8
+ }
9
+ /**
10
+ * A signature capture pad: draw with mouse, pen, or touch on a DPR-aware
11
+ * `<canvas>`, with Clear and Undo controls. Strokes are kept as point lists so
12
+ * Undo can fully redraw the remaining ones rather than trying to erase pixels.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * <SignaturePad height={220} onChange={(dataUrl) => setSignature(dataUrl)} />
17
+ * ```
18
+ */
19
+ export declare function SignaturePad(props: SignaturePadProps): JSX.Element;
@@ -0,0 +1,27 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface SpreadsheetGridProps {
3
+ /** Number of rows in the grid (fixed for the component's lifetime). */
4
+ rows: number;
5
+ /** Number of columns in the grid (fixed for the component's lifetime). */
6
+ cols: number;
7
+ /** Initial cell values, seeded once on mount (missing cells default to `''`). */
8
+ data?: string[][];
9
+ /** Called with the full `rows×cols` matrix after any edit or paste. */
10
+ onChange?: (data: string[][]) => void;
11
+ /** Column header labels; defaults to `A, B, C, …, Z, AA, AB, …`. */
12
+ columnHeaders?: string[];
13
+ class?: string;
14
+ }
15
+ /**
16
+ * Excel-like editable grid. Arrow keys move the active cell; typing or Enter
17
+ * opens an inline editor that commits on Enter/blur and cancels on Escape.
18
+ * Shift+click / Shift+arrow extend a rectangular selection (Ctrl/Cmd+C copies
19
+ * it as TSV, Ctrl/Cmd+V pastes TSV starting at the active cell).
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * const [sheet, setSheet] = createSignal<string[][]>([])
24
+ * <SpreadsheetGrid rows={10} cols={6} onChange={setSheet} />
25
+ * ```
26
+ */
27
+ export declare function SpreadsheetGrid(props: SpreadsheetGridProps): JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a4ui/core",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "A4ui — Spatial Glass design system & component library for SolidJS (Kobalte behavior + Tailwind glass tokens + motion).",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  // import '@a4ui/core/styles.css'
9
9
  // import { Button, Card, Modal } from '@a4ui/core'
10
10
 
11
- export const A4UI_VERSION = '0.34.0'
11
+ export const A4UI_VERSION = '0.35.0'
12
12
 
13
13
  // Helpers (src/lib) — generic, framework-level utilities.
14
14
  export { cn } from './lib/cn'
@@ -233,6 +233,41 @@ export { AudioWaveform, type AudioWaveformProps } from './ui/AudioWaveform'
233
233
  export { Lamp, type LampProps } from './ui/Lamp'
234
234
  export { FollowingPointer, type FollowingPointerProps } from './ui/FollowingPointer'
235
235
  export { SheetSnap, type SheetSnapProps } from './ui/SheetSnap'
236
+
237
+ // Advanced form inputs.
238
+ export { OtpInput, type OtpInputProps } from './ui/OtpInput'
239
+ export { MaskedInput, type MaskedInputProps } from './ui/MaskedInput'
240
+ export { CodeEditor, type CodeEditorProps } from './ui/CodeEditor'
241
+ export { SignaturePad, type SignaturePadProps } from './ui/SignaturePad'
242
+ export { EmojiPicker, type EmojiPickerProps } from './ui/EmojiPicker'
243
+
244
+ // Scheduling.
245
+ export { EventScheduler, type SchedulerEvent, type EventSchedulerProps } from './ui/EventScheduler'
246
+ export { AvailabilityPicker, type AvailabilityPickerProps } from './ui/AvailabilityPicker'
247
+
248
+ // Geo.
249
+ export { InteractiveMap, type MapMarker, type InteractiveMapProps } from './ui/InteractiveMap'
250
+ export { LocationPicker, type LocationValue, type LocationPickerProps } from './ui/LocationPicker'
251
+
252
+ // Dev / data tooling.
253
+ export {
254
+ QueryBuilder,
255
+ type QueryField,
256
+ type QueryRule,
257
+ type QueryGroup,
258
+ type QueryBuilderProps,
259
+ } from './ui/QueryBuilder'
260
+ export { JsonViewer, type JsonViewerProps } from './ui/JsonViewer'
261
+ export { SpreadsheetGrid, type SpreadsheetGridProps } from './ui/SpreadsheetGrid'
262
+
263
+ // Collaboration.
264
+ export {
265
+ PresenceAvatars,
266
+ type PresenceUser,
267
+ type RemoteCursor,
268
+ type PresenceAvatarsProps,
269
+ } from './ui/PresenceAvatars'
270
+ export { ActivityFeed, type ActivityItem, type ActivityFeedProps } from './ui/ActivityFeed'
236
271
  export {
237
272
  CopyButton,
238
273
  type CopyButtonProps,