@assistant-ui/react-generative-ui 0.0.22 → 0.0.23

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.
Files changed (74) hide show
  1. package/dist/a2ui/convert.d.ts.map +1 -1
  2. package/dist/a2ui/convert.js +21 -4
  3. package/dist/a2ui/convert.js.map +1 -1
  4. package/dist/constants.d.ts +1 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/constants.js +2 -1
  7. package/dist/constants.js.map +1 -1
  8. package/dist/slack/decodeBlockAction.d.ts.map +1 -1
  9. package/dist/slack/decodeBlockAction.js +64 -26
  10. package/dist/slack/decodeBlockAction.js.map +1 -1
  11. package/dist/slack/fromSlackBlocks.d.ts.map +1 -1
  12. package/dist/slack/fromSlackBlocks.js +23 -0
  13. package/dist/slack/fromSlackBlocks.js.map +1 -1
  14. package/dist/slack/toSlackBlocks.d.ts.map +1 -1
  15. package/dist/slack/toSlackBlocks.js +74 -18
  16. package/dist/slack/toSlackBlocks.js.map +1 -1
  17. package/dist/slack/types.d.ts +20 -1
  18. package/dist/slack/types.d.ts.map +1 -1
  19. package/dist/slack.d.ts +1 -1
  20. package/dist/slack.d.ts.map +1 -1
  21. package/dist/teams/decodeSubmitData.d.ts.map +1 -1
  22. package/dist/teams/decodeSubmitData.js +24 -3
  23. package/dist/teams/decodeSubmitData.js.map +1 -1
  24. package/dist/teams/temporalId.d.ts +5 -0
  25. package/dist/teams/temporalId.d.ts.map +1 -0
  26. package/dist/teams/temporalId.js +28 -0
  27. package/dist/teams/temporalId.js.map +1 -0
  28. package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
  29. package/dist/teams/toAdaptiveCard.js +80 -1
  30. package/dist/teams/toAdaptiveCard.js.map +1 -1
  31. package/dist/teams/toTeamsAttachments.d.ts.map +1 -1
  32. package/dist/teams/toTeamsAttachments.js.map +1 -1
  33. package/dist/teams/types.d.ts +19 -1
  34. package/dist/teams/types.d.ts.map +1 -1
  35. package/dist/teams.d.ts +1 -1
  36. package/dist/teams.d.ts.map +1 -1
  37. package/dist/temporal.d.ts +33 -0
  38. package/dist/temporal.d.ts.map +1 -0
  39. package/dist/temporal.js +152 -0
  40. package/dist/temporal.js.map +1 -0
  41. package/dist/vocabulary/collectFormValues.d.ts +1 -1
  42. package/dist/vocabulary/collectFormValues.d.ts.map +1 -1
  43. package/dist/vocabulary/collectFormValues.js +7 -3
  44. package/dist/vocabulary/collectFormValues.js.map +1 -1
  45. package/dist/vocabulary/data.d.ts +1 -1
  46. package/dist/vocabulary/interactive.d.ts +7 -1
  47. package/dist/vocabulary/interactive.d.ts.map +1 -1
  48. package/dist/vocabulary/interactive.js +62 -12
  49. package/dist/vocabulary/interactive.js.map +1 -1
  50. package/package.json +5 -5
  51. package/src/a2ui/convert.test.ts +223 -14
  52. package/src/a2ui/convert.ts +41 -7
  53. package/src/constants.ts +1 -0
  54. package/src/slack/datePicker.test.ts +612 -0
  55. package/src/slack/decodeBlockAction.ts +114 -41
  56. package/src/slack/fromSlackBlocks.ts +29 -0
  57. package/src/slack/toSlackBlocks.ts +123 -36
  58. package/src/slack/types.ts +24 -0
  59. package/src/slack.ts +2 -0
  60. package/src/teams/decodeSubmitData.test.ts +216 -0
  61. package/src/teams/decodeSubmitData.ts +49 -4
  62. package/src/teams/temporal.test.ts +766 -0
  63. package/src/teams/temporalId.ts +56 -0
  64. package/src/teams/toAdaptiveCard.ts +166 -2
  65. package/src/teams/toTeamsAttachments.ts +4 -1
  66. package/src/teams/types.ts +17 -0
  67. package/src/teams.ts +1 -0
  68. package/src/temporal.test.ts +319 -0
  69. package/src/temporal.ts +259 -0
  70. package/src/vocabulary/collectFormValues.test.ts +198 -1
  71. package/src/vocabulary/collectFormValues.ts +31 -2
  72. package/src/vocabulary/datepicker.dom.test.tsx +1148 -0
  73. package/src/vocabulary/interactive.dom.test.tsx +59 -11
  74. package/src/vocabulary/interactive.tsx +151 -15
