@k2b/ui 0.39.0 → 0.41.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.
Files changed (98) hide show
  1. package/dist/browser/chat/ChatComposer.js +759 -570
  2. package/dist/browser/chat/ChatComposer.js.map +1 -1
  3. package/dist/browser/inputs/ChoiceGroups.js +30 -18
  4. package/dist/browser/inputs/ChoiceGroups.js.map +1 -1
  5. package/dist/browser/inputs/Select.js +32 -19
  6. package/dist/browser/inputs/Select.js.map +1 -1
  7. package/dist/browser/inputs/SpecialInputs.js +54 -25
  8. package/dist/browser/inputs/SpecialInputs.js.map +1 -1
  9. package/dist/browser/inputs/choice.js +4 -1
  10. package/dist/browser/inputs/choice.js.map +1 -1
  11. package/dist/browser/inputs/dictation/Dictation.js +546 -0
  12. package/dist/browser/inputs/dictation/Dictation.js.map +1 -0
  13. package/dist/browser/inputs/dictation/create-dictation.js +324 -0
  14. package/dist/browser/inputs/dictation/create-dictation.js.map +1 -0
  15. package/dist/browser/inputs/dictation/dictation-messages.js +115 -0
  16. package/dist/browser/inputs/dictation/dictation-messages.js.map +1 -0
  17. package/dist/browser/inputs/dictation/text-dictation.js +152 -0
  18. package/dist/browser/inputs/dictation/text-dictation.js.map +1 -0
  19. package/dist/browser/inputs/dictation/types.js +2 -0
  20. package/dist/browser/inputs/dictation/types.js.map +1 -0
  21. package/dist/browser/inputs/icon-messages.js +29 -2
  22. package/dist/browser/inputs/icon-messages.js.map +1 -1
  23. package/dist/browser/inputs/icon-texts.js +172 -0
  24. package/dist/browser/inputs/icon-texts.js.map +1 -0
  25. package/dist/browser/inputs/index.js +2 -0
  26. package/dist/browser/inputs/index.js.map +1 -1
  27. package/dist/browser/layout/AnchoredPopover.js +1 -1
  28. package/dist/browser/layout/AnchoredPopover.js.map +1 -1
  29. package/dist/browser/layout/AppWorkspace.js +31 -17
  30. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  31. package/dist/browser/layout/SettingsModal.js +10 -5
  32. package/dist/browser/layout/SettingsModal.js.map +1 -1
  33. package/dist/browser/layout/app-workspace-controller.js +49 -5
  34. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  35. package/dist/browser/text-editor/TextEditor.js +74 -25
  36. package/dist/browser/text-editor/TextEditor.js.map +1 -1
  37. package/dist/browser/text-editor/dictation.js +166 -0
  38. package/dist/browser/text-editor/dictation.js.map +1 -0
  39. package/dist/browser/text-editor.js +1 -0
  40. package/dist/browser/text-editor.js.map +1 -1
  41. package/dist/ssr/chat/ChatComposer.js +271 -99
  42. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  43. package/dist/ssr/inputs/ChoiceGroups.js +12 -3
  44. package/dist/ssr/inputs/ChoiceGroups.js.map +1 -1
  45. package/dist/ssr/inputs/Select.js +8 -2
  46. package/dist/ssr/inputs/Select.js.map +1 -1
  47. package/dist/ssr/inputs/SpecialInputs.js +54 -25
  48. package/dist/ssr/inputs/SpecialInputs.js.map +1 -1
  49. package/dist/ssr/inputs/choice.js +4 -1
  50. package/dist/ssr/inputs/choice.js.map +1 -1
  51. package/dist/ssr/inputs/dictation/Dictation.js +386 -0
  52. package/dist/ssr/inputs/dictation/Dictation.js.map +1 -0
  53. package/dist/ssr/inputs/dictation/create-dictation.js +324 -0
  54. package/dist/ssr/inputs/dictation/create-dictation.js.map +1 -0
  55. package/dist/ssr/inputs/dictation/dictation-messages.js +115 -0
  56. package/dist/ssr/inputs/dictation/dictation-messages.js.map +1 -0
  57. package/dist/ssr/inputs/dictation/text-dictation.js +152 -0
  58. package/dist/ssr/inputs/dictation/text-dictation.js.map +1 -0
  59. package/dist/ssr/inputs/dictation/types.js +2 -0
  60. package/dist/ssr/inputs/dictation/types.js.map +1 -0
  61. package/dist/ssr/inputs/icon-messages.js +29 -2
  62. package/dist/ssr/inputs/icon-messages.js.map +1 -1
  63. package/dist/ssr/inputs/icon-texts.js +172 -0
  64. package/dist/ssr/inputs/icon-texts.js.map +1 -0
  65. package/dist/ssr/inputs/index.js +2 -0
  66. package/dist/ssr/inputs/index.js.map +1 -1
  67. package/dist/ssr/layout/AnchoredPopover.js +1 -1
  68. package/dist/ssr/layout/AnchoredPopover.js.map +1 -1
  69. package/dist/ssr/layout/AppWorkspace.js +31 -17
  70. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  71. package/dist/ssr/layout/SettingsModal.js +10 -5
  72. package/dist/ssr/layout/SettingsModal.js.map +1 -1
  73. package/dist/ssr/layout/app-workspace-controller.js +49 -5
  74. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  75. package/dist/ssr/text-editor/TextEditor.js +74 -25
  76. package/dist/ssr/text-editor/TextEditor.js.map +1 -1
  77. package/dist/ssr/text-editor/dictation.js +166 -0
  78. package/dist/ssr/text-editor/dictation.js.map +1 -0
  79. package/dist/ssr/text-editor.js +1 -0
  80. package/dist/ssr/text-editor.js.map +1 -1
  81. package/dist/styles.css +1 -1
  82. package/dist/types/chat/ChatComposer.d.ts +9 -0
  83. package/dist/types/inputs/SpecialInputs.d.ts +8 -0
  84. package/dist/types/inputs/dictation/Dictation.d.ts +26 -0
  85. package/dist/types/inputs/dictation/create-dictation.d.ts +77 -0
  86. package/dist/types/inputs/dictation/dictation-messages.d.ts +54 -0
  87. package/dist/types/inputs/dictation/text-dictation.d.ts +36 -0
  88. package/dist/types/inputs/dictation/types.d.ts +74 -0
  89. package/dist/types/inputs/icon-messages.d.ts +14 -0
  90. package/dist/types/inputs/icon-texts.d.ts +13 -0
  91. package/dist/types/inputs/index.d.ts +5 -0
  92. package/dist/types/layout/AnchoredPopover.d.ts +5 -0
  93. package/dist/types/layout/AppWorkspace.d.ts +14 -0
  94. package/dist/types/layout/app-workspace-controller.d.ts +2 -0
  95. package/dist/types/text-editor/TextEditor.d.ts +10 -1
  96. package/dist/types/text-editor/dictation.d.ts +20 -0
  97. package/dist/types/text-editor.d.ts +1 -0
  98. package/package.json +1 -1
