@textui/widgets 0.5.0 → 0.7.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 (63) hide show
  1. package/dist/chart/line-chart.d.ts.map +1 -1
  2. package/dist/chart/line-chart.js +3 -2
  3. package/dist/control/select.d.ts.map +1 -1
  4. package/dist/control/select.js +4 -2
  5. package/dist/control/switch.d.ts.map +1 -1
  6. package/dist/control/switch.js +7 -2
  7. package/dist/data/index.d.ts.map +1 -1
  8. package/dist/data/index.js +3 -2
  9. package/dist/data/list.d.ts.map +1 -1
  10. package/dist/data/list.js +3 -2
  11. package/dist/data/log-viewer.d.ts.map +1 -1
  12. package/dist/data/log-viewer.js +7 -2
  13. package/dist/data/markdown-view.d.ts.map +1 -1
  14. package/dist/data/markdown-view.js +3 -2
  15. package/dist/data/pagination.d.ts.map +1 -1
  16. package/dist/data/pagination.js +3 -2
  17. package/dist/display/error-state.d.ts.map +1 -1
  18. package/dist/display/error-state.js +4 -3
  19. package/dist/form/danger-zone.d.ts.map +1 -1
  20. package/dist/form/danger-zone.js +7 -3
  21. package/dist/form/form-actions.d.ts.map +1 -1
  22. package/dist/form/form-actions.js +3 -2
  23. package/dist/navigation/menu.d.ts.map +1 -1
  24. package/dist/navigation/menu.js +3 -2
  25. package/dist/overlay/command-palette.d.ts +0 -14
  26. package/dist/overlay/command-palette.d.ts.map +1 -1
  27. package/dist/overlay/command-palette.js +127 -38
  28. package/dist/overlay/dialog.d.ts +11 -0
  29. package/dist/overlay/dialog.d.ts.map +1 -1
  30. package/dist/overlay/dialog.js +24 -1
  31. package/dist/overlay/index.d.ts.map +1 -1
  32. package/dist/overlay/index.js +11 -19
  33. package/dist/overlay/path-picker.d.ts.map +1 -1
  34. package/dist/overlay/path-picker.js +19 -11
  35. package/dist/overlay/prompt-dialog.d.ts.map +1 -1
  36. package/dist/overlay/prompt-dialog.js +5 -4
  37. package/dist/panel/index.d.ts.map +1 -1
  38. package/dist/panel/index.js +8 -7
  39. package/dist/panel/resource-panel.d.ts.map +1 -1
  40. package/dist/panel/resource-panel.js +9 -5
  41. package/dist/surface/mount-view.d.ts.map +1 -1
  42. package/dist/surface/mount-view.js +3 -2
  43. package/package.json +2 -2
  44. package/src/chart/line-chart.ts +3 -2
  45. package/src/control/select.ts +4 -2
  46. package/src/control/switch.ts +9 -2
  47. package/src/data/index.ts +3 -1
  48. package/src/data/list.ts +3 -1
  49. package/src/data/log-viewer.ts +7 -1
  50. package/src/data/markdown-view.ts +7 -1
  51. package/src/data/pagination.ts +3 -2
  52. package/src/display/error-state.ts +4 -3
  53. package/src/form/danger-zone.ts +7 -3
  54. package/src/form/form-actions.ts +5 -2
  55. package/src/navigation/menu.ts +3 -2
  56. package/src/overlay/command-palette.ts +152 -29
  57. package/src/overlay/dialog.ts +37 -1
  58. package/src/overlay/index.ts +11 -19
  59. package/src/overlay/path-picker.ts +23 -10
  60. package/src/overlay/prompt-dialog.ts +5 -4
  61. package/src/panel/index.ts +9 -7
  62. package/src/panel/resource-panel.ts +9 -4
  63. package/src/surface/mount-view.ts +3 -2
@@ -1,23 +1,11 @@
1
- import { defineComponent, h, stringWidth, useEffect, useFocusScope, useInput, useRuntime, useState, useTheme, } from '@textui/core';
1
+ import { defineComponent, h, stringWidth, useEffect, useFocusScope, useI18n, useInput, useRuntime, useState, useTheme, } from '@textui/core';
2
2
  import { TextInput } from '../control/index.js';
3
3
  import { Menu } from '../navigation/index.js';
4
4
  import { hint } from './shared.js';
