@signalcore/ui 1.0.0-beta.3 → 1.0.0-beta.4
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/README.md +79 -0
- package/dist/AgentChat.d.ts +19 -3
- package/dist/AgentChat.js +149 -27
- package/dist/AgentChat.js.map +1 -1
- package/dist/AgentSpace.d.ts +14 -2
- package/dist/AgentSpace.js +3 -1
- package/dist/AgentSpace.js.map +1 -1
- package/dist/View.d.ts +48 -0
- package/dist/View.js +101 -0
- package/dist/View.js.map +1 -0
- package/dist/blocks.d.ts +83 -2
- package/dist/client.d.ts +9 -1
- package/dist/client.js +1 -0
- package/dist/client.js.map +1 -1
- package/dist/es.js +12 -0
- package/dist/es.js.map +1 -1
- package/dist/index.d.ts +11 -5
- package/dist/index.js +7 -1
- package/dist/kit/Agenda.d.ts +25 -0
- package/dist/kit/Agenda.js +119 -0
- package/dist/kit/Agenda.js.map +1 -0
- package/dist/kit/Combobox.js +1 -1
- package/dist/kit/DateField.js +1 -1
- package/dist/kit/Kanban.d.ts +17 -0
- package/dist/kit/Kanban.js +157 -0
- package/dist/kit/Kanban.js.map +1 -0
- package/dist/kit/TimeField.js +1 -1
- package/dist/kit/Timeline.d.ts +14 -0
- package/dist/kit/Timeline.js +71 -0
- package/dist/kit/Timeline.js.map +1 -0
- package/dist/kit/context.d.ts +1 -1
- package/dist/kit/context.js.map +1 -1
- package/dist/kit/messages.d.ts +22 -0
- package/dist/kit/messages.js +10 -0
- package/dist/kit/messages.js.map +1 -1
- package/dist/surface/Placed.d.ts +20 -0
- package/dist/surface/Placed.js +70 -0
- package/dist/surface/Placed.js.map +1 -0
- package/dist/surface/Surface.d.ts +4 -2
- package/dist/surface/Surface.js +78 -2
- package/dist/surface/Surface.js.map +1 -1
- package/dist/surface/places.d.ts +16 -0
- package/dist/surface/places.js +15 -0
- package/dist/surface/places.js.map +1 -0
- package/dist/surface/scope.d.ts +17 -1
- package/dist/surface/scope.js +1 -0
- package/dist/surface/scope.js.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.js.map +1 -1
- package/dist/widget.js +17 -17
- package/package.json +1 -1
- package/src/AgentChat.tsx +215 -34
- package/src/AgentSpace.tsx +17 -1
- package/src/View.tsx +117 -0
- package/src/blocks.ts +100 -2
- package/src/client.ts +16 -0
- package/src/contract.ts +166 -5
- package/src/es.ts +9 -0
- package/src/index.ts +27 -2
- package/src/kit/Agenda.tsx +161 -0
- package/src/kit/Kanban.tsx +182 -0
- package/src/kit/Timeline.tsx +58 -0
- package/src/kit/context.tsx +45 -1
- package/src/kit/messages.ts +31 -0
- package/src/styles.css +568 -0
- package/src/surface/Placed.tsx +98 -0
- package/src/surface/Surface.tsx +92 -1
- package/src/surface/places.ts +19 -0
- package/src/surface/scope.ts +24 -1
- package/src/types.ts +13 -0
- package/src/widget/element.tsx +41 -3
package/src/client.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
FileLink,
|
|
14
14
|
FilePreview,
|
|
15
15
|
StoredFile,
|
|
16
|
+
ViewRendered,
|
|
16
17
|
} from "./types";
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -153,6 +154,14 @@ export interface Client {
|
|
|
153
154
|
/** One run of an automation with its record: every call it made, step by step. */
|
|
154
155
|
get: (id: string) => Promise<RunRecord>;
|
|
155
156
|
};
|
|
157
|
+
/** What an agent keeps on show for each person it serves (`compose_view`, `/agents/{id}/views`). */
|
|
158
|
+
views: {
|
|
159
|
+
/**
|
|
160
|
+
* A view rendered from the rows now: for a person, their own; for the business, for the
|
|
161
|
+
* contact it names (`contact`, their id).
|
|
162
|
+
*/
|
|
163
|
+
render: (name: string, contact?: string) => Promise<ViewRendered>;
|
|
164
|
+
};
|
|
156
165
|
/**
|
|
157
166
|
* The tasks an agent runs for contacts, each with its newest runs: a person's own only (what
|
|
158
167
|
* they asked the agent for in their conversations); the business's, every one.
|
|
@@ -366,6 +375,13 @@ export function createClient(options: ClientOptions): Client {
|
|
|
366
375
|
runs: {
|
|
367
376
|
get: (id) => json("GET", `/runs/${seg(id)}`),
|
|
368
377
|
},
|
|
378
|
+
views: {
|
|
379
|
+
render: (name, contact) =>
|
|
380
|
+
json(
|
|
381
|
+
"GET",
|
|
382
|
+
`/views/${seg(name)}/render${contact === undefined ? "" : `?contact=${seg(contact)}`}`,
|
|
383
|
+
),
|
|
384
|
+
},
|
|
369
385
|
tasks: {
|
|
370
386
|
list: (agentId) => json("GET", `/agents/${seg(agentId)}/tasks`),
|
|
371
387
|
switch: (agentId, taskId, on) =>
|
package/src/contract.ts
CHANGED
|
@@ -247,6 +247,20 @@ export interface AutomationOut {
|
|
|
247
247
|
last_run: RunOut | null;
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
+
/** What a host block is for, in a sentence the agent reads, and the JSON Schema of its props: an object's. */
|
|
251
|
+
export interface BlockIn {
|
|
252
|
+
description: string;
|
|
253
|
+
schema: Record<string, unknown>;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export interface BlockOut {
|
|
257
|
+
name: string;
|
|
258
|
+
description: string;
|
|
259
|
+
schema: Record<string, unknown>;
|
|
260
|
+
created_at: string;
|
|
261
|
+
updated_at: string;
|
|
262
|
+
}
|
|
263
|
+
|
|
250
264
|
/** What the automation moves: its table's rows counted by the value of one field. */
|
|
251
265
|
export interface Board {
|
|
252
266
|
table: string;
|
|
@@ -255,6 +269,38 @@ export interface Board {
|
|
|
255
269
|
counts: Array<Count>;
|
|
256
270
|
}
|
|
257
271
|
|
|
272
|
+
/** Cards in columns, a column per stage. With `action`, the person may move a card to another column, which sends `action` with `{"card": id, "column": id}`: the agent then does what moving it means. */
|
|
273
|
+
export interface BoardBlock {
|
|
274
|
+
type: "board";
|
|
275
|
+
columns: Array<BoardColumn>;
|
|
276
|
+
action?: string | null;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** One card of a board. */
|
|
280
|
+
export interface BoardCard {
|
|
281
|
+
id: string;
|
|
282
|
+
title: string;
|
|
283
|
+
subtitle?: string | null;
|
|
284
|
+
meta?: string | null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface BoardColumn {
|
|
288
|
+
id: string;
|
|
289
|
+
title: string;
|
|
290
|
+
cards: Array<BoardCard>;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** The rows as cards in columns, a column per option of a choice (`column`). */
|
|
294
|
+
export interface BoardPiece {
|
|
295
|
+
type: "board";
|
|
296
|
+
title: string;
|
|
297
|
+
item: string;
|
|
298
|
+
column: string;
|
|
299
|
+
subtitle?: string | null;
|
|
300
|
+
meta?: string | null;
|
|
301
|
+
query: Rows;
|
|
302
|
+
}
|
|
303
|
+
|
|
258
304
|
/** One thing the person can do: pressing it sends `action`, or, with `url`, opens the page (a payment, a document). Two buttons that do different things carry different action names: the name is the whole of what comes back. */
|
|
259
305
|
export interface Button {
|
|
260
306
|
type: "button";
|
|
@@ -264,6 +310,38 @@ export interface Button {
|
|
|
264
310
|
tone?: "primary" | "neutral" | "danger";
|
|
265
311
|
}
|
|
266
312
|
|
|
313
|
+
/** A day's events, or a week's from `start`, at their hours. With `action`, pressing one sends it with `{"event": id}`; one with `url` opens its page instead. */
|
|
314
|
+
export interface Calendar {
|
|
315
|
+
type: "calendar";
|
|
316
|
+
span?: "day" | "week";
|
|
317
|
+
start: string;
|
|
318
|
+
events: Array<CalendarEvent>;
|
|
319
|
+
action?: string | null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** One thing on a calendar: its title at its time (a day alone: all of it), until `end`, with a line of detail (where, with whom) and a page to open (`url`). */
|
|
323
|
+
export interface CalendarEvent {
|
|
324
|
+
id: string;
|
|
325
|
+
title: string;
|
|
326
|
+
start: string;
|
|
327
|
+
end?: string | null;
|
|
328
|
+
detail?: string | null;
|
|
329
|
+
url?: string | null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** The rows whose date (`at`) falls today (`day`) or this week, at their hours: each called by `item`, until `end`, with `detail` under it and `link` (an https address) to open. */
|
|
333
|
+
export interface CalendarPiece {
|
|
334
|
+
type: "calendar";
|
|
335
|
+
title: string;
|
|
336
|
+
span?: "day" | "week";
|
|
337
|
+
item: string;
|
|
338
|
+
at: string;
|
|
339
|
+
end?: string | null;
|
|
340
|
+
detail?: string | null;
|
|
341
|
+
link?: string | null;
|
|
342
|
+
query: Scope;
|
|
343
|
+
}
|
|
344
|
+
|
|
267
345
|
/** The call a conversation is (VOICE.md): the owner's in the browser or a phone call, when the worker took it and when it ended, why and how long. */
|
|
268
346
|
export interface CallGlance {
|
|
269
347
|
id: string;
|
|
@@ -290,7 +368,7 @@ export interface Card {
|
|
|
290
368
|
title?: string | null;
|
|
291
369
|
subtitle?: string | null;
|
|
292
370
|
image?: string | null;
|
|
293
|
-
children: Array<Card | Stack | Divider | Text | Fields | Table | Listing | Stat | Chart | Note | Image | Button | Choice | Form | AutomationBlock | FileBlock>;
|
|
371
|
+
children: Array<Card | Stack | Divider | Text | Fields | Table | Listing | Stat | Chart | Note | Image | Button | Choice | Form | Calendar | Timeline | BoardBlock | AutomationBlock | FileBlock | HostBlock>;
|
|
294
372
|
}
|
|
295
373
|
|
|
296
374
|
/** A page of the apps a search finds. */
|
|
@@ -603,7 +681,7 @@ export interface DashboardOut {
|
|
|
603
681
|
export interface DashboardView {
|
|
604
682
|
id: string;
|
|
605
683
|
title: string;
|
|
606
|
-
blocks: Array<Card | Stack | Divider | Text | Fields | Table | Listing | Stat | Chart | Note | Image | Button | Choice | Form | AutomationBlock | FileBlock>;
|
|
684
|
+
blocks: Array<Card | Stack | Divider | Text | Fields | Table | Listing | Stat | Chart | Note | Image | Button | Choice | Form | Calendar | Timeline | BoardBlock | AutomationBlock | FileBlock | HostBlock>;
|
|
607
685
|
rendered_at: string;
|
|
608
686
|
}
|
|
609
687
|
|
|
@@ -952,6 +1030,24 @@ export interface HolderIn {
|
|
|
952
1030
|
title?: string | null;
|
|
953
1031
|
}
|
|
954
1032
|
|
|
1033
|
+
/** One of the host's own blocks, by the name it declared: `props` as its schema says (the API checks them against it), and `text`, the same in words, which a page that doesn't draw it shows instead, as a channel does. */
|
|
1034
|
+
export interface HostBlock {
|
|
1035
|
+
type: "host";
|
|
1036
|
+
name: string;
|
|
1037
|
+
props: Record<string, unknown>;
|
|
1038
|
+
text: string;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/** One of the host's own blocks: its `props` as given; with a rows `query`, one block per row, each prop of `fields` taken from that row's field. `text`: the same in words. */
|
|
1042
|
+
export interface HostPiece {
|
|
1043
|
+
type: "host";
|
|
1044
|
+
name: string;
|
|
1045
|
+
text: string;
|
|
1046
|
+
props?: Record<string, unknown>;
|
|
1047
|
+
fields?: Record<string, string>;
|
|
1048
|
+
query?: Rows | null;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
955
1051
|
/** The week, in the agent's time zone: each day's stretches, in order and apart; a day left out, or empty, is closed. */
|
|
956
1052
|
export interface Hours {
|
|
957
1053
|
mon?: Array<Span>;
|
|
@@ -1466,6 +1562,11 @@ export interface SchemasDecisionOut {
|
|
|
1466
1562
|
run_id: string | null;
|
|
1467
1563
|
}
|
|
1468
1564
|
|
|
1565
|
+
export interface Scope {
|
|
1566
|
+
table: string;
|
|
1567
|
+
where?: Array<Where>;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1469
1570
|
export interface SecretIn {
|
|
1470
1571
|
value: string;
|
|
1471
1572
|
hosts?: Array<string>;
|
|
@@ -1548,7 +1649,7 @@ export interface Span {
|
|
|
1548
1649
|
export interface Stack {
|
|
1549
1650
|
type: "stack";
|
|
1550
1651
|
direction?: "column" | "row";
|
|
1551
|
-
children: Array<Card | Stack | Divider | Text | Fields | Table | Listing | Stat | Chart | Note | Image | Button | Choice | Form | AutomationBlock | FileBlock>;
|
|
1652
|
+
children: Array<Card | Stack | Divider | Text | Fields | Table | Listing | Stat | Chart | Note | Image | Button | Choice | Form | Calendar | Timeline | BoardBlock | AutomationBlock | FileBlock | HostBlock>;
|
|
1552
1653
|
}
|
|
1553
1654
|
|
|
1554
1655
|
/** One number that matters, under its label, with a line of context (a change, a goal). */
|
|
@@ -1729,6 +1830,33 @@ export interface TextPreview {
|
|
|
1729
1830
|
truncated: boolean;
|
|
1730
1831
|
}
|
|
1731
1832
|
|
|
1833
|
+
/** Dated things, one under another, the newest first. */
|
|
1834
|
+
export interface Timeline {
|
|
1835
|
+
type: "timeline";
|
|
1836
|
+
items: Array<TimelineItem>;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
/** One thing on a timeline: what happened (or will) and when, a line about it, and where it stands: `status` in a word, `tone` its mark. */
|
|
1840
|
+
export interface TimelineItem {
|
|
1841
|
+
id?: string | null;
|
|
1842
|
+
at: string;
|
|
1843
|
+
title: string;
|
|
1844
|
+
text?: string | null;
|
|
1845
|
+
status?: string | null;
|
|
1846
|
+
tone?: "info" | "success" | "warning" | "danger" | null;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
/** The rows by a date (`at`), the newest first: each called by `item`, with `text` under it and `status`, where it stands, in a word. */
|
|
1850
|
+
export interface TimelinePiece {
|
|
1851
|
+
type: "timeline";
|
|
1852
|
+
title: string;
|
|
1853
|
+
item: string;
|
|
1854
|
+
at: string;
|
|
1855
|
+
text?: string | null;
|
|
1856
|
+
status?: string | null;
|
|
1857
|
+
query: Rows;
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1732
1860
|
export interface TokenIn {
|
|
1733
1861
|
agents: Array<string>;
|
|
1734
1862
|
external_id: string;
|
|
@@ -1848,6 +1976,39 @@ export interface UsedOut {
|
|
|
1848
1976
|
unpriced: number;
|
|
1849
1977
|
}
|
|
1850
1978
|
|
|
1979
|
+
/** A view's name, title or blocks changed: only what is sent. */
|
|
1980
|
+
export interface ViewChange {
|
|
1981
|
+
name?: string | null;
|
|
1982
|
+
title?: string | null;
|
|
1983
|
+
blocks?: Array<StatPiece | ChartPiece | TablePiece | ListPiece | NotePiece | CalendarPiece | TimelinePiece | BoardPiece | HostPiece> | null;
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
export interface ViewIn {
|
|
1987
|
+
name: string;
|
|
1988
|
+
title: string;
|
|
1989
|
+
blocks: Array<StatPiece | ChartPiece | TablePiece | ListPiece | NotePiece | CalendarPiece | TimelinePiece | BoardPiece | HostPiece>;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
export interface ViewOut {
|
|
1993
|
+
id: string;
|
|
1994
|
+
agent_id: string;
|
|
1995
|
+
name: string;
|
|
1996
|
+
title: string;
|
|
1997
|
+
blocks: Array<StatPiece | ChartPiece | TablePiece | ListPiece | NotePiece | CalendarPiece | TimelinePiece | BoardPiece | HostPiece>;
|
|
1998
|
+
created_at: string;
|
|
1999
|
+
updated_at: string;
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
/** A view rendered for one contact: its blocks as the kit draws them, filled from the rows now, and `text`, the same in words (what a page that can't draw them shows). */
|
|
2003
|
+
export interface ViewRendered {
|
|
2004
|
+
name: string;
|
|
2005
|
+
title: string;
|
|
2006
|
+
contact_id: string;
|
|
2007
|
+
blocks: Array<Card | Stack | Divider | Text | Fields | Table | Listing | Stat | Chart | Note | Image | Button | Choice | Form | Calendar | Timeline | BoardBlock | AutomationBlock | FileBlock | HostBlock>;
|
|
2008
|
+
text: string;
|
|
2009
|
+
rendered_at: string;
|
|
2010
|
+
}
|
|
2011
|
+
|
|
1851
2012
|
/** How an agent talks on a call (VOICE.md). The defaults are the old product's, in Spanish: its ElevenLabs voice (Carolina, from Spain), up to ten minutes, a goodbye ends it. */
|
|
1852
2013
|
export interface Voice {
|
|
1853
2014
|
language?: string;
|
|
@@ -1919,10 +2080,10 @@ export interface WhatsAppIn {
|
|
|
1919
2080
|
mode?: "cloud_api" | "coexistence";
|
|
1920
2081
|
}
|
|
1921
2082
|
|
|
1922
|
-
/** One filter: the field compared with `value` by `op`. `last_days` keeps the rows whose date falls in the last `value` days; `contains` looks for words in a text. */
|
|
2083
|
+
/** One filter: the field compared with `value` by `op`. `last_days` keeps the rows whose date falls in the last `value` days, `next_days` those in the next `value` days (from now on); `contains` looks for words in a text. */
|
|
1923
2084
|
export interface Where {
|
|
1924
2085
|
field: string;
|
|
1925
|
-
op?: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "contains" | "last_days";
|
|
2086
|
+
op?: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "contains" | "last_days" | "next_days";
|
|
1926
2087
|
value: string | number | boolean;
|
|
1927
2088
|
}
|
|
1928
2089
|
|
package/src/es.ts
CHANGED
|
@@ -233,6 +233,13 @@ export const KIT_MESSAGES_ES: KitMessages = {
|
|
|
233
233
|
failed: "No se ha podido conectar",
|
|
234
234
|
preparing: "Preparando la conexión",
|
|
235
235
|
},
|
|
236
|
+
calendar: { allDay: "Todo el día", empty: "Nada previsto" },
|
|
237
|
+
board: {
|
|
238
|
+
move: (card) => `Mover ${card}`,
|
|
239
|
+
moveTo: "Mover a",
|
|
240
|
+
moved: (card, column) => `${card} a ${column}`,
|
|
241
|
+
empty: "Nada aquí",
|
|
242
|
+
},
|
|
236
243
|
};
|
|
237
244
|
|
|
238
245
|
export const BROWSER_MESSAGES_ES: BrowserMessages = {
|
|
@@ -321,6 +328,8 @@ export const CHAT_MESSAGES_ES: ChatMessages = {
|
|
|
321
328
|
declineAll: "Rechazar todo",
|
|
322
329
|
confirming: "Esperando la confirmación del negocio",
|
|
323
330
|
handedOff: "Pasada a una persona",
|
|
331
|
+
opened: (name, title) => `${name} abrió ${title}`,
|
|
332
|
+
closePlaced: "Cerrar",
|
|
324
333
|
handover: (holder, by, name) => {
|
|
325
334
|
const automation = by.kind === "automation" ? ` por «${by.title}»` : "";
|
|
326
335
|
switch (holder) {
|
package/src/index.ts
CHANGED
|
@@ -144,7 +144,12 @@ export type {
|
|
|
144
144
|
export type {
|
|
145
145
|
AutomationBlock,
|
|
146
146
|
Block,
|
|
147
|
+
BoardBlock,
|
|
148
|
+
BoardCard,
|
|
149
|
+
BoardColumn,
|
|
147
150
|
ButtonBlock,
|
|
151
|
+
CalendarBlock,
|
|
152
|
+
CalendarEvent,
|
|
148
153
|
CardBlock,
|
|
149
154
|
ChartBlock,
|
|
150
155
|
ChartPoint,
|
|
@@ -156,15 +161,19 @@ export type {
|
|
|
156
161
|
FieldValue,
|
|
157
162
|
FormBlock,
|
|
158
163
|
FormField,
|
|
164
|
+
HostBlock,
|
|
159
165
|
ImageBlock,
|
|
160
166
|
ListBlock,
|
|
161
167
|
NoteBlock,
|
|
162
168
|
Option,
|
|
169
|
+
Place,
|
|
163
170
|
StackBlock,
|
|
164
171
|
StatBlock,
|
|
165
172
|
Surface as SurfaceData,
|
|
166
173
|
TableBlock,
|
|
167
174
|
TextBlock,
|
|
175
|
+
TimelineBlock,
|
|
176
|
+
TimelineItem,
|
|
168
177
|
Tone,
|
|
169
178
|
} from "./blocks";
|
|
170
179
|
export { ApiError, createClient } from "./client";
|
|
@@ -179,6 +188,8 @@ export { FILES_PER_MESSAGE, TOOL_ERROR_MAX, toolResultOf } from "./frames";
|
|
|
179
188
|
export type { Frame, ToolResult, UpFrame } from "./frames";
|
|
180
189
|
export { Button } from "./kit/Button";
|
|
181
190
|
export type { ButtonProps } from "./kit/Button";
|
|
191
|
+
export { Agenda, daysOf, hoursOf } from "./kit/Agenda";
|
|
192
|
+
export { Kanban, placed } from "./kit/Kanban";
|
|
182
193
|
export { Card } from "./kit/Card";
|
|
183
194
|
export { Chips, Choices } from "./kit/Choices";
|
|
184
195
|
export { Combobox } from "./kit/Combobox";
|
|
@@ -203,7 +214,7 @@ export { Mark } from "./kit/Mark";
|
|
|
203
214
|
export type { MarkProps } from "./kit/Mark";
|
|
204
215
|
export { MarkStack } from "./kit/MarkStack";
|
|
205
216
|
export { KIT_MESSAGES } from "./kit/messages";
|
|
206
|
-
export type { KitLocale, KitMessages } from "./kit/messages";
|
|
217
|
+
export type { BoardMessages, CalendarMessages, KitLocale, KitMessages } from "./kit/messages";
|
|
207
218
|
export { Note } from "./kit/Note";
|
|
208
219
|
export { RangeField } from "./kit/RangeField";
|
|
209
220
|
export { RatingField } from "./kit/RatingField";
|
|
@@ -213,11 +224,22 @@ export { AudioPlayer } from "./kit/AudioPlayer";
|
|
|
213
224
|
export type { AudioPlayerProps } from "./kit/AudioPlayer";
|
|
214
225
|
export type { SwitchProps } from "./kit/Switch";
|
|
215
226
|
export { Tag } from "./kit/Tag";
|
|
227
|
+
export { formatWhen, Timeline } from "./kit/Timeline";
|
|
216
228
|
export { Tile, Tiles } from "./kit/Tile";
|
|
217
229
|
export type { TileProps } from "./kit/Tile";
|
|
218
230
|
export { DateTimeField, TimeField } from "./kit/TimeField";
|
|
219
231
|
export type { DateTimeFieldProps, TimeFieldProps } from "./kit/TimeField";
|
|
220
|
-
export type {
|
|
232
|
+
export type {
|
|
233
|
+
BlockProps,
|
|
234
|
+
HostBlockProps,
|
|
235
|
+
HostBlocks,
|
|
236
|
+
SurfaceComponents,
|
|
237
|
+
SurfacePart,
|
|
238
|
+
} from "./surface/scope";
|
|
239
|
+
export { EVERY_PLACE, placeOf } from "./surface/places";
|
|
240
|
+
export type { SurfacePlaces } from "./surface/places";
|
|
241
|
+
export { Placed } from "./surface/Placed";
|
|
242
|
+
export type { PlacedPart } from "./surface/Placed";
|
|
221
243
|
export { Surface } from "./surface/Surface";
|
|
222
244
|
export type { SurfaceProps } from "./surface/Surface";
|
|
223
245
|
export { chosen, filled, labelOf, picked, pressed, problemOf } from "./surface/values";
|
|
@@ -263,6 +285,7 @@ export type {
|
|
|
263
285
|
StepState,
|
|
264
286
|
StoredFile,
|
|
265
287
|
ToolCall,
|
|
288
|
+
ViewRendered,
|
|
266
289
|
Weekday,
|
|
267
290
|
WeekHours,
|
|
268
291
|
WidgetConfig,
|
|
@@ -271,6 +294,8 @@ export type {
|
|
|
271
294
|
} from "./types";
|
|
272
295
|
export { WIDGET_FONTS } from "./types";
|
|
273
296
|
export { useAgentFace } from "./useAgentFace";
|
|
297
|
+
export { View, VIEW_POLL_MS, useView } from "./View";
|
|
298
|
+
export type { ViewProps, ViewRead } from "./View";
|
|
274
299
|
export type { FaceRead } from "./useAgentFace";
|
|
275
300
|
export { NO_TOOL, useConversation } from "./useConversation";
|
|
276
301
|
export type { LiveConversation, ToolHandler } from "./useConversation";
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Fragment, type ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import type { CalendarEvent } from "../blocks";
|
|
4
|
+
import { useKit, useParts } from "./context";
|
|
5
|
+
import { dayOf, formatTime, isoDay, momentParts, TIME } from "./dates";
|
|
6
|
+
|
|
7
|
+
/** The days a calendar shows from its first: a day's, or a week's. */
|
|
8
|
+
export function daysOf(span: "day" | "week", start: string): string[] {
|
|
9
|
+
const first = dayOf(start);
|
|
10
|
+
if (!first) return [];
|
|
11
|
+
return Array.from({ length: span === "week" ? 7 : 1 }, (_, index) => {
|
|
12
|
+
const day = new Date(first);
|
|
13
|
+
day.setDate(first.getDate() + index);
|
|
14
|
+
return isoDay(day);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** An event's hours as the language writes them: "10:00 – 11:00", one end, or none (a day). */
|
|
19
|
+
export function hoursOf(event: CalendarEvent, code: string): string | null {
|
|
20
|
+
const [day, from] = momentParts(event.start);
|
|
21
|
+
if (!TIME.test(from)) return null;
|
|
22
|
+
const [endDay, to] = momentParts(event.end ?? null);
|
|
23
|
+
const until = endDay === day && TIME.test(to) ? to : null;
|
|
24
|
+
return until === null
|
|
25
|
+
? formatTime(from, code)
|
|
26
|
+
: `${formatTime(from, code)} – ${formatTime(until, code)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A day's events, or a week's, at their hours: each day under its weekday and number (today in
|
|
31
|
+
* the accent), its events in order, each with its hours (or "all day"), its title and a quiet
|
|
32
|
+
* line of detail. In a narrow place the days go one under another, an empty one a single quiet
|
|
33
|
+
* line; wide enough, the week stands as seven columns. An event with a page opens it apart;
|
|
34
|
+
* with `onEvent`, pressing one sends it.
|
|
35
|
+
*/
|
|
36
|
+
export function Agenda({
|
|
37
|
+
span,
|
|
38
|
+
start,
|
|
39
|
+
events,
|
|
40
|
+
onEvent,
|
|
41
|
+
disabled = false,
|
|
42
|
+
today = new Date(),
|
|
43
|
+
}: {
|
|
44
|
+
span: "day" | "week";
|
|
45
|
+
/** The first day shown, "YYYY-MM-DD". */
|
|
46
|
+
start: string;
|
|
47
|
+
events: CalendarEvent[];
|
|
48
|
+
onEvent?: ((event: CalendarEvent) => void) | undefined;
|
|
49
|
+
disabled?: boolean | undefined;
|
|
50
|
+
/** What counts as today; now by default. */
|
|
51
|
+
today?: Date | undefined;
|
|
52
|
+
}) {
|
|
53
|
+
const part = useParts();
|
|
54
|
+
const { code, messages } = useKit();
|
|
55
|
+
const now = isoDay(today);
|
|
56
|
+
const days = daysOf(span, start);
|
|
57
|
+
const weekday = new Intl.DateTimeFormat(code, { weekday: "short" });
|
|
58
|
+
const whole = new Intl.DateTimeFormat(code, { weekday: "long", day: "numeric", month: "long" });
|
|
59
|
+
return (
|
|
60
|
+
<div
|
|
61
|
+
part="agenda"
|
|
62
|
+
className={part("sc-agenda", ...(span === "day" ? (["sc-agenda--day"] as const) : []))}
|
|
63
|
+
>
|
|
64
|
+
<div className={part("sc-agenda__days")}>
|
|
65
|
+
{days.map((day) => {
|
|
66
|
+
const date = dayOf(day) ?? today;
|
|
67
|
+
const own = events.filter((event) => event.start.slice(0, 10) === day);
|
|
68
|
+
return (
|
|
69
|
+
<section
|
|
70
|
+
key={day}
|
|
71
|
+
aria-label={whole.format(date)}
|
|
72
|
+
className={part(
|
|
73
|
+
"sc-agenda__day",
|
|
74
|
+
...(day === now ? (["sc-agenda__day--today"] as const) : []),
|
|
75
|
+
...(own.length === 0 ? (["sc-agenda__day--empty"] as const) : []),
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
{span === "week" && (
|
|
79
|
+
<h4 aria-hidden className={part("sc-agenda__date")}>
|
|
80
|
+
<span className={part("sc-agenda__weekday")}>{weekday.format(date)}</span>
|
|
81
|
+
<span className={part("sc-agenda__number")}>{date.getDate()}</span>
|
|
82
|
+
</h4>
|
|
83
|
+
)}
|
|
84
|
+
{own.length === 0 ? (
|
|
85
|
+
<p className={part("sc-agenda__empty")}>{messages.calendar.empty}</p>
|
|
86
|
+
) : (
|
|
87
|
+
<ol className={part("sc-agenda__events")}>
|
|
88
|
+
{own.map((event) => (
|
|
89
|
+
<li key={event.id}>
|
|
90
|
+
<Event event={event} onEvent={onEvent} disabled={disabled}>
|
|
91
|
+
<span className={part("sc-agenda__time")}>
|
|
92
|
+
{(hoursOf(event, code) ?? messages.calendar.allDay)
|
|
93
|
+
.split(" – ")
|
|
94
|
+
.map((end, index) =>
|
|
95
|
+
// A range breaks before its dash, never inside a time ("5:00 PM").
|
|
96
|
+
index === 0 ? (
|
|
97
|
+
<span key={index}>{end}</span>
|
|
98
|
+
) : (
|
|
99
|
+
<Fragment key={index}>
|
|
100
|
+
{" "}
|
|
101
|
+
<span>– {end}</span>
|
|
102
|
+
</Fragment>
|
|
103
|
+
),
|
|
104
|
+
)}
|
|
105
|
+
</span>
|
|
106
|
+
<span className={part("sc-agenda__what")}>
|
|
107
|
+
<span className={part("sc-agenda__title")}>{event.title}</span>
|
|
108
|
+
{event.detail !== undefined && (
|
|
109
|
+
<span className={part("sc-agenda__detail")}>{event.detail}</span>
|
|
110
|
+
)}
|
|
111
|
+
</span>
|
|
112
|
+
</Event>
|
|
113
|
+
</li>
|
|
114
|
+
))}
|
|
115
|
+
</ol>
|
|
116
|
+
)}
|
|
117
|
+
</section>
|
|
118
|
+
);
|
|
119
|
+
})}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** One event: a link to its page, a button that sends it, or just its words. */
|
|
126
|
+
function Event({
|
|
127
|
+
event,
|
|
128
|
+
onEvent,
|
|
129
|
+
disabled,
|
|
130
|
+
children,
|
|
131
|
+
}: {
|
|
132
|
+
event: CalendarEvent;
|
|
133
|
+
onEvent: ((event: CalendarEvent) => void) | undefined;
|
|
134
|
+
disabled: boolean;
|
|
135
|
+
children: ReactNode;
|
|
136
|
+
}) {
|
|
137
|
+
const part = useParts();
|
|
138
|
+
const className = part("sc-agenda__event");
|
|
139
|
+
if (event.url !== undefined && /^https:\/\//i.test(event.url)) {
|
|
140
|
+
return (
|
|
141
|
+
<a className={className} href={event.url} target="_blank" rel="noreferrer noopener">
|
|
142
|
+
{children}
|
|
143
|
+
</a>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
if (onEvent !== undefined) {
|
|
147
|
+
return (
|
|
148
|
+
<button
|
|
149
|
+
type="button"
|
|
150
|
+
className={className}
|
|
151
|
+
disabled={disabled}
|
|
152
|
+
onClick={() => {
|
|
153
|
+
onEvent(event);
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
{children}
|
|
157
|
+
</button>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
return <div className={className}>{children}</div>;
|
|
161
|
+
}
|