@@ -27,17 +27,20 @@ var _tmpl$ = ["<div class=\"k2b-ste-size-picker\">", "", "</div>"],
27
27
  import { history, historyKeymap, redo, undo } from "@codemirror/commands";
28
28
  import { EditorView, keymap } from "@codemirror/view";
29
29
  import { clipboard } from "@k2b/stdlib/solid";
30
- import { createEffect, createSignal, createUniqueId, For, onCleanup, onMount, Show, untrack } from "solid-js";
30
+ import { children, createEffect, createMemo, createSignal, createUniqueId, For, on, onCleanup, onMount, Show, untrack } from "solid-js";
31
31
  import { Button, IconButton } from "../actions/Button";
32
32
  import { Dropdown } from "../actions/Dropdown";
33
33
  import { SegmentedControl } from "../actions/SegmentedControl";
34
34
  import { Toolbar } from "../actions/Toolbar";
35
35
  import { Kbd } from "../content/Kbd";
36
36
  import { dialogCore } from "../feedback/dialog-core";
37
+ import { createDictation } from "../inputs/dictation/create-dictation";
38
+ import { DictationBar, DictationButton, dictationBarShown } from "../inputs/dictation/Dictation";
37
39
  import { NumberInput } from "../inputs/NumberInput";
38
40
  import { LocaleProvider, useLocale } from "../intl/locale";