5
- /**
6
- * The command palette.
7
- *
8
- * It searches the command registry rather than a list someone maintained, so
9
- * a command registered anywhere is reachable here the moment it exists - which
10
- * is the payoff for insisting actions are commands. It also *runs* what it
11
- * finds, so choosing "Open dialog" here and pressing the button that opens a
12
- * dialog are the same act, reaching the same code.
13
- *
14
- * A command that declares an argument with `choices` gets a second level:
15
- * choosing it lists the choices, and picking one runs the command with it.
16
- * That is where sub-items come from - the command says what it needs and the
17
- * palette asks, rather than every caller inventing its own submenu.
18
- */
19
5
  export const CommandPalette = defineComponent('CommandPalette', (props) => {
20
6
  const theme = useTheme();
7
+ const i18n = useI18n();
8
+ const ellipsis = theme.glyphs.ellipsis;
21
9
  const runtime = useRuntime();
22
10
  const { commands, placeholder, onRun, onClose, execute = true, grouped = true, visibleRows = 8, width, maxWidth = 60, openAt, descriptions = 'inline', ...rest } = props;
23
11
  const [query, setQuery] = useState('');
@@ -42,7 +30,9 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
42
30
  const app = runtime.app();
43
31
  const given = typeof commands === 'function' ? commands() : commands;
44
32
  const all = given ?? app?.commands.list({ slot: 'palette', enabledOnly: true }) ?? [];
45
- const matches = pending ? [] : filterCommands(all, query);
33
+ const matches = pending
34
+ ? []
35
+ : grouped && query.trim() === '' ? byCategory(all) : filterCommands(all, query);
46
36
  const offered = pending ? filterChoices(choices, query) : [];
47
37
  const rows = pending ? offered.map((choice) => choice.value) : matches.map((c) => c.id);
48
38
  const index = Math.max(0, Math.min(highlight, rows.length - 1));
@@ -56,7 +46,9 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
56
46
  // the only thing the palette itself knows about a value.
57
47
  ...(choice.description
58
48
  ? { description: choice.description }
59
- : pending.arg.default === choice.value ? { description: 'default' } : {}),
49
+ : pending.arg.default === choice.value
50
+ ? { description: i18n.t('textui.palette.default', undefined, 'default') }
51
+ : {}),
60
52
  }))
61
53
  // One row, saying which kind of nothing this is. A disabled item rather
62
54
  // than no items: the panel keeps its height, so the answer arriving does
@@ -64,8 +56,10 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
64
56
  : [{
65
57
  id: '',
66
58
  label: asking
67
- ? `Asking${theme.glyphs.ellipsis}`
68
- : (query === '' ? 'Nothing to choose' : 'No match'),
59
+ ? i18n.t('textui.palette.asking', { ellipsis }, 'Asking{ellipsis}')
60
+ : (query === ''
61
+ ? i18n.t('textui.palette.nothingToChoose', undefined, 'Nothing to choose')
62
+ : i18n.t('textui.palette.noMatch', undefined, 'No match')),
69
63
  disabled: true,
70
64
  }])
71
65
  : matches.map((command, i) => ({
@@ -99,10 +93,29 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
99
93
  ? { sectionBefore: command.category }
100
94
  : {}),
101
95
  }));
96
+ /** The argument answered last, when this question came after one. */
97
+ const previousOf = (asked) => {
98
+ const last = Object.keys(asked.collected).at(-1);
99
+ return last === undefined ? undefined : (asked.command.args ?? []).find((arg) => arg.name === last);
100
+ };
101
+ /**
102
+ * One question back.
103
+ *
104
+ * After a first question the second is asked again from the start with
105
+ * the earlier answer withdrawn: a wrong provider is corrected by choosing
106
+ * another, not by closing the whole picker and opening it again. At the
107
+ * first question, the command list.
108
+ */
102
109
  const back = () => {
103
110
  // `null` is "never mind": whatever the preview did gets undone by whoever
104
111
  // did it, because only the command knows what it changed.
105
112
  pending?.arg.preview?.(null);
113
+ const previous = pending ? previousOf(pending) : undefined;
114
+ if (pending && previous) {
115
+ const { [previous.name]: _withdrawn, ...rest } = pending.collected;
116
+ drillInto(pending.command, previous, rest);
117
+ return;
118
+ }
106
119
  setPending(null);
107
120
  setChoices([]);
108
121
  setQuery('');
@@ -144,9 +157,16 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
144
157
  setRefresh((n) => n + 1);
145
158
  onRun?.(id, args);
146
159
  };