@@ -1,5 +1,11 @@
1
1
  import type { Action } from "../ir";
2
2
  import { resolveFieldReferences } from "../fieldReferences";
3
+ import {
4
+ formatTemporalUnixSeconds,
5
+ mergeTemporalMinutes,
6
+ splitTemporalMinutes,
7
+ } from "../temporal";
8
+ import type { FieldMapping } from "./types";
3
9
 
4
10
  const isRecord = (value: unknown): value is Record<string, unknown> =>
5
11
  typeof value === "object" && value !== null && !Array.isArray(value);
@@ -9,7 +15,26 @@ const optionValue = (value: unknown): string | undefined =>
9
15
  ? value["value"]
10
16
  : undefined;
11
17
 
12
- const selectedValue = (action: Record<string, unknown>): unknown => {
18
+ const selectedValue = (
19
+ action: Record<string, unknown>,
20
+ field?: FieldMapping,
21
+ ): unknown => {
22
+ if (action["type"] === "datetimepicker" || "selected_date_time" in action) {
23
+ const seconds = action["selected_date_time"];
24
+ return seconds === null
25
+ ? ""
26
+ : typeof seconds === "number"
27
+ ? formatTemporalUnixSeconds(seconds, field?.offset)
28
+ : undefined;
29
+ }
30
+ if (action["type"] === "timepicker" || "selected_time" in action) {
31
+ const time = action["selected_time"];
32
+ if (time === null) return "";
33
+ const parts =
34
+ typeof time === "string" ? splitTemporalMinutes(time) : undefined;
35
+ return parts?.date === undefined ? parts?.time : undefined;
36
+ }
37
+ if (field?.part === "date" && action["selected_date"] === null) return "";
13
38
  const selectedOption = optionValue(action["selected_option"]);
14
39
  const selectedDate =
15
40
  typeof action["selected_date"] === "string"
@@ -35,22 +60,40 @@ const selectedValue = (action: Record<string, unknown>): unknown => {
35
60
  );
36
61
  };
37
62
 
38
- const fieldMappingsFromBlockId = (
39
- blockId: string,
40
- ): readonly (readonly [string, string, boolean])[] => {
63
+ const fieldMappingsFromBlockId = (blockId: string): readonly FieldMapping[] => {
41
64
  if (!/^aui:\d+:/.test(blockId)) return [];
42
65
  const mappingStart = blockId.indexOf(":", 4);
43
66
  if (mappingStart === -1) return [];
44
67
  try {
45
68
  const parsed: unknown = JSON.parse(blockId.slice(mappingStart + 1));
46
69
  if (!Array.isArray(parsed)) return [];
47
- return parsed.flatMap((entry): (readonly [string, string, boolean])[] =>
48
- Array.isArray(entry) &&
49
- typeof entry[0] === "string" &&
50
- typeof entry[1] === "string"
51
- ? [[entry[0], entry[1], entry[2] === "Checkbox"]]
52
- : [],
53
- );
70
+ return parsed.flatMap((entry): FieldMapping[] => {
71
+ if (
72
+ !Array.isArray(entry) ||
73
+ typeof entry[0] !== "string" ||
74
+ typeof entry[1] !== "string"
75
+ )
76
+ return [];
77
+ return [
78
+ {
79
+ actionId: entry[0],
80
+ name: entry[1],
81
+ component: typeof entry[2] === "string" ? entry[2] : "",
82
+ ...(entry[2] === "DatePicker" &&
83
+ (entry[3] === "time" || entry[3] === "datetime")
84
+ ? {
85
+ inputType: entry[3],
86
+ ...(typeof entry[4] === "string" ? { offset: entry[4] } : {}),
87
+ ...((entry[5] === "date" || entry[5] === "time") &&
88
+ Number.isSafeInteger(entry[6]) &&
89
+ entry[6] >= 0
90
+ ? { part: entry[5], pairId: entry[6] }
91
+ : {}),
92
+ }
93
+ : {}),
94
+ },
95
+ ];
96
+ });
54
97
  } catch {
55
98
  return [];
56
99
  }
@@ -64,43 +107,53 @@ const checkboxValue = (
64
107
  ? value["selected_options"].some((option) => optionValue(option) === name)
65
108
  : undefined;
66
109
 
67
- const stateFieldValue = (
68
- value: unknown,
69
- name: string,
70
- isCheckbox: boolean,
71
- ): unknown => {
110
+ const stateFieldValue = (value: unknown, field: FieldMapping): unknown => {
72
111
  if (!isRecord(value)) return undefined;
73
- if (isCheckbox && value["type"] === "checkboxes") {
74
- return checkboxValue(value, name);
112
+ if (field.component === "Checkbox" && value["type"] === "checkboxes") {
113
+ return checkboxValue(value, field.name);
75
114
  }
76
115
  if (value["type"] === "plain_text_input") {
77
116
  return typeof value["value"] === "string" ? value["value"] : undefined;
78
117
  }
79
- return selectedValue(value);
118
+ return selectedValue(value, field);
80
119
  };
81
120
 
82
121
  const fieldValuesFromState = (
83
122
  stateValues: unknown,
84
- ): Record<string, unknown> => {
123
+ action: Record<string, unknown>,
124
+ actionField: FieldMapping | undefined,
125
+ ) => {
85
126
  const fields: Record<string, unknown> = Object.create(null);
86
- if (!isRecord(stateValues)) return fields;
87
- for (const [blockId, rawBlockValues] of Object.entries(stateValues)) {
88
- if (!isRecord(rawBlockValues)) continue;
89
- for (const [actionId, name, isCheckbox] of fieldMappingsFromBlockId(
90
- blockId,
91
- )) {
92
- if (!Object.hasOwn(rawBlockValues, actionId)) continue;
93
- const value = stateFieldValue(rawBlockValues[actionId], name, isCheckbox);
94
- if (value === undefined) continue;
95
- Object.defineProperty(fields, name, {
96
- value,
97
- enumerable: true,
98
- configurable: true,
99
- writable: true,
100
- });
127
+ const pairs = new Map<number, { name: string; date: string; time: string }>();
128
+ const collect = (raw: unknown, field: FieldMapping) => {
129
+ const value = stateFieldValue(raw, field);
130
+ if (field.part !== undefined && field.pairId !== undefined) {
131
+ const pair = pairs.get(field.pairId) ?? {
132
+ name: field.name,
133
+ date: "",
134
+ time: "",
135
+ };
136
+ pair[field.part] = typeof value === "string" ? value : "";
137
+ pairs.set(field.pairId, pair);
138
+ } else if (field.name && value !== undefined) {
139
+ fields[field.name] = value;
101
140
  }
141
+ };
142
+ if (isRecord(stateValues)) {
143
+ for (const [blockId, rawBlockValues] of Object.entries(stateValues)) {
144
+ if (!isRecord(rawBlockValues)) continue;
145
+ for (const field of fieldMappingsFromBlockId(blockId)) {
146
+ if (Object.hasOwn(rawBlockValues, field.actionId))
147
+ collect(rawBlockValues[field.actionId], field);
148
+ }
149
+ }
150
+ }
151
+ if (actionField?.inputType !== undefined) collect(action, actionField);
152
+ for (const pair of pairs.values()) {
153
+ if (pair.name)
154
+ fields[pair.name] = mergeTemporalMinutes(pair.date, pair.time);
102
155
  }
103
- return fields;
156
+ return { fields, pairs };
104
157
  };
105
158
 
106
159
  /**
@@ -140,7 +193,30 @@ export function decodeBlockAction(
140
193
  }
141
194
  }
142
195
 
143
- const input = selectedValue(action) ?? plainValue;
196
+ const actionField =
197
+ typeof action["block_id"] === "string"
198
+ ? fieldMappingsFromBlockId(action["block_id"]).find(
199
+ (field) => field.actionId === actionId,
200
+ )
201
+ : undefined;
202
+ const { fields, pairs } = fieldValuesFromState(
203
+ stateValues,
204
+ action,
205
+ actionField,
206
+ );
207
+ let input = selectedValue(action, actionField) ?? plainValue;
208
+ if (actionField?.pairId !== undefined) {
209
+ const pair = pairs.get(actionField.pairId);
210
+ input =
211
+ pair === undefined ? "" : mergeTemporalMinutes(pair.date, pair.time);
212
+ if (!input) return undefined;
213
+ }
214
+ if (
215
+ (action["type"] === "timepicker" ||
216
+ action["type"] === "datetimepicker") &&
217
+ input === undefined
218
+ )
219
+ return undefined;
144
220
 
145
221
  const decoded = {
146
222
  ...Object.fromEntries(
@@ -149,10 +225,7 @@ export function decodeBlockAction(
149
225
  type: actionId,
150
226
  ...(input !== undefined ? { $input: input } : {}),
151
227
  };
152
- return resolveFieldReferences(
153
- decoded,
154
- fieldValuesFromState(stateValues),
155
- ) as Action;
228
+ return resolveFieldReferences(decoded, fields) as Action;
156
229
  } catch {
157
230
  return undefined;
158
231
  }
@@ -1,5 +1,6 @@
1
1
  import { copyBounded } from "../convert/copyBounded";
2
2
  import type { Action, UIElement } from "../ir";
3
+ import { formatTemporalUnixSeconds } from "../temporal";
3
4
  import {
4
5
  ACTIONS_ELEMENT_CAP,
5
6
  CARD_ACTIONS_CAP,
@@ -331,6 +332,27 @@ const actionElementFrom = (
331
332
  return selectFrom(element, warnings);
332
333
  case "datepicker":
333
334
  return datePickerFrom(element);
335
+ case "timepicker":
336
+ return {
337
+ $type: "DatePicker",
338
+ inputType: "time",
339
+ ...(typeof element["initial_time"] === "string"
340
+ ? { value: element["initial_time"] }
341
+ : {}),
342
+ $action: decodeAction(element["action_id"], element["value"]),
343
+ };
344
+ case "datetimepicker": {
345
+ const value =
346
+ typeof element["initial_date_time"] === "number"
347
+ ? formatTemporalUnixSeconds(element["initial_date_time"])
348
+ : undefined;
349
+ return {
350
+ $type: "DatePicker",
351
+ inputType: "datetime",
352
+ ...(value !== undefined ? { value } : {}),
353
+ $action: decodeAction(element["action_id"], element["value"]),
354
+ };
355
+ }
334
356
  case "checkboxes":
335
357
  return Array.isArray(element["options"]) &&
336
358
  element["options"].length > 1
@@ -372,6 +394,13 @@ const inputFrom = (
372
394
  warnings: SlackConversionWarning[],
373
395
  ): UIElement[] => {
374
396
  const element = block["element"];
397
+ if (
398
+ isRecord(element) &&
399
+ (element["type"] === "timepicker" || element["type"] === "datetimepicker")
400
+ ) {
401
+ const picker = actionElementFrom(element, warnings);
402
+ return picker ? [{ ...picker, label: textOf(block["label"]) }] : [];
403
+ }
375
404
  if (!isRecord(element) || element["type"] !== "plain_text_input") {
376
405
  warn(
377
406
  warnings,
@@ -6,6 +6,7 @@ import {
6
6
  import { copyBounded } from "../convert/copyBounded";
7
7
  import { isElement } from "../convert/isElement";
8
8
  import { takeRun } from "../convert/takeRun";
9
+ import { classifyTemporal, splitTemporalMinutes } from "../temporal";
9
10
  import {
10
11
  normalizeSpec,
11
12
  type NormalizedUIElement,
@@ -53,6 +54,7 @@ import {
53
54
  buildDataTableBlock,
54
55
  } from "./constants";
55
56
  import type {
57
+ FieldMapping,
56
58
  SlackActionElement,
57
59
  SlackBlock,
58
60
  SlackButtonElement,
@@ -73,17 +75,12 @@ type ConversionContext = {
73
75
  readonly warnings: SlackConversionWarning[];
74
76
  readonly omittedPasswordNames: Set<string>;
75
77
  fieldBlockIdSequence: number;
78
+ dateTimePairSequence: number;
76
79
  markdownCharacters: number;
77
80
  markdownExhausted: boolean;
78
81
  dataTableCharacters: number;
79
82
  };
80
83
 
81
- type FieldMapping = {
82
- readonly actionId: string;
83
- readonly name: string;
84
- readonly component: string;
85
- };
86
-
87
84
  const SLACK_BLOCK_ID_CAP = 255;
88
85
 
89
86
  const INTERACTIVE_TYPES = new Set([
@@ -170,10 +167,21 @@ const serializeFieldBlockId = (
170
167
  fields: readonly FieldMapping[],
171
168
  ): string =>
172
169
  `aui:${sequence}:${JSON.stringify(
173
- fields.map(({ actionId, name, component }) =>
174
- component === "Checkbox"
175
- ? [actionId, name, "Checkbox"]
176
- : [actionId, name],
170
+ fields.map(
171
+ ({ actionId, name, component, inputType, offset, part, pairId }) =>
172
+ inputType !== undefined
173
+ ? [
174
+ actionId,
175
+ name,
176
+ component,
177
+ inputType,
178
+ offset ?? null,
179
+ part ?? null,
180
+ pairId ?? null,
181
+ ]
182
+ : component === "Checkbox"
183
+ ? [actionId, name, "Checkbox"]
184
+ : [actionId, name],
177
185
  ),
178
186
  )}`;
179
187
 
@@ -365,7 +373,7 @@ const warnDroppedOptions = (
365
373
  const toActionElement = (
366
374
  element: NormalizedUIElement,
367
375
  context: ConversionContext,
368
- ): SlackActionElement | undefined => {
376
+ ): SlackActionElement | SlackActionElement[] | undefined => {
369
377
  const { props, action } = element;
370
378
  switch (element.type) {
371
379
  case "Button":
@@ -425,6 +433,69 @@ const toActionElement = (
425
433
  }
426
434
  case "DatePicker": {
427
435
  const rawDate = asString(props["value"]);
436
+ const inputType = props["inputType"];
437
+ if (inputType === "time" || inputType === "datetime") {
438
+ const actionId = asActionId(action, "DatePicker", context);
439
+ const temporal = classifyTemporal(rawDate);
440
+ const parts = splitTemporalMinutes(rawDate);
441
+ if (
442
+ (inputType === "time" && temporal.kind === "time") ||
443
+ (inputType === "datetime" && temporal.kind === "floating")
444
+ ) {
445
+ if (parts?.droppedPrecision) {
446
+ warn(
447
+ context,
448
+ "dropped",
449
+ "DatePicker",
450
+ "Seconds were dropped because Slack timepickers only support minute precision.",
451
+ );
452
+ }
453
+ const timePicker: SlackActionElement = {
454
+ type: "timepicker",
455
+ action_id: actionId,
456
+ initial_time: parts!.time,
457
+ };
458
+ return inputType === "time"
459
+ ? timePicker
460
+ : [
461
+ {
462
+ type: "datepicker",
463
+ action_id: actionId,
464
+ initial_date: parts!.date!,
465
+ },
466
+ timePicker,
467
+ ];
468
+ }
469
+ if (inputType === "datetime" && temporal.kind === "instant") {
470
+ if (
471
+ temporal.epochMs % 1000 !== 0 ||
472
+ /[1-9]/.test(temporal.subMillisecondDigits ?? "")
473
+ ) {
474
+ warn(
475
+ context,
476
+ "dropped",
477
+ "DatePicker",
478
+ "Fractional seconds were dropped because Slack datetimepickers only support second precision.",
479
+ );
480
+ }
481
+ return {
482
+ type: "datetimepicker",
483
+ action_id: actionId,
484
+ initial_date_time: Math.floor(temporal.epochMs / 1000),
485
+ };
486
+ }
487
+ if (rawDate)
488
+ warn(
489
+ context,
490
+ "dropped",
491
+ "DatePicker",
492
+ `value did not match the ${inputType} format and was dropped.`,
493
+ );
494
+ return {
495
+ type: inputType === "time" ? "timepicker" : "datetimepicker",
496
+ action_id: actionId,
497
+ };
498
+ }
428
499
  const initialDate = DATE_PATTERN.test(rawDate) ? rawDate : undefined;
429
500
  if (rawDate && initialDate === undefined) {
430
501
  warn(
@@ -593,42 +664,57 @@ const convertActions = (
593
664
  elements: readonly NormalizedUIElement[],
594
665
  context: ConversionContext,
595
666
  ): SlackBlock[] => {
596
- const converted = elements
597
- .map((source) => ({
598
- source,
599
- element: toActionElement(source, context),
600
- }))
601
- .filter(
602
- (
603
- entry,
604
- ): entry is {
605
- readonly source: NormalizedUIElement;
606
- readonly element: SlackActionElement;
607
- } => entry.element !== undefined,
608
- );
667
+ const converted = elements.flatMap((source) => {
668
+ const result = toActionElement(source, context);
669
+ if (result === undefined) return [];
670
+ const controls = Array.isArray(result) ? result : [result];
671
+ const inputType =
672
+ source.type === "DatePicker" ? source.props["inputType"] : undefined;
673
+ const temporal =
674
+ inputType === "datetime"
675
+ ? classifyTemporal(asString(source.props["value"]))
676
+ : undefined;
677
+ const pairId =
678
+ controls.length > 1 ? context.dateTimePairSequence++ : undefined;
679
+ return controls.map((element) => {
680
+ const name = asString(source.props["name"]);
681
+ const field: FieldMapping | undefined =
682
+ inputType === "time" || inputType === "datetime"
683
+ ? {
684
+ actionId: element.action_id,
685
+ name,
686
+ component: source.type,
687
+ inputType,
688
+ ...(temporal?.kind === "instant"
689
+ ? { offset: temporal.offset }
690
+ : {}),
691
+ ...(pairId !== undefined
692
+ ? ({
693
+ part: element.type === "datepicker" ? "date" : "time",
694
+ pairId,
695
+ } as const)
696
+ : {}),
697
+ }
698
+ : name
699
+ ? { actionId: element.action_id, name, component: source.type }
700
+ : undefined;
701
+ return { element, field };
702
+ });
703
+ });
609
704
  const blocks: SlackBlock[] = [];
610
705
  const groups: (typeof converted)[] = [];
611
706
  let group: typeof converted = [];
612
707
  let actionIds = new Set<string>();
613
- const hasFieldName = (entry: (typeof converted)[number]): boolean => {
614
- const name = entry.source.props["name"];
615
- return typeof name === "string" && name.length > 0;
616
- };
617
708
  const fieldsFor = (entries: typeof converted): FieldMapping[] =>
618
- entries.flatMap(({ source, element }) => {
619
- const name = source.props["name"];
620
- return typeof name === "string" && name.length > 0
621
- ? [{ actionId: element.action_id, name, component: source.type }]
622
- : [];
623
- });
709
+ entries.flatMap(({ field }) => (field === undefined ? [] : [field]));
624
710
  for (const entry of converted) {
625
711
  const repeatedMappedActionId =
626
712
  actionIds.has(entry.element.action_id) &&
627
- (hasFieldName(entry) ||
713
+ (entry.field !== undefined ||
628
714
  group.some(
629
715
  (candidate) =>
630
716
  candidate.element.action_id === entry.element.action_id &&
631
- hasFieldName(candidate),
717
+ candidate.field !== undefined,
632
718
  ));
633
719
  if (group.length === ACTIONS_ELEMENT_CAP || repeatedMappedActionId) {
634
720
  groups.push(group);
@@ -1690,6 +1776,7 @@ export function toSlackBlocks(
1690
1776
  warnings: [],
1691
1777
  omittedPasswordNames: new Set(),
1692
1778
  fieldBlockIdSequence: 0,
1779
+ dateTimePairSequence: 0,
1693
1780
  markdownCharacters: 0,
1694
1781
  markdownExhausted: false,
1695
1782
  dataTableCharacters: 0,
@@ -1,5 +1,15 @@
1
1
  import type { UIElement } from "../ir";
2
2
 
3
+ export type FieldMapping = {
4
+ readonly actionId: string;
5
+ readonly name: string;
6
+ readonly component: string;
7
+ readonly inputType?: "time" | "datetime";
8
+ readonly offset?: string;
9
+ readonly part?: "date" | "time";
10
+ readonly pairId?: number;
11
+ };
12
+
3
13
  /** A Slack plain-text composition object. */
4
14
  export interface SlackPlainText {
5
15
  readonly type: "plain_text";
@@ -46,6 +56,18 @@ export interface SlackDatePickerElement {
46
56
  readonly initial_date?: string;
47
57
  }
48
58
 
59
+ export interface SlackTimePickerElement {
60
+ readonly type: "timepicker";
61
+ readonly action_id: string;
62
+ readonly initial_time?: string;
63
+ }
64
+
65
+ export interface SlackDateTimePickerElement {
66
+ readonly type: "datetimepicker";
67
+ readonly action_id: string;
68
+ readonly initial_date_time?: number;
69
+ }
70
+
49
71
  /** A Slack checkbox-group element. */
50
72
  export interface SlackCheckboxesElement {
51
73
  readonly type: "checkboxes";
@@ -76,6 +98,8 @@ export type SlackActionElement =
76
98
  | SlackButtonElement
77
99
  | SlackStaticSelectElement
78
100
  | SlackDatePickerElement
101
+ | SlackTimePickerElement
102
+ | SlackDateTimePickerElement
79
103
  | SlackCheckboxesElement
80
104
  | SlackRadioButtonsElement;
81
105
 
package/src/slack.ts CHANGED
@@ -20,6 +20,7 @@ export type {
20
20
  SlackDataTableRawNumberCell,
21
21
  SlackDataTableRawTextCell,
22
22
  SlackDatePickerElement,
23
+ SlackDateTimePickerElement,
23
24
  SlackDividerBlock,
24
25
  SlackHeaderBlock,
25
26
  SlackImageBlock,
@@ -33,5 +34,6 @@ export type {
33
34
  SlackSectionBlock,
34
35
  SlackStaticSelectElement,
35
36
  SlackTextObject,
37
+ SlackTimePickerElement,
36
38
  ToSlackBlocksOptions,
37
39
  } from "./slack/types";