39
41
  import { formatShortcut, keyboardPlatform } from "../intl/shortcut";
40
42
  import BottomSheet, { bottomSheetAdaptiveOptions } from "../layout/BottomSheet";
43
+ import { codeMirrorDictationTarget, dictationExtension } from "./dictation";
41
44
  import { createTextEditor } from "./engine";
42
45
  import { commands, formatLabels } from "./format";
43
46
  import { findTables, inspectTableStructure } from "./markdown-table";
@@ -266,6 +269,7 @@ export function TextEditor(props) {
266
269
  const locale = useLocale();
267
270
  const t = () => textEditorMessages.resolve([locale()]).t;
268
271
  const [mode, setMode] = createSignal(props.mode ?? "formatted");
272
+ const status = children(() => props.status);
269
273
  const [ready, setReady] = createSignal(false);
270
274
  const [recovery, setRecovery] = createSignal();
271
275
  const [notice, setNotice] = createSignal();
@@ -372,6 +376,26 @@ export function TextEditor(props) {
372
376
  let root;
373
377
  let mount;
374
378
  let editor;
379
+ // The view is read-only while it loads or recovers, too; dictation only runs where words can land.
380
+ const dictationWritable = () => !props.readOnly && !props.loading && ready() && recovery() === undefined && mode() !== "plain";
381
+ const dictation = createDictation({
382
+ source: {
383
+ start: options => props.dictation.source.start(options),
384
+ devices: () => props.dictation?.source.devices() ?? Promise.resolve([])
385
+ },
386
+ get alternative() {
387
+ return props.dictation?.alternative;
388
+ },
389
+ target: codeMirrorDictationTarget(() => editor?.view),
390
+ disabled: () => !props.dictation || !dictationWritable()
391
+ });
392
+ // A field that turns read-only or plain hides the toolbar; dictation then ends and the words so far stay.
393
+ // A memo compares the value, so ordinary edits never end it.
394
+ const dictationScope = createMemo(() => `${Boolean(props.dictation)}:${dictationWritable()}`);
395
+ createEffect(on(dictationScope, () => dictation.end(), {
396
+ defer: true
397
+ }));
398
+ const dictating = () => Boolean(props.dictation) && dictationBarShown(dictation);
375
399
  const menuBlocked = () => !!props.loading || !ready() || recovery() !== undefined;
376
400
  const blocked = () => !!props.readOnly || menuBlocked();
377
401
  const updateCheck = () => {
@@ -847,7 +871,8 @@ export function TextEditor(props) {
847
871
  }
848
872
  });
849
873
  const selectMode = next => {
850
- const restoreEditorFocus = !!editor?.view.contentDOM.contains(document.activeElement);
874
+ // Returning from the source view removes its switch; keyboard focus then moves into the text.
875
+ const restoreEditorFocus = !!editor?.view.contentDOM.contains(document.activeElement) || !!root.querySelector(".k2b-ste-views")?.contains(document.activeElement);
851
876
  menuOpen = false;
852
877
  setCell(undefined);
853
878
  setMode(next);
@@ -879,7 +904,7 @@ export function TextEditor(props) {
879
904
  }), EditorView.updateListener.of(update => {
880
905
  schedulePosition();
881
906
  if (update.docChanged) queueMicrotask(() => setDocumentRevision(revision => revision + 1));
882
- }), props.extensions ?? []],
907
+ }), props.extensions ?? [], props.dictation ? dictationExtension() : []],
883
908
  host: {
884
909
  ...props.host,
885
910
  undo: props.host?.undo ?? (() => editor && undo(editor.view)),
@@ -1083,10 +1108,10 @@ export function TextEditor(props) {
1083
1108
  });