147
- /** Ask about one command. `choices` may be a function, and may be async. */
160
+ /**
161
+ * Ask about one command. `choices` may be a function, and may be async.
162
+ *
163
+ * A resolver is handed what was answered before this argument - and an
164
+ * argument that was not asked because its `default` stood was answered by
165
+ * that default. Left out, "the models of the chosen provider" would see no
166
+ * provider exactly when there was only one to choose from.
167
+ */
148
168
  const drillInto = (command, arg, collected = {}) => {
149
- const resolved = typeof arg.choices === 'function' ? arg.choices() : arg.choices ?? [];
169
+ const resolved = typeof arg.choices === 'function' ? arg.choices(answeredBefore(command, arg, collected)) : arg.choices ?? [];
150
170
  setPending({ command, arg, collected });
151
171
  setQuery('');
152
172
  /*
@@ -253,8 +273,10 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
253
273
  // anybody chose to be at: the caller drilled in on their behalf, and
254
274
  // the level underneath is a list of one. Backing out to it reads as
255
275
  // "escape did nothing", and the second escape - the one that would
256
- // close it - is spent leaving a screen nobody asked to see.
257
- if (pending && !openAt) {
276
+ // close it - is spent leaving a screen nobody asked to see. A question
277
+ // that came after one is different: there the level underneath is the
278
+ // earlier question, which somebody did choose to be at.
279
+ if (pending && (!openAt || previousOf(pending) !== undefined)) {
258
280
  back();
259
281
  return true;
260
282
  }
@@ -267,7 +289,7 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
267
289
  onClose?.();
268
290
  return true;
269
291
  }
270
- if (event.name === 'left' && pending && query === '' && !openAt) {
292
+ if (event.name === 'left' && pending && query === '' && (!openAt || previousOf(pending) !== undefined)) {
271
293
  back();
272
294
  return true;
273
295
  }
@@ -290,17 +312,21 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
290
312
  return false;
291
313
  }, { global: true });
292
314
  const highlighted = pending ? undefined : matches[index];
293
- const move = `${theme.glyphs.arrowUp}${theme.glyphs.arrowDown} move`;
315
+ const move = i18n.t('textui.palette.hint.move', { arrows: `${theme.glyphs.arrowUp}${theme.glyphs.arrowDown}` }, '{arrows} move');
316
+ const escBack = i18n.t('textui.palette.hint.back', undefined, 'esc back');
294
317
  // What the highlighted row is, in full.
295
318
  //
296
319
  // The rows themselves have to fit, so a choice's own sentence is truncated
297
320
  // there - and a sentence about what a mode does is exactly the thing a
298
321
  // person needs whole. So the line under the list follows the highlight: the
299
322
  // choice's description while there is one, the question's otherwise.
323
+ // It is the one line in the panel that wraps rather than truncates,
324
+ // because it is the one place a sentence can be read whole.
300
325
  const chosen = pending ? offered[index] : undefined;
301
326
  const detail = pending
302
327
  ? chosen?.description
303
- ?? pending.arg.description ?? `${pending.command.title} needs a ${pending.arg.name}`
328
+ ?? pending.arg.description
329
+ ?? i18n.t('textui.palette.needs', { command: pending.command.title, arg: pending.arg.name }, '{command} needs a {arg}')
304
330
  : highlighted?.description ?? highlighted?.id ?? '';
305
331
  /*
306
332
  * How wide the panel wants to be.
@@ -315,10 +341,17 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
315
341
  * the things that decide it: a question with two short answers still needs
316
342
  * somewhere to type and a line saying what the keys do.
317
343
  */
318
- const content = Math.max(...items.map((item) => rowWidth(item, descriptions)), ...(pending ? [stringWidth(pending.command.title) + 12] : [stringWidth(placeholder ?? '') + 4]));
344
+ const content = Math.max(...items.map((item) => rowWidth(item, descriptions)), ...(pending ? [stringWidth(pending.command.title) + 12] : [stringWidth(placeholder ?? '') + 4]),
345
+ // The sentences the line under the list may show, so a question with
346
+ // three one-word answers is not a panel 28 wide wrapping a sentence
347
+ // three times under them. Capped like everything else by `maxWidth`.
348
+ ...(pending
349
+ ? [pending.arg.description ?? '', ...offered.map((choice) => choice.description ?? '')]
350
+ .map((sentence) => (sentence === '' ? 0 : stringWidth(sentence) + 6))
351
+ : []));
319
352
  return h('box', {
320
353
  role: 'dialog',
321
- label: 'Commands',
354
+ label: i18n.t('textui.palette.label', undefined, 'Commands'),
322
355
  border: theme.border,
323
356
  bg: 'overlay',
324
357
  // A stated width is a width. Left off, it fits what it holds.
@@ -334,8 +367,8 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
334
367
  // where you are; "commands › id" is what the parameter happens to be
335
368
  // called, which is the author's business rather than the reader's.
336
369
  title: pending
337
- ? ` commands ${theme.glyphs.breadcrumb} ${pending.command.title} `
338
- : ' commands ',
370
+ ? ` ${i18n.t('textui.palette.title', undefined, 'commands')} ${theme.glyphs.breadcrumb} ${pending.command.title} `
371
+ : ` ${i18n.t('textui.palette.title', undefined, 'commands')} `,
339
372
  ...rest,
340
373
  }, h(TextInput, {
341
374
  value: query,
@@ -361,11 +394,20 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
361
394
  if (command && argumentOf(command))
362
395
  choose();
363
396
  },
397
+ // A typed answer's field is the answer, so its placeholder is the
398
+ // question. A list's field is a filter, and the question goes where
399
+ // there is room to say it once: here, while the line under the list
400
+ // is busy saying what each answer means; under the list, whole and
401
+ // wrapped, when the answers have nothing to say for themselves and
402
+ // that line would otherwise repeat this one, cut to whatever width
403
+ // three short answers gave the panel.
364
404
  placeholder: pending
365
- ? (pending.arg.description ?? (pending.arg.choices === undefined
366
- ? `${pending.command.title}${theme.glyphs.ellipsis}`
367
- : `Choose ${pending.command.title.toLowerCase()}${theme.glyphs.ellipsis}`))
368
- : (placeholder ?? `Type a command${theme.glyphs.ellipsis}`),
405
+ ? (pending.arg.choices === undefined
406
+ ? pending.arg.description ?? `${pending.command.title}${theme.glyphs.ellipsis}`
407
+ : offered.some((choice) => choice.description) && pending.arg.description
408
+ ? pending.arg.description
409
+ : i18n.t('textui.palette.choose', { command: pending.command.title.toLowerCase(), ellipsis }, 'Choose {command}{ellipsis}'))
410
+ : (placeholder ?? i18n.t('textui.palette.placeholder', { ellipsis }, 'Type a command{ellipsis}')),
369
411
  search: true,
370
412
  autoFocus: true,
371
413
  border: 'none',
@@ -386,14 +428,25 @@ export const CommandPalette = defineComponent('CommandPalette', (props) => {
386
428
  }), h('box', { height: 1, fill: theme.borderChars().top, fg: 'borderSubtle' }),
387
429
  // What the highlighted row actually is, and how to move around. A palette
388
430
  // that shows only titles makes you run something to find out what it does.
389
- h('box', { direction: 'row', gap: 1 }, h('text', { content: detail, fg: 'muted', flex: 1, truncate: 'end' }), h('text', { content: `${rows.length}`, fg: 'subtle' })), h('box', { direction: 'row', gap: 1 }, h('text', {
431
+ h('box', { direction: 'row', gap: 1, align: 'start' }, h('text', { content: detail, fg: 'muted', flex: 1, wrap: 'word' }), h('text', { content: `${rows.length}`, fg: 'subtle' })), h('box', { direction: 'row', gap: 1 }, h('text', {
390
432
  content: pending
391
433
  ? (pending.arg.choices === undefined
392
- ? hint(theme, ['type it', 'enter confirm', 'esc back'])
434
+ ? hint(theme, [
435
+ i18n.t('textui.palette.hint.type', undefined, 'type it'),
436
+ i18n.t('textui.palette.hint.confirm', undefined, 'enter confirm'),
437
+ escBack,
438
+ ])
393
439
  // Nothing to choose is nothing to press enter on, and offering it
394
440
  // is how a panel reads as broken rather than as empty.
395
- : hint(theme, rows.length > 0 ? [move, 'enter choose', 'esc back'] : ['esc back']))
396
- : hint(theme, [move, 'enter run', `${theme.glyphs.chevronRight} sub-items`, 'esc close']),
441
+ : hint(theme, rows.length > 0
442
+ ? [move, i18n.t('textui.palette.hint.choose', undefined, 'enter choose'), escBack]
443
+ : [escBack]))
444
+ : hint(theme, [
445
+ move,
446
+ i18n.t('textui.palette.hint.run', undefined, 'enter run'),
447
+ i18n.t('textui.palette.hint.subItems', { glyph: theme.glyphs.chevronRight }, '{glyph} sub-items'),
448
+ i18n.t('textui.palette.hint.close', undefined, 'esc close'),
449
+ ]),
397
450
  fg: 'subtle',
398
451
  truncate: 'end',
399
452
  })));
@@ -418,6 +471,23 @@ export function argumentOf(command, collected = {}) {
418
471
  return (command.args ?? []).find((arg) => collected[arg.name] === undefined &&
419
472
  (arg.choices !== undefined || (arg.required === true && arg.default === undefined)));
420
473
  }
474
+ /**
475
+ * What a `choices` resolver is told: the answers given, under the defaults
476
+ * of the arguments before this one that stood in for a question.
477
+ *
478
+ * Only the ones ahead of it in the declaration. An argument after this one
479
+ * has not been reached, and its default is not yet an answer to anything.
480
+ */
481
+ function answeredBefore(command, arg, collected) {
482
+ const answered = {};
483
+ for (const spec of command.args ?? []) {
484
+ if (spec === arg)
485
+ break;
486
+ if (spec.default !== undefined)
487
+ answered[spec.name] = spec.default;
488
+ }
489
+ return { ...answered, ...collected };
490
+ }
421
491
  /** The short form and the long one, as one shape. */
422
492
  function asChoice(choice) {
423
493
  return typeof choice === 'string' ? { value: choice } : choice;
@@ -436,6 +506,25 @@ function filterChoices(choices, query) {
436
506
  return choices.filter((choice) => `${choice.label ?? ''} ${choice.value} ${choice.description ?? ''}`
437
507
  .toLowerCase().includes(q));
438
508
  }
509
+ /**
510
+ * Each category's commands together, the categories in the order they first
511
+ * appear and the commands in the order they came.
512
+ *
513
+ * Registration order is whatever order the code happened to run in, so a
514
+ * category registered in two places would be two groups with the same name
515
+ * over them.
516
+ */
517
+ function byCategory(commands) {
518
+ const groups = new Map();
519
+ for (const command of commands) {
520
+ const group = groups.get(command.category);
521
+ if (group)
522
+ group.push(command);
523
+ else
524
+ groups.set(command.category, [command]);
525
+ }
526
+ return [...groups.values()].flat();
527
+ }
439
528
  export function filterCommands(commands, query) {
440
529
  const q = query.trim().toLowerCase();
441
530
  if (q === '')
@@ -13,4 +13,15 @@ export interface DialogProps extends BoxProps {
13
13
  width?: number;
14
14
  }
15
15
  export declare const Dialog: (props: DialogProps) => import("@textui/core").RenderOutput;
16
+ export interface ConfirmDialogProps extends BoxProps {
17
+ title?: string;
18
+ message: string;
19
+ confirmLabel?: string;
20
+ cancelLabel?: string;
21
+ tone?: SemanticVariant;
22
+ onConfirm?(): void;
23
+ onCancel?(): void;
24
+ }
25
+ /** Two-button dialog behind the `confirm` helper. */
26
+ export declare const ConfirmDialog: (props: ConfirmDialogProps) => import("@textui/core").RenderOutput;
16
27
  //# sourceMappingURL=dialog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../src/overlay/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAI9D,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,eAAe,CAAC;QAAC,OAAO,CAAC,IAAI,IAAI,CAAA;KAAE,EAAE,CAAC;IACpF,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,MAAM,6DAmDjB,CAAC"}
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../src/overlay/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAI9D,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,eAAe,CAAC;QAAC,OAAO,CAAC,IAAI,IAAI,CAAA;KAAE,EAAE,CAAC;IACpF,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,MAAM,6DAmDjB,CAAC;AAEH,MAAM,WAAW,kBAAmB,SAAQ,QAAQ;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,SAAS,CAAC,IAAI,IAAI,CAAC;IACnB,QAAQ,CAAC,IAAI,IAAI,CAAC;CACnB;AAED,qDAAqD;AACrD,eAAO,MAAM,aAAa,oEAuBxB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { defineComponent, h, useFocusScope, useInput, useTheme } from '@textui/core';
1
+ import { defineComponent, h, useFocusScope, useI18n, useInput, useTheme } from '@textui/core';
2
2
  import { Button } from '../control/index.js';
3
3
  export const Dialog = defineComponent('Dialog', (props) => {
4
4
  const theme = useTheme();
@@ -42,3 +42,26 @@ export const Dialog = defineComponent('Dialog', (props) => {
42
42
  })))
43
43
  : null);
44
44
  });
45
+ /** Two-button dialog behind the `confirm` helper. */
46
+ export const ConfirmDialog = defineComponent('ConfirmDialog', (props) => {
47
+ const i18n = useI18n();
48
+ const { title, message, confirmLabel, cancelLabel, tone, onConfirm, onCancel, ...rest } = props;
49
+ return h(Dialog, {
50
+ title: title ?? i18n.t('textui.confirmDialog.title', undefined, 'Confirm'),
51
+ width: 50,
52
+ actions: [
53
+ {
54
+ id: 'confirm',
55
+ label: confirmLabel ?? i18n.t('textui.confirmDialog.confirm', undefined, 'Confirm'),
56
+ tone: tone ?? 'primary',
57
+ onPress: onConfirm,
58
+ },
59
+ {
60
+ id: 'cancel',
61
+ label: cancelLabel ?? i18n.t('textui.confirmDialog.cancel', undefined, 'Cancel'),
62
+ onPress: onCancel,
63
+ },
64
+ ],
65
+ ...rest,
66
+ }, h('text', { content: message, wrap: 'word' }));
67
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/overlay/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,UAAU,EACV,UAAU,EACV,aAAa,EACb,eAAe,EACf,SAAS,EACV,MAAM,cAAc,CAAC;AAMtB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD;;;;;;GAMG;AACH,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,MAAM,EAAE;IAAE,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG;QAAE,OAAO,IAAI,IAAI,CAAA;KAAE,CAAA;CAAE,EACxD,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,CAwClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,MAAM,CACpB,MAAM,EAAE;IAAE,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG;QAAE,OAAO,IAAI,IAAI,CAAA;KAAE,CAAA;CAAE,EACxD,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6BxB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8BjF;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAID,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,UAAU,CAQzE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG,aAAa,CAO7E;AAED,eAAO,MAAM,kBAAkB,EAAE,mBAAmB,EASnD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/overlay/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,UAAU,EACV,UAAU,EACV,aAAa,EACb,eAAe,EACf,SAAS,EACV,MAAM,cAAc,CAAC;AAMtB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD;;;;;;GAMG;AACH,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,MAAM,EAAE;IAAE,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG;QAAE,OAAO,IAAI,IAAI,CAAA;KAAE,CAAA;CAAE,EACxD,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,CA+BlB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,MAAM,CACpB,MAAM,EAAE;IAAE,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG;QAAE,OAAO,IAAI,IAAI,CAAA;KAAE,CAAA;CAAE,EACxD,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6BxB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8BjF;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAID,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,UAAU,CAQzE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG,aAAa,CAO7E;AAED,eAAO,MAAM,kBAAkB,EAAE,mBAAmB,EAUnD,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { CommandPalette } from './command-palette.js';
2
- import { Dialog } from './dialog.js';
2
+ import { ConfirmDialog, Dialog } from './dialog.js';
3
3
  import { LayerScope } from './layer-scope.js';
4
4
  import { PathPicker } from './path-picker.js';
5
5
  import { PromptDialog } from './prompt-dialog.js';
@@ -45,23 +45,14 @@ export function confirm(layers, options) {
45
45
  dismissOnEscape: true,
46
46
  onClose: () => finish(false),
47
47
  node: {
48
- component: 'Dialog',
49
- title: options.title ?? 'Confirm',
50
- width: 50,
51
- children: { component: 'text', content: options.message, wrap: 'word' },
52
- actions: [
53
- {
54
- id: 'confirm',
55
- label: options.confirmLabel ?? 'Confirm',
56
- tone: options.tone ?? 'primary',
57
- onPress: () => finish(true),
58
- },
59
- {
60
- id: 'cancel',
61
- label: options.cancelLabel ?? 'Cancel',
62
- onPress: () => finish(false),
63
- },
64
- ],
48
+ component: 'ConfirmDialog',
49
+ title: options.title,
50
+ message: options.message,
51
+ confirmLabel: options.confirmLabel,
52
+ cancelLabel: options.cancelLabel,
53
+ tone: options.tone,
54
+ onConfirm: { handler: () => finish(true) },
55
+ onCancel: { handler: () => finish(false) },
65
56
  },
66
57
  });
67
58
  });
@@ -85,7 +76,7 @@ export function prompt(layers, options) {
85
76
  onClose: () => finish(null),
86
77
  node: {
87
78
  component: 'PromptDialog',
88
- title: options.title ?? 'Input',
79
+ title: options.title,
89
80
  message: options.message,
90
81
  placeholder: options.placeholder,
91
82
  initialValue: options.initialValue,
@@ -147,6 +138,7 @@ export function toastPosition(anchor) {
147
138
  }
148
139
  export const OVERLAY_COMPONENTS = [
149
140
  { component: 'Dialog', category: 'overlay', renderer: { kind: 'function', render: Dialog }, role: 'dialog', description: 'Modal box with actions; traps focus and restores it.' },
141
+ { component: 'ConfirmDialog', category: 'overlay', renderer: { kind: 'function', render: ConfirmDialog }, role: 'dialog', description: 'Two-button dialog behind the `confirm` helper.' },
150
142
  { component: 'PromptDialog', category: 'overlay', renderer: { kind: 'function', render: PromptDialog }, role: 'dialog', description: 'One-field dialog behind the `prompt` helper.' },
151
143
  { component: 'PathPicker', category: 'overlay', renderer: { kind: 'function', render: PathPicker }, role: 'dialog', description: 'Walk the resource tree and pick a file or a folder.' },
152
144
  { component: 'Tooltip', category: 'overlay', renderer: { kind: 'function', render: Tooltip }, role: 'tooltip', description: 'Small anchored hint.' },
@@ -1 +1 @@
1
- {"version":3,"file":"path-picker.d.ts","sourceRoot":"","sources":["../../src/overlay/path-picker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAgB7C,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,IAAI,CAAC;CACnB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQnD;AAED,eAAO,MAAM,UAAU,iEAiLrB,CAAC"}
1
+ {"version":3,"file":"path-picker.d.ts","sourceRoot":"","sources":["../../src/overlay/path-picker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAiB7C,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,IAAI,CAAC;CACnB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQnD;AAED,eAAO,MAAM,UAAU,iEA6LrB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { defineComponent, h, nameOf, useEffect, useInput, useRuntime, useState, useTheme, } from '@textui/core';
1
+ import { defineComponent, h, nameOf, useEffect, useI18n, useInput, useRuntime, useState, useTheme, } from '@textui/core';
2
2
  import { TextInput } from '../control/index.js';
3
3
  import { Menu } from '../navigation/index.js';
4
4
  import { hint } from './shared.js';
@@ -17,6 +17,8 @@ export function parentOf(uri) {
17
17
  export const PathPicker = defineComponent('PathPicker', (props) => {
18
18
  const { start, wants = 'file', title, placeholder, visibleRows = 10, width = 60, onPick, onCancel, ...rest } = props;
19
19
  const theme = useTheme();
20
+ const i18n = useI18n();
21
+ const ellipsis = theme.glyphs.ellipsis;
20
22
  const runtime = useRuntime();
21
23
  const app = runtime.app();
22
24
  const [at, setAt] = useState(start);
@@ -63,7 +65,7 @@ export const PathPicker = defineComponent('PathPicker', (props) => {
63
65
  // child to press enter on and a hidden chord for it is a chord nobody
64
66
  // finds. It is first, since it is the answer most often wanted.
65
67
  ...(wants === 'directory'
66
- ? [{ id: '.', label: 'Use this folder', icon: theme.glyphs.check }]
68
+ ? [{ id: '.', label: i18n.t('textui.pathPicker.useFolder', undefined, 'Use this folder'), icon: theme.glyphs.check }]
67
69
  : []),
68
70
  ...(parent !== null ? [{ id: '..', label: '..', icon: theme.glyphs.chevronUp }] : []),
69
71
  ...shown.map((e) => ({
@@ -130,16 +132,18 @@ export const PathPicker = defineComponent('PathPicker', (props) => {
130
132
  }
131
133
  return false;
132
134
  }, { global: true });
133
- const move = `${theme.glyphs.arrowUp}${theme.glyphs.arrowDown} move`;
135
+ const move = i18n.t('textui.pathPicker.hint.move', { arrows: `${theme.glyphs.arrowUp}${theme.glyphs.arrowDown}` }, '{arrows} move');
134
136
  return h('box', {
135
137
  role: 'dialog',
136
- label: title ?? 'Choose',
138
+ label: title ?? i18n.t('textui.pathPicker.label', undefined, 'Choose'),
137
139
  border: theme.border,
138
140
  bg: 'overlay',
139
141
  width,
140
142
  direction: 'column',
141
143
  ...(theme.border === 'none' ? { padding: { left: 1, right: 1 } } : {}),
142
- title: ` ${title ?? (wants === 'directory' ? 'choose a folder' : 'choose a file')} `,
144
+ title: ` ${title ?? (wants === 'directory'
145
+ ? i18n.t('textui.pathPicker.titleFolder', undefined, 'choose a folder')
146
+ : i18n.t('textui.pathPicker.titleFile', undefined, 'choose a file'))} `,
143
147
  ...rest,
144
148
  },
145
149
  // Where you are. A column of bare names with no header is a list you can
@@ -161,7 +165,7 @@ export const PathPicker = defineComponent('PathPicker', (props) => {
161
165
  */
162
166
  onEdge: (edge) => { if (edge === 'start')
163
167
  up(); },
164
- placeholder: placeholder ?? `Filter${theme.glyphs.ellipsis}`,
168
+ placeholder: placeholder ?? i18n.t('textui.pathPicker.placeholder', { ellipsis }, 'Filter{ellipsis}'),
165
169
  search: true,
166
170
  autoFocus: true,
167
171
  border: 'none',
@@ -183,16 +187,20 @@ export const PathPicker = defineComponent('PathPicker', (props) => {
183
187
  shown.length === 0
184
188
  ? h('text', {
185
189
  content: loading
186
- ? `Reading${theme.glyphs.ellipsis}`
187
- : (q === '' ? 'Nothing here.' : 'Nothing matches.'),
190
+ ? i18n.t('textui.pathPicker.reading', { ellipsis }, 'Reading{ellipsis}')
191
+ : (q === ''
192
+ ? i18n.t('textui.pathPicker.empty', undefined, 'Nothing here.')
193
+ : i18n.t('textui.pathPicker.noMatch', undefined, 'Nothing matches.')),
188
194
  fg: 'muted',
189
195
  })
190
196
  : null, h('box', { height: 1, fill: theme.borderChars().top, fg: 'borderSubtle' }), h('text', {
191
197
  content: hint(theme, [
192
198
  move,
193
- wants === 'directory' ? 'enter open' : 'enter choose',
194
- `${theme.glyphs.chevronLeft} up`,
195
- 'esc cancel',
199
+ wants === 'directory'
200
+ ? i18n.t('textui.pathPicker.hint.open', undefined, 'enter open')
201
+ : i18n.t('textui.pathPicker.hint.choose', undefined, 'enter choose'),
202
+ i18n.t('textui.pathPicker.hint.up', { glyph: theme.glyphs.chevronLeft }, '{glyph} up'),
203
+ i18n.t('textui.pathPicker.hint.cancel', undefined, 'esc cancel'),
196
204
  ]),
197
205
  fg: 'subtle',
198
206
  truncate: 'end',
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-dialog.d.ts","sourceRoot":"","sources":["../../src/overlay/prompt-dialog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C,MAAM,WAAW,iBAAkB,SAAQ,QAAQ;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,IAAI,IAAI,CAAC;CACnB;AAED,eAAO,MAAM,YAAY,mEA6BvB,CAAC"}
1
+ {"version":3,"file":"prompt-dialog.d.ts","sourceRoot":"","sources":["../../src/overlay/prompt-dialog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C,MAAM,WAAW,iBAAkB,SAAQ,QAAQ;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,IAAI,IAAI,CAAC;CACnB;AAED,eAAO,MAAM,YAAY,mEA8BvB,CAAC"}
@@ -1,16 +1,17 @@
1
- import { defineComponent, h, useState } from '@textui/core';
1
+ import { defineComponent, h, useI18n, useState } from '@textui/core';
2
2
  import { TextInput } from '../control/index.js';
3
3
  import { Dialog } from './dialog.js';
4
4
  export const PromptDialog = defineComponent('PromptDialog', (props) => {
5
5
  const { title, message, placeholder, initialValue = '', mask, onSubmit, onCancel, ...rest } = props;
6
+ const i18n = useI18n();
6
7
  const [value, setValue] = useState(initialValue);
7
8
  return h(Dialog, {
8
- title,
9
+ title: title ?? i18n.t('textui.promptDialog.title', undefined, 'Input'),
9
10
  width: 50,
10
11
  onClose: onCancel,
11
12
  actions: [
12
- { id: 'ok', label: 'OK', tone: 'primary', onPress: () => onSubmit?.(value) },
13
- { id: 'cancel', label: 'Cancel', onPress: onCancel },
13
+ { id: 'ok', label: i18n.t('textui.promptDialog.ok', undefined, 'OK'), tone: 'primary', onPress: () => onSubmit?.(value) },
14
+ { id: 'cancel', label: i18n.t('textui.promptDialog.cancel', undefined, 'Cancel'), onPress: onCancel },
14
15
  ],
15
16
  ...rest,
16
17
  }, message ? h('text', { content: message, wrap: 'word' }) : null, h(TextInput, {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/panel/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAEX,iBAAiB,EACjB,aAAa,EAEb,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAalE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,cAAc,qBAAqB,CAAC;AAEpC,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEvD;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAEjE;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAEpF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAE/D;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAExE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAElF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE9E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE1F;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,IAAI,CAMN;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,IAAI,WAAW,GAAG,IAAI,CAE7C;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,QAAQ,EAAE,CAAC,GACV,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CA0BlC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAUxD;AAgDD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,GAAG,iBAAiB,EAAE,CAsFjE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/panel/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAEX,iBAAiB,EACjB,aAAa,EAEb,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAalE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,cAAc,qBAAqB,CAAC;AAEpC,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEvD;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAEjE;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAEpF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAE/D;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAExE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAElF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE9E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE1F;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,IAAI,CAMN;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,IAAI,WAAW,GAAG,IAAI,CAE7C;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,QAAQ,EAAE,CAAC,GACV,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CA0BlC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAUxD;AAgDD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,GAAG,iBAAiB,EAAE,CAwFjE"}
@@ -182,18 +182,19 @@ export function panelCommands(app) {
182
182
  * to draw it.
183
183
  */
184
184
  const targetUri = (args, id) => args.uri ?? (id === null ? null : panelUri(app.store, id));
185
+ const category = app.i18n.t('textui.panel.category', undefined, 'View');
185
186
  return [
186
187
  {
187
188
  id: 'panel.openWith',
188
- title: 'Open With…',
189
- category: 'View',
189
+ title: app.i18n.t('textui.panel.openWith', undefined, 'Open With…'),
190
+ category,
190
191
  slots: ['palette'],
191
192
  when: PANEL_PATH,
192
193
  args: [{
193
194
  name: 'renderer',
194
195
  type: 'string',
195
196
  required: true,
196
- description: 'How to show this resource',
197
+ description: app.i18n.t('textui.panel.renderer', undefined, 'How to show this resource'),
197
198
  choices: async () => {
198
199
  const id = activePanel(app.store);
199
200
  return (await choicesFor(app, id === null ? null : panelUri(app.store, id)))
@@ -210,8 +211,8 @@ export function panelCommands(app) {
210
211
  },
211
212
  {
212
213
  id: 'panel.nextRenderer',
213
- title: 'Next View',
214
- category: 'View',
214
+ title: app.i18n.t('textui.panel.nextView', undefined, 'Next View'),
215
+ category,
215
216
  slots: ['palette'],
216
217
  when: PANEL_PATH,
217
218
  run: async (args, ctx) => {
@@ -230,8 +231,8 @@ export function panelCommands(app) {
230
231
  },
231
232
  {
232
233
  id: 'panel.toggleEdit',
233
- title: 'Edit / View',
234
- category: 'View',
234
+ title: app.i18n.t('textui.panel.toggleEdit', undefined, 'Edit / View'),
235
+ category,
235
236
  slots: ['palette'],
236
237
  when: PANEL_PATH,
237
238
  run: async (args, ctx) => {
@@ -1 +1 @@
1
- {"version":3,"file":"resource-panel.d.ts","sourceRoot":"","sources":["../../src/panel/resource-panel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EACR,mBAAmB,EAEnB,QAAQ,EACR,0BAA0B,EAC3B,MAAM,cAAc,CAAC;AAetB,sCAAsC;AACtC,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC,sCAAsC;AACtC,eAAO,MAAM,UAAU,EAAmB,WAAW,CAAC;AAEtD,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEjD;AAED,mDAAmD;AACnD,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAElE;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEpD;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEtD;AAED,MAAM,WAAW,SAAS;IACxB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,0BAA0B,EAAE,GACtC,0BAA0B,GAAG,IAAI,CAEnC;AAID,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAID,MAAM,WAAW,kBAAmB,SAAQ,QAAQ;IAClD;;;;;;OAMG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,oEAsJxB,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,mBAAmB,EAOjD,CAAC"}
1
+ {"version":3,"file":"resource-panel.d.ts","sourceRoot":"","sources":["../../src/panel/resource-panel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EACR,mBAAmB,EAEnB,QAAQ,EACR,0BAA0B,EAC3B,MAAM,cAAc,CAAC;AAgBtB,sCAAsC;AACtC,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC,sCAAsC;AACtC,eAAO,MAAM,UAAU,EAAmB,WAAW,CAAC;AAEtD,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEjD;AAED,mDAAmD;AACnD,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAElE;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEpD;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEtD;AAED,MAAM,WAAW,SAAS;IACxB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,0BAA0B,EAAE,GACtC,0BAA0B,GAAG,IAAI,CAEnC;AAID,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAID,MAAM,WAAW,kBAAmB,SAAQ,QAAQ;IAClD;;;;;;OAMG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,oEA0JxB,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,mBAAmB,EAOjD,CAAC"}