1084
1109
  return _$ssr(_tmpl$15, `k2b-text-editor ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-mode", _$escape(mode(), true), false) + _$ssrAttribute("data-readonly", props.readOnly ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-active", active() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("aria-busy", _$escape(props.loading || !ready(), true), false), _$escape(announcement()), _$escape(_$createComponent(Show, {
1085
1110
  get when() {
1086
- return !props.presentation || "status" in props || check();
1111
+ return _$memo(() => !!(status() !== undefined && status() !== null))() && status() !== false || check();
1087
1112
  },
1088
1113
  get children() {
1089
- return _$ssr(_tmpl$10, _$escape(props.status), _$escape(_$createComponent(Show, {
1114
+ return _$ssr(_tmpl$10, _$escape(status()), _$escape(_$createComponent(Show, {
1090
1115
  get when() {
1091
1116
  return check();
1092
1117
  },
@@ -1132,9 +1157,18 @@ export function TextEditor(props) {
1132
1157
  return t().formatting;
1133
1158
  },
1134
1159
  get children() {
1135
- return [_$createComponent(For, {
1160
+ return [_$createComponent(Show, {
1161
+ get when() {
1162
+ return dictating();
1163
+ },
1164
+ get children() {
1165
+ return _$createComponent(DictationBar, {
1166
+ dictation: dictation
1167
+ });
1168
+ }
1169
+ }), _$createComponent(For, {
1136
1170
  get each() {
1137
- return [toolbar.slice(0, 3), toolbar.slice(3, 6), toolbar.slice(6)];
1171
+ return _$memo(() => !!dictating())() ? [] : [toolbar.slice(0, 3), toolbar.slice(3, 6), toolbar.slice(6)];
1138
1172
  },
1139
1173
  children: group => _$createComponent(Toolbar.Group, {
1140
1174
  "class": "k2b-ste-tool-group",
@@ -1176,27 +1210,42 @@ export function TextEditor(props) {
1176
1210
  });
1177
1211
  }
1178
1212
  })
1179
- }), _$createComponent(SegmentedControl, {
1180
- "class": "k2b-ste-views",
1181
- size: "sm",
1182
- get ariaLabel() {
1183
- return t().view;
1184
- },
1185
- get value() {
1186
- return mode() === "source" ? "source" : "formatted";
1213
+ }), _$createComponent(Show, {
1214
+ get when() {
1215
+ return _$memo(() => mode() === "source")() && !dictating();
1187
1216
  },
1188
- get options() {
1189
- return [{
1190
- value: "formatted",
1191
- label: t().formatted,
1192
- icon: "ti ti-typography"
1193
- }, {
1217
+ get children() {
1218
+ return _$createComponent(SegmentedControl, {
1219
+ "class": "k2b-ste-views",
1220
+ size: "sm",
1221
+ get ariaLabel() {
1222
+ return t().view;
1223
+ },
1194
1224
  value: "source",
1195
- label: t().source,
1196
- icon: "ti ti-markdown"
1197
- }];
1225
+ get options() {
1226
+ return [{
1227
+ value: "formatted",
1228
+ label: t().formatted,
1229
+ icon: "ti ti-typography"
1230
+ }, {
1231
+ value: "source",
1232
+ label: t().source,
1233
+ icon: "ti ti-markdown"
1234
+ }];
1235
+ },
1236
+ onValueChange: selectMode
1237
+ });
1238
+ }
1239
+ }), _$createComponent(Show, {
1240
+ get when() {
1241
+ return _$memo(() => !!props.dictation)() && !dictating();
1198
1242
  },
1199
- onValueChange: selectMode
1243
+ get children() {
1244
+ return _$createComponent(DictationButton, {
1245
+ dictation: dictation,
1246
+ "class": "k2b-ste-tool k2b-ste-dictate"
1247
+ });
1248
+ }
1200
1249
  })];
1201
1250
  }
1202
1251
  })));